diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 816deda..08029f9 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -228,6 +228,62 @@ do { \ matches = completion_matches(text, complete_from_query); \ } while (0) +#define COMPLETE_WITH_LIST2(s1, s2) \ +do { \ + static const char *const list[] = { s1, s2, NULL }; \ + completion_charpp = list; \ + completion_case_sensitive = false; \ + matches = completion_matches(text, complete_from_list); \ +} while (0) + +#define COMPLETE_WITH_LIST3(s1, s2, s3) \ +do { \ + static const char *const list[] = { s1, s2, s3, NULL }; \ + completion_charpp = list; \ + completion_case_sensitive = false; \ + matches = completion_matches(text, complete_from_list); \ +} while (0) + +#define COMPLETE_WITH_LIST4(s1, s2, s3, s4) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, NULL }; \ + completion_charpp = list; \ + completion_case_sensitive = false; \ + matches = completion_matches(text, complete_from_list); \ +} while (0) + +#define COMPLETE_WITH_LIST5(s1, s2, s3, s4, s5) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, NULL }; \ + completion_charpp = list; \ + completion_case_sensitive = false; \ + matches = completion_matches(text, complete_from_list); \ +} while (0) + +#define COMPLETE_WITH_LIST6(s1, s2, s3, s4, s5, s6) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, s6, NULL }; \ + completion_charpp = list; \ + completion_case_sensitive = false; \ + matches = completion_matches(text, complete_from_list); \ +} while (0) + +#define COMPLETE_WITH_LIST7(s1, s2, s3, s4, s5, s6, s7) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, NULL }; \ + completion_charpp = list; \ + completion_case_sensitive = false; \ + matches = completion_matches(text, complete_from_list); \ +} while (0) + +#define COMPLETE_WITH_LIST8(s1, s2, s3, s4, s5, s6, s7, s8) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, NULL }; \ + completion_charpp = list; \ + completion_case_sensitive = false; \ + matches = completion_matches(text, complete_from_list); \ +} while (0) + /* * Assembly instructions for schema queries */ @@ -872,6 +928,59 @@ initialize_readline(void) */ } +/* + * Check if 'word' matches any of the '|'-separated strings in 'pattern', + * using case-insensitive comparison, or the pattern is NULL indicating a + * wildcard that matches any word. + */ +static bool +word_matches(const char *pattern, const char *word) +{ + const char *c = word; + + /* + * NULL means match any word, but we don't match empty strings because + * they indicate that the [END_]MATCHESn macro is trying to look before + * the start of the user's input string. + */ + if (pattern == NULL) + return word[0] != '\0'; + + while (*pattern != '\0') + { + if (*c == '\0' && *pattern == '|') + return true; + else if (*c == '\0' || tolower(*pattern) != tolower(*c)) + { + /* Skip to next word in pattern and rewind word. */ + while (*pattern != '\0' && *pattern != '|') + ++pattern; + if (*pattern == '\0') + return false; + else + ++pattern; + c = word; + } + else + { + ++pattern; + ++c; + } + } + + return *c == '\0'; +} + +/* + * Check if the final character of 's' is 'c'. + */ +static bool +ends_with(const char *s, char c) +{ + size_t length = strlen(s); + + return length > 0 && s[length - 1] == c; +} /* * The completion function. @@ -898,6 +1007,66 @@ psql_completion(const char *text, int start, int end) #define prev5_wd (previous_words[4]) #define prev6_wd (previous_words[5]) +#define ANY NULL + +#define TAIL_MATCHES1(p1) \ +(word_matches(p1, prev_wd)) \ + +#define TAIL_MATCHES2(p2, p1) \ +(word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd)) + +#define TAIL_MATCHES3(p3, p2, p1) \ +(word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd)) + +#define TAIL_MATCHES4(p4, p3, p2, p1) \ +(word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd)) + +#define TAIL_MATCHES5(p5, p4, p3, p2, p1) \ +(word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd)) + +#define TAIL_MATCHES6(p6, p5, p4, p3, p2, p1) \ +(word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd) && \ + word_matches(p6, prev6_wd)) + +#define TAIL_MATCHES7(p7, p6, p5, p4, p3, p2, p1) \ +(word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd) && \ + word_matches(p6, prev6_wd) && \ + word_matches(p7, prev7_wd)) + +#define TAIL_MATCHES8(p8, p7, p6, p5, p4, p3, p2, p1) \ +(word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd) && \ + word_matches(p6, prev6_wd) && \ + word_matches(p7, prev7_wd) && \ + word_matches(p8, prev8_wd)) + +#define MATCHES1(p1) TAIL_MATCHES2("", p1) +#define MATCHES2(p1, p2) TAIL_MATCHES3("", p1, p2) +#define MATCHES3(p1, p2, p3) TAIL_MATCHES4("", p1, p2, p3) +#define MATCHES4(p1, p2, p3, p4) TAIL_MATCHES5("", p1, p2, p3, p4) +#define MATCHES5(p1, p2, p3, p4, p5) TAIL_MATCHES6("", p1, p2, p3, p4, p5) + static const char *const sql_commands[] = { "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", @@ -931,6 +1100,22 @@ psql_completion(const char *text, int start, int end) rl_completion_append_character = ' '; #endif + /* TODO:TM -- begin temporary, not part of the patch! */ + Assert(!word_matches(NULL, "")); + Assert(word_matches(NULL, "walrus")); + Assert(word_matches("", "")); + Assert(word_matches("a", "A")); + Assert(word_matches("ab", "Ab")); + Assert(!word_matches("ab", "b")); + Assert(word_matches("a|b", "b")); + Assert(word_matches("a|b|c", "b")); + Assert(!word_matches("a|b|c", "d")); + Assert(!word_matches("a|b|c", "bb")); + Assert(word_matches("|foo", "")); + Assert(word_matches("foo|", "")); + Assert(!word_matches("foo", "")); + /* TODO:TM -- end temporary */ + /* Clear a few things. */ completion_charp = NULL; completion_charpp = NULL; @@ -960,36 +1145,31 @@ psql_completion(const char *text, int start, int end) } /* If no previous word, suggest one of the basic sql commands */ - else if (prev_wd[0] == '\0') + else if (TAIL_MATCHES1("")) COMPLETE_WITH_LIST(sql_commands); /* CREATE */ /* complete with something you can create */ - else if (pg_strcasecmp(prev_wd, "CREATE") == 0) + else if (TAIL_MATCHES1("CREATE")) matches = completion_matches(text, create_command_generator); /* DROP, but not DROP embedded in other commands */ /* complete with something you can drop */ - else if (pg_strcasecmp(prev_wd, "DROP") == 0 && - prev2_wd[0] == '\0') + else if (MATCHES1("DROP")) matches = completion_matches(text, drop_command_generator); /* ALTER */ /* ALTER TABLE */ - else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 && - pg_strcasecmp(prev_wd, "TABLE") == 0) - { + else if (TAIL_MATCHES2("ALTER", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "UNION SELECT 'ALL IN TABLESPACE'"); - } /* * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're * in ALTER TABLE sth ALTER */ - else if (pg_strcasecmp(prev_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLE") != 0) + else if (TAIL_MATCHES1("ALTER") && !TAIL_MATCHES3("TABLE", ANY, "ALTER")) { static const char *const list_ALTER[] = {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", @@ -1002,153 +1182,67 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTER); } /* ALTER TABLE,INDEX,MATERIALIZED VIEW xxx ALL IN TABLESPACE xxx */ - else if (pg_strcasecmp(prev4_wd, "ALL") == 0 && - pg_strcasecmp(prev3_wd, "IN") == 0 && - pg_strcasecmp(prev2_wd, "TABLESPACE") == 0) - { - static const char *const list_ALTERALLINTSPC[] = - {"SET TABLESPACE", "OWNED BY", NULL}; - - COMPLETE_WITH_LIST(list_ALTERALLINTSPC); - } + else if (TAIL_MATCHES4("ALL", "IN", "TABLESPACE", ANY)) + COMPLETE_WITH_LIST2("SET TABLESPACE", "OWNED BY"); /* ALTER TABLE,INDEX,MATERIALIZED VIEW xxx ALL IN TABLESPACE xxx OWNED BY */ - else if (pg_strcasecmp(prev6_wd, "ALL") == 0 && - pg_strcasecmp(prev5_wd, "IN") == 0 && - pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 && - pg_strcasecmp(prev2_wd, "OWNED") == 0 && - pg_strcasecmp(prev4_wd, "BY") == 0) - { + else if (TAIL_MATCHES6("ALL", "IN", "TABLESPACE", ANY, "OWNED", "BY")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); - } /* ALTER AGGREGATE,FUNCTION */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 || - pg_strcasecmp(prev2_wd, "FUNCTION") == 0)) + else if (TAIL_MATCHES3("ALTER", "AGGREGATE|FUNCTION", ANY)) COMPLETE_WITH_CONST("("); /* ALTER AGGREGATE,FUNCTION (...) */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 || - pg_strcasecmp(prev3_wd, "FUNCTION") == 0)) + else if (TAIL_MATCHES4("ALTER", "AGGREGATE|FUNCTION", ANY, ANY)) { - if (prev_wd[strlen(prev_wd) - 1] == ')') - { - static const char *const list_ALTERAGG[] = - {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERAGG); - } + if (ends_with(prev_wd, ')')) + COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA"); else COMPLETE_WITH_FUNCTION_ARG(prev2_wd); } /* ALTER SCHEMA */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "SCHEMA") == 0) - { - static const char *const list_ALTERGEN[] = - {"OWNER TO", "RENAME TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERGEN); - } + else if (TAIL_MATCHES3("ALTER", "SCHEMA", ANY)) + COMPLETE_WITH_LIST2("OWNER TO", "RENAME TO"); /* ALTER COLLATION */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "COLLATION") == 0) - { - static const char *const list_ALTERGEN[] = - {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERGEN); - } + else if (TAIL_MATCHES3("ALTER", "COLLATION", ANY)) + COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA"); /* ALTER CONVERSION */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "CONVERSION") == 0) - { - static const char *const list_ALTERGEN[] = - {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERGEN); - } + else if (TAIL_MATCHES3("ALTER", "CONVERSION", ANY)) + COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA"); /* ALTER DATABASE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "DATABASE") == 0) - { - static const char *const list_ALTERDATABASE[] = - {"RESET", "SET", "OWNER TO", "RENAME TO", "IS_TEMPLATE", - "ALLOW_CONNECTIONS", "CONNECTION LIMIT", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDATABASE); - } + else if (TAIL_MATCHES3("ALTER", "DATABASE", ANY)) + COMPLETE_WITH_LIST7("RESET", "SET", "OWNER TO", "RENAME TO", + "IS_TEMPLATE", "ALLOW_CONNECTIONS", + "CONNECTION LIMIT"); /* ALTER EVENT TRIGGER */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "EVENT") == 0 && - pg_strcasecmp(prev_wd, "TRIGGER") == 0) - { + else if (TAIL_MATCHES3("ALTER", "EVENT", "TRIGGER")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers); - } /* ALTER EVENT TRIGGER */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "EVENT") == 0 && - pg_strcasecmp(prev2_wd, "TRIGGER") == 0) - { - static const char *const list_ALTER_EVENT_TRIGGER[] = - {"DISABLE", "ENABLE", "OWNER TO", "RENAME TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER); - } + else if (TAIL_MATCHES4("ALTER", "EVENT", "TRIGGER", ANY)) + COMPLETE_WITH_LIST4("DISABLE", "ENABLE", "OWNER TO", "RENAME TO"); /* ALTER EVENT TRIGGER ENABLE */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "EVENT") == 0 && - pg_strcasecmp(prev3_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev_wd, "ENABLE") == 0) - { - static const char *const list_ALTER_EVENT_TRIGGER_ENABLE[] = - {"REPLICA", "ALWAYS", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER_ENABLE); - } + else if (TAIL_MATCHES5("ALTER", "EVENT", "TRIGGER", ANY, "ENABLE")) + COMPLETE_WITH_LIST2("REPLICA", "ALWAYS"); /* ALTER EXTENSION */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "EXTENSION") == 0) - { - static const char *const list_ALTEREXTENSION[] = - {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTEREXTENSION); - } + else if (TAIL_MATCHES3("ALTER", "EXTENSION", ANY)) + COMPLETE_WITH_LIST4("ADD", "DROP", "UPDATE", "SET SCHEMA"); /* ALTER FOREIGN */ - else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const list_ALTER_FOREIGN[] = - {"DATA WRAPPER", "TABLE", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_FOREIGN); - } + else if (TAIL_MATCHES2("ALTER", "FOREIGN")) + COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); /* ALTER FOREIGN DATA WRAPPER */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev3_wd, "DATA") == 0 && - pg_strcasecmp(prev2_wd, "WRAPPER") == 0) - { - static const char *const list_ALTER_FDW[] = - {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_FDW); - } + else if (TAIL_MATCHES5("ALTER", "FOREIGN", "DATA", "WRAPPER", ANY)) + COMPLETE_WITH_LIST4("HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO"); /* ALTER FOREIGN TABLE */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev2_wd, "TABLE") == 0) + else if (TAIL_MATCHES4("ALTER", "FOREIGN", "TABLE", ANY)) { static const char *const list_ALTER_FOREIGN_TABLE[] = {"ADD", "ALTER", "DISABLE TRIGGER", "DROP", "ENABLE", "INHERIT", @@ -1159,84 +1253,37 @@ psql_completion(const char *text, int start, int end) } /* ALTER INDEX */ - else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 && - pg_strcasecmp(prev_wd, "INDEX") == 0) - { + else if (TAIL_MATCHES2("ALTER", "INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, "UNION SELECT 'ALL IN TABLESPACE'"); - } /* ALTER INDEX */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "INDEX") == 0) - { - static const char *const list_ALTERINDEX[] = - {"OWNER TO", "RENAME TO", "SET", "RESET", NULL}; - - COMPLETE_WITH_LIST(list_ALTERINDEX); - } + else if (TAIL_MATCHES3("ALTER", "INDEX", ANY)) + COMPLETE_WITH_LIST4("OWNER TO", "RENAME TO", "SET", "RESET"); /* ALTER INDEX SET */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "INDEX") == 0 && - pg_strcasecmp(prev_wd, "SET") == 0) - { - static const char *const list_ALTERINDEXSET[] = - {"(", "TABLESPACE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERINDEXSET); - } + else if (TAIL_MATCHES4("ALTER", "INDEX", ANY, "SET")) + COMPLETE_WITH_LIST2("(", "TABLESPACE"); /* ALTER INDEX RESET */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "INDEX") == 0 && - pg_strcasecmp(prev_wd, "RESET") == 0) + else if (TAIL_MATCHES4("ALTER", "INDEX", ANY, "RESET")) COMPLETE_WITH_CONST("("); /* ALTER INDEX SET|RESET ( */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "INDEX") == 0 && - (pg_strcasecmp(prev2_wd, "SET") == 0 || - pg_strcasecmp(prev2_wd, "RESET") == 0) && - pg_strcasecmp(prev_wd, "(") == 0) - { - static const char *const list_INDEXOPTIONS[] = - {"fillfactor", "fastupdate", "gin_pending_list_limit", NULL}; - - COMPLETE_WITH_LIST(list_INDEXOPTIONS); - } + else if (TAIL_MATCHES5("ALTER", "INDEX", ANY, "SET|RESET", "(")) + COMPLETE_WITH_LIST3("fillfactor", "fastupdate", "gin_pending_list_limit"); /* ALTER LANGUAGE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "LANGUAGE") == 0) - { - static const char *const list_ALTERLANGUAGE[] = - {"OWNER TO", "RENAME TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERLANGUAGE); - } + else if (TAIL_MATCHES3("ALTER", "LANGUAGE", ANY)) + COMPLETE_WITH_LIST2("OWNER_TO", "RENAME TO"); /* ALTER LARGE OBJECT */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "LARGE") == 0 && - pg_strcasecmp(prev2_wd, "OBJECT") == 0) - { - static const char *const list_ALTERLARGEOBJECT[] = - {"OWNER TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT); - } + else if (TAIL_MATCHES4("ALTER", "LARGE", "OBJECT", ANY)) + COMPLETE_WITH_CONST("OWNER TO"); /* ALTER MATERIALIZED VIEW */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev_wd, "VIEW") == 0) - { + else if (TAIL_MATCHES3("ALTER", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, "UNION SELECT 'ALL IN TABLESPACE'"); - } /* ALTER USER,ROLE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) && - (pg_strcasecmp(prev2_wd, "USER") == 0 || - pg_strcasecmp(prev2_wd, "ROLE") == 0)) + else if (TAIL_MATCHES3("ALTER", "USER|ROLE", ANY) && !TAIL_MATCHES2("USER", "MAPPING")) { static const char *const list_ALTERUSER[] = {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", @@ -1250,10 +1297,7 @@ psql_completion(const char *text, int start, int end) } /* ALTER USER,ROLE WITH */ - else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 && - (pg_strcasecmp(prev3_wd, "USER") == 0 || - pg_strcasecmp(prev3_wd, "ROLE") == 0) && - pg_strcasecmp(prev_wd, "WITH") == 0)) + else if (TAIL_MATCHES4("ALTER", "USER|ROLE", ANY, "WITH")) { /* Similar to the above, but don't complete "WITH" again. */ static const char *const list_ALTERUSER_WITH[] = @@ -1268,78 +1312,32 @@ psql_completion(const char *text, int start, int end) } /* complete ALTER USER,ROLE ENCRYPTED,UNENCRYPTED with PASSWORD */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) && - (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0)) - { + else if (TAIL_MATCHES4("ALTER", "USER|ROLE", ANY, "ENCRYPTED|UNENCRYPTED")) COMPLETE_WITH_CONST("PASSWORD"); - } /* ALTER DEFAULT PRIVILEGES */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "DEFAULT") == 0 && - pg_strcasecmp(prev_wd, "PRIVILEGES") == 0) - { - static const char *const list_ALTER_DEFAULT_PRIVILEGES[] = - {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES); - } + else if (TAIL_MATCHES3("ALTER", "DEFAULT", "PRIVILEGES")) + COMPLETE_WITH_LIST3("FOR ROLE", "FOR USER", "IN SCHEMA"); /* ALTER DEFAULT PRIVILEGES FOR */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "DEFAULT") == 0 && - pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 && - pg_strcasecmp(prev_wd, "FOR") == 0) - { - static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] = - {"ROLE", "USER", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR); - } + else if (TAIL_MATCHES4("ALTER", "DEFAULT", "PRIVILEGES", "FOR")) + COMPLETE_WITH_LIST2("ROLE", "USER"); /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */ - else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 && - pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 && - (pg_strcasecmp(prev3_wd, "FOR") == 0 || - pg_strcasecmp(prev3_wd, "IN") == 0)) - { - static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] = - {"GRANT", "REVOKE", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST); - } + else if (TAIL_MATCHES5("DEFAULT", "PRIVILEGES", "FOR", "ROLE", ANY) || + TAIL_MATCHES5("DEFAULT", "PRIVILEGES", "IN", "SCHEMA", ANY)) + COMPLETE_WITH_LIST2("GRANT", "REVOKE"); /* ALTER DOMAIN */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "DOMAIN") == 0) - { - static const char *const list_ALTERDOMAIN[] = - {"ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDOMAIN); - } + else if (TAIL_MATCHES3("ALTER", "DOMAIN", ANY)) + COMPLETE_WITH_LIST6("ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT"); /* ALTER DOMAIN DROP */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "DOMAIN") == 0 && - pg_strcasecmp(prev_wd, "DROP") == 0) - { - static const char *const list_ALTERDOMAIN2[] = - {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDOMAIN2); - } + else if (TAIL_MATCHES4("ALTER", "DOMAIN", ANY, "DROP")) + COMPLETE_WITH_LIST3("CONSTRAINT", "DEFAULT", "NOT NULL"); /* ALTER DOMAIN DROP|RENAME|VALIDATE CONSTRAINT */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "DOMAIN") == 0 && - (pg_strcasecmp(prev2_wd, "DROP") == 0 || - pg_strcasecmp(prev2_wd, "RENAME") == 0 || - pg_strcasecmp(prev2_wd, "VALIDATE") == 0) && - pg_strcasecmp(prev_wd, "CONSTRAINT") == 0) + else if (TAIL_MATCHES5("ALTER", "DOMAIN", ANY, "DROP|RENAME|VALIDATE", "CONSTRAINT")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_constraint_of_type); } /* ALTER DOMAIN RENAME */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "DOMAIN") == 0 && - pg_strcasecmp(prev_wd, "RENAME") == 0) + else if (TAIL_MATCHES4("ALTER", "DOMAIN", ANY, "RENAME")) { static const char *const list_ALTERDOMAIN[] = {"CONSTRAINT", "TO", NULL}; @@ -1347,24 +1345,14 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTERDOMAIN); } /* ALTER DOMAIN RENAME CONSTRAINT */ - else if (pg_strcasecmp(prev5_wd, "DOMAIN") == 0 && - pg_strcasecmp(prev3_wd, "RENAME") == 0 && - pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) + else if (TAIL_MATCHES3("RENAME", "CONSTRAINT", ANY)) COMPLETE_WITH_CONST("TO"); /* ALTER DOMAIN SET */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "DOMAIN") == 0 && - pg_strcasecmp(prev_wd, "SET") == 0) - { - static const char *const list_ALTERDOMAIN3[] = - {"DEFAULT", "NOT NULL", "SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDOMAIN3); - } + else if (TAIL_MATCHES4("ALTER", "DOMAIN", ANY, "SET")) + COMPLETE_WITH_LIST3("DEFAULT", "NOT NULL", "SCHEMA"); /* ALTER SEQUENCE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "SEQUENCE") == 0) + else if (TAIL_MATCHES3("ALTER", "SEQUENCE", ANY)) { static const char *const list_ALTERSEQUENCE[] = {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE", @@ -1373,123 +1361,63 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTERSEQUENCE); } /* ALTER SEQUENCE NO */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 && - pg_strcasecmp(prev_wd, "NO") == 0) - { - static const char *const list_ALTERSEQUENCE2[] = - {"MINVALUE", "MAXVALUE", "CYCLE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERSEQUENCE2); - } + else if (TAIL_MATCHES4("ALTER", "SEQUEMCE", ANY, "NO")) + COMPLETE_WITH_LIST3("MINVALUE", "MAXVALUE", "CYCLE"); /* ALTER SERVER */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "SERVER") == 0) - { - static const char *const list_ALTER_SERVER[] = - {"VERSION", "OPTIONS", "OWNER TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_SERVER); - } + else if (TAIL_MATCHES3("ALTER", "SERVER", ANY)) + COMPLETE_WITH_LIST3("VERSION", "OPTIONS", "OWNER TO"); /* ALTER SYSTEM SET, RESET, RESET ALL */ - else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 && - pg_strcasecmp(prev_wd, "SYSTEM") == 0) - { - static const char *const list_ALTERSYSTEM[] = - {"SET", "RESET", NULL}; - - COMPLETE_WITH_LIST(list_ALTERSYSTEM); - } + else if (TAIL_MATCHES2("ALTER", "SYSTEM")) + COMPLETE_WITH_LIST2("SET", "RESET"); /* ALTER SYSTEM SET|RESET */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "SYSTEM") == 0 && - (pg_strcasecmp(prev_wd, "SET") == 0 || - pg_strcasecmp(prev_wd, "RESET") == 0)) + else if (TAIL_MATCHES4("ALTER", "SYSTEM", "SET|RESET", ANY)) COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars); /* ALTER VIEW */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "VIEW") == 0) - { - static const char *const list_ALTERVIEW[] = - {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERVIEW); - } + else if (TAIL_MATCHES3("ALTER", "VIEW", ANY)) + COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA"); /* ALTER MATERIALIZED VIEW */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev2_wd, "VIEW") == 0) - { - static const char *const list_ALTERMATVIEW[] = - {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERMATVIEW); - } + else if (TAIL_MATCHES4("ALTER", "MATERIALIZED", "VIEW", ANY)) + COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA"); /* ALTER POLICY ON */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "POLICY") == 0) + else if (TAIL_MATCHES3("ALTER", "POLICY", ANY)) COMPLETE_WITH_CONST("ON"); /* ALTER POLICY ON */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "POLICY") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES4("ALTER", "POLICY", ANY, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* ALTER POLICY ON
- show options */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "POLICY") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0) - { - static const char *const list_ALTERPOLICY[] = - {"RENAME TO", "TO", "USING", "WITH CHECK", NULL}; - - COMPLETE_WITH_LIST(list_ALTERPOLICY); - } + else if (TAIL_MATCHES5("ALTER", "POLICY", ANY, "ON", ANY)) + COMPLETE_WITH_LIST4("RENAME TO", "TO", "USING", "WITH CHECK"); /* ALTER POLICY ON
TO */ - else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 && - pg_strcasecmp(prev5_wd, "POLICY") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) + else if (TAIL_MATCHES6("ALTER", "POLICY", ANY, "ON", ANY, "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); /* ALTER POLICY ON
USING ( */ - else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 && - pg_strcasecmp(prev5_wd, "POLICY") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "USING") == 0) + else if (TAIL_MATCHES6("ALTER", "POLICY", ANY, "ON", ANY, "USING")) COMPLETE_WITH_CONST("("); /* ALTER POLICY ON
WITH CHECK ( */ - else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 && - pg_strcasecmp(prev4_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "WITH") == 0 && - pg_strcasecmp(prev_wd, "CHECK") == 0) + else if (TAIL_MATCHES6("POLICY", ANY, "ON", ANY, "WITH", "CHECK")) COMPLETE_WITH_CONST("("); /* ALTER RULE , add ON */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "RULE") == 0) + else if (TAIL_MATCHES3("ALTER", "RULE", ANY)) COMPLETE_WITH_CONST("ON"); /* If we have ALTER RULE ON, then add the correct tablename */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "RULE") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES4("ALTER", "RULE", ANY, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule); } /* ALTER RULE ON */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "RULE") == 0) + else if (TAIL_MATCHES5("ALTER", "RULE", ANY, "ON", ANY)) COMPLETE_WITH_CONST("RENAME TO"); /* ALTER TRIGGER , add ON */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TRIGGER") == 0) + else if (TAIL_MATCHES3("ALTER", "TRIGGER", ANY)) COMPLETE_WITH_CONST("ON"); - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TRIGGER") == 0) + else if (TAIL_MATCHES4("ALTER", "TRIGGER", ANY, ANY)) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger); @@ -1498,22 +1426,17 @@ psql_completion(const char *text, int start, int end) /* * 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) + else if (TAIL_MATCHES4("ALTER", "TRIGGER", ANY, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* ALTER TRIGGER ON */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0) + else if (TAIL_MATCHES5("ALTER", "TRIGGER", ANY, "ON", ANY)) COMPLETE_WITH_CONST("RENAME TO"); /* * If we detect ALTER TABLE , suggest sub commands */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TABLE") == 0) + else if (TAIL_MATCHES3("ALTER", "TABLE", ANY)) { static const char *const list_ALTER2[] = {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT", @@ -1523,279 +1446,135 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTER2); } /* ALTER TABLE xxx ENABLE */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "ENABLE") == 0) - { - static const char *const list_ALTERENABLE[] = - {"ALWAYS", "REPLICA", "ROW LEVEL SECURITY", "RULE", "TRIGGER", NULL}; - - COMPLETE_WITH_LIST(list_ALTERENABLE); - } - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "ENABLE") == 0 && - (pg_strcasecmp(prev_wd, "REPLICA") == 0 || - pg_strcasecmp(prev_wd, "ALWAYS") == 0)) - { - static const char *const list_ALTERENABLE2[] = - {"RULE", "TRIGGER", NULL}; - - COMPLETE_WITH_LIST(list_ALTERENABLE2); - } - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "ENABLE") == 0 && - pg_strcasecmp(prev_wd, "RULE") == 0) + else if (TAIL_MATCHES4("ALTER", "TABLE", ANY, "ENABLE")) + COMPLETE_WITH_LIST5("ALWAYS", "REPLICA", "ROW LEVEL SECURITY", "RULE", + "TRIGGER"); + else if (TAIL_MATCHES4("TABLE", ANY, "ENABLE", "REPLICA|ALWAYS")) + COMPLETE_WITH_LIST2("RULE", "TRIGGER"); + else if (TAIL_MATCHES5("ALTER", "TABLE", ANY, "ENABLE", "RULE")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_rule_of_table); } - else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 && - pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "ENABLE") == 0 && - pg_strcasecmp(prev_wd, "RULE") == 0) + else if (TAIL_MATCHES6("ALTER", "TABLE", ANY, "ENABLE", ANY, "RULE")) { completion_info_charp = prev4_wd; COMPLETE_WITH_QUERY(Query_for_rule_of_table); } - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "ENABLE") == 0 && - pg_strcasecmp(prev_wd, "TRIGGER") == 0) + else if (TAIL_MATCHES5("ALTER", "TABLE", ANY, "ENABLE", "TRIGGER")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_trigger_of_table); } - else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 && - pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "ENABLE") == 0 && - pg_strcasecmp(prev_wd, "TRIGGER") == 0) + else if (TAIL_MATCHES6("ALTER", "TABLE", ANY, "ENABLE", ANY, "TRIGGER")) { completion_info_charp = prev4_wd; COMPLETE_WITH_QUERY(Query_for_trigger_of_table); } /* ALTER TABLE xxx INHERIT */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "INHERIT") == 0) - { + else if (TAIL_MATCHES4("ALTER", "TABLE", ANY, "INHERIT")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); - } /* ALTER TABLE xxx NO INHERIT */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "NO") == 0 && - pg_strcasecmp(prev_wd, "INHERIT") == 0) - { + else if (TAIL_MATCHES5("ALTER", "TABLE", ANY, "NO", "INHERIT")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); - } /* ALTER TABLE xxx DISABLE */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "DISABLE") == 0) - { - static const char *const list_ALTERDISABLE[] = - {"ROW LEVEL SECURITY", "RULE", "TRIGGER", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDISABLE); - } - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "DISABLE") == 0 && - pg_strcasecmp(prev_wd, "RULE") == 0) + else if (TAIL_MATCHES4("ALTER", "TABLE", ANY, "DISABLE")) + COMPLETE_WITH_LIST3("ROW LEVEL SECURITY", "RULE", "TRIGGER"); + else if (TAIL_MATCHES5("ALTER", "TABLE", ANY, "DISABLE", "RULE")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_rule_of_table); } - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "DISABLE") == 0 && - pg_strcasecmp(prev_wd, "TRIGGER") == 0) + else if (TAIL_MATCHES5("ALTER", "TABLE", ANY, "DISABLE", "TRIGGER")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_trigger_of_table); } - else if (pg_strcasecmp(prev4_wd, "DISABLE") == 0 && - pg_strcasecmp(prev3_wd, "ROW") == 0 && - pg_strcasecmp(prev2_wd, "LEVEL") == 0 && - pg_strcasecmp(prev_wd, "SECURITY") == 0) - { - static const char *const list_DISABLERLS[] = - {"CASCADE", NULL}; - - COMPLETE_WITH_LIST(list_DISABLERLS); - } + else if (TAIL_MATCHES4("DISABLE", "ROW", "LEVEL", "SECURITY")) + COMPLETE_WITH_CONST("CASCADE"); /* ALTER TABLE xxx ALTER */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "ALTER") == 0) + else if (TAIL_MATCHES4("ALTER", "TABLE", ANY, "ALTER")) COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT'"); /* ALTER TABLE xxx RENAME */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "RENAME") == 0) + else if (TAIL_MATCHES4("ALTER", "TABLE", ANY, "RENAME")) COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'"); /* * If we have TABLE ALTER COLUMN|RENAME COLUMN, provide list of * columns */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - (pg_strcasecmp(prev2_wd, "ALTER") == 0 || - pg_strcasecmp(prev2_wd, "RENAME") == 0) && - pg_strcasecmp(prev_wd, "COLUMN") == 0) + else if (TAIL_MATCHES4("TABLE", ANY, "ALTER|RENAME", "COLUMN")) COMPLETE_WITH_ATTR(prev3_wd, ""); /* ALTER TABLE xxx RENAME yyy */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "RENAME") == 0 && - pg_strcasecmp(prev_wd, "CONSTRAINT") != 0 && - pg_strcasecmp(prev_wd, "TO") != 0) + else if (TAIL_MATCHES5("ALTER", "TABLE", ANY, "RENAME", ANY) && + !TAIL_MATCHES1("CONSTRAINT|TO")) COMPLETE_WITH_CONST("TO"); /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */ - else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "RENAME") == 0 && - (pg_strcasecmp(prev2_wd, "COLUMN") == 0 || - pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) && - pg_strcasecmp(prev_wd, "TO") != 0) + else if (TAIL_MATCHES6("ALTER", "TABLE", ANY, "RENAME", "COLUMN|CONSTRAINT", ANY) && + !TAIL_MATCHES1("TO")) COMPLETE_WITH_CONST("TO"); /* If we have TABLE DROP, provide COLUMN or CONSTRAINT */ - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "DROP") == 0) - { - static const char *const list_TABLEDROP[] = - {"COLUMN", "CONSTRAINT", NULL}; - - COMPLETE_WITH_LIST(list_TABLEDROP); - } + else if (TAIL_MATCHES3("TABLE", ANY, "DROP")) + COMPLETE_WITH_LIST2("COLUMN", "CONSTRAINT"); /* If we have ALTER TABLE DROP COLUMN, provide list of columns */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "DROP") == 0 && - pg_strcasecmp(prev_wd, "COLUMN") == 0) + else if (TAIL_MATCHES5("ALTER", "TABLE", ANY, "DROP", "COLUMN")) COMPLETE_WITH_ATTR(prev3_wd, ""); /* * If we have ALTER TABLE ALTER|DROP|RENAME|VALIDATE CONSTRAINT, * provide list of constraints */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLE") == 0 && - (pg_strcasecmp(prev2_wd, "ALTER") == 0 || - pg_strcasecmp(prev2_wd, "DROP") == 0 || - pg_strcasecmp(prev2_wd, "RENAME") == 0 || - pg_strcasecmp(prev2_wd, "VALIDATE") == 0) && - pg_strcasecmp(prev_wd, "CONSTRAINT") == 0) + else if (TAIL_MATCHES5("ALTER", "TABLE", ANY, "ALTER|DROP|RENAME|VALIDATE", "CONSTRAINT")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_constraint_of_table); } /* ALTER TABLE ALTER [COLUMN] */ - else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "COLUMN") == 0) || - (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "ALTER") == 0)) - { - static const char *const list_COLUMNALTER[] = - {"TYPE", "SET", "RESET", "DROP", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNALTER); - } + else if (TAIL_MATCHES3("ALTER", "COLUMN", ANY) || + TAIL_MATCHES4("TABLE", ANY, "ALTER", ANY)) + COMPLETE_WITH_LIST4("TYPE", "SET", "RESET", "DROP"); /* ALTER TABLE ALTER [COLUMN] SET */ - else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "COLUMN") == 0) || - (pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "ALTER") == 0)) && - pg_strcasecmp(prev_wd, "SET") == 0) - { - static const char *const list_COLUMNSET[] = - {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNSET); - } + else if (TAIL_MATCHES4("ALTER", "COLUMN", ANY, "SET") || + TAIL_MATCHES5("TABLE", ANY, "ALTER", ANY, "SET")) + COMPLETE_WITH_LIST5("(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE"); /* ALTER TABLE ALTER [COLUMN] SET ( */ - else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "COLUMN") == 0) || - pg_strcasecmp(prev4_wd, "ALTER") == 0) && - pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "(") == 0) - { - static const char *const list_COLUMNOPTIONS[] = - {"n_distinct", "n_distinct_inherited", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNOPTIONS); - } + else if (TAIL_MATCHES5("ALTER", "COLUMN", ANY, "SET", "(") || + TAIL_MATCHES4("ALTER", ANY, "SET", "(")) + COMPLETE_WITH_LIST2("n_distinct", "n_distinct_inherited"); /* ALTER TABLE ALTER [COLUMN] SET STORAGE */ - else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "COLUMN") == 0) || - pg_strcasecmp(prev4_wd, "ALTER") == 0) && - pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "STORAGE") == 0) - { - static const char *const list_COLUMNSTORAGE[] = - {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNSTORAGE); - } + else if (TAIL_MATCHES5("ALTER", "COLUMN", ANY, "SET", "STORAGE") || + TAIL_MATCHES4("ALTER", ANY, "SET", "STORAGE")) + COMPLETE_WITH_LIST4("PLAIN", "EXTERNAL", "EXTENDED", "MAIN"); /* ALTER TABLE ALTER [COLUMN] DROP */ - else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "COLUMN") == 0) || - (pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "ALTER") == 0)) && - pg_strcasecmp(prev_wd, "DROP") == 0) - { - static const char *const list_COLUMNDROP[] = - {"DEFAULT", "NOT NULL", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNDROP); - } - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "CLUSTER") == 0) + else if (TAIL_MATCHES4("ALTER", "COLUMN", ANY, "DROP") || + TAIL_MATCHES5("TABLE", ANY, "ALTER", ANY, "DROP")) + COMPLETE_WITH_LIST2("DEFAULT", "NOT NULL"); + else if (TAIL_MATCHES3("TABLE", ANY, "CLUSTER")) COMPLETE_WITH_CONST("ON"); - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES4("TABLE", ANY, "CLUSTER", "ON")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_index_of_table); } /* If we have TABLE SET, provide list of attributes and '(' */ - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "SET") == 0) - { - static const char *const list_TABLESET[] = - {"(", "LOGGED", "SCHEMA", "TABLESPACE", "UNLOGGED", "WITH", "WITHOUT", NULL}; - - COMPLETE_WITH_LIST(list_TABLESET); - } + else if (TAIL_MATCHES3("TABLE", ANY, "SET")) + COMPLETE_WITH_LIST7("(", "LOGGED", "SCHEMA", "TABLESPACE", "UNLOGGED", "WITH", "WITHOUT"); /* If we have TABLE SET TABLESPACE provide a list of tablespaces */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "TABLESPACE") == 0) + else if (TAIL_MATCHES4("TABLE", ANY, "SET", "TABLESPACE")) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); /* If we have TABLE SET WITHOUT provide CLUSTER or OIDS */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "WITHOUT") == 0) - { - static const char *const list_TABLESET2[] = - {"CLUSTER", "OIDS", NULL}; - - COMPLETE_WITH_LIST(list_TABLESET2); - } + else if (TAIL_MATCHES4("TABLE", ANY, "SET", "WITHOUT")) + COMPLETE_WITH_LIST2("CLUSTER", "OIDS"); /* ALTER TABLE RESET */ - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "RESET") == 0) + else if (TAIL_MATCHES3("TABLE", ANY, "RESET")) COMPLETE_WITH_CONST("("); /* ALTER TABLE SET|RESET ( */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - (pg_strcasecmp(prev2_wd, "SET") == 0 || - pg_strcasecmp(prev2_wd, "RESET") == 0) && - pg_strcasecmp(prev_wd, "(") == 0) + else if (TAIL_MATCHES4("TABLE", ANY, "SET|RESET", "(")) { static const char *const list_TABLEOPTIONS[] = { @@ -1832,246 +1611,109 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_TABLEOPTIONS); } - else if (pg_strcasecmp(prev4_wd, "REPLICA") == 0 && - pg_strcasecmp(prev3_wd, "IDENTITY") == 0 && - pg_strcasecmp(prev2_wd, "USING") == 0 && - pg_strcasecmp(prev_wd, "INDEX") == 0) + else if (TAIL_MATCHES4("REPLICA", "IDENTITY", "USING", "INDEX")) { completion_info_charp = prev5_wd; COMPLETE_WITH_QUERY(Query_for_index_of_table); } - else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "REPLICA") == 0 && - pg_strcasecmp(prev2_wd, "IDENTITY") == 0 && - pg_strcasecmp(prev_wd, "USING") == 0) - { + else if (TAIL_MATCHES5("TABLE", ANY, "REPLICA", "IDENTITY", "USING")) COMPLETE_WITH_CONST("INDEX"); - } - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "REPLICA") == 0 && - pg_strcasecmp(prev_wd, "IDENTITY") == 0) - { - static const char *const list_REPLICAID[] = - {"FULL", "NOTHING", "DEFAULT", "USING", NULL}; - - COMPLETE_WITH_LIST(list_REPLICAID); - } - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "REPLICA") == 0) - { + else if (TAIL_MATCHES4("TABLE", ANY, "REPLICA", "IDENTITY")) + COMPLETE_WITH_LIST4("FULL", "NOTHING", "DEFAULT", "USING"); + else if (TAIL_MATCHES3("TABLE", ANY, "REPLICA")) COMPLETE_WITH_CONST("IDENTITY"); - } /* ALTER TABLESPACE with RENAME TO, OWNER TO, SET, RESET */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TABLESPACE") == 0) - { - static const char *const list_ALTERTSPC[] = - {"RENAME TO", "OWNER TO", "SET", "RESET", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTSPC); - } + else if (TAIL_MATCHES3("ALTER", "TABLESPACE", ANY)) + COMPLETE_WITH_LIST4("RENAME TO", "OWNER TO", "SET", "RESET"); /* ALTER TABLESPACE SET|RESET */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 && - (pg_strcasecmp(prev_wd, "SET") == 0 || - pg_strcasecmp(prev_wd, "RESET") == 0)) + else if (TAIL_MATCHES4("ALTER", "TABLESPACE", ANY, "SET|RESET")) COMPLETE_WITH_CONST("("); /* ALTER TABLESPACE SET|RESET ( */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 && - (pg_strcasecmp(prev2_wd, "SET") == 0 || - pg_strcasecmp(prev2_wd, "RESET") == 0) && - pg_strcasecmp(prev_wd, "(") == 0) - { - static const char *const list_TABLESPACEOPTIONS[] = - {"seq_page_cost", "random_page_cost", NULL}; - - COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS); - } + else if (TAIL_MATCHES5("ALTER", "TABLESPACE", ANY, "SET|RESET", "(")) + COMPLETE_WITH_LIST2("seq_page_cost", "random_page_cost"); /* ALTER TEXT SEARCH */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TEXT") == 0 && - pg_strcasecmp(prev_wd, "SEARCH") == 0) - { - static const char *const list_ALTERTEXTSEARCH[] = - {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH); - } - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 || - pg_strcasecmp(prev2_wd, "PARSER") == 0)) - { - static const char *const list_ALTERTEXTSEARCH2[] = - {"RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2); - } - - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - pg_strcasecmp(prev2_wd, "DICTIONARY") == 0) - { - static const char *const list_ALTERTEXTSEARCH3[] = - {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3); - } - - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0) - { - static const char *const list_ALTERTEXTSEARCH4[] = - {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4); - } + else if (TAIL_MATCHES3("ALTER", "TEXT", "SEARCH")) + COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); + else if (TAIL_MATCHES5("ALTER", "TEXT", "SEARCH", "TEMPLATE|PARSER", ANY)) + COMPLETE_WITH_LIST2("RENAME TO", "SET SCHEMA"); + else if (TAIL_MATCHES5("ALTER", "TEXT", "SEARCH", "DICTIONARY", ANY)) + COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA"); + else if (TAIL_MATCHES5("ALTER", "TEXT", "SEARCH", "CONFIGURATION", ANY)) + COMPLETE_WITH_LIST6("ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", + "OWNER TO", "RENAME TO", "SET SCHEMA"); /* complete ALTER TYPE with actions */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TYPE") == 0) - { - static const char *const list_ALTERTYPE[] = - {"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE", - "OWNER TO", "RENAME", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTYPE); - } + else if (TAIL_MATCHES3("ALTER", "TYPE", ANY)) + COMPLETE_WITH_LIST7("ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", + "DROP ATTRIBUTE", "OWNER TO", "RENAME", "SET SCHEMA"); /* complete ALTER TYPE ADD with actions */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TYPE") == 0 && - pg_strcasecmp(prev_wd, "ADD") == 0) - { - static const char *const list_ALTERTYPE[] = - {"ATTRIBUTE", "VALUE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTYPE); - } + else if (TAIL_MATCHES4("ALTER", "TYPE", ANY, "ADD")) + COMPLETE_WITH_LIST2("ATTRIBUTE", "VALUE"); /* ALTER TYPE RENAME */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TYPE") == 0 && - pg_strcasecmp(prev_wd, "RENAME") == 0) - { - static const char *const list_ALTERTYPE[] = - {"ATTRIBUTE", "TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTYPE); - } + else if (TAIL_MATCHES4("ALTER", "TYPE", ANY, "RENAME")) + COMPLETE_WITH_LIST2("ATTRIBUTE", "TO"); /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */ - else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 && - pg_strcasecmp(prev3_wd, "RENAME") == 0 && - pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0) + else if (TAIL_MATCHES5("TYPE", ANY, "RENAME", "ATTRIBUTE", ANY)) COMPLETE_WITH_CONST("TO"); /* * If we have TYPE ALTER/DROP/RENAME ATTRIBUTE, provide list of * attributes */ - else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 && - (pg_strcasecmp(prev2_wd, "ALTER") == 0 || - pg_strcasecmp(prev2_wd, "DROP") == 0 || - pg_strcasecmp(prev2_wd, "RENAME") == 0) && - pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0) + else if (TAIL_MATCHES4("TYPE", ANY, "ALTER|DROP|RENAME", "ATTRIBUTE")) COMPLETE_WITH_ATTR(prev3_wd, ""); /* ALTER TYPE ALTER ATTRIBUTE */ - else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)) - { + else if (TAIL_MATCHES3("ALTER", "ATTRIBUTE", ANY)) COMPLETE_WITH_CONST("TYPE"); - } /* complete ALTER GROUP */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "GROUP") == 0) - { - static const char *const list_ALTERGROUP[] = - {"ADD USER", "DROP USER", "RENAME TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERGROUP); - } + else if (TAIL_MATCHES3("ALTER", "GROUP", ANY)) + COMPLETE_WITH_LIST3("ADD USER", "DROP USER", "RENAME TO"); /* complete ALTER GROUP ADD|DROP with USER */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "GROUP") == 0 && - (pg_strcasecmp(prev_wd, "ADD") == 0 || - pg_strcasecmp(prev_wd, "DROP") == 0)) + else if (TAIL_MATCHES4("ALTER", "GROUP", ANY, "ADD|DROP")) COMPLETE_WITH_CONST("USER"); /* complete {ALTER} GROUP ADD|DROP USER with a user name */ - else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 && - (pg_strcasecmp(prev2_wd, "ADD") == 0 || - pg_strcasecmp(prev2_wd, "DROP") == 0) && - pg_strcasecmp(prev_wd, "USER") == 0) + else if (TAIL_MATCHES4("GROUP", ANY, "ADD|DROP", "USER")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); /* BEGIN, END, ABORT */ - else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 || - pg_strcasecmp(prev_wd, "END") == 0 || - pg_strcasecmp(prev_wd, "ABORT") == 0) - { - static const char *const list_TRANS[] = - {"WORK", "TRANSACTION", NULL}; - - COMPLETE_WITH_LIST(list_TRANS); - } + else if (TAIL_MATCHES1("BEGIN|END|ABORT")) + COMPLETE_WITH_LIST2("WORK", "TRANSACTION"); /* COMMIT */ - else if (pg_strcasecmp(prev_wd, "COMMIT") == 0) - { - static const char *const list_COMMIT[] = - {"WORK", "TRANSACTION", "PREPARED", NULL}; - - COMPLETE_WITH_LIST(list_COMMIT); - } + else if (TAIL_MATCHES1("COMMIT")) + COMPLETE_WITH_LIST3("WORK", "TRANSACTION", "PREPARED"); /* RELEASE SAVEPOINT */ - else if (pg_strcasecmp(prev_wd, "RELEASE") == 0) + else if (TAIL_MATCHES1("RELEASE")) COMPLETE_WITH_CONST("SAVEPOINT"); /* ROLLBACK*/ - else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0) - { - static const char *const list_TRANS[] = - {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL}; - - COMPLETE_WITH_LIST(list_TRANS); - } + else if (TAIL_MATCHES1("ROLLBACK")) + COMPLETE_WITH_LIST4("WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED"); /* CLUSTER */ /* * If the previous word is CLUSTER and not WITHOUT produce list of tables */ - else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev2_wd, "WITHOUT") != 0) + else if (TAIL_MATCHES1("CLUSTER") && !TAIL_MATCHES2("WITHOUT", "CLUSTER")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "UNION SELECT 'VERBOSE'"); /* * If the previous words are CLUSTER VERBOSE produce list of tables */ - else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 && - pg_strcasecmp(prev2_wd, "CLUSTER") == 0) + else if (TAIL_MATCHES2("CLUSTER", "VERBOSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL); /* If we have CLUSTER , then add "USING" */ - else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev_wd, "ON") != 0 && - pg_strcasecmp(prev_wd, "VERBOSE") != 0) - { + else if (TAIL_MATCHES2("CLUSTER", ANY) && !TAIL_MATCHES1("VERBOSE")) COMPLETE_WITH_CONST("USING"); - } /* If we have CLUSTER VERBOSE , then add "USING" */ - else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev2_wd, "VERBOSE") == 0) - { + else if (TAIL_MATCHES3("CLUSTER", "VERBOSE", ANY)) COMPLETE_WITH_CONST("USING"); - } /* * If we have CLUSTER USING, then add the index as well. */ - else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev_wd, "USING") == 0) + else if (TAIL_MATCHES3("CLUSTER", ANY, "USING")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_index_of_table); @@ -2080,19 +1722,16 @@ psql_completion(const char *text, int start, int end) /* * If we have CLUSTER VERBOSE USING, then add the index as well. */ - else if (pg_strcasecmp(prev4_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev3_wd, "VERBOSE") == 0 && - pg_strcasecmp(prev_wd, "USING") == 0) + else if (TAIL_MATCHES4("CLUSTER", "VERBOSE", ANY, "USING")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_index_of_table); } /* COMMENT */ - else if (pg_strcasecmp(prev_wd, "COMMENT") == 0) + else if (TAIL_MATCHES1("COMMENT")) COMPLETE_WITH_CONST("ON"); - else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES2("COMMENT", "ON")) { static const char *const list_COMMENT[] = {"CAST", "COLLATION", "CONVERSION", "DATABASE", "EVENT TRIGGER", "EXTENSION", @@ -2104,66 +1743,27 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_COMMENT); } - else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const list_TRANS2[] = - {"DATA WRAPPER", "TABLE", NULL}; - - COMPLETE_WITH_LIST(list_TRANS2); - } - else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "TEXT") == 0 && - pg_strcasecmp(prev_wd, "SEARCH") == 0) - { - static const char *const list_TRANS2[] = - {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL}; - - COMPLETE_WITH_LIST(list_TRANS2); - } - else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "CONSTRAINT") == 0) - { + else if (TAIL_MATCHES3("COMMENT", "ON", "FOREIGN")) + COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); + else if (TAIL_MATCHES4("COMMENT", "ON", "TEXT", "SEARCH")) + COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); + else if (TAIL_MATCHES3("COMMENT", "ON", "CONSTRAINT")) COMPLETE_WITH_QUERY(Query_for_all_table_constraints); - } - else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) - { + else if (TAIL_MATCHES4("COMMENT", "ON", "CONSTRAINT", ANY)) COMPLETE_WITH_CONST("ON"); - } - else if (pg_strcasecmp(prev5_wd, "COMMENT") == 0 && - pg_strcasecmp(prev4_wd, "ON") == 0 && - pg_strcasecmp(prev3_wd, "CONSTRAINT") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES5("COMMENT", "ON", "CONSTRAINT", ANY, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint); } - else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev_wd, "VIEW") == 0) - { + else if (TAIL_MATCHES4("COMMENT", "ON", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); - } - else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "EVENT") == 0 && - pg_strcasecmp(prev_wd, "TRIGGER") == 0) - { + else if (TAIL_MATCHES4("COMMENT", "ON", "EVENT", "TRIGGER")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers); - } - else if (((pg_strcasecmp(prev4_wd, "COMMENT") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0) || - (pg_strcasecmp(prev5_wd, "COMMENT") == 0 && - pg_strcasecmp(prev4_wd, "ON") == 0) || - (pg_strcasecmp(prev6_wd, "COMMENT") == 0 && - pg_strcasecmp(prev5_wd, "ON") == 0)) && - pg_strcasecmp(prev_wd, "IS") != 0) + else if ((TAIL_MATCHES4("COMMENT", "ON", ANY, ANY) || + TAIL_MATCHES5("COMMENT", "ON", ANY, ANY, ANY) || + TAIL_MATCHES6("COMMENT", "ON", ANY, ANY, ANY, ANY)) && + !TAIL_MATCHES1("IS")) COMPLETE_WITH_CONST("IS"); /* COPY */ @@ -2172,59 +1772,28 @@ psql_completion(const char *text, int start, int end) * If we have COPY [BINARY] (which you'd have to type yourself), offer * list of tables (Also cover the analogous backslash command) */ - else if (pg_strcasecmp(prev_wd, "COPY") == 0 || - pg_strcasecmp(prev_wd, "\\copy") == 0 || - (pg_strcasecmp(prev2_wd, "COPY") == 0 && - pg_strcasecmp(prev_wd, "BINARY") == 0)) + else if (TAIL_MATCHES1("COPY|\\copy") || TAIL_MATCHES2("COPY", "BINARY")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* If we have COPY|BINARY , complete it with "TO" or "FROM" */ - else if (pg_strcasecmp(prev2_wd, "COPY") == 0 || - pg_strcasecmp(prev2_wd, "\\copy") == 0 || - pg_strcasecmp(prev2_wd, "BINARY") == 0) - { - static const char *const list_FROMTO[] = - {"FROM", "TO", NULL}; - - COMPLETE_WITH_LIST(list_FROMTO); - } + else if (TAIL_MATCHES2("COPY|\\copy|BINARY", ANY)) + COMPLETE_WITH_LIST2("FROM", "TO"); /* If we have COPY|BINARY FROM|TO, complete with filename */ - else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 || - pg_strcasecmp(prev3_wd, "\\copy") == 0 || - pg_strcasecmp(prev3_wd, "BINARY") == 0) && - (pg_strcasecmp(prev_wd, "FROM") == 0 || - pg_strcasecmp(prev_wd, "TO") == 0)) + else if (TAIL_MATCHES3("COPY|\\copy|BINARY", ANY, "FROM|TO")) { completion_charp = ""; matches = completion_matches(text, complete_from_files); } /* Handle COPY|BINARY FROM|TO filename */ - else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 || - pg_strcasecmp(prev4_wd, "\\copy") == 0 || - pg_strcasecmp(prev4_wd, "BINARY") == 0) && - (pg_strcasecmp(prev2_wd, "FROM") == 0 || - pg_strcasecmp(prev2_wd, "TO") == 0)) - { - static const char *const list_COPY[] = - {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL}; - - COMPLETE_WITH_LIST(list_COPY); - } + else if (TAIL_MATCHES4("COPY|\\copy|BINARY", ANY, "FROM|TO", ANY)) + COMPLETE_WITH_LIST6("BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING"); /* Handle COPY|BINARY FROM|TO filename CSV */ - else if (pg_strcasecmp(prev_wd, "CSV") == 0 && - (pg_strcasecmp(prev3_wd, "FROM") == 0 || - pg_strcasecmp(prev3_wd, "TO") == 0)) - { - static const char *const list_CSV[] = - {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL}; - - COMPLETE_WITH_LIST(list_CSV); - } + else if (TAIL_MATCHES3("FROM|TO", ANY, "CSV")) + COMPLETE_WITH_LIST5("HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL"); /* CREATE DATABASE */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "DATABASE") == 0) + else if (TAIL_MATCHES3("CREATE", "DATABASE", ANY)) { static const char *const list_DATABASE[] = {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "IS_TEMPLATE", @@ -2234,403 +1803,194 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_DATABASE); } - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "DATABASE") == 0 && - pg_strcasecmp(prev_wd, "TEMPLATE") == 0) + else if (TAIL_MATCHES4("CREATE", "DATABASE", ANY, "TEMPLATE")) COMPLETE_WITH_QUERY(Query_for_list_of_template_databases); /* CREATE EXTENSION */ /* Complete with available extensions rather than installed ones. */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "EXTENSION") == 0) + else if (TAIL_MATCHES2("CREATE", "EXTENSION")) COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions); /* CREATE EXTENSION */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "EXTENSION") == 0) + else if (TAIL_MATCHES3("CREATE", "EXTENSION", ANY)) COMPLETE_WITH_CONST("WITH SCHEMA"); /* CREATE FOREIGN */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const list_CREATE_FOREIGN[] = - {"DATA WRAPPER", "TABLE", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_FOREIGN); - } + else if (TAIL_MATCHES2("CREATE", "FOREIGN")) + COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); /* CREATE FOREIGN DATA WRAPPER */ - else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev3_wd, "DATA") == 0 && - pg_strcasecmp(prev2_wd, "WRAPPER") == 0) - { - static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] = - {"HANDLER", "VALIDATOR", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER); - } + else if (TAIL_MATCHES5("CREATE", "FOREIGN", "DATA", "WRAPPER", ANY)) + COMPLETE_WITH_LIST2("HANDLER", "VALIDATOR"); /* CREATE INDEX */ /* First off we complete CREATE UNIQUE with "INDEX" */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "UNIQUE") == 0) + else if (TAIL_MATCHES2("CREATE", "UNIQUE")) COMPLETE_WITH_CONST("INDEX"); /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */ - else if (pg_strcasecmp(prev_wd, "INDEX") == 0 && - (pg_strcasecmp(prev2_wd, "CREATE") == 0 || - pg_strcasecmp(prev2_wd, "UNIQUE") == 0)) + else if (TAIL_MATCHES2("CREATE|UNIQUE", "INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, " UNION SELECT 'ON'" " UNION SELECT 'CONCURRENTLY'"); /* Complete ... INDEX [] ON with a list of tables */ - else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 || - pg_strcasecmp(prev2_wd, "INDEX") == 0 || - pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES3("INDEX", ANY, "ON") || + TAIL_MATCHES2("INDEX|CONCURRENTLY", "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL); /* If we have CREATE|UNIQUE INDEX CONCURRENTLY, then add "ON" */ - else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 || - pg_strcasecmp(prev2_wd, "INDEX") == 0) && - pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0) + else if (TAIL_MATCHES3("INDEX", ANY, "CONCURRENTLY") || + TAIL_MATCHES2("INDEX", "CONCURRENTLY")) COMPLETE_WITH_CONST("ON"); /* If we have CREATE|UNIQUE INDEX , then add "ON" or "CONCURRENTLY" */ - else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 || - pg_strcasecmp(prev3_wd, "UNIQUE") == 0) && - pg_strcasecmp(prev2_wd, "INDEX") == 0) - { - static const char *const list_CREATE_INDEX[] = - {"CONCURRENTLY", "ON", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_INDEX); - } + else if (TAIL_MATCHES3("CREATE|UNIQUE", "INDEX", ANY)) + COMPLETE_WITH_LIST2("CONCURRENTLY", "ON"); /* * Complete INDEX ON
with a list of table columns (which * should really be in parens) */ - else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 || - pg_strcasecmp(prev3_wd, "INDEX") == 0 || - pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) && - pg_strcasecmp(prev2_wd, "ON") == 0) - { - static const char *const list_CREATE_INDEX2[] = - {"(", "USING", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_INDEX2); - } - else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 || - pg_strcasecmp(prev4_wd, "INDEX") == 0 || - pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "(") == 0) + else if (TAIL_MATCHES4("INDEX", ANY, "ON", ANY) || + TAIL_MATCHES3("INDEX|CONCURRENTLY", "ON", ANY)) + COMPLETE_WITH_LIST2("(", "USING"); + else if (TAIL_MATCHES5("INDEX", ANY, "ON", ANY, "(") || + TAIL_MATCHES4("INDEX|CONCURRENTLY", "ON", ANY, "(")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* same if you put in USING */ - else if (pg_strcasecmp(prev5_wd, "ON") == 0 && - pg_strcasecmp(prev3_wd, "USING") == 0 && - pg_strcasecmp(prev_wd, "(") == 0) + else if (TAIL_MATCHES5("ON", ANY, "USING", ANY, "(")) COMPLETE_WITH_ATTR(prev4_wd, ""); /* Complete USING with an index method */ - else if ((pg_strcasecmp(prev6_wd, "INDEX") == 0 || - pg_strcasecmp(prev5_wd, "INDEX") == 0 || - pg_strcasecmp(prev4_wd, "INDEX") == 0) && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "USING") == 0) + else if (TAIL_MATCHES6("INDEX", ANY, ANY, "ON", ANY, "USING") || + TAIL_MATCHES5("INDEX", ANY, "ON", ANY, "USING") || + TAIL_MATCHES4("INDEX", "ON", ANY, "USING")) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); - else if (pg_strcasecmp(prev4_wd, "ON") == 0 && - (!(pg_strcasecmp(prev6_wd, "POLICY") == 0) && - !(pg_strcasecmp(prev4_wd, "FOR") == 0)) && - pg_strcasecmp(prev2_wd, "USING") == 0) + else if (TAIL_MATCHES4("ON", ANY, "USING", ANY) && + !TAIL_MATCHES6("POLICY", ANY, ANY, ANY, ANY, ANY) && + !TAIL_MATCHES4("FOR", ANY, ANY, ANY)) COMPLETE_WITH_CONST("("); /* CREATE POLICY */ /* Complete "CREATE POLICY ON" */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "POLICY") == 0) + else if (TAIL_MATCHES3("CREATE", "POLICY", ANY)) COMPLETE_WITH_CONST("ON"); /* Complete "CREATE POLICY ON
" */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "POLICY") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES4("CREATE", "POLICY", ANY, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* Complete "CREATE POLICY ON
FOR|TO|USING|WITH CHECK" */ - else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "POLICY") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0) - { - static const char *const list_POLICYOPTIONS[] = - {"FOR", "TO", "USING", "WITH CHECK", NULL}; - - COMPLETE_WITH_LIST(list_POLICYOPTIONS); - } + else if (TAIL_MATCHES5("CREATE", "POLICY", ANY, "ON", ANY)) + COMPLETE_WITH_LIST4("FOR", "TO", "USING", "WITH CHECK"); /* * Complete "CREATE POLICY ON
FOR * ALL|SELECT|INSERT|UPDATE|DELETE" */ - else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 && - pg_strcasecmp(prev5_wd, "POLICY") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "FOR") == 0) - { - static const char *const list_POLICYCMDS[] = - {"ALL", "SELECT", "INSERT", "UPDATE", "DELETE", NULL}; - - COMPLETE_WITH_LIST(list_POLICYCMDS); - } + else if (TAIL_MATCHES6("CREATE", "POLICY", ANY, "ON", ANY, "FOR")) + COMPLETE_WITH_LIST5("ALL", "SELECT", "INSERT", "UPDATE", "DELETE"); /* Complete "CREATE POLICY ON
FOR INSERT TO|WITH CHECK" */ - else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 && - pg_strcasecmp(prev4_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "FOR") == 0 && - pg_strcasecmp(prev_wd, "INSERT") == 0) - { - static const char *const list_POLICYOPTIONS[] = - {"TO", "WITH CHECK", NULL}; - - COMPLETE_WITH_LIST(list_POLICYOPTIONS); - } + else if (TAIL_MATCHES6("POLICY", ANY, "ON", ANY, "FOR", "INSERT")) + COMPLETE_WITH_LIST2("TO", "WITH CHECK"); /* * Complete "CREATE POLICY ON
FOR SELECT TO|USING" Complete * "CREATE POLICY ON
FOR DELETE TO|USING" */ - else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 && - pg_strcasecmp(prev4_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "FOR") == 0 && - (pg_strcasecmp(prev_wd, "SELECT") == 0 || - pg_strcasecmp(prev_wd, "DELETE") == 0)) - { - static const char *const list_POLICYOPTIONS[] = - {"TO", "USING", NULL}; - - COMPLETE_WITH_LIST(list_POLICYOPTIONS); - } + else if (TAIL_MATCHES6("POLICY", ANY, "ON", ANY, "FOR", "SELECT|DELETE")) + COMPLETE_WITH_LIST2("TO", "USING"); /* * Complete "CREATE POLICY ON
FOR ALL TO|USING|WITH CHECK" * Complete "CREATE POLICY ON
FOR UPDATE TO|USING|WITH * CHECK" */ - else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 && - pg_strcasecmp(prev4_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "FOR") == 0 && - (pg_strcasecmp(prev_wd, "ALL") == 0 || - pg_strcasecmp(prev_wd, "UPDATE") == 0)) - { - static const char *const list_POLICYOPTIONS[] = - {"TO", "USING", "WITH CHECK", NULL}; - - COMPLETE_WITH_LIST(list_POLICYOPTIONS); - } + else if (TAIL_MATCHES6("POLICY", ANY, "ON", ANY, "FOR", "ALL|UPDATE")) + COMPLETE_WITH_LIST3("TO", "USING", "WITH CHECK"); /* Complete "CREATE POLICY ON
TO " */ - else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 && - pg_strcasecmp(prev5_wd, "POLICY") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) + else if (TAIL_MATCHES6("CREATE", "POLICY", ANY, "ON", ANY, "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); /* Complete "CREATE POLICY ON
USING (" */ - else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 && - pg_strcasecmp(prev5_wd, "POLICY") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "USING") == 0) + else if (TAIL_MATCHES6("CREATE", "POLICY", ANY, "ON", ANY, "USING")) COMPLETE_WITH_CONST("("); /* CREATE RULE */ /* Complete "CREATE RULE " with "AS" */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "RULE") == 0) + else if (TAIL_MATCHES3("CREATE", "RULE", ANY)) COMPLETE_WITH_CONST("AS"); /* Complete "CREATE RULE AS with "ON" */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "RULE") == 0 && - pg_strcasecmp(prev_wd, "AS") == 0) + else if (TAIL_MATCHES4("CREATE", "RULE", ANY, "AS")) COMPLETE_WITH_CONST("ON"); /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */ - else if (pg_strcasecmp(prev4_wd, "RULE") == 0 && - pg_strcasecmp(prev2_wd, "AS") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) - { - static const char *const rule_events[] = - {"SELECT", "UPDATE", "INSERT", "DELETE", NULL}; - - COMPLETE_WITH_LIST(rule_events); - } + else if (TAIL_MATCHES4("RULE", ANY, "AS", "ON")) + COMPLETE_WITH_LIST4("SELECT", "UPDATE", "INSERT", "DELETE"); /* Complete "AS ON " with a "TO" */ - else if (pg_strcasecmp(prev3_wd, "AS") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0 && - (pg_toupper((unsigned char) prev_wd[4]) == 'T' || - pg_toupper((unsigned char) prev_wd[5]) == 'T')) + else if (TAIL_MATCHES3("AS", "ON", "SELECT|UPDATE|DELETE|INSERT")) COMPLETE_WITH_CONST("TO"); /* Complete "AS ON TO" with a table name */ - else if (pg_strcasecmp(prev4_wd, "AS") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) + else if (TAIL_MATCHES4("AS", "ON", "SELECT|UPDATE|DELETE|INSERT", "TO")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* CREATE TEMP/TEMPORARY SEQUENCE */ - else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "SEQUENCE") == 0) || - (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - (pg_strcasecmp(prev3_wd, "TEMP") == 0 || - pg_strcasecmp(prev3_wd, "TEMPORARY") == 0) && - pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)) - { - static const char *const list_CREATESEQUENCE[] = - {"INCREMENT BY", "MINVALUE", "MAXVALUE", "NO", "CACHE", - "CYCLE", "OWNED BY", "START WITH", NULL}; - - COMPLETE_WITH_LIST(list_CREATESEQUENCE); - } + else if (TAIL_MATCHES3("CREATE", "SEQUENCE", ANY) || + TAIL_MATCHES4("CREATE", "TEMP|TEMPORARY", "SEQUENCE", ANY)) + COMPLETE_WITH_LIST8("INCREMENT BY", "MINVALUE", "MAXVALUE", "NO", "CACHE", + "CYCLE", "OWNED BY", "START WITH"); /* CREATE TEMP/TEMPORARY SEQUENCE NO */ - else if (((pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "SEQUENCE") == 0) || - (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - (pg_strcasecmp(prev4_wd, "TEMP") == 0 || - pg_strcasecmp(prev4_wd, "TEMPORARY") == 0) && - pg_strcasecmp(prev3_wd, "SEQUENCE") == 0)) && - pg_strcasecmp(prev_wd, "NO") == 0) - { - static const char *const list_CREATESEQUENCE2[] = - {"MINVALUE", "MAXVALUE", "CYCLE", NULL}; - - COMPLETE_WITH_LIST(list_CREATESEQUENCE2); - } + else if (TAIL_MATCHES4("CREATE", "SEQUENCE", ANY, "NO") || + TAIL_MATCHES5("CREATE", "TEMP|TEMPORARY", "SEQUENCE", ANY, "NO")) + COMPLETE_WITH_LIST3("MINVALUE", "MAXVALUE", "CYCLE"); /* CREATE SERVER */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "SERVER") == 0) - { - static const char *const list_CREATE_SERVER[] = - {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_SERVER); - } + else if (TAIL_MATCHES3("CREATE", "SERVER", ANY)) + COMPLETE_WITH_LIST3("TYPE", "VERSION", "FOREIGN DATA WRAPPER"); /* CREATE TABLE */ /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - (pg_strcasecmp(prev_wd, "TEMP") == 0 || - pg_strcasecmp(prev_wd, "TEMPORARY") == 0)) - { - static const char *const list_TEMP[] = - {"SEQUENCE", "TABLE", "VIEW", NULL}; - - COMPLETE_WITH_LIST(list_TEMP); - } + else if (TAIL_MATCHES2("CREATE", "TEMP|TEMPORARY")) + COMPLETE_WITH_LIST3("SEQUENCE", "TABLE", "VIEW"); /* Complete "CREATE UNLOGGED" with TABLE */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "UNLOGGED") == 0) - { - static const char *const list_UNLOGGED[] = - {"TABLE", "MATERIALIZED VIEW", NULL}; - - COMPLETE_WITH_LIST(list_UNLOGGED); - } + else if (TAIL_MATCHES2("CREATE", "UNLOGGED")) + COMPLETE_WITH_LIST2("TABLE", "MATERIALIZED VIEW"); /* CREATE TABLESPACE */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "TABLESPACE") == 0) - { - static const char *const list_CREATETABLESPACE[] = - {"OWNER", "LOCATION", NULL}; - - COMPLETE_WITH_LIST(list_CREATETABLESPACE); - } + else if (TAIL_MATCHES3("CREATE", "TABLESPACE", ANY)) + COMPLETE_WITH_LIST2("OWNER", "LOCATION"); /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */ - else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 && - pg_strcasecmp(prev2_wd, "OWNER") == 0) - { + else if (TAIL_MATCHES5("CREATE", "TABLESPACE", ANY, "OWNER", ANY)) COMPLETE_WITH_CONST("LOCATION"); - } /* CREATE TEXT SEARCH */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "TEXT") == 0 && - pg_strcasecmp(prev_wd, "SEARCH") == 0) - { - static const char *const list_CREATETEXTSEARCH[] = - {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL}; - - COMPLETE_WITH_LIST(list_CREATETEXTSEARCH); - } - else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0) + else if (TAIL_MATCHES3("CREATE", "TEXT", "SEARCH")) + COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); + else if (TAIL_MATCHES4("TEXT", "SEARCH", "CONFIGURATION", ANY)) COMPLETE_WITH_CONST("("); /* CREATE TRIGGER */ /* complete CREATE TRIGGER with BEFORE,AFTER */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "TRIGGER") == 0) - { - static const char *const list_CREATETRIGGER[] = - {"BEFORE", "AFTER", "INSTEAD OF", NULL}; - - COMPLETE_WITH_LIST(list_CREATETRIGGER); - } + else if (TAIL_MATCHES3("CREATE", "TRIGGER", ANY)) + COMPLETE_WITH_LIST3("BEFORE", "AFTER", "INSTEAD OF"); /* 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}; - - COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS); - } + else if (TAIL_MATCHES4("CREATE", "TRIGGER", ANY, "BEFORE|AFTER")) + COMPLETE_WITH_LIST4("INSERT", "DELETE", "UPDATE", "TRUNCATE"); /* complete CREATE TRIGGER INSTEAD OF with an event */ - else if (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", NULL}; - - COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS); - } + else if (TAIL_MATCHES5("CREATE", "TRIGGER", ANY, "INSTEAD", "OF")) + COMPLETE_WITH_LIST3("INSERT", "DELETE", "UPDATE"); /* 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(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}; - - COMPLETE_WITH_LIST(list_CREATETRIGGER2); - } + else if (TAIL_MATCHES5("CREATE", "TRIGGER", ANY, "BEFORE|AFTER", ANY) || + TAIL_MATCHES6("CREATE", "TRIGGER", ANY, "INSTEAD", "OF", ANY)) + COMPLETE_WITH_LIST2("ON", "OR"); /* * complete CREATE TRIGGER BEFORE,AFTER event ON with a list of * tables */ - else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 && - (pg_strcasecmp(prev3_wd, "BEFORE") == 0 || - pg_strcasecmp(prev3_wd, "AFTER") == 0) && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES5("TRIGGER", ANY, "BEFORE|AFTER", ANY, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */ - else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 && - pg_strcasecmp(prev3_wd, "OF") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES4("INSTEAD", "OF", ANY, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */ - else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 && - !(pg_strcasecmp(prev2_wd, "GRANT") == 0 && prev3_wd[0] == '\0') && - prev2_wd[0] != '\0') + else if (TAIL_MATCHES1("EXECUTE") && !TAIL_MATCHES3("", "|GRANT", "EXECUTE")) COMPLETE_WITH_CONST("PROCEDURE"); /* CREATE ROLE,USER,GROUP */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) && - (pg_strcasecmp(prev2_wd, "ROLE") == 0 || - pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0)) + else if (TAIL_MATCHES3("CREATE", "ROLE|GROUP|USER", ANY) && + !TAIL_MATCHES3("CREATE", "USER", "MAPPING")) { static const char *const list_CREATEROLE[] = {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", @@ -2644,11 +2004,7 @@ psql_completion(const char *text, int start, int end) } /* CREATE ROLE,USER,GROUP WITH */ - else if ((pg_strcasecmp(prev4_wd, "CREATE") == 0 && - (pg_strcasecmp(prev3_wd, "ROLE") == 0 || - pg_strcasecmp(prev3_wd, "GROUP") == 0 || - pg_strcasecmp(prev3_wd, "USER") == 0) && - pg_strcasecmp(prev_wd, "WITH") == 0)) + else if (TAIL_MATCHES4("CREATE", "ROLE|GROUP|USER", ANY, "WITH")) { /* Similar to the above, but don't complete "WITH" again. */ static const char *const list_CREATEROLE_WITH[] = @@ -2666,91 +2022,47 @@ psql_completion(const char *text, int start, int end) * complete CREATE ROLE,USER,GROUP ENCRYPTED,UNENCRYPTED with * PASSWORD */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - (pg_strcasecmp(prev3_wd, "ROLE") == 0 || - pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) && - (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0)) - { + else if (TAIL_MATCHES4("CREATE", "ROLE|USER|GROUP", ANY, "ENCRYPTED|UNENCRYPTED")) COMPLETE_WITH_CONST("PASSWORD"); - } /* complete CREATE ROLE,USER,GROUP IN with ROLE,GROUP */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - (pg_strcasecmp(prev3_wd, "ROLE") == 0 || - pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) && - pg_strcasecmp(prev_wd, "IN") == 0) - { - static const char *const list_CREATEROLE3[] = - {"GROUP", "ROLE", NULL}; - - COMPLETE_WITH_LIST(list_CREATEROLE3); - } + else if (TAIL_MATCHES4("CREATE", "ROLE|USER|GROUP", ANY, "IN")) + COMPLETE_WITH_LIST2("GROUP", "ROLE"); /* CREATE VIEW */ /* Complete CREATE VIEW with AS */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "VIEW") == 0) + else if (TAIL_MATCHES3("CREATE", "VIEW", ANY)) COMPLETE_WITH_CONST("AS"); /* Complete "CREATE VIEW AS with "SELECT" */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "VIEW") == 0 && - pg_strcasecmp(prev_wd, "AS") == 0) + else if (TAIL_MATCHES4("CREATE", "VIEW", ANY, "AS")) COMPLETE_WITH_CONST("SELECT"); /* CREATE MATERIALIZED VIEW */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "MATERIALIZED") == 0) + else if (TAIL_MATCHES2("CREATE", "MATERIALIZED")) COMPLETE_WITH_CONST("VIEW"); /* Complete CREATE MATERIALIZED VIEW with AS */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev2_wd, "VIEW") == 0) + else if (TAIL_MATCHES3("CREATE", "MATERIALIZED", "VIEW")) COMPLETE_WITH_CONST("AS"); /* Complete "CREATE MATERIALIZED VIEW AS with "SELECT" */ - else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev3_wd, "VIEW") == 0 && - pg_strcasecmp(prev_wd, "AS") == 0) + else if (TAIL_MATCHES5("CREATE", "MATERIALIZED", "VIEW", ANY, "AS")) COMPLETE_WITH_CONST("SELECT"); /* CREATE EVENT TRIGGER */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "EVENT") == 0) + else if (TAIL_MATCHES2("CREATE", "EVENT")) COMPLETE_WITH_CONST("TRIGGER"); /* Complete CREATE EVENT TRIGGER with ON */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "EVENT") == 0 && - pg_strcasecmp(prev2_wd, "TRIGGER") == 0) + else if (TAIL_MATCHES4("CREATE", "EVENT", "TRIGGER", ANY)) COMPLETE_WITH_CONST("ON"); /* Complete CREATE EVENT TRIGGER ON with event_type */ - else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "EVENT") == 0 && - pg_strcasecmp(prev3_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) - { - static const char *const list_CREATE_EVENT_TRIGGER_ON[] = - {"ddl_command_start", "ddl_command_end", "sql_drop", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_EVENT_TRIGGER_ON); - } + else if (TAIL_MATCHES5("CREATE", "EVENT", "TRIGGER", ANY, "ON")) + COMPLETE_WITH_LIST3("ddl_command_start", "ddl_command_end", "sql_drop"); /* DECLARE */ - else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0) - { - static const char *const list_DECLARE[] = - {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL}; - - COMPLETE_WITH_LIST(list_DECLARE); - } + else if (TAIL_MATCHES2("DECLARE", ANY)) + COMPLETE_WITH_LIST5("BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR"); /* CURSOR */ - else if (pg_strcasecmp(prev_wd, "CURSOR") == 0) - { - static const char *const list_DECLARECURSOR[] = - {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL}; - - COMPLETE_WITH_LIST(list_DECLARECURSOR); - } - + else if (TAIL_MATCHES1("CURSOR")) + COMPLETE_WITH_LIST3("WITH HOLD", "WITHOUT HOLD", "FOR"); /* DELETE */ @@ -2758,231 +2070,109 @@ psql_completion(const char *text, int start, int end) * Complete DELETE with FROM (only if the word before that is not "ON" * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT) */ - else if (pg_strcasecmp(prev_wd, "DELETE") == 0 && - !(pg_strcasecmp(prev2_wd, "ON") == 0 || - pg_strcasecmp(prev2_wd, "GRANT") == 0 || - pg_strcasecmp(prev2_wd, "BEFORE") == 0 || - pg_strcasecmp(prev2_wd, "AFTER") == 0)) + else if (TAIL_MATCHES1("DELETE") && !TAIL_MATCHES2("ON|GRANT|BEFORE|AFTER", "DELETE")) COMPLETE_WITH_CONST("FROM"); /* Complete DELETE FROM with a list of tables */ - else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 && - pg_strcasecmp(prev_wd, "FROM") == 0) + else if (TAIL_MATCHES2("DELETE", "FROM")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL); /* Complete DELETE FROM
*/ - else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 && - pg_strcasecmp(prev2_wd, "FROM") == 0) - { - static const char *const list_DELETE[] = - {"USING", "WHERE", "SET", NULL}; - - COMPLETE_WITH_LIST(list_DELETE); - } + else if (TAIL_MATCHES3("DELETE", "FROM", ANY)) + COMPLETE_WITH_LIST3("USING", "WHERE", "SET"); /* XXX: implement tab completion for DELETE ... USING */ /* DISCARD */ - else if (pg_strcasecmp(prev_wd, "DISCARD") == 0) - { - static const char *const list_DISCARD[] = - {"ALL", "PLANS", "SEQUENCES", "TEMP", NULL}; - - COMPLETE_WITH_LIST(list_DISCARD); - } + else if (TAIL_MATCHES1("DISCARD")) + COMPLETE_WITH_LIST4("ALL", "PLANS", "SEQUENCES", "TEMP"); /* DO */ /* * Complete DO with LANGUAGE. */ - else if (pg_strcasecmp(prev_wd, "DO") == 0) - { - static const char *const list_DO[] = - {"LANGUAGE", NULL}; - - COMPLETE_WITH_LIST(list_DO); - } + else if (TAIL_MATCHES1("DO")) + COMPLETE_WITH_CONST("LANGUAGE"); /* DROP (when not the previous word) */ /* DROP AGGREGATE */ - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "AGGREGATE") == 0) + else if (TAIL_MATCHES3("DROP", "AGGREGATE", ANY)) COMPLETE_WITH_CONST("("); /* DROP object with CASCADE / RESTRICT */ - else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 && - (pg_strcasecmp(prev2_wd, "COLLATION") == 0 || - pg_strcasecmp(prev2_wd, "CONVERSION") == 0 || - pg_strcasecmp(prev2_wd, "DOMAIN") == 0 || - pg_strcasecmp(prev2_wd, "EXTENSION") == 0 || - pg_strcasecmp(prev2_wd, "FUNCTION") == 0 || - pg_strcasecmp(prev2_wd, "INDEX") == 0 || - pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 || - pg_strcasecmp(prev2_wd, "SCHEMA") == 0 || - pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 || - pg_strcasecmp(prev2_wd, "SERVER") == 0 || - pg_strcasecmp(prev2_wd, "TABLE") == 0 || - pg_strcasecmp(prev2_wd, "TYPE") == 0 || - pg_strcasecmp(prev2_wd, "VIEW") == 0)) || - (pg_strcasecmp(prev4_wd, "DROP") == 0 && - pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 && - prev_wd[strlen(prev_wd) - 1] == ')') || - (pg_strcasecmp(prev4_wd, "DROP") == 0 && - pg_strcasecmp(prev3_wd, "EVENT") == 0 && - pg_strcasecmp(prev2_wd, "TRIGGER") == 0) || - (pg_strcasecmp(prev5_wd, "DROP") == 0 && - pg_strcasecmp(prev4_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev3_wd, "DATA") == 0 && - pg_strcasecmp(prev2_wd, "WRAPPER") == 0) || - (pg_strcasecmp(prev5_wd, "DROP") == 0 && - pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 || - pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 || - pg_strcasecmp(prev2_wd, "PARSER") == 0 || - pg_strcasecmp(prev2_wd, "TEMPLATE") == 0)) - ) - { - if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "FUNCTION") == 0) - { + else if (TAIL_MATCHES3("DROP", + "COLLATION|CONVERSION|DOMAIN|EXTENSION|FUNCTION|INDEX|LANGUAGE|SCHEMA|SEQUENCES|SERVER|TABLE|TYPE|VIEW", + ANY) || + (TAIL_MATCHES4("DROP", "AGGREGATE", ANY, ANY) && ends_with(prev_wd, ')')) || + TAIL_MATCHES4("DROP", "EVENT", "TRIGGER", ANY) || + TAIL_MATCHES5("DROP", "FOREIGN", "DATA", "WRAPPER", ANY) || + TAIL_MATCHES5("DROP", "TEXT", "SEARCH", "CONFIGURATION|DICTIONARY|PARSER|TEMPLATE", ANY)) + { + if (TAIL_MATCHES3("DROP", "FUNCTION", ANY)) COMPLETE_WITH_CONST("("); - } else - { - static const char *const list_DROPCR[] = - {"CASCADE", "RESTRICT", NULL}; - - COMPLETE_WITH_LIST(list_DROPCR); - } - } - else if (pg_strcasecmp(prev2_wd, "DROP") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const drop_CREATE_FOREIGN[] = - {"DATA WRAPPER", "TABLE", NULL}; - - COMPLETE_WITH_LIST(drop_CREATE_FOREIGN); + COMPLETE_WITH_LIST2("CASCADE", "RESTRICT"); } + else if (TAIL_MATCHES2("DROP", "FOREIGN")) + COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); /* DROP MATERIALIZED VIEW */ - else if (pg_strcasecmp(prev2_wd, "DROP") == 0 && - pg_strcasecmp(prev_wd, "MATERIALIZED") == 0) - { + else if (TAIL_MATCHES2("DROP", "MATERIALIZED")) COMPLETE_WITH_CONST("VIEW"); - } - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev_wd, "VIEW") == 0) - { + else if (TAIL_MATCHES3("DROP", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); - } - else if (pg_strcasecmp(prev4_wd, "DROP") == 0 && - (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 || - pg_strcasecmp(prev3_wd, "FUNCTION") == 0) && - pg_strcasecmp(prev_wd, "(") == 0) + else if (TAIL_MATCHES4("DROP", "AGGREGATE|FUNCTION", ANY, "(")) COMPLETE_WITH_FUNCTION_ARG(prev2_wd); /* DROP OWNED BY */ - else if (pg_strcasecmp(prev2_wd, "DROP") == 0 && - pg_strcasecmp(prev_wd, "OWNED") == 0) + else if (TAIL_MATCHES2("DROP", "OWNED")) COMPLETE_WITH_CONST("BY"); - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "OWNED") == 0 && - pg_strcasecmp(prev_wd, "BY") == 0) + else if (TAIL_MATCHES3("DROP", "OWNED", "BY")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "TEXT") == 0 && - pg_strcasecmp(prev_wd, "SEARCH") == 0) - { - - static const char *const list_ALTERTEXTSEARCH[] = - {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH); - } + else if (TAIL_MATCHES3("DROP", "TEXT", "SEARCH")) + COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); /* DROP TRIGGER */ - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "TRIGGER") == 0) - { + else if (TAIL_MATCHES3("DROP", "TRIGGER", ANY)) COMPLETE_WITH_CONST("ON"); - } - else if (pg_strcasecmp(prev4_wd, "DROP") == 0 && - pg_strcasecmp(prev3_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES4("DROP", "TRIGGER", ANY, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger); } - else if (pg_strcasecmp(prev5_wd, "DROP") == 0 && - pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0) - { - static const char *const list_DROPCR[] = - {"CASCADE", "RESTRICT", NULL}; - - COMPLETE_WITH_LIST(list_DROPCR); - } + else if (TAIL_MATCHES5("DROP", "TRIGGER", ANY, "ON", ANY)) + COMPLETE_WITH_LIST2("CASCADE", "RESTRICT"); /* DROP EVENT TRIGGER */ - else if (pg_strcasecmp(prev2_wd, "DROP") == 0 && - pg_strcasecmp(prev_wd, "EVENT") == 0) - { + else if (TAIL_MATCHES2("DROP", "EVENT")) COMPLETE_WITH_CONST("TRIGGER"); - } - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "EVENT") == 0 && - pg_strcasecmp(prev_wd, "TRIGGER") == 0) - { + else if (TAIL_MATCHES3("DROP", "EVENT", "TRIGGER")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers); - } /* DROP POLICY */ - else if (pg_strcasecmp(prev2_wd, "DROP") == 0 && - pg_strcasecmp(prev_wd, "POLICY") == 0) - { + else if (TAIL_MATCHES2("DROP", "POLICY")) COMPLETE_WITH_QUERY(Query_for_list_of_policies); - } /* DROP POLICY ON */ - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "POLICY") == 0) - { + else if (TAIL_MATCHES3("DROP", "POLICY", ANY)) COMPLETE_WITH_CONST("ON"); - } /* DROP POLICY ON
*/ - else if (pg_strcasecmp(prev4_wd, "DROP") == 0 && - pg_strcasecmp(prev3_wd, "POLICY") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES4("DROP", "POLICY", ANY, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy); } /* DROP RULE */ - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "RULE") == 0) - { + else if (TAIL_MATCHES3("DROP", "RULE", ANY)) COMPLETE_WITH_CONST("ON"); - } - else if (pg_strcasecmp(prev4_wd, "DROP") == 0 && - pg_strcasecmp(prev3_wd, "RULE") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES4("DROP", "RULE", ANY, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule); } - else if (pg_strcasecmp(prev5_wd, "DROP") == 0 && - pg_strcasecmp(prev4_wd, "RULE") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0) - { - static const char *const list_DROPCR[] = - {"CASCADE", "RESTRICT", NULL}; - - COMPLETE_WITH_LIST(list_DROPCR); - } + else if (TAIL_MATCHES5("DROP", "RULE", ANY, "ON", ANY)) + COMPLETE_WITH_LIST2("CASCADE", "RESTRICT"); /* EXECUTE, but not EXECUTE embedded in other commands */ - else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 && - prev2_wd[0] == '\0') + else if (MATCHES1("EXECUTE")) COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements); /* EXPLAIN */ @@ -2990,85 +2180,45 @@ psql_completion(const char *text, int start, int end) /* * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands */ - else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0) - { - static const char *const list_EXPLAIN[] = - {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL}; - - COMPLETE_WITH_LIST(list_EXPLAIN); - } - else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 && - pg_strcasecmp(prev_wd, "ANALYZE") == 0) - { - static const char *const list_EXPLAIN[] = - {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL}; - - COMPLETE_WITH_LIST(list_EXPLAIN); - } - else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 && - pg_strcasecmp(prev_wd, "VERBOSE") == 0) || - (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 && - pg_strcasecmp(prev2_wd, "ANALYZE") == 0 && - pg_strcasecmp(prev_wd, "VERBOSE") == 0)) - { - static const char *const list_EXPLAIN[] = - {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL}; - - COMPLETE_WITH_LIST(list_EXPLAIN); - } + else if (TAIL_MATCHES1("EXPLAIN")) + COMPLETE_WITH_LIST7("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", + "ANALYZE", "VERBOSE"); + else if (TAIL_MATCHES2("EXPLAIN", "ANALYZE|ANALYSE")) + COMPLETE_WITH_LIST6("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE"); + else if (TAIL_MATCHES2("EXPLAIN", "VERBOSE") || + TAIL_MATCHES3("EXPLAIN", "ANALYZE|ANALYSE", "VERBOSE")) + COMPLETE_WITH_LIST5("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE"); /* FETCH && MOVE */ /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */ - else if (pg_strcasecmp(prev_wd, "FETCH") == 0 || - pg_strcasecmp(prev_wd, "MOVE") == 0) - { - static const char *const list_FETCH1[] = - {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL}; - - COMPLETE_WITH_LIST(list_FETCH1); - } + else if (TAIL_MATCHES1("FETCH|MOVE")) + COMPLETE_WITH_LIST4("ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE"); /* Complete FETCH with one of ALL, NEXT, PRIOR */ - else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 || - pg_strcasecmp(prev2_wd, "MOVE") == 0) - { - static const char *const list_FETCH2[] = - {"ALL", "NEXT", "PRIOR", NULL}; - - COMPLETE_WITH_LIST(list_FETCH2); - } + else if (TAIL_MATCHES2("FETCH|MOVE", ANY)) + COMPLETE_WITH_LIST3("ALL", "NEXT", "PRIOR"); /* * Complete FETCH with "FROM" or "IN". These are equivalent, * but we may as well tab-complete both: perhaps some users prefer one * variant or the other. */ - else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 || - pg_strcasecmp(prev3_wd, "MOVE") == 0) - { - static const char *const list_FROMIN[] = - {"FROM", "IN", NULL}; - - COMPLETE_WITH_LIST(list_FROMIN); - } + else if (TAIL_MATCHES3("FETCH|MOVE", ANY, ANY)) + COMPLETE_WITH_LIST2("FROM", "IN"); /* FOREIGN DATA WRAPPER */ /* applies in ALTER/DROP FDW and in CREATE SERVER */ - else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 && - pg_strcasecmp(prev3_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev2_wd, "DATA") == 0 && - pg_strcasecmp(prev_wd, "WRAPPER") == 0) + else if (TAIL_MATCHES3("FOREIGN", "DATA", "WRAPPER") && + !TAIL_MATCHES4("CREATE", "FOREIGN", "DATA", "WRAPPER")) COMPLETE_WITH_QUERY(Query_for_list_of_fdws); /* FOREIGN TABLE */ - else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 && - pg_strcasecmp(prev2_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev_wd, "TABLE") == 0) + else if (TAIL_MATCHES2("FOREIGN", "TABLE") && + !TAIL_MATCHES3("CREATE", "FOREIGN", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL); /* GRANT && REVOKE */ /* Complete GRANT/REVOKE with a list of roles and privileges */ - else if (pg_strcasecmp(prev_wd, "GRANT") == 0 || - pg_strcasecmp(prev_wd, "REVOKE") == 0) + else if (TAIL_MATCHES1("GRANT|REVOKE")) { COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'SELECT'" @@ -3090,27 +2240,13 @@ psql_completion(const char *text, int start, int end) * Complete GRANT/REVOKE with "ON", GRANT/REVOKE with * TO/FROM */ - else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 || - pg_strcasecmp(prev2_wd, "REVOKE") == 0) + else if (TAIL_MATCHES2("GRANT|REVOKE", ANY)) { - if (pg_strcasecmp(prev_wd, "SELECT") == 0 - || pg_strcasecmp(prev_wd, "INSERT") == 0 - || pg_strcasecmp(prev_wd, "UPDATE") == 0 - || pg_strcasecmp(prev_wd, "DELETE") == 0 - || pg_strcasecmp(prev_wd, "TRUNCATE") == 0 - || pg_strcasecmp(prev_wd, "REFERENCES") == 0 - || pg_strcasecmp(prev_wd, "TRIGGER") == 0 - || pg_strcasecmp(prev_wd, "CREATE") == 0 - || pg_strcasecmp(prev_wd, "CONNECT") == 0 - || pg_strcasecmp(prev_wd, "TEMPORARY") == 0 - || pg_strcasecmp(prev_wd, "TEMP") == 0 - || pg_strcasecmp(prev_wd, "EXECUTE") == 0 - || pg_strcasecmp(prev_wd, "USAGE") == 0 - || pg_strcasecmp(prev_wd, "ALL") == 0) + if (TAIL_MATCHES1("SELECT|INSERT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER|CREATE|CONNECT|TEMPORARY|TEMP|EXECUTE|USAGE|ALL")) COMPLETE_WITH_CONST("ON"); else { - if (pg_strcasecmp(prev2_wd, "GRANT") == 0) + if (TAIL_MATCHES2("GRANT", ANY)) COMPLETE_WITH_CONST("TO"); else COMPLETE_WITH_CONST("FROM"); @@ -3128,9 +2264,7 @@ psql_completion(const char *text, int start, int end) * here will only work if the privilege list contains exactly one * privilege */ - else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 || - pg_strcasecmp(prev3_wd, "REVOKE") == 0) && - pg_strcasecmp(prev_wd, "ON") == 0) + else if (TAIL_MATCHES3("GRANT|REVOKE", ANY, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, " UNION SELECT 'DATABASE'" " UNION SELECT 'DOMAIN'" @@ -3142,195 +2276,138 @@ psql_completion(const char *text, int start, int end) " UNION SELECT 'SCHEMA'" " UNION SELECT 'TABLESPACE'" " UNION SELECT 'TYPE'"); - else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 || - pg_strcasecmp(prev4_wd, "REVOKE") == 0) && - pg_strcasecmp(prev2_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const list_privilege_foreign[] = - {"DATA WRAPPER", "SERVER", NULL}; - - COMPLETE_WITH_LIST(list_privilege_foreign); - } + else if (TAIL_MATCHES4("GRANT|REVOKE", ANY, "ON", "FOREIGN")) + COMPLETE_WITH_LIST2("DATA WRAPPER", "SERVER"); /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */ - else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 || - pg_strcasecmp(prev4_wd, "REVOKE") == 0) && - pg_strcasecmp(prev2_wd, "ON") == 0) + else if (TAIL_MATCHES4("GRANT|REVOKE", ANY, "ON", ANY)) { - if (pg_strcasecmp(prev_wd, "DATABASE") == 0) + if (TAIL_MATCHES1("DATABASE")) COMPLETE_WITH_QUERY(Query_for_list_of_databases); - else if (pg_strcasecmp(prev_wd, "DOMAIN") == 0) + else if (TAIL_MATCHES1("DOMAIN")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL); - else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0) + else if (TAIL_MATCHES1("FUNCTION")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); - else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0) + else if (TAIL_MATCHES1("LANGUAGE")) COMPLETE_WITH_QUERY(Query_for_list_of_languages); - else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0) + else if (TAIL_MATCHES1("SCHEMA")) COMPLETE_WITH_QUERY(Query_for_list_of_schemas); - else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0) + else if (TAIL_MATCHES1("TABLESPACE")) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); - else if (pg_strcasecmp(prev_wd, "TYPE") == 0) + else if (TAIL_MATCHES1("TYPE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL); - else if (pg_strcasecmp(prev4_wd, "GRANT") == 0) + else if (TAIL_MATCHES4("GRANT", ANY, ANY, ANY)) COMPLETE_WITH_CONST("TO"); else COMPLETE_WITH_CONST("FROM"); } /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */ - else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0) + else if (TAIL_MATCHES5("GRANT", ANY, "ON", ANY, ANY)) { - if (pg_strcasecmp(prev_wd, "TO") == 0) + if (TAIL_MATCHES1("TO")) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); else COMPLETE_WITH_CONST("TO"); } - else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0) + else if (TAIL_MATCHES5("REVOKE", ANY, "ON", ANY, ANY)) { - if (pg_strcasecmp(prev_wd, "FROM") == 0) + if (TAIL_MATCHES1("FROM")) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); else COMPLETE_WITH_CONST("FROM"); } /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */ - else if (pg_strcasecmp(prev3_wd, "GRANT") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) - { + else if (TAIL_MATCHES3("GRANT", ANY, "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); - } - else if (pg_strcasecmp(prev3_wd, "REVOKE") == 0 && - pg_strcasecmp(prev_wd, "FROM") == 0) - { + else if (TAIL_MATCHES3("REVOKE", ANY, "FROM")) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); - } /* GROUP BY */ - else if (pg_strcasecmp(prev3_wd, "FROM") == 0 && - pg_strcasecmp(prev_wd, "GROUP") == 0) + else if (TAIL_MATCHES3("FROM", ANY, "GROUP")) COMPLETE_WITH_CONST("BY"); /* IMPORT FOREIGN SCHEMA */ - else if (pg_strcasecmp(prev_wd, "IMPORT") == 0) + else if (TAIL_MATCHES1("IMPORT")) COMPLETE_WITH_CONST("FOREIGN SCHEMA"); - else if (pg_strcasecmp(prev2_wd, "IMPORT") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) + else if (TAIL_MATCHES2("IMPORT", "FOREIGN")) COMPLETE_WITH_CONST("SCHEMA"); /* INSERT */ /* Complete INSERT with "INTO" */ - else if (pg_strcasecmp(prev_wd, "INSERT") == 0) + else if (TAIL_MATCHES1("INSERT")) COMPLETE_WITH_CONST("INTO"); /* Complete INSERT INTO with table names */ - else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 && - pg_strcasecmp(prev_wd, "INTO") == 0) + else if (TAIL_MATCHES2("INSERT", "INTO")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL); /* Complete "INSERT INTO
(" with attribute names */ - else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 && - pg_strcasecmp(prev3_wd, "INTO") == 0 && - pg_strcasecmp(prev_wd, "(") == 0) + else if (TAIL_MATCHES4("INSERT", "INTO", ANY, "(")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* * Complete INSERT INTO
with "(" or "VALUES" or "SELECT" or * "TABLE" or "DEFAULT VALUES" */ - else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 && - pg_strcasecmp(prev2_wd, "INTO") == 0) - { - static const char *const list_INSERT[] = - {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL}; - - COMPLETE_WITH_LIST(list_INSERT); - } + else if (TAIL_MATCHES3("INSERT", "INTO", ANY)) + COMPLETE_WITH_LIST5("(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES"); /* * Complete INSERT INTO
(attribs) with "VALUES" or "SELECT" or * "TABLE" */ - else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 && - pg_strcasecmp(prev3_wd, "INTO") == 0 && - prev_wd[strlen(prev_wd) - 1] == ')') - { - static const char *const list_INSERT[] = - {"SELECT", "TABLE", "VALUES", NULL}; - - COMPLETE_WITH_LIST(list_INSERT); - } + else if (TAIL_MATCHES4("INSERT", "INTO", ANY, ANY) && ends_with(prev_wd, ')')) + COMPLETE_WITH_LIST3("SELECT", "TABLE", "VALUES"); /* Insert an open parenthesis after "VALUES" */ - else if (pg_strcasecmp(prev_wd, "VALUES") == 0 && - pg_strcasecmp(prev2_wd, "DEFAULT") != 0) + else if (TAIL_MATCHES1("VALUES") && !TAIL_MATCHES2("DEFAULT", "VALUES")) COMPLETE_WITH_CONST("("); /* LOCK */ /* Complete LOCK [TABLE] with a list of tables */ - else if (pg_strcasecmp(prev_wd, "LOCK") == 0) + else if (TAIL_MATCHES1("LOCK")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, " UNION SELECT 'TABLE'"); - else if (pg_strcasecmp(prev_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "LOCK") == 0) + else if (TAIL_MATCHES2("LOCK", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* For the following, handle the case of a single table only for now */ /* Complete LOCK [TABLE]
with "IN" */ - else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 && - pg_strcasecmp(prev_wd, "TABLE") != 0) || - (pg_strcasecmp(prev2_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "LOCK") == 0)) + else if ((TAIL_MATCHES2("LOCK", ANY) && !TAIL_MATCHES2("LOCK", "TABLE")) || + TAIL_MATCHES3("LOCK", "TABLE", ANY)) COMPLETE_WITH_CONST("IN"); /* Complete LOCK [TABLE]
IN with a lock mode */ - else if (pg_strcasecmp(prev_wd, "IN") == 0 && - (pg_strcasecmp(prev3_wd, "LOCK") == 0 || - (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev4_wd, "LOCK") == 0))) - { - static const char *const lock_modes[] = - {"ACCESS SHARE MODE", - "ROW SHARE MODE", "ROW EXCLUSIVE MODE", - "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE", - "SHARE ROW EXCLUSIVE MODE", - "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL}; - - COMPLETE_WITH_LIST(lock_modes); - } + else if (TAIL_MATCHES3("LOCK", ANY, "IN") || + TAIL_MATCHES4("LOCK", "TABLE", ANY, "IN")) + COMPLETE_WITH_LIST8("ACCESS SHARE MODE", + "ROW SHARE MODE", "ROW EXCLUSIVE MODE", + "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE", + "SHARE ROW EXCLUSIVE MODE", + "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE"); /* NOTIFY */ - else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0) + else if (TAIL_MATCHES1("NOTIFY")) COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s'"); /* OPTIONS */ - else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0) + else if (TAIL_MATCHES1("OPTIONS")) COMPLETE_WITH_CONST("("); /* OWNER TO - complete with available roles */ - else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) + else if (TAIL_MATCHES2("OWNER", "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); /* ORDER BY */ - else if (pg_strcasecmp(prev3_wd, "FROM") == 0 && - pg_strcasecmp(prev_wd, "ORDER") == 0) + else if (TAIL_MATCHES3("FROM", ANY, "ORDER")) COMPLETE_WITH_CONST("BY"); - else if (pg_strcasecmp(prev4_wd, "FROM") == 0 && - pg_strcasecmp(prev2_wd, "ORDER") == 0 && - pg_strcasecmp(prev_wd, "BY") == 0) + else if (TAIL_MATCHES4("FROM", ANY, "ORDER", "BY")) COMPLETE_WITH_ATTR(prev3_wd, ""); /* PREPARE xx AS */ - else if (pg_strcasecmp(prev_wd, "AS") == 0 && - pg_strcasecmp(prev3_wd, "PREPARE") == 0) - { - static const char *const list_PREPARE[] = - {"SELECT", "UPDATE", "INSERT", "DELETE", NULL}; - - COMPLETE_WITH_LIST(list_PREPARE); - } + else if (TAIL_MATCHES3("PREPARE", ANY, "AS")) + COMPLETE_WITH_LIST4("SELECT", "UPDATE", "INSERT", "DELETE"); /* * PREPARE TRANSACTION is missing on purpose. It's intended for transaction @@ -3338,116 +2415,62 @@ psql_completion(const char *text, int start, int end) */ /* REASSIGN OWNED BY xxx TO yyy */ - else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0) + else if (TAIL_MATCHES1("REASSIGN")) COMPLETE_WITH_CONST("OWNED"); - else if (pg_strcasecmp(prev_wd, "OWNED") == 0 && - pg_strcasecmp(prev2_wd, "REASSIGN") == 0) + else if (TAIL_MATCHES2("REASSIGN", "OWNED")) COMPLETE_WITH_CONST("BY"); - else if (pg_strcasecmp(prev_wd, "BY") == 0 && - pg_strcasecmp(prev2_wd, "OWNED") == 0 && - pg_strcasecmp(prev3_wd, "REASSIGN") == 0) + else if (TAIL_MATCHES3("REASSIGN", "OWNED", "BY")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); - else if (pg_strcasecmp(prev2_wd, "BY") == 0 && - pg_strcasecmp(prev3_wd, "OWNED") == 0 && - pg_strcasecmp(prev4_wd, "REASSIGN") == 0) + else if (TAIL_MATCHES4("REASSIGN", "OWNED", "BY", ANY)) COMPLETE_WITH_CONST("TO"); - else if (pg_strcasecmp(prev_wd, "TO") == 0 && - pg_strcasecmp(prev3_wd, "BY") == 0 && - pg_strcasecmp(prev4_wd, "OWNED") == 0 && - pg_strcasecmp(prev5_wd, "REASSIGN") == 0) + else if (TAIL_MATCHES5("REASSIGN", "OWNED", "BY", ANY, "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); /* REFRESH MATERIALIZED VIEW */ - else if (pg_strcasecmp(prev_wd, "REFRESH") == 0) + else if (TAIL_MATCHES1("REFRESH")) COMPLETE_WITH_CONST("MATERIALIZED VIEW"); - else if (pg_strcasecmp(prev2_wd, "REFRESH") == 0 && - pg_strcasecmp(prev_wd, "MATERIALIZED") == 0) + else if (TAIL_MATCHES2("REFRESH", "MATERIALIZED")) COMPLETE_WITH_CONST("VIEW"); - else if (pg_strcasecmp(prev3_wd, "REFRESH") == 0 && - pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev_wd, "VIEW") == 0) + else if (TAIL_MATCHES3("REFRESH", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, " UNION SELECT 'CONCURRENTLY'"); - else if (pg_strcasecmp(prev4_wd, "REFRESH") == 0 && - pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev2_wd, "VIEW") == 0 && - pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0) + else if (TAIL_MATCHES4("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); - else if (pg_strcasecmp(prev4_wd, "REFRESH") == 0 && - pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev2_wd, "VIEW") == 0) + else if (TAIL_MATCHES4("REFRESH", "MATERIALIZED", "VIEW", ANY)) COMPLETE_WITH_CONST("WITH"); - else if (pg_strcasecmp(prev5_wd, "REFRESH") == 0 && - pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev3_wd, "VIEW") == 0 && - pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) + else if (TAIL_MATCHES5("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", ANY)) COMPLETE_WITH_CONST("WITH DATA"); - else if (pg_strcasecmp(prev5_wd, "REFRESH") == 0 && - pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev3_wd, "VIEW") == 0 && - pg_strcasecmp(prev_wd, "WITH") == 0) - { - static const char *const list_WITH_DATA[] = - {"NO DATA", "DATA", NULL}; - - COMPLETE_WITH_LIST(list_WITH_DATA); - } - else if (pg_strcasecmp(prev6_wd, "REFRESH") == 0 && - pg_strcasecmp(prev5_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev4_wd, "VIEW") == 0 && - pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0 && - pg_strcasecmp(prev_wd, "WITH") == 0) + else if (TAIL_MATCHES5("REFRESH", "MATERIALIZED", "VIEW", ANY, "WITH")) + COMPLETE_WITH_LIST2("NO DATA", "DATA"); + else if (TAIL_MATCHES6("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", ANY, "WITH")) COMPLETE_WITH_CONST("DATA"); - else if (pg_strcasecmp(prev6_wd, "REFRESH") == 0 && - pg_strcasecmp(prev5_wd, "MATERIALIZED") == 0 && - pg_strcasecmp(prev4_wd, "VIEW") == 0 && - pg_strcasecmp(prev2_wd, "WITH") == 0 && - pg_strcasecmp(prev_wd, "NO") == 0) + else if (TAIL_MATCHES6("REFRESH", "MATERIALIZED", "VIEW", ANY, "WITH", "NO")) COMPLETE_WITH_CONST("DATA"); /* REINDEX */ - else if (pg_strcasecmp(prev_wd, "REINDEX") == 0) - { - static const char *const list_REINDEX[] = - {"TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE", NULL}; - - COMPLETE_WITH_LIST(list_REINDEX); - } - else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0) + else if (TAIL_MATCHES1("REINDEX")) + COMPLETE_WITH_LIST5("TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE"); + else if (TAIL_MATCHES2("REINDEX", ANY)) { - if (pg_strcasecmp(prev_wd, "TABLE") == 0) + if (TAIL_MATCHES1("TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL); - else if (pg_strcasecmp(prev_wd, "INDEX") == 0) + else if (TAIL_MATCHES1("INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL); - else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0) + else if (TAIL_MATCHES1("SCHEMA")) COMPLETE_WITH_QUERY(Query_for_list_of_schemas); - else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 || - pg_strcasecmp(prev_wd, "DATABASE") == 0) + else if (TAIL_MATCHES1("SYSTEM|DATABASE")) COMPLETE_WITH_QUERY(Query_for_list_of_databases); } /* SECURITY LABEL */ - else if (pg_strcasecmp(prev_wd, "SECURITY") == 0) + else if (TAIL_MATCHES1("SECURITY")) COMPLETE_WITH_CONST("LABEL"); - else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 && - pg_strcasecmp(prev_wd, "LABEL") == 0) - { - static const char *const list_SECURITY_LABEL_preposition[] = - {"ON", "FOR"}; - - COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition); - } - else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 && - pg_strcasecmp(prev3_wd, "LABEL") == 0 && - pg_strcasecmp(prev2_wd, "FOR") == 0) + else if (TAIL_MATCHES2("SECURITY", "LABEL")) + COMPLETE_WITH_LIST2("ON", "FOR"); + else if (TAIL_MATCHES4("SECURITY", "LABEL", "FOR", ANY)) COMPLETE_WITH_CONST("ON"); - else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 && - pg_strcasecmp(prev2_wd, "LABEL") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) || - (pg_strcasecmp(prev5_wd, "SECURITY") == 0 && - pg_strcasecmp(prev4_wd, "LABEL") == 0 && - pg_strcasecmp(prev3_wd, "FOR") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0)) + else if (TAIL_MATCHES3("SECURITY", "LABEL", "ON") || + TAIL_MATCHES5("SECURITY", "LABEL", "FOR", ANY, "ON")) { static const char *const list_SECURITY_LABEL[] = {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", @@ -3456,9 +2479,7 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_SECURITY_LABEL); } - else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 && - pg_strcasecmp(prev4_wd, "LABEL") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0) + else if (TAIL_MATCHES5("SECURITY", "LABEL", "ON", ANY, ANY)) COMPLETE_WITH_CONST("IS"); /* SELECT */ @@ -3466,135 +2487,51 @@ psql_completion(const char *text, int start, int end) /* SET, RESET, SHOW */ /* Complete with a variable name */ - else if ((pg_strcasecmp(prev_wd, "SET") == 0 && - pg_strcasecmp(prev3_wd, "UPDATE") != 0) || - pg_strcasecmp(prev_wd, "RESET") == 0) + else if (TAIL_MATCHES1("SET|RESET") && !MATCHES3("UPDATE", ANY, "SET")) COMPLETE_WITH_QUERY(Query_for_list_of_set_vars); - else if (pg_strcasecmp(prev_wd, "SHOW") == 0) + else if (TAIL_MATCHES1("SHOW")) COMPLETE_WITH_QUERY(Query_for_list_of_show_vars); /* Complete "SET TRANSACTION" */ - else if ((pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "TRANSACTION") == 0) - || (pg_strcasecmp(prev2_wd, "START") == 0 - && pg_strcasecmp(prev_wd, "TRANSACTION") == 0) - || (pg_strcasecmp(prev2_wd, "BEGIN") == 0 - && pg_strcasecmp(prev_wd, "WORK") == 0) - || (pg_strcasecmp(prev2_wd, "BEGIN") == 0 - && pg_strcasecmp(prev_wd, "TRANSACTION") == 0) - || (pg_strcasecmp(prev4_wd, "SESSION") == 0 - && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 - && pg_strcasecmp(prev2_wd, "AS") == 0 - && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)) - { - static const char *const my_list[] = - {"ISOLATION LEVEL", "READ", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if ((pg_strcasecmp(prev3_wd, "SET") == 0 - || pg_strcasecmp(prev3_wd, "BEGIN") == 0 - || pg_strcasecmp(prev3_wd, "START") == 0 - || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0 - && pg_strcasecmp(prev3_wd, "AS") == 0)) - && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 - || pg_strcasecmp(prev2_wd, "WORK") == 0) - && pg_strcasecmp(prev_wd, "ISOLATION") == 0) + else if (TAIL_MATCHES2("SET|BEGIN|START", "TRANSACTION") || + TAIL_MATCHES2("BEGIN", "WORK") || + TAIL_MATCHES4("SESSION", "CHARACTERISTICS", "AS", "TRANSACTION")) + COMPLETE_WITH_LIST2("ISOLATION LEVEL", "READ"); + else if (TAIL_MATCHES3("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION") || + TAIL_MATCHES4("CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION")) COMPLETE_WITH_CONST("LEVEL"); - else if ((pg_strcasecmp(prev4_wd, "SET") == 0 - || pg_strcasecmp(prev4_wd, "BEGIN") == 0 - || pg_strcasecmp(prev4_wd, "START") == 0 - || pg_strcasecmp(prev4_wd, "AS") == 0) - && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0 - || pg_strcasecmp(prev3_wd, "WORK") == 0) - && pg_strcasecmp(prev2_wd, "ISOLATION") == 0 - && pg_strcasecmp(prev_wd, "LEVEL") == 0) - { - static const char *const my_list[] = - {"READ", "REPEATABLE", "SERIALIZABLE", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 || - pg_strcasecmp(prev4_wd, "WORK") == 0) && - pg_strcasecmp(prev3_wd, "ISOLATION") == 0 && - pg_strcasecmp(prev2_wd, "LEVEL") == 0 && - pg_strcasecmp(prev_wd, "READ") == 0) - { - static const char *const my_list[] = - {"UNCOMMITTED", "COMMITTED", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 || - pg_strcasecmp(prev4_wd, "WORK") == 0) && - pg_strcasecmp(prev3_wd, "ISOLATION") == 0 && - pg_strcasecmp(prev2_wd, "LEVEL") == 0 && - pg_strcasecmp(prev_wd, "REPEATABLE") == 0) + else if (TAIL_MATCHES4("SET|BEGIN|START|AS", "TRANSACTION|WORK", "ISOLATION", "LEVEL")) + COMPLETE_WITH_LIST3("READ", "REPEATABLE", "SERIALIZABLE"); + else if (TAIL_MATCHES4("TRANSACTION|WORK", "ISOLATION", "LEVEL", "READ")) + COMPLETE_WITH_LIST2("UNCOMMITTED", "COMMITTED"); + else if (TAIL_MATCHES4("TRANSACTION|WORK", "ISOLATION", "LEVEL", "REPEATABLE")) COMPLETE_WITH_CONST("READ"); - else if ((pg_strcasecmp(prev3_wd, "SET") == 0 || - pg_strcasecmp(prev3_wd, "BEGIN") == 0 || - pg_strcasecmp(prev3_wd, "START") == 0 || - pg_strcasecmp(prev3_wd, "AS") == 0) && - (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 || - pg_strcasecmp(prev2_wd, "WORK") == 0) && - pg_strcasecmp(prev_wd, "READ") == 0) - { - static const char *const my_list[] = - {"ONLY", "WRITE", NULL}; - - COMPLETE_WITH_LIST(my_list); - } + else if (TAIL_MATCHES3("SET|BEGIN|START|AS", "TRANSACTION|WORK", "READ")) + COMPLETE_WITH_LIST2("ONLY", "WRITE"); /* SET CONSTRAINTS */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "CONSTRAINTS") == 0) - { + else if (TAIL_MATCHES2("SET", "CONSTRAINTS")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, "UNION SELECT 'ALL'"); - } /* Complete SET CONSTRAINTS with DEFERRED|IMMEDIATE */ - else if (pg_strcasecmp(prev3_wd, "SET") == 0 && - pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0) - { - static const char *const constraint_list[] = - {"DEFERRED", "IMMEDIATE", NULL}; - - COMPLETE_WITH_LIST(constraint_list); - } + else if (TAIL_MATCHES3("SET", "CONSTRAINTS", ANY)) + COMPLETE_WITH_LIST2("DEFERRED", "IMMEDIATE"); /* Complete SET ROLE */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "ROLE") == 0) + else if (TAIL_MATCHES2("SET", "ROLE")) COMPLETE_WITH_QUERY(Query_for_list_of_roles); /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "SESSION") == 0) - { - static const char *const my_list[] = - {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL}; - - COMPLETE_WITH_LIST(my_list); - } + else if (TAIL_MATCHES2("SET", "SESSION")) + COMPLETE_WITH_LIST2("AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION"); /* Complete SET SESSION AUTHORIZATION with username */ - else if (pg_strcasecmp(prev3_wd, "SET") == 0 - && pg_strcasecmp(prev2_wd, "SESSION") == 0 - && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0) + else if (TAIL_MATCHES3("SET", "SESSION", "AUTHORIZATION")) COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'"); /* Complete RESET SESSION with AUTHORIZATION */ - else if (pg_strcasecmp(prev2_wd, "RESET") == 0 && - pg_strcasecmp(prev_wd, "SESSION") == 0) + else if (TAIL_MATCHES2("RESET", "SESSION")) COMPLETE_WITH_CONST("AUTHORIZATION"); /* Complete SET with "TO" */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev4_wd, "UPDATE") != 0 && - pg_strcasecmp(prev_wd, "TABLESPACE") != 0 && - pg_strcasecmp(prev_wd, "SCHEMA") != 0 && - prev_wd[strlen(prev_wd) - 1] != ')' && - prev_wd[strlen(prev_wd) - 1] != '=' && - pg_strcasecmp(prev4_wd, "DOMAIN") != 0) + else if (MATCHES2("SET", ANY)) COMPLETE_WITH_CONST("TO"); /* Suggest possible variable values */ - else if (pg_strcasecmp(prev3_wd, "SET") == 0 && - (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0)) + else if (TAIL_MATCHES3("SET", ANY, "TO|=")) { - if (pg_strcasecmp(prev2_wd, "DateStyle") == 0) + if (TAIL_MATCHES2("DateStyle", "TO|=")) { static const char *const my_list[] = {"ISO", "SQL", "Postgres", "German", @@ -3604,66 +2541,48 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(my_list); } - else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0) - { - static const char *const my_list[] = - {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if (pg_strcasecmp(prev2_wd, "GEQO") == 0) - { - static const char *const my_list[] = - {"ON", "OFF", "DEFAULT", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if (pg_strcasecmp(prev2_wd, "search_path") == 0) - { + else if (TAIL_MATCHES2("IntervalStyle", "TO|=")) + COMPLETE_WITH_LIST4("postgres", "postgres_verbose", "sql_standard", "iso_8601"); + else if (TAIL_MATCHES2("GEQO", "TO|=")) + COMPLETE_WITH_LIST3("ON", "OFF", "DEFAULT"); + else if (TAIL_MATCHES2("search_path", "TO|=")) COMPLETE_WITH_QUERY(Query_for_list_of_schemas " AND nspname not like 'pg\\_toast%%' " " AND nspname not like 'pg\\_temp%%' " " UNION SELECT 'DEFAULT' "); - } else - { - static const char *const my_list[] = - {"DEFAULT", NULL}; - - COMPLETE_WITH_LIST(my_list); - } + COMPLETE_WITH_CONST("DEFAULT"); } /* START TRANSACTION */ - else if (pg_strcasecmp(prev_wd, "START") == 0) + else if (TAIL_MATCHES1("START")) COMPLETE_WITH_CONST("TRANSACTION"); /* TABLE, but not TABLE embedded in other commands */ - else if (pg_strcasecmp(prev_wd, "TABLE") == 0 && - prev2_wd[0] == '\0') + else if (TAIL_MATCHES2("", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL); /* TABLESAMPLE */ - else if (pg_strcasecmp(prev_wd, "TABLESAMPLE") == 0) + else if (TAIL_MATCHES1("TABLESAMPLE")) COMPLETE_WITH_QUERY(Query_for_list_of_tablesample_methods); - else if (pg_strcasecmp(prev2_wd, "TABLESAMPLE") == 0) + else if (TAIL_MATCHES2("TABLESTAMPLE", ANY)) COMPLETE_WITH_CONST("("); /* TRUNCATE */ - else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0) + else if (TAIL_MATCHES1("TRUNCATE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* UNLISTEN */ - else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0) + else if (TAIL_MATCHES1("UNLISTEN")) COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s' UNION SELECT '*'"); /* UPDATE */ /* If prev. word is UPDATE suggest a list of tables */ - else if (pg_strcasecmp(prev_wd, "UPDATE") == 0) + else if (TAIL_MATCHES1("UPDATE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL); /* Complete UPDATE
with "SET" */ - else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0) + else if (TAIL_MATCHES2("UPDATE", ANY)) COMPLETE_WITH_CONST("SET"); /* @@ -3671,83 +2590,54 @@ psql_completion(const char *text, int start, int end) * word) the word before it was (hopefully) a table name and we'll now * make a list of attributes. */ - else if (pg_strcasecmp(prev_wd, "SET") == 0) + else if (TAIL_MATCHES2(ANY, "SET")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* UPDATE xx SET yy = */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev4_wd, "UPDATE") == 0) + else if (TAIL_MATCHES4("UPDATE", ANY, "SET", ANY)) COMPLETE_WITH_CONST("="); /* USER MAPPING */ - else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 || - pg_strcasecmp(prev3_wd, "CREATE") == 0 || - pg_strcasecmp(prev3_wd, "DROP") == 0) && - pg_strcasecmp(prev2_wd, "USER") == 0 && - pg_strcasecmp(prev_wd, "MAPPING") == 0) + else if (TAIL_MATCHES3("ALTER|CREATE|DROP", "USER", "MAPPING")) COMPLETE_WITH_CONST("FOR"); - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "USER") == 0 && - pg_strcasecmp(prev2_wd, "MAPPING") == 0 && - pg_strcasecmp(prev_wd, "FOR") == 0) + else if (TAIL_MATCHES4("CREATE", "USER", "MAPPING", "FOR")) COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'CURRENT_USER'" " UNION SELECT 'PUBLIC'" " UNION SELECT 'USER'"); - else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 || - pg_strcasecmp(prev4_wd, "DROP") == 0) && - pg_strcasecmp(prev3_wd, "USER") == 0 && - pg_strcasecmp(prev2_wd, "MAPPING") == 0 && - pg_strcasecmp(prev_wd, "FOR") == 0) + else if (TAIL_MATCHES4("ALTER|DROP", "USER", "MAPPING", "FOR")) COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings); - else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 || - pg_strcasecmp(prev5_wd, "ALTER") == 0 || - pg_strcasecmp(prev5_wd, "DROP") == 0) && - pg_strcasecmp(prev4_wd, "USER") == 0 && - pg_strcasecmp(prev3_wd, "MAPPING") == 0 && - pg_strcasecmp(prev2_wd, "FOR") == 0) + else if (TAIL_MATCHES5("CREATE|ALTER|DROP", "USER", "MAPPING", "FOR", ANY)) COMPLETE_WITH_CONST("SERVER"); /* * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ] * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ] */ - else if (pg_strcasecmp(prev_wd, "VACUUM") == 0) + else if (TAIL_MATCHES1("VACUUM")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'FULL'" " UNION SELECT 'FREEZE'" " UNION SELECT 'ANALYZE'" " UNION SELECT 'VERBOSE'"); - else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 && - (pg_strcasecmp(prev_wd, "FULL") == 0 || - pg_strcasecmp(prev_wd, "FREEZE") == 0)) + else if (TAIL_MATCHES2("VACUUM", "FULL|FREEZE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'ANALYZE'" " UNION SELECT 'VERBOSE'"); - else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 && - pg_strcasecmp(prev_wd, "ANALYZE") == 0 && - (pg_strcasecmp(prev2_wd, "FULL") == 0 || - pg_strcasecmp(prev2_wd, "FREEZE") == 0)) + else if (TAIL_MATCHES3("VACUUM", "FULL|FREEZE", "ANALYZE|ANALYSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'VERBOSE'"); - else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 && - pg_strcasecmp(prev_wd, "VERBOSE") == 0 && - (pg_strcasecmp(prev2_wd, "FULL") == 0 || - pg_strcasecmp(prev2_wd, "FREEZE") == 0)) + else if (TAIL_MATCHES3("VACUUM", "FULL|FREEZE", "VERBOSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'ANALYZE'"); - else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 && - pg_strcasecmp(prev_wd, "VERBOSE") == 0) + else if TAIL_MATCHES2("VACUUM", "VERBOSE") COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'ANALYZE'"); - else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 && - pg_strcasecmp(prev_wd, "ANALYZE") == 0) + else if (TAIL_MATCHES2("VACUUM", "ANALYZE|ANALYSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'VERBOSE'"); - else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 && - pg_strcasecmp(prev2_wd, "VERBOSE") == 0) || - (pg_strcasecmp(prev_wd, "VERBOSE") == 0 && - pg_strcasecmp(prev2_wd, "ANALYZE") == 0)) + else if (TAIL_MATCHES2("VERBOSE", "ANALYZE|ANALYSE") || + TAIL_MATCHES2("ANALYZE|ANALYSE", "VERBOSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL); /* WITH [RECURSIVE] */ @@ -3756,29 +2646,26 @@ psql_completion(const char *text, int start, int end) * Only match when WITH is the first word, as WITH may appear in many * other contexts. */ - else if (pg_strcasecmp(prev_wd, "WITH") == 0 && - prev2_wd[0] == '\0') + else if (MATCHES1("WITH")) COMPLETE_WITH_CONST("RECURSIVE"); /* ANALYZE */ /* If the previous word is ANALYZE, produce list of tables */ - else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0) + else if (TAIL_MATCHES1("ANALYZE|ANALYSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, NULL); /* WHERE */ /* Simple case of the word before the where being the table name */ - else if (pg_strcasecmp(prev_wd, "WHERE") == 0) + else if (TAIL_MATCHES1("WHERE")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* ... FROM ... */ /* TODO: also include SRF ? */ - else if (pg_strcasecmp(prev_wd, "FROM") == 0 && - pg_strcasecmp(prev3_wd, "COPY") != 0 && - pg_strcasecmp(prev3_wd, "\\copy") != 0) + else if (TAIL_MATCHES1("FROM") && !MATCHES3("COPY|\\copy", ANY, "FROM")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL); /* ... JOIN ... */ - else if (pg_strcasecmp(prev_wd, "JOIN") == 0) + else if (TAIL_MATCHES1("JOIN")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL); /* Backslash commands */