diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 4c468a8..9c027f0 100644 *** a/src/bin/psql/tab-complete.c --- b/src/bin/psql/tab-complete.c *************** static const SchemaQuery Query_for_list_ *** 303,308 **** --- 303,359 ---- NULL }; + /* The bit masks for the following three functions come from + * src/include/catalog/pg_trigger.h. + */ + static const SchemaQuery Query_for_list_of_insertables = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS " + "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL + }; + + static const SchemaQuery Query_for_list_of_deletables = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS " + "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL + }; + + static const SchemaQuery Query_for_list_of_updatables = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS " + "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL + }; + static const SchemaQuery Query_for_list_of_tisv = { /* catname */ "pg_catalog.pg_class c", *************** static const SchemaQuery Query_for_list_ *** 333,338 **** --- 384,404 ---- NULL }; + static const SchemaQuery Query_for_list_of_tv = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "c.relkind IN ('r', 'v')", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL + }; + static const SchemaQuery Query_for_list_of_views = { /* catname */ "pg_catalog.pg_class c", *************** psql_completion(char *text, int start, i *** 630,636 **** *prev2_wd, *prev3_wd, *prev4_wd, ! *prev5_wd; static const char *const sql_commands[] = { "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", --- 696,703 ---- *prev2_wd, *prev3_wd, *prev4_wd, ! *prev5_wd, ! *prev6_wd; static const char *const sql_commands[] = { "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", *************** psql_completion(char *text, int start, i *** 669,675 **** completion_info_charp2 = NULL; /* ! * Scan the input line before our current position for the last five * words. According to those we'll make some smart decisions on what the * user is probably intending to type. TODO: Use strtokx() to do this. */ --- 736,742 ---- completion_info_charp2 = NULL; /* ! * Scan the input line before our current position for the last six * words. According to those we'll make some smart decisions on what the * user is probably intending to type. TODO: Use strtokx() to do this. */ *************** psql_completion(char *text, int start, i *** 678,683 **** --- 745,751 ---- prev3_wd = previous_word(start, 2); prev4_wd = previous_word(start, 3); prev5_wd = previous_word(start, 4); + prev6_wd = previous_word(start, 5); /* If a backslash command was started, continue */ if (text[0] == '\\') *************** psql_completion(char *text, int start, i *** 974,987 **** COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger); } - /* - * If we have ALTER TRIGGER ON, then add the correct tablename - */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - /* ALTER TRIGGER ON */ else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && pg_strcasecmp(prev2_wd, "ON") == 0) --- 1042,1047 ---- *************** psql_completion(char *text, int start, i *** 1593,1599 **** else if (pg_strcasecmp(prev4_wd, "AS") == 0 && pg_strcasecmp(prev3_wd, "ON") == 0 && pg_strcasecmp(prev_wd, "TO") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* CREATE SERVER */ else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && --- 1653,1659 ---- else if (pg_strcasecmp(prev4_wd, "AS") == 0 && pg_strcasecmp(prev3_wd, "ON") == 0 && pg_strcasecmp(prev_wd, "TO") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tv, NULL); /* CREATE SERVER */ else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && *************** psql_completion(char *text, int start, i *** 1655,1669 **** pg_strcasecmp(prev2_wd, "TRIGGER") == 0) { static const char *const list_CREATETRIGGER[] = ! {"BEFORE", "AFTER", NULL}; COMPLETE_WITH_LIST(list_CREATETRIGGER); } /* complete CREATE TRIGGER BEFORE,AFTER with an event */ ! else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && pg_strcasecmp(prev3_wd, "TRIGGER") == 0 && (pg_strcasecmp(prev_wd, "BEFORE") == 0 || ! pg_strcasecmp(prev_wd, "AFTER") == 0)) { static const char *const list_CREATETRIGGER_EVENTS[] = {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL}; --- 1715,1734 ---- pg_strcasecmp(prev2_wd, "TRIGGER") == 0) { static const char *const list_CREATETRIGGER[] = ! {"BEFORE", "AFTER", "INSTEAD OF", NULL}; COMPLETE_WITH_LIST(list_CREATETRIGGER); } /* complete CREATE TRIGGER BEFORE,AFTER with an event */ ! else if ((pg_strcasecmp(prev4_wd, "CREATE") == 0 && pg_strcasecmp(prev3_wd, "TRIGGER") == 0 && (pg_strcasecmp(prev_wd, "BEFORE") == 0 || ! pg_strcasecmp(prev_wd, "AFTER") == 0)) || ! (pg_strcasecmp(prev5_wd, "CREATE") == 0 && ! pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && ! pg_strcasecmp(prev2_wd, "INSTEAD") == 0 && ! pg_strcasecmp(prev_wd, "OF") == 0)) ! { static const char *const list_CREATETRIGGER_EVENTS[] = {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL}; *************** psql_completion(char *text, int start, i *** 1671,1680 **** COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS); } /* complete CREATE TRIGGER BEFORE,AFTER sth with OR,ON */ ! else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && (pg_strcasecmp(prev2_wd, "BEFORE") == 0 || ! pg_strcasecmp(prev2_wd, "AFTER") == 0)) { static const char *const list_CREATETRIGGER2[] = {"ON", "OR", NULL}; --- 1736,1749 ---- COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS); } /* complete CREATE TRIGGER BEFORE,AFTER sth with OR,ON */ ! else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 && pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && (pg_strcasecmp(prev2_wd, "BEFORE") == 0 || ! pg_strcasecmp(prev2_wd, "AFTER") == 0)) || ! (pg_strcasecmp(prev6_wd, "CREATE") == 0 && ! pg_strcasecmp(prev5_wd, "TRIGGER") == 0 && ! (pg_strcasecmp(prev3_wd, "INSTEAD") == 0 && ! (pg_strcasecmp(prev2_wd, "OF") == 0)))) { static const char *const list_CREATETRIGGER2[] = {"ON", "OR", NULL}; *************** psql_completion(char *text, int start, i *** 1691,1696 **** --- 1760,1770 ---- pg_strcasecmp(prev3_wd, "AFTER") == 0) && pg_strcasecmp(prev_wd, "ON") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + else if (pg_strcasecmp(prev6_wd, "TRIGGER") == 0 && + pg_strcasecmp(prev4_wd, "INSTEAD") == 0 && + pg_strcasecmp(prev3_wd, "OF") == 0 && + pg_strcasecmp(prev_wd, "ON") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */ else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0) COMPLETE_WITH_CONST("PROCEDURE"); *************** psql_completion(char *text, int start, i *** 1778,1784 **** /* Complete DELETE FROM with a list of tables */ else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 && pg_strcasecmp(prev_wd, "FROM") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* Complete DELETE FROM */ else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 && pg_strcasecmp(prev2_wd, "FROM") == 0) --- 1852,1858 ---- /* Complete DELETE FROM with a list of tables */ else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 && pg_strcasecmp(prev_wd, "FROM") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL); /* Complete DELETE FROM
*/ else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 && pg_strcasecmp(prev2_wd, "FROM") == 0) *************** psql_completion(char *text, int start, i *** 2066,2072 **** /* Complete INSERT INTO with table names */ else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 && pg_strcasecmp(prev_wd, "INTO") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* Complete "INSERT INTO
(" with attribute names */ else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 && pg_strcasecmp(prev3_wd, "INTO") == 0 && --- 2140,2146 ---- /* Complete INSERT INTO with table names */ else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 && pg_strcasecmp(prev_wd, "INTO") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL); /* Complete "INSERT INTO
(" with attribute names */ else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 && pg_strcasecmp(prev3_wd, "INTO") == 0 && *************** psql_completion(char *text, int start, i *** 2423,2429 **** /* UPDATE */ /* If prev. word is UPDATE suggest a list of tables */ else if (pg_strcasecmp(prev_wd, "UPDATE") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* Complete UPDATE
with "SET" */ else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0) COMPLETE_WITH_CONST("SET"); --- 2497,2503 ---- /* UPDATE */ /* If prev. word is UPDATE suggest a list of tables */ else if (pg_strcasecmp(prev_wd, "UPDATE") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL); /* Complete UPDATE
with "SET" */ else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0) COMPLETE_WITH_CONST("SET");