From ee87e03e479fd920d6aa697e95617c52abc664e2 Mon Sep 17 00:00:00 2001 From: chenxiaobin <1025221611@qq.com> Date: Fri, 19 Mar 2021 15:39:15 +0800 Subject: [PATCH 1/2] add HISTSIZE for readline to limit the number of cached commands --- doc/src/sgml/ref/psql-ref.sgmlin | 16 +++++++++++ src/bin/psql/command.cpp | 12 ++++++++ src/bin/psql/input.cpp | 39 ++++++++++++++++++++++++++ src/bin/psql/input.h | 4 ++- src/bin/psql/mainloop.cpp | 5 ++++ src/bin/psql/startup.cpp | 1 + src/bin/psql/tab-complete.cpp | 4 +++ src/test/regress/expected/readline.out | 8 ++++++ src/test/regress/sql/readline.sql | 8 ++++++ 9 files changed, 96 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/psql-ref.sgmlin b/doc/src/sgml/ref/psql-ref.sgmlin index bfbc6b136..8e387204e 100644 --- a/doc/src/sgml/ref/psql-ref.sgmlin +++ b/doc/src/sgml/ref/psql-ref.sgmlin @@ -2833,6 +2833,22 @@ bar + + HISTSIZE + + + The number of commands to store in the command history. The + default value is 500. + + + + This feature was shamelessly plagiarized from + Bash. + + + + + HOST diff --git a/src/bin/psql/command.cpp b/src/bin/psql/command.cpp index 56a5413a8..f0587febd 100644 --- a/src/bin/psql/command.cpp +++ b/src/bin/psql/command.cpp @@ -1051,6 +1051,12 @@ static backslashResult exec_command(const char* cmd, PsqlScanState scan_state, P success = false; } +#ifdef USE_READLINE + if (useReadline && pset.cur_cmd_interactive) { + setHistSize(opt0, newval, false); + } +#endif + free(newval); newval = NULL; if (temp_opt != NULL) @@ -1255,6 +1261,12 @@ static backslashResult exec_command(const char* cmd, PsqlScanState scan_state, P success = false; } +#ifdef USE_READLINE + if (useReadline && pset.cur_cmd_interactive) { + setHistSize(opt, NULL, true); + } +#endif + if (NULL != opt) { free(opt); opt = NULL; diff --git a/src/bin/psql/input.cpp b/src/bin/psql/input.cpp index aac0ab555..cc48a2559 100644 --- a/src/bin/psql/input.cpp +++ b/src/bin/psql/input.cpp @@ -248,6 +248,45 @@ bool SensitiveStrCheck(const char* target) } } +void setHistSize(const char* targetName, const char* targetValue, bool setToDefault) +{ +#ifndef ENABLE_LLT + char* end = NULL; + long int result; +#define MAXHISTSIZE 500 +#define DEFHISTSIZE 32 + if (targetName == NULL) { + return; + } + if (strcmp(targetName, "HISTSIZE") == 0) { + if (!setToDefault) { + if (targetValue == NULL || strlen(targetValue) == 0) { + fprintf(stderr, "warning:\"HISTSIZE\" is not changed,because its value can not be null\n"); + return; + } else { + errno = 0; + result = strtol(targetValue, &end, 0); + if ((errno == ERANGE && (result == LONG_MAX || result == LONG_MIN)) || (errno != 0 && result == 0)) { + fprintf(stderr, "warning:\"HISTSIZE\" is not changed,because its value overflows\n"); + return; + } + if (*end || result < 0) { + fprintf(stderr, "warning:\"HISTSIZE\" is not changed,because its value must be positive integer\n"); + return; + } + } + if (result > MAXHISTSIZE) { + fprintf(stderr, "warning:\"HISTSIZE\" is set to 500,because its value can not be greater than 500\n"); + result = MAXHISTSIZE; + } + } else { + result = DEFHISTSIZE; + } + stifle_history((int)result); + } +#endif +} + /* * Put any startup stuff related to input in here. It's good to maintain * abstraction this way. diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h index b184f0217..5e871518f 100644 --- a/src/bin/psql/input.h +++ b/src/bin/psql/input.h @@ -8,7 +8,6 @@ #ifndef INPUT_H #define INPUT_H -#ifdef HAVE_LIBREADLINE /* * If some other file needs to have access to readline/history, include this * file and save yourself all this work. @@ -17,6 +16,8 @@ */ #define USE_READLINE 1 +#ifdef HAVE_LIBREADLINE + #if defined(HAVE_READLINE_READLINE_H) #include #include @@ -36,6 +37,7 @@ char* gets_fromFile(FILE* source); void pg_append_history(const char* s, PQExpBuffer history_buf); void pg_send_history(PQExpBuffer history_buf); +void setHistSize(const char* targetName, const char* targetValue, bool setToDefault); extern bool useReadline; extern bool SensitiveStrCheck(const char* target); diff --git a/src/bin/psql/mainloop.cpp b/src/bin/psql/mainloop.cpp index 1931e7c84..ecd7cc09b 100644 --- a/src/bin/psql/mainloop.cpp +++ b/src/bin/psql/mainloop.cpp @@ -148,6 +148,11 @@ int MainLoop(FILE* source, char* querystring) } pset.lineno = 0; + if (pset.cur_cmd_interactive) { + const char* val = GetVariable(pset.vars, "HISTSIZE"); + setHistSize("HISTSIZE", val, val == NULL); + } + /* Create working state */ scan_state = psql_scan_create(); diff --git a/src/bin/psql/startup.cpp b/src/bin/psql/startup.cpp index 288140366..f20c593c4 100755 --- a/src/bin/psql/startup.cpp +++ b/src/bin/psql/startup.cpp @@ -781,6 +781,7 @@ static void parse_psql_options(int argc, char* const argv[], struct adhoc_opts* fprintf(stderr, _("%s: could not set variable \"%s\"\n"), pset.progname, value); exit(EXIT_FAILURE); } + setHistSize(value, equal_loc + 1, false); } free(value); diff --git a/src/bin/psql/tab-complete.cpp b/src/bin/psql/tab-complete.cpp index 5942fdd98..cf854c436 100644 --- a/src/bin/psql/tab-complete.cpp +++ b/src/bin/psql/tab-complete.cpp @@ -754,8 +754,12 @@ void initialize_readline(void) { rl_readline_name = (char *)pset.progname; +#ifdef HAVE_READLINE_READLINE_H /* PsqlCompletion is deleted because it's too complex and not be used at all. */ rl_attempted_completion_function = PsqlCompletion; +#else + rl_attempted_completion_function = NULL; +#endif rl_basic_word_break_characters = WORD_BREAKS; diff --git a/src/test/regress/expected/readline.out b/src/test/regress/expected/readline.out index 048f3b4b6..a2d33fb25 100644 --- a/src/test/regress/expected/readline.out +++ b/src/test/regress/expected/readline.out @@ -7,3 +7,11 @@ select * from 数据库; 1 (1 row) +\set HISTSIZE -1 +\set HISTSIZE 30.5 +\set HISTSIZE 0 +\set HISTSIZE 6 +\set HISTSIZE 500 +\set HISTSIZE 600 +\set HISTSIZE 66666666666666666666666600 +\set HISTSIZE -666666666666666666666666666 diff --git a/src/test/regress/sql/readline.sql b/src/test/regress/sql/readline.sql index de975aab3..0e81f8368 100644 --- a/src/test/regress/sql/readline.sql +++ b/src/test/regress/sql/readline.sql @@ -2,3 +2,11 @@ create table 数据库(f int); insert into 数据库 values (1); select * from 数据库; +\set HISTSIZE -1 +\set HISTSIZE 30.5 +\set HISTSIZE 0 +\set HISTSIZE 6 +\set HISTSIZE 500 +\set HISTSIZE 600 +\set HISTSIZE 66666666666666666666666600 +\set HISTSIZE -666666666666666666666666666 From 0d5034739d3908b92bc13502adc7442eb5d9c957 Mon Sep 17 00:00:00 2001 From: chenxiaobin <1025221611@qq.com> Date: Fri, 16 Apr 2021 10:33:00 +0800 Subject: [PATCH 2/2] fix some unsupported syntax for tab-completion --- src/bin/psql/tab-complete.cpp | 630 +++++++++++++++++++++++++++++----- 1 file changed, 551 insertions(+), 79 deletions(-) diff --git a/src/bin/psql/tab-complete.cpp b/src/bin/psql/tab-complete.cpp index cf854c436..18fa3115f 100644 --- a/src/bin/psql/tab-complete.cpp +++ b/src/bin/psql/tab-complete.cpp @@ -313,7 +313,7 @@ static const SchemaQuery Query_for_list_of_tables = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r')", + "c.relkind IN ('r', 'f')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -331,7 +331,7 @@ static const SchemaQuery Query_for_list_of_insertables = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS " + "(c.relkind IN ('r', 'f') OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS " "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", @@ -435,6 +435,21 @@ static const SchemaQuery Query_for_list_of_tm = { NULL }; +static const SchemaQuery Query_for_list_of_tmi = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "c.relkind IN ('r', 'm', 'i')", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL +}; + static const SchemaQuery Query_for_list_of_views = { /* catname */ "pg_catalog.pg_class c", @@ -522,6 +537,12 @@ static const SchemaQuery Query_for_list_of_matviews = { #define Query_for_list_of_schemas "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace " \ " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'" +#define Query_for_list_of_alter_system_set_vars "SELECT name FROM " \ + " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\ + " WHERE context != 'internal' "\ + " UNION ALL SELECT 'all') ss "\ + " WHERE substring(name,1,%d)='%s'" + #define Query_for_list_of_set_vars "SELECT name FROM " \ " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings " \ " WHERE context IN ('user', 'superuser') " \ @@ -652,6 +673,7 @@ static const pgsql_thing_t words_after_create[] = { #endif {"CAST", NULL, NULL, 0}, /* Casts have complex structures for names, so * skip it */ + {"CLIENT MASTER KEY", NULL, NULL, 0}, {"COLLATION", "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding IN (-1, " "pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) AND " @@ -659,6 +681,7 @@ static const pgsql_thing_t words_after_create[] = { NULL, 0}, + {"COLUMN ENCRYPTION KEY", NULL, NULL, 0}, /* * CREATE CONSTRAINT TRIGGER is not supported here because it is designed * to be used only by pg_dump. @@ -673,24 +696,26 @@ static const pgsql_thing_t words_after_create[] = { {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW}, {"DOMAIN", NULL, &Query_for_list_of_domains, 0}, {"EXTENSION", Query_for_list_of_extensions, NULL, 0}, -#ifndef PGXC {"FOREIGN DATA WRAPPER", NULL, NULL, 0}, {"FOREIGN TABLE", NULL, NULL, 0}, -#endif {"FUNCTION", NULL, &Query_for_list_of_functions, 0}, + {"GLOBAL", NULL, NULL, 0}, {"GROUP", Query_for_list_of_roles, NULL, 0}, + {"INCREMENTAL MATERIALIZED VIEW", NULL, NULL, 0}, {"INDEX", NULL, &Query_for_list_of_indexes, 0}, {"LANGUAGE", Query_for_list_of_languages, NULL, 0}, + {"LOCAL", NULL, NULL, 0}, {"MATERIALIZED VIEW", NULL, &Query_for_list_of_matviews, 0}, #ifdef PGXC {"NODE", Query_for_list_of_available_nodenames, NULL, 0}, {"NODE GROUP", Query_for_list_of_available_nodegroup_names, NULL, 0}, #endif - {"OPERATOR", NULL, NULL, 0}, /* Querying for this is probably not such a - * good idea. */ + {"OPERATOR", NULL, NULL, 0}, /* Querying for this is probably not such a good idea. */ + {"OR REPLACE", NULL, NULL, THING_NO_DROP}, {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */ {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW}, {"POLICY", NULL, NULL, 0}, + {"PROCEDURAL", NULL, NULL, 0}, {"PROCEDURE", NULL, Query_for_list_of_procedures, 0}, {"ROLE", Query_for_list_of_roles, NULL, 0}, {"RULE", @@ -698,11 +723,10 @@ static const pgsql_thing_t words_after_create[] = { "substring(pg_catalog.quote_ident(rulename),1,%d)='%s'", NULL, 0}, + {"ROW LEVEL SECURITY POLICY", NULL, NULL, 0}, {"SCHEMA", Query_for_list_of_schemas, NULL, 0}, {"SEQUENCE", NULL, &Query_for_list_of_sequences, 0}, -#ifndef PGXC {"SERVER", Query_for_list_of_servers, NULL, 0}, -#endif {"TABLE", NULL, &Query_for_list_of_tables, 0}, {"TABLESPACE", Query_for_list_of_tablespaces, NULL, 0}, {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */ @@ -714,6 +738,7 @@ static const pgsql_thing_t words_after_create[] = { "substring(pg_catalog.quote_ident(tgname),1,%d)='%s'", NULL, 0}, + {"TRUSTED", NULL, NULL, THING_NO_DROP}, {"TYPE", NULL, &Query_for_list_of_datatypes, 0}, {"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */ {"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE @@ -849,7 +874,7 @@ static char** PsqlCompletion(const char *text, int start, int end) char **matches = NULL; /* This array will contain some scannage of the input line. */ - char *previousWords[7]; + char *previousWords[8]; /* For compactness, we use these macros to reference previous_words[]. */ #define PREV_WD (previousWords[0]) @@ -859,9 +884,10 @@ static char** PsqlCompletion(const char *text, int start, int end) #define PREV5_WD (previousWords[4]) #define PREV6_WD (previousWords[5]) #define PREV7_WD (previousWords[6]) +#define PREV8_WD (previousWords[7]) static const char* const sqlCommands[] = { - "ABORT", "ALTER", "ANALYZE", "BEGIN", "CALL", "CHECKPOINT", "CLOSE", "CLUSTER", + "ABORT", "ALTER", "ANALYSE", "ANALYZE", "BEGIN", "CALL", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE", @@ -942,14 +968,86 @@ static char** PsqlCompletion(const char *text, int start, int end) /* CREATE */ /* complete with something you can create */ - else if (pg_strcasecmp(PREV_WD, "CREATE") == 0) + else if (pg_strcasecmp(PREV_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "GRANT") != 0 && + pg_strcasecmp(PREV2_WD, "REVOKE") != 0) matches = completion_matches(text, CreateCommandGenerator); + /* complete with something you can create or replace */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "OR") == 0 && + pg_strcasecmp(PREV_WD, "REPLACE") == 0) { + static const char* const listCreateOrReplace[] = {"FUNCTION", "PROCEDURE", "LANGUAGE", "RULE", "VIEW", + "AGGREGATE", "TRANSFORM", "TRIGGER", NULL}; + COMPLETE_WITH_LIST(listCreateOrReplace); + } + + else if ((pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "DATABASE") == 0 && + pg_strcasecmp(PREV_WD, "OWNER") == 0) || (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && + pg_strcasecmp(PREV4_WD, "DATABASE") == 0 && pg_strcasecmp(PREV2_WD, "OWNER") == 0 && + pg_strcasecmp(PREV_WD, "=") == 0)) { + COMPLETE_WITH_QUERY(Query_for_list_of_roles); + } + + /* complete CREATE COLUMN ENCRYPTION KEY with WITH VALUES ( */ + else if (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "COLUMN") == 0 && + pg_strcasecmp(PREV3_WD, "ENCRYPTION") == 0 && pg_strcasecmp(PREV2_WD, "KEY") == 0) { + COMPLETE_WITH_CONST("WITH VALUES ("); + } + + /* complete CREATE COLUMN ENCRYPTION KEY WITH VALUES ( with CLIENT_MASTER_KEY = */ + else if (pg_strcasecmp(PREV8_WD, "CREATE") == 0 && pg_strcasecmp(PREV7_WD, "COLUMN") == 0 && + pg_strcasecmp(PREV6_WD, "ENCRYPTION") == 0 && pg_strcasecmp(PREV5_WD, "KEY") == 0 && + pg_strcasecmp(PREV3_WD, "WITH") == 0 && pg_strcasecmp(PREV2_WD, "VALUES") == 0 && + pg_strcasecmp(PREV_WD, "(") == 0) { + COMPLETE_WITH_CONST("CLIENT_MASTER_KEY ="); + } + + /* complete CREATE COLUMN ENCRYPTION KEY WITH VALUES ( CLIENT_MASTER_KEY = , with ALGORITHM = */ + else if (pg_strcasecmp(PREV4_WD, "CLIENT_MASTER_KEY") == 0 && pg_strcasecmp(PREV3_WD, "=") == 0 && + pg_strcasecmp(PREV_WD, ",") == 0) { + COMPLETE_WITH_CONST("ALGORITHM ="); + } + else if (pg_strcasecmp(PREV8_WD, "CLIENT_MASTER_KEY") == 0 && pg_strcasecmp(PREV4_WD, "ALGORITHM") == 0 && + pg_strcasecmp(PREV3_WD, "=") == 0 && pg_strcasecmp(PREV_WD, ",") == 0) { + COMPLETE_WITH_CONST("ENCRYPTED_VALUE ="); + } + + /* complete CREATE CLIENT MASTER KEY with WITH ( */ + else if (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "CLIENT") == 0 && + pg_strcasecmp(PREV3_WD, "MASTER") == 0 && pg_strcasecmp(PREV2_WD, "KEY") == 0) { + COMPLETE_WITH_CONST("WITH ("); + } + + /* complete CREATE CLIENT MASTER KEY WITH ( with KEY_STORE = */ + else if (pg_strcasecmp(PREV7_WD, "CREATE") == 0 && pg_strcasecmp(PREV6_WD, "CLIENT") == 0 && + pg_strcasecmp(PREV5_WD, "MASTER") == 0 && pg_strcasecmp(PREV4_WD, "KEY") == 0 && + pg_strcasecmp(PREV2_WD, "WITH") == 0 && pg_strcasecmp(PREV_WD, "(") == 0) { + COMPLETE_WITH_CONST("KEY_STORE ="); + } + else if (pg_strcasecmp(PREV4_WD, "KEY_STORE") == 0 && pg_strcasecmp(PREV3_WD, "=") == 0 && + pg_strcasecmp(PREV_WD, ",") == 0) { + COMPLETE_WITH_CONST("KEY_PATH ="); + } + else if (pg_strcasecmp(PREV4_WD, "KEY_PATH") == 0 && pg_strcasecmp(PREV3_WD, "=") == 0 && + pg_strcasecmp(PREV_WD, ",") == 0) { + COMPLETE_WITH_CONST("ALGORITHM ="); + } + + /* complete with AUTHORIZATION in ALTER SCHEMA xxx */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "SCHEMA") == 0 && + pg_strcasecmp(PREV_WD, "AUTHORIZATION") != 0) + COMPLETE_WITH_CONST("AUTHORIZATION"); + + else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "SCHEMA") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_schemas "UNION SELECT 'AUTHORIZATION'"); + /* 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') matches = completion_matches(text, DropCommandGenerator); + else if (pg_strcasecmp(PREV3_WD, "PARTITION") == 0 && pg_strcasecmp(PREV_WD, "VALUES")) + COMPLETE_WITH_CONST("LESS THAN"); + /* ALTER */ /* @@ -961,14 +1059,14 @@ static char** PsqlCompletion(const char *text, int start, int end) "AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION", "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR", - "POLICY", "PROCEDURE", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE", - "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", - "USER", "USER MAPPING FOR", "VIEW", NULL + "POLICY", "PROCEDURE", "ROLE", "ROW LEVEL SECURITY POLICY", "RULE", "SCHEMA", + "SERVER", "SESSION", "SEQUENCE", "SYSTEM", "TABLE", "TABLESPACE", "TEXT SEARCH", "TRIGGER", + "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL }; COMPLETE_WITH_LIST(listAlter); } - /* ALTER AGGREGATE,FUNCTION,PROCEDURE */ + /* ALTER AGGREGATE,FUNCTION,PROCEDURE */ else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && (pg_strcasecmp(PREV2_WD, "AGGREGATE") == 0 || pg_strcasecmp(PREV2_WD, "FUNCTION") == 0 || pg_strcasecmp(PREV2_WD, "PROCEDURE") == 0)) COMPLETE_WITH_CONST("("); @@ -990,6 +1088,21 @@ static char** PsqlCompletion(const char *text, int start, int end) } } + /* ALTER SESSION */ + else if (pg_strcasecmp(PREV2_WD, "ALTER") == 0 && pg_strcasecmp(PREV_WD, "SESSION") == 0) + COMPLETE_WITH_CONST("SET"); + + /* ALTER SYSTEM */ + else if (pg_strcasecmp(PREV2_WD, "ALTER") == 0 && pg_strcasecmp(PREV_WD, "SYSTEM") == 0) { + static const char* const listAlterSystem[] = {"KILL SESSION", "SET", NULL}; + + COMPLETE_WITH_LIST(listAlterSystem); + } + + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SYSTEM") == 0 && + pg_strcasecmp(PREV_WD, "SET") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars); + /* ALTER SCHEMA */ else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SCHEMA") == 0) { static const char* const listAlterGen[] = {"OWNER TO", "RENAME TO", NULL}; @@ -1014,10 +1127,18 @@ static char** PsqlCompletion(const char *text, int start, int end) /* ALTER DATABASE */ else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "DATABASE") == 0) { static const char* const listAlterDatabase[] = { - "RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL + "WITH", "RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", "ENABLE PRIVATE OBJECT", + "DISABLE PRIVATE OBJECT", NULL }; COMPLETE_WITH_LIST(listAlterDatabase); + } else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "DATABASE") == 0 && + pg_strcasecmp(PREV_WD, "WITH") == 0) { + static const char* const listAlterDatabaseWith[] = { + "CONNECTION LIMIT", "ENABLE PRIVATE OBJECT", "DISABLE PRIVATE OBJECT", NULL + }; + + COMPLETE_WITH_LIST(listAlterDatabaseWith); } /* ALTER EXTENSION */ @@ -1102,34 +1223,64 @@ static char** PsqlCompletion(const char *text, int start, int end) !(pg_strcasecmp(PREV2_WD, "USER") == 0 && pg_strcasecmp(PREV_WD, "MAPPING") == 0) && (pg_strcasecmp(PREV2_WD, "USER") == 0 || pg_strcasecmp(PREV2_WD, "ROLE") == 0)) { static const char* const listAlterUser[] = { - "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", - "ENCRYPTED", "IDENT", "IDENTIFIED BY", "INHERIT", "LOGIN", - "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", - "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO", - "REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED", - "VALID UNTIL", "WITH", NULL + "ACCOUNT", "AUDITADMIN", "CONNECTION LIMIT", "CREATEDB", + "CREATEROLE", "CREATEUSER", "ENCRYPTED", "IDENT", "IDENTIFIED BY", + "INDEPENDENT", "INHERIT", "LOGIN", "MONADMIN", "NOAUDITADMIN", + "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NODE GROUP", + "NOINDEPENDENT", "NOINHERIT", "NOLOGIN", "NOMONADMIN", "NOOPRADMIN", + "NOPERSISTENCE", "NOPOLADMIN", "NOREPLICATION", "NOSUPERUSER", + "NOSYSADMIN", "NOUSEFT", "NOVCADMIN", "OPRADMIN", "PASSWORD", + "PERM SPACE", "PERSISTENCE", "PGUSER", "POLADMIN", "RENAME TO", + "REPLICATION", "RESET", "RESOURCE POOL", "SET", "SPILL SPACE", + "SUPERUSER", "SYSADMIN", "TEMP SPACE", "UNENCRYPTED", "USEFT", + "USER GROUP", "VALID", "VCADMIN", "WITH", NULL }; COMPLETE_WITH_LIST(listAlterUser); } + /* ALTER USER,ROLE VALID*/ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && + !(pg_strcasecmp(PREV3_WD, "USER") == 0 && pg_strcasecmp(PREV2_WD, "MAPPING") == 0) && + (pg_strcasecmp(PREV3_WD, "USER") == 0 || pg_strcasecmp(PREV3_WD, "ROLE") == 0) && + pg_strcasecmp(PREV_WD, "VALID") == 0) { + static const char* const listAlterUserValid[] = {"BEGIN", "UNTIL", NULL}; + + COMPLETE_WITH_LIST(listAlterUserValid); + } + /* 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)) { /* Similar to the above, but don't complete "WITH" again. */ static const char* const listAlterUserWith[] = { - "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", - "ENCRYPTED", "IDENT", "IDENTIFIED BY", "INHERIT", "LOGIN", - "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", - "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO", - "REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED", - "VALID UNTIL", NULL + "ACCOUNT", "AUDITADMIN", "CONNECTION LIMIT", "CREATEDB", + "CREATEROLE", "CREATEUSER", "ENCRYPTED", "IDENT", "IDENTIFIED BY", + "INDEPENDENT", "INHERIT", "LOGIN", "MONADMIN", "NOAUDITADMIN", + "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NODE GROUP", + "NOINDEPENDENT", "NOINHERIT", "NOLOGIN", "NOMONADMIN", "NOOPRADMIN", + "NOPERSISTENCE", "NOPOLADMIN", "NOREPLICATION", "NOSUPERUSER", + "NOSYSADMIN", "NOUSEFT", "NOVCADMIN", "OPRADMIN", "PASSWORD", + "PERM SPACE", "PERSISTENCE", "PGUSER", "POLADMIN", "RENAME TO", + "REPLICATION", "RESET", "RESOURCE POOL", "SET", "SPILL SPACE", + "SUPERUSER", "SYSADMIN", "TEMP SPACE", "UNENCRYPTED", "USEFT", + "USER GROUP", "VALID", "VCADMIN", NULL }; COMPLETE_WITH_LIST(listAlterUserWith); } + /* ALTER USER,ROLE WITH VALID*/ + else if ((pg_strcasecmp(PREV5_WD, "ALTER") == 0 && + (pg_strcasecmp(PREV4_WD, "USER") == 0 || pg_strcasecmp(PREV4_WD, "ROLE") == 0) && + pg_strcasecmp(PREV2_WD, "WITH") == 0) && pg_strcasecmp(PREV_WD, "VALID") == 0) { + /* Similar to the above, but don't complete "WITH" again. */ + static const char* const listAlterUserWithValid[] = {"BEGIN", "UNTIL", NULL}; + + COMPLETE_WITH_LIST(listAlterUserWithValid); + } + /* ALTER USER,ROLE ENCRYPTED,UNENCRYPTED */ else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && (pg_strcasecmp(PREV3_WD, "ROLE") == 0 || pg_strcasecmp(PREV3_WD, "USER") == 0) && @@ -1140,7 +1291,7 @@ static char** PsqlCompletion(const char *text, int start, int end) /* ALTER USER,ROLE WITH ENCRYPTED,UNENCRYPTED */ else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && (pg_strcasecmp(PREV4_WD, "ROLE") == 0 || - pg_strcasecmp(PREV4_WD, "USER") == 0) && pg_strcasecmp(PREV2_WD, "WITH") && + pg_strcasecmp(PREV4_WD, "USER") == 0) && pg_strcasecmp(PREV2_WD, "WITH") == 0 && (pg_strcasecmp(PREV_WD, "ENCRYPTED") == 0 || pg_strcasecmp(PREV_WD, "UNENCRYPTED") == 0)) { static const char* const listAlterUserWithEncrypted[] = {"IDENTIFIED BY", "PASSWORD", NULL}; COMPLETE_WITH_LIST(listAlterUserWithEncrypted); @@ -1204,23 +1355,16 @@ static char** PsqlCompletion(const char *text, int start, int end) /* ALTER SEQUENCE */ else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SEQUENCE") == 0) { static const char* const listAlterSequence[] = { - "INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE", - "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL + "MAXVALUE", "NO MAXVALUE", "NOMAXVALUE", "OWNED BY", "OWNER TO", NULL }; COMPLETE_WITH_LIST(listAlterSequence); } - /* 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 listAlterSequencE2[] = {"MINVALUE", "MAXVALUE", "CYCLE", NULL}; - COMPLETE_WITH_LIST(listAlterSequencE2); - } /* ALTER SERVER */ else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SERVER") == 0) { static const char* const listAlterServer[] = { - "VERSION", "OPTIONS", "OWNER TO", NULL + "VERSION", "OPTIONS", "OWNER TO", "RENAME TO", NULL }; COMPLETE_WITH_LIST(listAlterServer); @@ -1267,6 +1411,15 @@ static char** PsqlCompletion(const char *text, int start, int end) COMPLETE_WITH_LIST(listAlterview); } + + /* ALTER [ROW LEVEL SECURITY] POLICY on */ + else if ((pg_strcasecmp(PREV8_WD, "ALTER") == 0 || pg_strcasecmp(PREV5_WD, "ALTER") == 0) && + pg_strcasecmp(PREV4_WD, "POLICY") == 0 && pg_strcasecmp(PREV2_WD, "ON") == 0) { + static const char* const listAlterPolicy[] = {"RENAME TO", "TO", "USING (", NULL}; + + COMPLETE_WITH_LIST(listAlterPolicy); + } + /* ALTER TRIGGER , add ON */ else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TRIGGER") == 0) COMPLETE_WITH_CONST("ON"); @@ -1284,7 +1437,8 @@ static char** PsqlCompletion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* ALTER TRIGGER ON */ - else if (pg_strcasecmp(PREV4_WD, "TRIGGER") == 0 && pg_strcasecmp(PREV2_WD, "ON") == 0) + else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "TRIGGER") == 0 && + pg_strcasecmp(PREV2_WD, "ON") == 0) COMPLETE_WITH_CONST("RENAME TO"); /* @@ -1638,8 +1792,10 @@ static char** PsqlCompletion(const char *text, int start, int end) (pg_strcasecmp(PREV2_WD, "COPY") == 0 && pg_strcasecmp(PREV_WD, "BINARY") == 0)) 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) { + else if ((pg_strcasecmp(PREV2_WD, "COPY") == 0 || pg_strcasecmp(PREV2_WD, "\\copy") == 0 || + pg_strcasecmp(PREV2_WD, "BINARY") == 0) || ((pg_strcasecmp(PREV3_WD, "COPY") == 0 || + pg_strcasecmp(PREV3_WD, "\\copy") == 0 || pg_strcasecmp(PREV3_WD, "BINARY") == 0) && + PREV_WD[strlen(PREV_WD) - 1] == ')')) { static const char* const listFromTo[] = {"FROM", "TO", NULL}; COMPLETE_WITH_LIST(listFromTo); @@ -1652,11 +1808,30 @@ static char** PsqlCompletion(const char *text, int start, int end) matches = completion_matches(text, CompleteFromFiles); } + else if ((pg_strcasecmp(PREV6_WD, "COPY") == 0 || pg_strcasecmp(PREV6_WD, "\\copy") == 0) && + (pg_strcasecmp(PREV4_WD, "TO") == 0 || pg_strcasecmp(PREV4_WD, "FROM") == 0) && + pg_strcasecmp(PREV2_WD, "WITH") == 0 && pg_strcasecmp(PREV_WD, "(") == 0) { + static const char* const listCopyFromToWith[] = { + "FORMAT", "OIDS", "DELIMITER", "NULL", "HEADER", "FILEHEADER", + "FREEZE", "QUOTE", "ESCAPE", "EOL", "NOESCAPING", "FORCE_QUOTE", + "FORCE_NOT_NULL", "ENCODING", "IGNORE_EXTRA_DATA", "FILL_MISSING_FIELDS", + "COMPATIBLE_ILLEGAL_CHARS", "DATE_FORMAT", "TIME_FORMAT", "TIMESTAMP_FORMAT", + "SMALLDATETIME_FORMAT", NULL + }; + COMPLETE_WITH_LIST(listCopyFromToWith); + } + /* 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 listCopy[] = {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL}; + static const char* const listCopy[] = { + "BINARY", "OIDS", "NULL", "CSV", "ENCODING", "HEADER", "FILEHEADER", + "FREEZE", "FORCE NOT NULL", "FORCE QUOTE", "QUOTE", "ESCAPE", + "EOL", "IGNORE_EXTRA_DATA", "FILL_MISSING_FIELDS", "FIXED FORMATTER", + "COMPATIBLE_ILLEGAL_CHARS", "DATE_FORMAT", "TIME_FORMAT", "TIMESTAMP_FORMAT", + "SMALLDATETIME_FORMAT", "WITH (", "WITHOUT ESCAPING", NULL + }; COMPLETE_WITH_LIST(listCopy); } @@ -1672,10 +1847,19 @@ static char** PsqlCompletion(const char *text, int start, int end) /* CREATE DATABASE */ else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "DATABASE") == 0) { static const char* const listDatabase[] = { - "OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT", NULL + "WITH", "OWNER", "TEMPLATE", "ENCODING", "LC_COLLATE", "LC_CTYPE", + "DBCOMPATIBILITY", "TABLESPACE", "CONNECTION LIMIT", NULL }; COMPLETE_WITH_LIST(listDatabase); + } else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "DATABASE") == 0 && + pg_strcasecmp(PREV_WD, "WITH") == 0) { + static const char* const listDatabaseWith[] = { + "OWNER", "TEMPLATE", "ENCODING", "LC_COLLATE", "LC_CTYPE", "DBCOMPATIBILITY", "TABLESPACE", + "CONNECTION LIMIT", NULL + }; + + COMPLETE_WITH_LIST(listDatabaseWith); } else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "DATABASE") == 0 && pg_strcasecmp(PREV_WD, "TEMPLATE") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_template_databases); @@ -1716,7 +1900,7 @@ static char** PsqlCompletion(const char *text, int start, int end) 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) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, 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) @@ -1750,9 +1934,140 @@ static char** PsqlCompletion(const char *text, int start, int end) /* Complete USING with an index method */ else if (pg_strcasecmp(PREV_WD, "USING") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); - else if (pg_strcasecmp(PREV4_WD, "ON") == 0 && pg_strcasecmp(PREV2_WD, "USING") == 0) + else if (pg_strcasecmp(PREV4_WD, "ON") == 0 && pg_strcasecmp(PREV2_WD, "USING") == 0 && + pg_strcasecmp(PREV6_WD, "POLICY") != 0) COMPLETE_WITH_CONST("("); + /* CREATE OR REPLACE */ + else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "OR") == 0) + COMPLETE_WITH_CONST("REPLACE"); + + /* CREATE|DROP|ALTER PROCEDURAL|TRUSTED LANGUAGE */ + else if ((pg_strcasecmp(PREV2_WD, "CREATE") == 0 || pg_strcasecmp(PREV2_WD, "DROP") == 0 || + pg_strcasecmp(PREV2_WD, "ALTER") == 0) && (pg_strcasecmp(PREV_WD, "PROCEDURAL") == 0 || + pg_strcasecmp(PREV_WD, "TRUSTED") == 0)) + COMPLETE_WITH_CONST("LANGUAGE"); + + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "LANGUAGE") == 0) { + static const char* const createLanguage[] = {"HANDLER", "INLINE", "VALIDATOR", NULL}; + COMPLETE_WITH_LIST(createLanguage); + } + + /* CREATE AGGREGATE xxx (input_data_type) ( */ + else if (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "AGGREGATE") == 0 && + PREV2_WD[strlen(PREV2_WD) - 1] == ')' && pg_strcasecmp(PREV_WD, "(") == 0) { + static const char* const listCreateAggregate[] = {"SFUNC", "STYPE", "FINALFUNC", "INITCOND", "SORTOP", NULL}; + COMPLETE_WITH_LIST(listCreateAggregate); + } + + /* CREATE AGGREGATE xxx ( */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "AGGREGATE") == 0 && + pg_strcasecmp(PREV_WD, "(") == 0) { + static const char* const listCreateAggregateOld[] = { + "BASETYPE", "SFUNC", "STYPE", "FINALFUNC", "INITCOND", "SORTOP", NULL + }; + COMPLETE_WITH_LIST(listCreateAggregateOld); + } + + /* CREATE TYPE xxx */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "TYPE") == 0) { + static const char* const listCreateType[] = {"AS", "AS ENUM", NULL}; + COMPLETE_WITH_LIST(listCreateType); + } + + /* CREATE TYPE xxx ( */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "TYPE") == 0 && + pg_strcasecmp(PREV_WD, "(") == 0) { + static const char* const listCreateTypeArgs[] = { + "INPUT", "OUTPUT", "RECEIVE", "SEND", "TYPMOD_IN", "TYPMOD_OUT", + "ANALYZE", "INTERNALLENGTH", "PASSEDBYVALUE", "ALIGNMENT", "STORAGE", + "LIKE", "CATEGORY", "PREFERRED", "DEFAULT", "ELEMENT", "DELIMITER", + "COLLATABLE", NULL + }; + COMPLETE_WITH_LIST(listCreateTypeArgs); + } + + /* CREATE OPERATOR xxx ( */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "OPERATOR") == 0 && + pg_strcasecmp(PREV_WD, "(") == 0) { + static const char* const listCreateTypeArgs[] = { + "PROCEDURE", "LEFTARG", "RIGHTARG", "COMMUTATOR", "NEGATOR", "RESTRICT", + "JOIN", "HASHES", "MERGES", NULL + }; + COMPLETE_WITH_LIST(listCreateTypeArgs); + } + + /* ALTER OPERATOR xxx (...) */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "OPERATOR") == 0 && + PREV_WD[strlen(PREV_WD) - 1] == ')') { + static const char* const listAlterOperator[] = {"OWNER TO", "SET SCHEMA", NULL}; + COMPLETE_WITH_LIST(listAlterOperator); + } + + /* CREATE POLICY */ + /* Complete "CREATE ROW LEVEL SECURITY POLICY */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "ROW") == 0 && + pg_strcasecmp(PREV2_WD, "LEVEL") == 0 && pg_strcasecmp(PREV_WD, "SECURITY") == 0) + COMPLETE_WITH_CONST("POLICY"); + /* Complete "CREATE POLICY ON" */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "POLICY") == 0) + 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) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + /* Complete "CREATE POLICY ON
AS|FOR|TO|USING" */ + else if ((pg_strcasecmp(PREV5_WD, "CREATE") == 0 || pg_strcasecmp(PREV8_WD, "CREATE") == 0) && + pg_strcasecmp(PREV4_WD, "POLICY") == 0 && pg_strcasecmp(PREV2_WD, "ON") == 0) { + static const char* const createPolicyOn[] = {"AS", "FOR", "TO", "USING (", NULL}; + COMPLETE_WITH_LIST(createPolicyOn); + } + /* CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE */ + else if (pg_strcasecmp(PREV6_WD, "CREATE") == 0 && pg_strcasecmp(PREV5_WD, "POLICY") == 0 && + pg_strcasecmp(PREV3_WD, "ON") == 0 && pg_strcasecmp(PREV_WD, "AS") == 0) { + static const char* const createPolicyOnAs[] = {"PERMISSIVE", "RESTRICTIVE", NULL}; + COMPLETE_WITH_LIST(createPolicyOnAs); + } + + /* + * CREATE POLICY ON
AS PERMISSIVE|RESTRICTIVE + * FOR|TO|USING + */ + else if (pg_strcasecmp(PREV7_WD, "CREATE") == 0 && pg_strcasecmp(PREV6_WD, "POLICY") == 0 && + pg_strcasecmp(PREV4_WD, "ON") == 0 && pg_strcasecmp(PREV2_WD, "AS") == 0) { + static const char* const createPolicyOnAsSth[] = {"FOR", "TO", "USING", NULL}; + COMPLETE_WITH_LIST(createPolicyOnAsSth); + } + /* 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 createPolicyOnFor[] = {"ALL", "SELECT", "INSERT", "UPDATE", "DELETE", NULL}; + COMPLETE_WITH_LIST(createPolicyOnFor); + } + /* Complete "CREATE POLICY ON
FOR INSERT TO" */ + else if (pg_strcasecmp(PREV7_WD, "CREATE") == 0 && pg_strcasecmp(PREV6_WD, "POLICY") == 0 && + pg_strcasecmp(PREV4_WD, "ON") == 0 && pg_strcasecmp(PREV2_WD, "FOR") == 0 && + pg_strcasecmp(PREV_WD, "INSERT") == 0) + COMPLETE_WITH_CONST("TO"); + /* Complete "CREATE POLICY ON
FOR SELECT|DELETE|ALL|UPDATE TO|USING" */ + else if (pg_strcasecmp(PREV7_WD, "CREATE") == 0 && 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 || + pg_strcasecmp(PREV_WD, "ALL") == 0 || pg_strcasecmp(PREV_WD, "UPDATE") == 0)) { + static const char* const createPolicyOnForSd[] = {"TO", "USING (", NULL}; + COMPLETE_WITH_LIST(createPolicyOnForSd); + } + /* 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) { + 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) { + COMPLETE_WITH_CONST("("); + } + /* CREATE RULE */ /* Complete "CREATE RULE " with "AS" */ else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "RULE") == 0) @@ -1777,13 +2092,34 @@ static char** PsqlCompletion(const char *text, int start, int end) pg_strcasecmp(PREV_WD, "TO") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + else if ((pg_strcasecmp(PREV4_WD, "CREATE") == 0 || pg_strcasecmp(PREV3_WD, "CREATE") == 0) && + pg_strcasecmp(PREV2_WD, "SEQUENCE") == 0) { + static const char* const listCreateSequence[] = { + "INCREMENT", "MINVALUE", "NOMINVALUE", "MAXVALUE", "NOMAXVALUE", + "START WITH", "NO", "CACHE", "CYCLE", "NOCYCLE", "OWNED BY", NULL + }; + + COMPLETE_WITH_LIST(listCreateSequence); + } + else if ((pg_strcasecmp(PREV4_WD, "CREATE") == 0 || pg_strcasecmp(PREV3_WD, "CREATE") == 0) && + pg_strcasecmp(PREV3_WD, "SEQUENCE") == 0 && pg_strcasecmp(PREV_WD, "NO") == 0) { + static const char* const listCreateSequencE2[] = {"MINVALUE", "MAXVALUE", "CYCLE", NULL}; + + COMPLETE_WITH_LIST(listCreateSequencE2); + } + /* 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}; + static const char* const listCreateServer[] = {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL}; - COMPLETE_WITH_LIST(list_CREATE_SERVER); + COMPLETE_WITH_LIST(listCreateServer); } + else if (pg_strcasecmp(PREV7_WD, "CREATE") == 0 && pg_strcasecmp(PREV6_WD, "SERVER") == 0 && + pg_strcasecmp(PREV4_WD, "foreign") == 0 && pg_strcasecmp(PREV3_WD, "data") == 0 && + pg_strcasecmp(PREV2_WD, "wrapper") == 0) + COMPLETE_WITH_CONST("OPTIONS"); + /* CREATE TABLE */ /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */ else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && @@ -1797,16 +2133,37 @@ static char** PsqlCompletion(const char *text, int start, int end) COMPLETE_WITH_CONST("TABLE"); } + else if ((pg_strcasecmp(PREV5_WD, "CREATE") == 0 || pg_strcasecmp(PREV4_WD, "CREATE") == 0) && + pg_strcasecmp(PREV3_WD, "TABLE") == 0 && PREV_WD[strlen(PREV_WD) - 1] == ')') { + static const char* const listCreateTable[] = { + "WITH (", "ON COMMIT", "COMPRESS", "NOCOMPRESS", "TABLESPACE", "PARTITION BY", NULL + }; + + COMPLETE_WITH_LIST(listCreateTable); + } + + else if ((pg_strcasecmp(PREV7_WD, "CREATE") == 0 || pg_strcasecmp(PREV6_WD, "CREATE") == 0) && + pg_strcasecmp(PREV5_WD, "TABLE") == 0 && PREV3_WD[strlen(PREV3_WD) - 1] == ')' && + pg_strcasecmp(PREV2_WD, "WITH") == 0 && pg_strcasecmp(PREV_WD, "(") == 0 ) { + static const char* const listCreateTableWith[] = { + "FILLFACTOR", "ORIENTATION", "COMPRESSION", "MAX_BATCHROW", "PARTIAL_CLUSTER_ROWS", + "DELTAROW_THRESHOLD", NULL + }; + + COMPLETE_WITH_LIST(listCreateTableWith); + } + /* CREATE TABLESPACE */ else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "TABLESPACE") == 0) { - static const char* const listCreateTablespace[] = {"OWNER", "LOCATION", NULL}; + static const char* const listCreateTablespace[] = {"OWNER", "LOCATION", "RELATIVE LOCATION", NULL}; COMPLETE_WITH_LIST(listCreateTablespace); } /* 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) { - COMPLETE_WITH_CONST("LOCATION"); + static const char* const listCreateTablespaceOwner[] = {"LOCATION", "RELATIVE LOCATION", NULL}; + COMPLETE_WITH_LIST(listCreateTablespaceOwner); } /* CREATE TEXT SEARCH */ @@ -1864,7 +2221,7 @@ static char** PsqlCompletion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */ else if (pg_strcasecmp(PREV_WD, "EXECUTE") == 0 && PREV2_WD[0] != '\0') - COMPLETE_WITH_CONST("PROCEDURE"); + COMPLETE_WITH_CONST("DIRECT"); /* CREATE ROLE,USER,GROUP */ else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && @@ -1872,16 +2229,32 @@ static char** PsqlCompletion(const char *text, int start, int end) (pg_strcasecmp(PREV2_WD, "ROLE") == 0 || pg_strcasecmp(PREV2_WD, "GROUP") == 0 || pg_strcasecmp(PREV2_WD, "USER") == 0)) { static const char* const listCreateRole[] = { - "ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", - "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB", - "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN", - "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE", - "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL + "ADMIN", "AUDITADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", + "CREATEUSER", "DEFAULT TABLESPACE", "ENCRYPTED", "IDENTIFIED BY", "IN", + "IN GROUP", "IN ROLE", "INDEPENDENT", "INHERIT", "LOGIN", "MONADMIN", + "NOAUDITADMIN", "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NODE GROUP", + "NOINDEPENDENT", "NOINHERIT", "NOLOGIN", "NOMONADMIN", "NOOPRADMIN", + "NOPERSISTENCE", "NOPOLADMIN", "NOREPLICATION", "NOSUPERUSER", "NOSYSADMIN", + "NOUSEFT", "NOVCADMIN", "OPRADMIN", "PASSWORD", "PERM SPACE", "PERSISTENCE", + "PGUSER", "POLADMIN", "PROFILE", "PROFILE DEFAULT", "REPLICATION", + "RESOURCE POOL", "ROLE", "SPILL SPACE", "SUPERUSER", "SYSADMIN", "SYSID", + "TEMP SPACE", "UNENCRYPTED", "USEFT", "USER", "USER GROUP", "VALID", + "VCADMIN", "WITH", NULL }; COMPLETE_WITH_LIST(listCreateRole); } + /* CREATE ROLE,USER,GROUP VALID*/ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && + !(pg_strcasecmp(PREV3_WD, "USER") == 0 && pg_strcasecmp(PREV2_WD, "MAPPING") == 0) && + (pg_strcasecmp(PREV3_WD, "ROLE") == 0 || pg_strcasecmp(PREV3_WD, "GROUP") == 0 || + pg_strcasecmp(PREV3_WD, "USER") == 0) && pg_strcasecmp(PREV_WD, "VALID") == 0) { + static const char* const listCreateRoleValid[] = {"BEGIN", "UNTIL", NULL}; + + COMPLETE_WITH_LIST(listCreateRoleValid); + } + /* 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 || @@ -1889,16 +2262,33 @@ static char** PsqlCompletion(const char *text, int start, int end) pg_strcasecmp(PREV_WD, "WITH") == 0)) { /* Similar to the above, but don't complete "WITH" again. */ static const char* const listCreateRoleWith[] = { - "ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", - "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB", - "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN", - "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE", - "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", NULL + "ADMIN", "AUDITADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", + "CREATEUSER", "DEFAULT TABLESPACE", "ENCRYPTED", "IDENTIFIED BY", "IN", + "IN GROUP", "IN ROLE", "INDEPENDENT", "INHERIT", "LOGIN", "MONADMIN", + "NOAUDITADMIN", "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NODE GROUP", + "NOINDEPENDENT", "NOINHERIT", "NOLOGIN", "NOMONADMIN", "NOOPRADMIN", + "NOPERSISTENCE", "NOPOLADMIN", "NOREPLICATION", "NOSUPERUSER", "NOSYSADMIN", + "NOUSEFT", "NOVCADMIN", "OPRADMIN", "PASSWORD", "PERM SPACE", "PERSISTENCE", + "PGUSER", "POLADMIN", "PROFILE", "PROFILE DEFAULT", "REPLICATION", + "RESOURCE POOL", "ROLE", "SPILL SPACE", "SUPERUSER", "SYSADMIN", "SYSID", + "TEMP SPACE", "UNENCRYPTED", "USEFT", "USER", "USER GROUP", "VALID", + "VCADMIN", NULL }; COMPLETE_WITH_LIST(listCreateRoleWith); } + /* CREATE ROLE,USER,GROUP WITH */ + else if ((pg_strcasecmp(PREV5_WD, "CREATE") == 0 && + (pg_strcasecmp(PREV4_WD, "ROLE") == 0 || pg_strcasecmp(PREV4_WD, "GROUP") == 0 || + pg_strcasecmp(PREV4_WD, "USER") == 0) && + pg_strcasecmp(PREV2_WD, "WITH") == 0) && pg_strcasecmp(PREV_WD, "VALID") == 0) { + /* Similar to the above, but don't complete "WITH" again. */ + static const char* const listCreateRoleWithValid[] = {"BEGIN", "UNTIL", NULL}; + + COMPLETE_WITH_LIST(listCreateRoleWithValid); + } + /* * complete CREATE ROLE,USER,GROUP ENCRYPTED,UNENCRYPTED with * PASSWORD @@ -1907,7 +2297,8 @@ static char** PsqlCompletion(const char *text, int start, int end) (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)) { - COMPLETE_WITH_CONST("PASSWORD"); + static const char* const listCreateRoleWithEncrypted[] = {"PASSWORD", "IDENTIFIED BY", NULL}; + COMPLETE_WITH_LIST(listCreateRoleWithEncrypted); } /* complete CREATE ROLE,USER,GROUP IN with ROLE,GROUP */ else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && @@ -1931,10 +2322,12 @@ static char** PsqlCompletion(const char *text, int start, int end) /* CREATE MATERIALIZED VIEW */ else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "MATERIALIZED") == 0) 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) - COMPLETE_WITH_CONST("AS"); + /* Complete CREATE MATERIALIZED VIEW with AS|TABLESPACE */ + else if ((pg_strcasecmp(PREV5_WD, "CREATE") == 0 || pg_strcasecmp(PREV4_WD, "CREATE") == 0) && + pg_strcasecmp(PREV3_WD, "MATERIALIZED") == 0 && pg_strcasecmp(PREV2_WD, "VIEW") == 0) { + static const char* const listCreateMaterializedView[] = {"AS", "TABLESPACE", NULL}; + COMPLETE_WITH_LIST(listCreateMaterializedView); + } /* 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) @@ -2003,9 +2396,10 @@ static char** PsqlCompletion(const char *text, int start, int end) 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, "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(PREV2_WD, "TYPE") == 0 || pg_strcasecmp(PREV2_WD, "VIEW") == 0 || + pg_strcasecmp(PREV2_WD, "USER") == 0)) || (pg_strcasecmp(PREV4_WD, "DROP") == 0 && pg_strcasecmp(PREV3_WD, "AGGREGATE") == 0 && PREV_WD[strlen(PREV_WD) - 1] == ')') || (pg_strcasecmp(PREV5_WD, "DROP") == 0 && pg_strcasecmp(PREV4_WD, "FOREIGN") == 0 && @@ -2055,6 +2449,21 @@ static char** PsqlCompletion(const char *text, int start, int end) COMPLETE_WITH_LIST(listAlterTextSearch); } + /* DROP TRIGGER */ + else if (pg_strcasecmp(PREV3_WD, "DROP") == 0 && pg_strcasecmp(PREV2_WD, "TRIGGER") == 0) + COMPLETE_WITH_CONST("ON"); + else if (pg_strcasecmp(PREV4_WD, "DROP") == 0 && pg_strcasecmp(PREV3_WD, "TRIGGER") == 0 && + pg_strcasecmp(PREV_WD, "ON") == 0) { + 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 listDropTriggerOn[] = {"CASCADE", "RESTRICT", NULL}; + + COMPLETE_WITH_LIST(listDropTriggerOn); + } + /* EXECUTE, but not EXECUTE embedded in other commands */ else if (pg_strcasecmp(PREV_WD, "EXECUTE") == 0 && PREV2_WD[0] == '\0') COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements); @@ -2066,7 +2475,9 @@ static char** PsqlCompletion(const char *text, int start, int end) */ else if (pg_strcasecmp(PREV_WD, "EXPLAIN") == 0) { static const char* const listExplain[] = { - "SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL + "SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", + "COSTS", "CPU", "DETAIL", "NODES", "NUM_NODES", "BUFFERS", "TIMING", + "PLAN", "FORMAT", "ANALYSE", "PERFORMANCE", NULL }; COMPLETE_WITH_LIST(listExplain); @@ -2133,7 +2544,14 @@ static char** PsqlCompletion(const char *text, int start, int end) " UNION SELECT 'TEMPORARY'" " UNION SELECT 'EXECUTE'" " UNION SELECT 'USAGE'" - " UNION SELECT 'ALL'"); + " UNION SELECT 'ALL'" + " UNION SELECT 'ALTER'" + " UNION SELECT 'DROP'" + " UNION SELECT 'COMMENT'" + " UNION SELECT 'INDEX'" + " UNION SELECT 'VACUUM'" + " UNION SELECT 'READ'" + " UNION SELECT 'WRITE'"); } /* @@ -2147,9 +2565,13 @@ static char** PsqlCompletion(const char *text, int start, int end) 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) + pg_strcasecmp(PREV_WD, "USAGE") == 0) COMPLETE_WITH_CONST("ON"); - else { + else if (pg_strcasecmp(PREV_WD, "ALL") == 0){ + static const char* const listGrantAll[] = {"ON", "PRIVILEGES", NULL}; + + COMPLETE_WITH_LIST(listGrantAll); + }else { if (pg_strcasecmp(PREV2_WD, "GRANT") == 0) COMPLETE_WITH_CONST("TO"); else @@ -2157,6 +2579,11 @@ static char** PsqlCompletion(const char *text, int start, int end) } } + else if ((pg_strcasecmp(PREV3_WD, "GRANT") == 0 || pg_strcasecmp(PREV3_WD, "REVOKE") == 0) && + pg_strcasecmp(PREV2_WD, "ALL") == 0 && pg_strcasecmp(PREV_WD, "PRIVILEGES") == 0) { + COMPLETE_WITH_CONST("ON"); + } + /* * Complete GRANT/REVOKE ON with a list of tables, views, sequences, * and indexes @@ -2210,6 +2637,10 @@ static char** PsqlCompletion(const char *text, int start, int end) COMPLETE_WITH_CONST("FROM"); } + else if ((pg_strcasecmp(PREV2_WD, "tablespace") == 0 && pg_strcasecmp(PREV_WD, "=") == 0) || + pg_strcasecmp(PREV_WD, "tablespace") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); + /* 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) { if (pg_strcasecmp(PREV_WD, "TO") == 0) @@ -2223,6 +2654,14 @@ static char** PsqlCompletion(const char *text, int start, int end) COMPLETE_WITH_CONST("FROM"); } + /* Complete "GRANT/REVOKE * ON SCHEMA/.. * TO" with username, GROUP, or PUBLIC */ + else if (pg_strcasecmp(PREV6_WD, "GRANT") == 0 && pg_strcasecmp(PREV4_WD, "ON") == 0) { + if (pg_strcasecmp(PREV_WD, "TO") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); + else + COMPLETE_WITH_CONST("TO"); + } + /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */ else if (pg_strcasecmp(PREV3_WD, "GRANT") == 0 && pg_strcasecmp(PREV_WD, "TO") == 0) { COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); @@ -2276,7 +2715,7 @@ static char** PsqlCompletion(const char *text, int start, int end) else if (pg_strcasecmp(PREV_WD, "LOCK") == 0) 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) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, " UNION ALL SELECT 'ONLY'"); /* For the following, handle the case of a single table only for now */ @@ -2383,7 +2822,7 @@ static char** PsqlCompletion(const char *text, int start, int end) } /* SECURITY LABEL */ - else if (pg_strcasecmp(PREV_WD, "SECURITY") == 0) + else if (pg_strcasecmp(PREV_WD, "SECURITY") == 0 && PREV2_WD[0] == '\0') COMPLETE_WITH_CONST("LABEL"); else if (pg_strcasecmp(PREV2_WD, "SECURITY") == 0 && pg_strcasecmp(PREV_WD, "LABEL") == 0) { static const char* const listSecurityLabelPreposition[] = {"ON", "FOR"}; @@ -2520,6 +2959,16 @@ static char** PsqlCompletion(const char *text, int start, int end) /* TRUNCATE */ else if (pg_strcasecmp(PREV_WD, "TRUNCATE") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, + " UNION SELECT 'TABLE'" + " UNION SELECT 'ONLY'"); + + else if (pg_strcasecmp(PREV2_WD, "TRUNCATE") == 0 && pg_strcasecmp(PREV_WD, "TABLE") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, + " UNION SELECT 'ONLY'"); + + else if (((pg_strcasecmp(PREV3_WD, "TRUNCATE") == 0 && pg_strcasecmp(PREV2_WD, "TABLE")) || + (pg_strcasecmp(PREV2_WD, "TRUNCATE") == 0)) && pg_strcasecmp(PREV_WD, "ONLY") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* UNLISTEN */ @@ -2575,9 +3024,17 @@ static char** PsqlCompletion(const char *text, int start, int end) 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)) + " UNION SELECT 'VERBOSE'" + " UNION SELECT 'DELTAMERGE'" + " UNION SELECT 'HDFSDIRECTORY'" + " UNION SELECT 'COMPACT'" + " UNION SELECT 'ANALYSE'" + " UNION SELECT 'PARTITION'"); + else if (pg_strcasecmp(PREV2_WD, "VACUUM") == 0 && pg_strcasecmp(PREV_WD, "FULL") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'ANALYZE'" + " UNION SELECT 'VERBOSE'" + " UNION SELECT 'COMPACT'"); + else if (pg_strcasecmp(PREV2_WD, "VACUUM") == 0 && pg_strcasecmp(PREV_WD, "FREEZE") == 0) 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 && @@ -2606,7 +3063,18 @@ static char** PsqlCompletion(const char *text, int start, int end) /* ANALYZE */ /* If the previous word is ANALYZE, produce list of tables */ else if (pg_strcasecmp(PREV_WD, "ANALYZE") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, " UNION SELECT 'VERBOSE'" + " UNION SELECT 'VERIFY'" + " UNION SELECT 'PARTITION'"); + else if (pg_strcasecmp(PREV2_WD, "ANALYZE") == 0 && pg_strcasecmp(PREV_WD, "VERIFY") == 0) { + static const char* const listAnalizeVerify[] = {"FAST", "COMPLETE", NULL}; + + COMPLETE_WITH_LIST_CS(listAnalizeVerify); + } + else if (pg_strcasecmp(PREV3_WD, "ANALYZE") == 0 && pg_strcasecmp(PREV2_WD, "VERIFY") == 0 && + (pg_strcasecmp(PREV_WD, "FAST") == 0 || pg_strcasecmp(PREV_WD, "COMPLETE") == 0)) { + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmi, NULL); + } /* WHERE */ /* Simple case of the word before the where being the table name */ @@ -2683,6 +3151,10 @@ static char** PsqlCompletion(const char *text, int start, int end) COMPLETE_WITH_QUERY(Query_for_list_of_encodings); else if (strcmp(PREV_WD, "\\h") == 0 || strcmp(PREV_WD, "\\help") == 0) COMPLETE_WITH_LIST(sqlCommands); + else if ((strcmp(PREV2_WD, "\\h") == 0 || strcmp(PREV2_WD, "\\help") == 0) && + pg_strcasecmp(PREV_WD, "DROP") == 0) { + matches = completion_matches(text, DropCommandGenerator); + } else if (strcmp(PREV_WD, "\\password") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_roles); else if (strcmp(PREV_WD, "\\pset") == 0) { @@ -2850,7 +3322,8 @@ static char *_CompleteFromQuery(int isSchemaQuery, const char *text, int state) * between not offering system catalogs for completion at all, and * having them swamp the result when the input is just "p". */ - if (strcmp(completion_squery->catname, "pg_catalog.pg_class c") == 0 && strncmp(text, "pg_", 3) != 0) { + if (strcmp(completion_squery->catname, "pg_catalog.pg_class c") == 0 && + strncmp(text, "pg_", 3) != 0 && strncmp(text, "gs_", 3) != 0) { appendPQExpBuffer(&queryBuffer, " AND c.relnamespace <> (SELECT oid FROM" " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')"); } @@ -3174,7 +3647,6 @@ static PGresult *ExecQuery(const char *query) result = PQexec(pset.db, query); if (PQresultStatus(result) != PGRES_TUPLES_OK) { - psql_error("tab completion query failed: %s\nQuery was:\n%s\n", PQerrorMessage(pset.db), query); PQclear(result); result = NULL; }