* psql - the openGauss interactive terminal
*
* Copyright (c) 2000-2012, PostgreSQL Global Development Group
*
* src/bin/psql/tab-complete.c
*/
* This file implements a somewhat more sophisticated readline "TAB
* completion" in psql. It is not intended to be AI, to replace
* learning SQL, or to relieve you from thinking about what you're
* doing. Also it does not always give you all the syntactically legal
* completions, only those that are the most common or the ones that
* the programmer felt most like implementing.
*
* CAVEAT: Tab completion causes queries to be sent to the backend.
* The number of tuples returned gets limited, in most default
* installations to 1000, but if you still don't like this prospect,
* you can turn off tab completion in your ~/.inputrc (or else
* ${INPUTRC}) file so:
*
* $if psql
* set disable-completion on
* $endif
*
* See `man 3 readline' or `info readline' for the full details. Also,
* hence the
*
* BUGS:
*
* - If you split your queries across lines, this whole thing gets
* confused. (To fix this, one would have to read psql's query
* buffer rather than readline's line buffer, which would require
* some major revisions of things.)
*
* - Table or attribute names with spaces in it may confuse it.
*
* - Quotes, parenthesis, and other funny characters are not handled
* all that gracefully.
* ----------------------------------------------------------------------
*/
#include "settings.h"
#include "postgres_fe.h"
#include "input.h"
#include "tab-complete.h"
#ifdef USE_READLINE
#include <ctype.h>
#include "libpq/libpq-fe.h"
#include "libpq/pqexpbuffer.h"
#include "common.h"
#include "stringutils.h"
#ifndef WIN32
#include "libpq/libpq-int.h"
#endif
* (implemented via SELECT ... LIMIT xx).
*/
static int completion_max_records;
#ifdef HAVE_READLINE_READLINE_H
* Communication variables set by COMPLETE_WITH_FOO macros and then used by
* the completion callback functions. Ugly but there is no better way.
*/
static const char* completion_charp;
static const char* const* completion_charpp;
static const char* completion_info_charp;
static const char* completion_info_charp2;
static const SchemaQuery* completion_squery;
static bool completion_case_sensitive;
static char** PsqlCompletion(const char *text, int start, int end);
static char* CreateCommandGenerator(const char* text, int state);
static char* DropCommandGenerator(const char* text, int state);
static char* CompleteFromQuery(const char* text, int state);
static char* CompleteFromSchemaQuery(const char* text, int state);
static char* _CompleteFromQuery(int isSchemaQuery, const char* text, int state);
static char* CompleteFromList(const char* text, int state);
static char* CompleteFromConst(const char* text, int state);
static char** CompleteFromVariables(const char* text, const char* prefix, const char* suffix);
static char* CompleteFromFiles(const char* text, int state);
static char* pg_strdup_keyword_case(const char* s, const char* ref);
static PGresult* ExecQuery(const char* query);
static void GetPreviousWords(int point, char** previousWords, int nwords);
* A few macros to ease typing. You can use these to complete the given
* string with
* 1) The results from a query you pass it. (Perhaps one of those below?)
* 2) The results from a schema query you pass it.
* 3) The items from a null-pointer-terminated list.
* 4) A string constant.
* 5) The list of attributes of the given table (possibly schema-qualified).
*/
#define COMPLETE_WITH_QUERY(query) do { \
completion_charp = query; \
matches = completion_matches(text, CompleteFromQuery); \
} while (0)
#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) do { \
completion_squery = &(query); \
completion_charp = addon; \
matches = completion_matches(text, CompleteFromSchemaQuery); \
} while (0)
#define COMPLETE_WITH_LIST_CS(list) do { \
completion_charpp = list; \
completion_case_sensitive = true; \
matches = completion_matches(text, CompleteFromList); \
} while (0)
#define COMPLETE_WITH_LIST(list) do { \
completion_charpp = list; \
completion_case_sensitive = false; \
matches = completion_matches(text, CompleteFromList); \
} while (0)
#define COMPLETE_WITH_CONST(string) do { \
completion_charp = string; \
completion_case_sensitive = false; \
matches = completion_matches(text, CompleteFromConst); \
} while (0)
#define COMPLETE_WITH_ATTR(relation, addon) \
do { \
char *_completion_schema; \
char *_completion_table; \
_completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, false, false, pset.encoding); \
(void)strtokx(NULL, " \t\n\r", ".", "\"", 0, false, false, pset.encoding); \
_completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, false, false, pset.encoding); \
if (_completion_table == NULL) { \
completion_charp = Query_for_list_of_attributes addon; \
completion_info_charp = relation; \
} else { \
completion_charp = Query_for_list_of_attributes_with_schema addon; \
completion_info_charp = _completion_table; \
completion_info_charp2 = _completion_schema; \
} \
matches = completion_matches(text, CompleteFromQuery); \
} while (0)
* Assembly instructions for schema queries
*/
static const SchemaQuery Query_for_list_of_aggregates = {
"pg_catalog.pg_proc p",
"p.proisagg",
"pg_catalog.pg_function_is_visible(p.oid)",
"p.pronamespace",
"pg_catalog.quote_ident(p.proname)",
NULL
};
static const SchemaQuery Query_for_list_of_datatypes = {
"pg_catalog.pg_type t",
"(t.typrelid = 0 "
" OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
"AND t.typname !~ '^_'",
"pg_catalog.pg_type_is_visible(t.oid)",
"t.typnamespace",
"pg_catalog.format_type(t.oid, NULL)",
"pg_catalog.quote_ident(t.typname)"
};
static const SchemaQuery Query_for_list_of_domains = {
"pg_catalog.pg_type t",
"t.typtype = 'd'",
"pg_catalog.pg_type_is_visible(t.oid)",
"t.typnamespace",
"pg_catalog.quote_ident(t.typname)",
NULL
};
static const SchemaQuery Query_for_list_of_functions = {
"pg_catalog.pg_proc p",
"p.prokind != 'p'",
"pg_catalog.pg_function_is_visible(p.oid)",
"p.pronamespace",
"pg_catalog.quote_ident(p.proname)",
NULL
};
static const SchemaQuery Query_for_list_of_procedures[] = {
"pg_catalog.pg_proc p",
"p.prokind = 'p'",
"pg_catalog.pg_function_is_visible(p.oid)",
"p.pronamespace",
"pg_catalog.quote_ident(p.proname)",
NULL
};
static const SchemaQuery Query_for_list_of_indexes = {
"pg_catalog.pg_class c",
"c.relkind IN ('i')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_sequences = {
"pg_catalog.pg_class c",
"c.relkind IN ('S', 'z')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_foreign_tables = {
"pg_catalog.pg_class c",
"c.relkind IN ('f')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_tables = {
"pg_catalog.pg_class c",
"c.relkind IN ('r', 'f')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
* src/include/catalog/pg_trigger.h.
*/
static const SchemaQuery Query_for_list_of_insertables = {
"pg_catalog.pg_class c",
"(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)))",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_deletables = {
"pg_catalog.pg_class c",
"(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
"(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_updatables = {
"pg_catalog.pg_class c",
"(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
"(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_relations = {
"pg_catalog.pg_class c",
NULL,
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_tsvmf = {
"pg_catalog.pg_class c",
"c.relkind IN ('r', 'S', 'z', 'v', 'm', 'f')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_tmf = {
"pg_catalog.pg_class c",
"c.relkind IN ('r', 'm', 'f')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_tm = {
"pg_catalog.pg_class c",
"c.relkind IN ('r', 'm')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_tmi = {
"pg_catalog.pg_class c",
"c.relkind IN ('r', 'm', 'i')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_views = {
"pg_catalog.pg_class c",
"c.relkind IN ('v')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_matviews = {
"pg_catalog.pg_class c",
"c.relkind IN ('m')",
"pg_catalog.pg_table_is_visible(c.oid)",
"c.relnamespace",
"pg_catalog.quote_ident(c.relname)",
NULL
};
static const SchemaQuery Query_for_list_of_constraints_with_schema = {
"pg_catalog.pg_constraint c",
"c.conrelid <> 0",
"true",
"c.connamespace",
"pg_catalog.quote_ident(c.conname)",
NULL
};
static const pgsql_thing_t words_after_create[] = {
{"AGGREGATE", NULL, &Query_for_list_of_aggregates, 0},
{"APP WORKLOAD GROUP", NULL, NULL, 0},
{"APP WORKLOAD GROUP MAPPING", NULL, NULL, 0},
#ifdef PGXC
{"BARRIER", NULL, NULL, 0},
#endif
{"CAST", NULL, NULL, 0},
* 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 "
"substring(pg_catalog.quote_ident(collname),1,%d)='%s'",
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.
*/
{"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
{"CONVERSION",
"SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE "
"substring(pg_catalog.quote_ident(conname),1,%d)='%s'",
NULL,
0},
{"DATABASE", Query_for_list_of_databases, NULL, 0},
{"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},
{"FOREIGN DATA WRAPPER", NULL, NULL, 0},
{"FOREIGN TABLE", NULL, NULL, 0},
{"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},
{"OR REPLACE", NULL, NULL, THING_NO_DROP},
{"OWNED", NULL, NULL, THING_NO_CREATE},
{"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},
{"PUBLICATION", NULL, NULL, 0},
{"ROLE", Query_for_list_of_roles, NULL, 0},
{"RULE",
"SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE "
"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},
{"SERVER", Query_for_list_of_servers, NULL, 0},
{"SUBSCRIPTION", NULL, NULL, 0},
{"TABLE", NULL, &Query_for_list_of_tables, 0},
{"TABLESPACE", Query_for_list_of_tablespaces, NULL, 0},
{"TEMP", NULL, NULL, THING_NO_DROP},
{"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
{"TEMPORARY", NULL, NULL, THING_NO_DROP},
{"TEXT SEARCH", NULL, NULL, 0},
{"TRIGGER",
"SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE "
"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},
{"UNLOGGED", NULL, NULL, THING_NO_DROP},
* ... */
{"USER", Query_for_list_of_roles, NULL, 0},
#ifndef PGXC
{"USER MAPPING FOR", NULL, NULL, 0},
#endif
{"VIEW", NULL, &Query_for_list_of_views, 0},
{NULL, NULL, NULL, 0}
};
* GENERATOR FUNCTIONS
*
* These functions do all the actual work of completing the input. They get
* passed the text so far and the count how many times they have been called
* so far with the same text.
* If you read the above carefully, you'll see that these don't get called
* directly but through the readline interface.
* The return value is expected to be the full completion of the text, going
* through a list each time, or NULL if there are no more matches. The string
* will be free()'d by readline, so you must run it through strdup() or
* something of that sort.
*/
* Common routine for CreateCommandGenerator and DropCommandGenerator.
* Entries that have 'excluded' flags are not returned.
*/
static char *create_or_DropCommandGenerator(const char *text, int state, bits32 excluded)
{
static int listIndex, stringLength;
const char *name = NULL;
if (state == 0) {
listIndex = 0;
stringLength = strlen(text);
}
while ((name = words_after_create[listIndex++].name)) {
if ((pg_strncasecmp(name, text, stringLength) == 0) && !(words_after_create[listIndex - 1].flags & excluded))
return pg_strdup_keyword_case(name, text);
}
return NULL;
}
* This one gives you one from a list of things you can put after CREATE
* as defined above.
*/
static char *CreateCommandGenerator(const char *text, int state)
{
return create_or_DropCommandGenerator(text, state, THING_NO_CREATE);
}
* This function gives you a list of things you can put after a DROP command.
*/
static char *DropCommandGenerator(const char *text, int state)
{
return create_or_DropCommandGenerator(text, state, THING_NO_DROP);
}
static char *CompleteFromQuery(const char *text, int state)
{
return _CompleteFromQuery(0, text, state);
}
static char *CompleteFromSchemaQuery(const char *text, int state)
{
return _CompleteFromQuery(1, text, state);
}
* The completion function.
*
* According to readline spec this gets passed the text entered so far and its
* start and end positions in the readline buffer. The return value is some
* partially obscure list format that can be generated by readline's
* completion_matches() function, so we don't have to worry about it.
*/
static char** PsqlCompletion(const char *text, int start, int end)
{
char **matches = NULL;
char *previousWords[8];
#define PREV_WD (previousWords[0])
#define PREV2_WD (previousWords[1])
#define PREV3_WD (previousWords[2])
#define PREV4_WD (previousWords[3])
#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", "ANALYSE", "ANALYZE", "BEGIN", "CALL", "CHECKPOINT", "CLOSE", "CLUSTER",
"COMMENT", "COMMIT", "COPY", "CREATE", "CURSOR", "DEALLOCATE", "DECLARE",
"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
"REASSIGN", "REFRESH", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
"SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
"TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
NULL
};
static const char* const backslashCommands[] = {
"\\a",
"\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
"\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\ddp", "\\dD", "\\ded",
"\\des", "\\det", "\\deu", "\\dew", "\\dE", "\\df", "\\dF", "\\dFd",
"\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", "\\dn", "\\do", "\\dO",
"\\dp", "\\drds", "\\ds", "\\dt", "\\dT", "\\dv", "\\du", "\\dx",
"\\e", "\\echo", "\\ef", "\\encoding",
"\\f",
"\\g", "\\gset",
"\\h", "\\help", "\\H",
"\\i", "\\i+", "\\ir", "\\ir+",
"\\l", "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
"\\o",
"\\p", "\\parallel", "\\prompt", "\\pset",
"\\q", "\\qecho",
"\\r",
"\\set", "\\setenv", "\\sf",
"\\t", "\\T", "\\timing",
"\\unset",
"\\x",
"\\w",
"\\z",
"\\!", "\\?",
NULL
};
(void)end;
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
rl_completion_append_character = ' ';
#endif
completion_charp = NULL;
completion_charpp = NULL;
completion_info_charp = NULL;
completion_info_charp2 = NULL;
* Scan the input line before our current position for the last few words.
* According to those we'll make some smart decisions on what the user is
* probably intending to type.
*/
GetPreviousWords(start, previousWords, lengthof(previousWords));
if (text[0] == '\\') {
COMPLETE_WITH_LIST_CS(backslashCommands);
}
else if (text[0] == ':' && text[1] != ':') {
if (text[1] == '\'') {
matches = CompleteFromVariables(text, ":'", "'");
}
else if (text[1] == '"') {
matches = CompleteFromVariables(text, ":\"", "\"");
}
else {
matches = CompleteFromVariables(text, ":", "");
}
}
else if (PREV_WD[0] == '\0') {
COMPLETE_WITH_LIST(sqlCommands);
}
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);
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);
}
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 (");
}
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 =");
}
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 =");
}
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 (");
}
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 =");
}
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'");
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");
* 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) {
static const char* const listAlter[] = {
"AGGREGATE", "APP WORKLOAD GROUP", "APP WORKLOAD GROUP MAPPING", "COLLATION", "CONVERSION",
"DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", "EXTENSION", "FOREIGN DATA WRAPPER",
"FOREIGN TABLE", "FUNCTION", "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT",
"MATERIALIZED VIEW", "OPERATOR", "POLICY", "PROCEDURE", "PUBLICATION", "ROLE", "ROW LEVEL SECURITY POLICY",
"RULE", "SCHEMA", "SERVER", "SESSION", "SEQUENCE", "SUBSCRIPTION", "SYSTEM", "TABLE", "TABLESPACE",
"TEXT SEARCH", "TRIGGER", "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL
};
COMPLETE_WITH_LIST(listAlter);
}
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("(");
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && (pg_strcasecmp(PREV3_WD, "AGGREGATE") == 0 ||
pg_strcasecmp(PREV3_WD, "FUNCTION") == 0 || pg_strcasecmp(PREV2_WD, "PROCEDURE") == 0)) {
if (PREV_WD[strlen(PREV_WD) - 1] == ')') {
static const char* const listAlterAgg[] = {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterAgg);
} else {
size_t tmpLength = strlen(Query_for_list_of_arguments) + strlen(PREV2_WD);
char *tmpBuf = (char *)pg_malloc(tmpLength);
int rc = sprintf_s(tmpBuf, tmpLength, Query_for_list_of_arguments, PREV2_WD);
securec_check_ss_c(rc, "", "");
COMPLETE_WITH_QUERY(tmpBuf);
free(tmpBuf);
}
}
else if (pg_strcasecmp(PREV2_WD, "ALTER") == 0 && pg_strcasecmp(PREV_WD, "PUBLICATION") == 0) {
static const char * const listAlterPub[] = {"ADD TABLE", "DROP TABLE", "OWNER TO", "RENAME TO", "SET", NULL};
COMPLETE_WITH_LIST(listAlterPub);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "PUBLICATION") == 0 &&
pg_strcasecmp(PREV_WD, "SET") == 0) {
static const char * const listAlterPubSet[] = {"(", "TABLE", NULL};
COMPLETE_WITH_LIST(listAlterPubSet);
}
else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "PUBLICATION") == 0 &&
pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "(") == 0) {
static const char * const listAlterPubSet2[] = {"publish", NULL};
COMPLETE_WITH_LIST(listAlterPubSet2);
}
else if (pg_strcasecmp(PREV2_WD, "ALTER") == 0 && pg_strcasecmp(PREV_WD, "SUBSCRIPTION") == 0) {
static const char * const listAlterSub[] = {"CONNECTION", "ENABLE", "DISABLE", "OWNER TO", "RENAME TO",
"SET", NULL};
COMPLETE_WITH_LIST(listAlterSub);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "SUBSCRIPTION") == 0 &&
pg_strcasecmp(PREV_WD, "SET") == 0) {
static const char * const listAlterSubSet[] = {"(", "PUBLICATION", NULL};
COMPLETE_WITH_LIST(listAlterSubSet);
}
else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "SUBSCRIPTION") == 0 &&
pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "(") == 0) {
static const char * const listAlterSubSet2[] = {"slot_name", "synchronous_commit", NULL};
COMPLETE_WITH_LIST(listAlterSubSet2);
}
else if (pg_strcasecmp(PREV2_WD, "ALTER") == 0 && pg_strcasecmp(PREV_WD, "SESSION") == 0)
COMPLETE_WITH_CONST("SET");
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);
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SCHEMA") == 0) {
static const char* const listAlterGen[] = {"OWNER TO", "RENAME TO", NULL};
COMPLETE_WITH_LIST(listAlterGen);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "COLLATION") == 0) {
static const char* const listAlterGen[] = {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterGen);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "CONVERSION") == 0) {
static const char* const listAlterGen[] = {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterGen);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "DATABASE") == 0) {
static const char* const listAlterDatabase[] = {
"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);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "EXTENSION") == 0) {
static const char* const listAlterExtension[] = {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterExtension);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "EXTENSION") == 0 &&
pg_strcasecmp(PREV_WD, "UPDATE") == 0) {
COMPLETE_WITH_CONST("TO");
}
else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "EXTENSION") == 0 &&
pg_strcasecmp(PREV2_WD, "UPDATE") == 0 && pg_strcasecmp(PREV_WD, "TO") == 0) {
completion_info_charp = PREV3_WD;
COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "EXTENSION") == 0 &&
(pg_strcasecmp(PREV_WD, "ADD") == 0 || pg_strcasecmp(PREV_WD, "DROP"))) {
static const char* const listAlterExtensionMemberObject[] = {
"AGGREGATE", "CAST", "COLLATION", "CONVERSION", "DOMAIN", "EVENT TRIGGER", "FOREIGN DATA WRAPPER",
"FOREIGN TABLE", "FUNCTION", "MATERIALIZED VIEW", "OPERATOR", "OPERATOR CLASS", "OPERATOR FAMILY ",
"PROCEDURAL LANGUAGE", "LANGUAGE", "SCHEMA", "SEQUENCE", "SERVER", "TABLE", "TEXT SEARCH CONFIGURATION",
"TEXT SEARCH DICTIONARY", "TEXT SEARCH PARSER", "TEXT SEARCH TEMPLATE", "TYPE", "VIEW", NULL};
COMPLETE_WITH_LIST(listAlterExtensionMemberObject);
}
else if (pg_strcasecmp(PREV2_WD, "ALTER") == 0 && pg_strcasecmp(PREV_WD, "FOREIGN") == 0) {
static const char* const listAlterForeign[] = {"DATA WRAPPER", "TABLE", NULL};
COMPLETE_WITH_LIST(listAlterForeign);
}
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 listAlterFdw[] = {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
COMPLETE_WITH_LIST(listAlterFdw);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "FOREIGN") == 0 &&
pg_strcasecmp(PREV2_WD, "TABLE") == 0) {
static const char* const listAlterForeignTable[] = {"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterForeignTable);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "INDEX") == 0) {
static const char* const listAlterindex[] = {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
COMPLETE_WITH_LIST(listAlterindex);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "INDEX") == 0 &&
pg_strcasecmp(PREV_WD, "SET") == 0) {
static const char* const listAlterindexset[] = {"(", "TABLESPACE", NULL};
COMPLETE_WITH_LIST(listAlterindexset);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "INDEX") == 0 &&
pg_strcasecmp(PREV_WD, "RESET") == 0)
COMPLETE_WITH_CONST("(");
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 listIndexOptions[] = {"fillfactor", "fastupdate", "deduplication", NULL};
COMPLETE_WITH_LIST(listIndexOptions);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "LANGUAGE") == 0) {
static const char* const listAlterLanguage[] = {"OWNER TO", "RENAME TO", NULL};
COMPLETE_WITH_LIST(listAlterLanguage);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "LARGE") == 0 &&
pg_strcasecmp(PREV2_WD, "OBJECT") == 0) {
static const char* const listAlterLargeObject[] = {"OWNER TO", NULL};
COMPLETE_WITH_LIST(listAlterLargeObject);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV2_WD, "VIEW") == 0) {
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
}
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)) {
static const char* const listAlterUser[] = {
"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",
"NOSYSADMIN", "NOUSEFT", "NOVCADMIN", "OPRADMIN", "PASSWORD",
"PERM SPACE", "PERSISTENCE", "PGUSER", "POLADMIN", "RENAME TO",
"REPLICATION", "RESET", "RESOURCE POOL", "SET", "SPILL SPACE",
"SYSADMIN", "TEMP SPACE", "UNENCRYPTED", "USEFT",
"USER GROUP", "VALID", "VCADMIN", "WITH", NULL
};
COMPLETE_WITH_LIST(listAlterUser);
}
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);
}
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)) {
static const char* const listAlterUserWith[] = {
"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",
"NOSYSADMIN", "NOUSEFT", "NOVCADMIN", "OPRADMIN", "PASSWORD",
"PERM SPACE", "PERSISTENCE", "PGUSER", "POLADMIN", "RENAME TO",
"REPLICATION", "RESET", "RESOURCE POOL", "SET", "SPILL SPACE",
"SYSADMIN", "TEMP SPACE", "UNENCRYPTED", "USEFT",
"USER GROUP", "VALID", "VCADMIN", NULL
};
COMPLETE_WITH_LIST(listAlterUserWith);
}
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) {
static const char* const listAlterUserWithValid[] = {"BEGIN", "UNTIL", NULL};
COMPLETE_WITH_LIST(listAlterUserWithValid);
}
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)) {
static const char* const listAlterUserEncrypted[] = {"IDENTIFIED BY", "PASSWORD", NULL};
COMPLETE_WITH_LIST(listAlterUserEncrypted);
}
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") == 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);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "DEFAULT") == 0 &&
pg_strcasecmp(PREV_WD, "PRIVILEGES") == 0) {
static const char* const listAlterDefaultPrivileges[] = {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterDefaultPrivileges);
}
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 listAlterDefaultPrivileges_FOR[] = {"ROLE", "USER", NULL};
COMPLETE_WITH_LIST(listAlterDefaultPrivileges_FOR);
}
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 listAlterDefaultPrivilegesRest[] = {"GRANT", "REVOKE", NULL};
COMPLETE_WITH_LIST(listAlterDefaultPrivilegesRest);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "DOMAIN") == 0) {
static const char* const listAlterDomain[] = {
"ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT", NULL
};
COMPLETE_WITH_LIST(listAlterDomain);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "DOMAIN") == 0 &&
pg_strcasecmp(PREV_WD, "DROP") == 0) {
static const char* const listAlterDomain2[] = {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
COMPLETE_WITH_LIST(listAlterDomain2);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "DOMAIN") == 0 &&
pg_strcasecmp(PREV_WD, "RENAME") == 0) {
static const char* const listAlterDomain[] = {"CONSTRAINT", "TO", NULL};
COMPLETE_WITH_LIST(listAlterDomain);
}
else if (pg_strcasecmp(PREV5_WD, "DOMAIN") == 0 && pg_strcasecmp(PREV3_WD, "RENAME") == 0 &&
pg_strcasecmp(PREV2_WD, "CONSTRAINT") == 0)
COMPLETE_WITH_CONST("TO");
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "DOMAIN") == 0 &&
pg_strcasecmp(PREV_WD, "SET") == 0) {
static const char* const listAlterDomain3[] = {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterDomain3);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SEQUENCE") == 0) {
static const char* const listAlterSequence[] = {
"MAXVALUE", "NO MAXVALUE", "NOMAXVALUE", "OWNED BY", "OWNER TO", NULL
};
COMPLETE_WITH_LIST(listAlterSequence);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SERVER") == 0) {
static const char* const listAlterServer[] = {
"VERSION", "OPTIONS", "OWNER TO", "RENAME TO", NULL
};
COMPLETE_WITH_LIST(listAlterServer);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV2_WD, "VIEW") == 0) {
static const char *const listAlterMatview[] = {
"ALTER COLUMN", "OWNER TO", "RENAME", "RESET (", "SET", NULL};
COMPLETE_WITH_LIST(listAlterMatview);
}
else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV3_WD, "VIEW") == 0 && pg_strcasecmp(PREV_WD, "RENAME") == 0)
COMPLETE_WITH_ATTR(PREV2_WD, " UNION SELECT 'COLUMN' UNION SELECT 'TO'");
else if (pg_strcasecmp(PREV6_WD, "ALTER") == 0 && pg_strcasecmp(PREV5_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV4_WD, "VIEW") == 0 && (pg_strcasecmp(PREV2_WD, "ALTER") == 0 ||
pg_strcasecmp(PREV2_WD, "RENAME") == 0) && pg_strcasecmp(PREV_WD, "COLUMN") == 0)
COMPLETE_WITH_ATTR(PREV3_WD, "");
else if (pg_strcasecmp(PREV6_WD, "ALTER") == 0 && pg_strcasecmp(PREV5_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV4_WD, "VIEW") == 0 && pg_strcasecmp(PREV2_WD, "RENAME") == 0 &&
pg_strcasecmp(PREV_WD, "TO") != 0)
COMPLETE_WITH_CONST("TO");
else if (pg_strcasecmp(PREV7_WD, "ALTER") == 0 && pg_strcasecmp(PREV6_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV5_WD, "VIEW") == 0 && pg_strcasecmp(PREV3_WD, "RENAME") == 0 &&
pg_strcasecmp(PREV2_WD, "COLUMN") == 0 && pg_strcasecmp(PREV_WD, "TO") != 0)
COMPLETE_WITH_CONST("TO");
else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV3_WD, "VIEW") == 0 && pg_strcasecmp(PREV_WD, "SET") == 0) {
static const char *const listAlterS[] = {
"(", "SCHEMA", "TABLESPACE", "WITHOUT CLUSTER", NULL};
COMPLETE_WITH_LIST(listAlterS);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "VIEW") == 0) {
static const char* const listAlterview[] = {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterview);
}
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);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TRIGGER") == 0)
COMPLETE_WITH_CONST("ON");
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TRIGGER") == 0) {
completion_info_charp = PREV2_WD;
COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
}
* If we have ALTER TRIGGER <sth> ON, then add the correct tablename
*/
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TRIGGER") == 0 &&
pg_strcasecmp(PREV_WD, "ON") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
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");
* If we detect ALTER TABLE <name>, suggest sub commands
*/
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TABLE") == 0) {
static const char* const listAlteR2[] = {
"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
"NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
"VALIDATE CONSTRAINT", NULL
};
COMPLETE_WITH_LIST(listAlteR2);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TABLE") == 0 &&
pg_strcasecmp(PREV_WD, "ENABLE") == 0) {
static const char* const listAlterEnable[] = {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
COMPLETE_WITH_LIST(listAlterEnable);
} 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 listAlterEnablE2[] = {"RULE", "TRIGGER", NULL};
COMPLETE_WITH_LIST(listAlterEnablE2);
} else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TABLE") == 0 &&
pg_strcasecmp(PREV_WD, "DISABLE") == 0) {
static const char* const listAlterDisable[] = {"RULE", "TRIGGER", NULL};
COMPLETE_WITH_LIST(listAlterDisable);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TABLE") == 0 &&
pg_strcasecmp(PREV_WD, "ALTER") == 0)
COMPLETE_WITH_ATTR(PREV2_WD, " UNION SELECT 'COLUMN'");
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TABLE") == 0 &&
pg_strcasecmp(PREV_WD, "RENAME") == 0)
COMPLETE_WITH_ATTR(PREV2_WD, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'");
* If we have TABLE <sth> 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)
COMPLETE_WITH_ATTR(PREV3_WD, "");
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)
COMPLETE_WITH_CONST("TO");
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)
COMPLETE_WITH_CONST("TO");
else if (pg_strcasecmp(PREV3_WD, "TABLE") == 0 && pg_strcasecmp(PREV_WD, "DROP") == 0) {
static const char* const listTableDrop[] = {"COLUMN", "CONSTRAINT", NULL};
COMPLETE_WITH_LIST(listTableDrop);
}
else if (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV2_WD, "DROP") == 0 &&
pg_strcasecmp(PREV_WD, "COLUMN") == 0)
COMPLETE_WITH_ATTR(PREV3_WD, "");
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 listColumnAlter[] = {"TYPE", "SET", "RESET", "DROP", NULL};
COMPLETE_WITH_LIST(listColumnAlter);
}
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 listColumnSet[] = {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
COMPLETE_WITH_LIST(listColumnSet);
}
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 listColumnOptions[] = {"n_distinct", "n_distinct_inherited", NULL};
COMPLETE_WITH_LIST(listColumnOptions);
}
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 listColumnStorage[] = {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
COMPLETE_WITH_LIST(listColumnStorage);
}
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 listColumnDrop[] = {"DEFAULT", "NOT NULL", NULL};
COMPLETE_WITH_LIST(listColumnDrop);
} else if (pg_strcasecmp(PREV3_WD, "TABLE") == 0 && pg_strcasecmp(PREV_WD, "CLUSTER") == 0)
COMPLETE_WITH_CONST("ON");
else if (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV2_WD, "CLUSTER") == 0 &&
pg_strcasecmp(PREV_WD, "ON") == 0) {
completion_info_charp = PREV3_WD;
COMPLETE_WITH_QUERY(Query_for_index_of_table);
}
else if (pg_strcasecmp(PREV3_WD, "TABLE") == 0 && pg_strcasecmp(PREV_WD, "SET") == 0) {
static const char* const listTableSet[] = {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
COMPLETE_WITH_LIST(listTableSet);
}
else if (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV2_WD, "SET") == 0 &&
pg_strcasecmp(PREV_WD, "TABLESPACE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
else if (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV2_WD, "SET") == 0 &&
pg_strcasecmp(PREV_WD, "WITHOUT") == 0) {
static const char* const listTableSet2[] = {"CLUSTER", "OIDS", NULL};
COMPLETE_WITH_LIST(listTableSet2);
}
else if (pg_strcasecmp(PREV3_WD, "TABLE") == 0 && pg_strcasecmp(PREV_WD, "RESET") == 0)
COMPLETE_WITH_CONST("(");
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) {
static const char* const listTableOptions[] = {
"autovacuum_analyze_scale_factor",
"autovacuum_analyze_threshold",
"autovacuum_enabled",
"autovacuum_freeze_max_age",
"autovacuum_freeze_min_age",
"autovacuum_freeze_table_age",
"autovacuum_vacuum_cost_delay",
"autovacuum_vacuum_cost_limit",
"autovacuum_vacuum_scale_factor",
"autovacuum_vacuum_threshold",
"fillfactor",
"toast.autovacuum_enabled",
"toast.autovacuum_freeze_max_age",
"toast.autovacuum_freeze_min_age",
"toast.autovacuum_freeze_table_age",
"toast.autovacuum_vacuum_cost_delay",
"toast.autovacuum_vacuum_cost_limit",
"toast.autovacuum_vacuum_scale_factor",
"toast.autovacuum_vacuum_threshold",
NULL
};
COMPLETE_WITH_LIST(listTableOptions);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TABLESPACE") == 0) {
static const char* const listAlterTspc[] = {"RENAME TO", "OWNER TO", "SET", "RESET", "RESIZE MAXSIZE", NULL};
COMPLETE_WITH_LIST(listAlterTspc);
}
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))
COMPLETE_WITH_CONST("(");
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 listTablespaceOptions[] = {"seq_page_cost", "random_page_cost", NULL};
COMPLETE_WITH_LIST(listTablespaceOptions);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TEXT") == 0 &&
pg_strcasecmp(PREV_WD, "SEARCH") == 0) {
static const char* const listAlterTextSearch[] = {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
COMPLETE_WITH_LIST(listAlterTextSearch);
} 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 listAlterTextSearcH2[] = {"RENAME TO", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterTextSearcH2);
} 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 listAlterTextSearch3[] = {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(listAlterTextSearch3);
} 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 listAlterTextSearch4[] = {
"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL
};
COMPLETE_WITH_LIST(listAlterTextSearch4);
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TYPE") == 0) {
static const char* const listAlterType[] = {
"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
"OWNER TO", "RENAME", "SET SCHEMA", NULL
};
COMPLETE_WITH_LIST(listAlterType);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TYPE") == 0 &&
pg_strcasecmp(PREV_WD, "ADD") == 0) {
static const char* const listAlterType[] = {"ATTRIBUTE", "VALUE", NULL};
COMPLETE_WITH_LIST(listAlterType);
}
else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TYPE") == 0 &&
pg_strcasecmp(PREV_WD, "RENAME") == 0) {
static const char* const listAlterType[] = {"ATTRIBUTE", "TO", NULL};
COMPLETE_WITH_LIST(listAlterType);
}
else if (pg_strcasecmp(PREV5_WD, "TYPE") == 0 && pg_strcasecmp(PREV3_WD, "RENAME") == 0 &&
pg_strcasecmp(PREV2_WD, "ATTRIBUTE") == 0)
COMPLETE_WITH_CONST("TO");
* If we have TYPE <sth> 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)
COMPLETE_WITH_ATTR(PREV3_WD, "");
else if ((pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "ATTRIBUTE") == 0)) {
COMPLETE_WITH_CONST("TYPE");
}
else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "GROUP") == 0) {
static const char* const listAlterGroup[] = {"ADD USER", "DROP USER", "RENAME TO", NULL};
COMPLETE_WITH_LIST(listAlterGroup);
}
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))
COMPLETE_WITH_CONST("USER");
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)
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
else if (pg_strcasecmp(PREV_WD, "BEGIN") == 0 || pg_strcasecmp(PREV_WD, "END") == 0 ||
pg_strcasecmp(PREV_WD, "ABORT") == 0) {
static const char* const listTrans[] = {"WORK", "TRANSACTION", NULL};
COMPLETE_WITH_LIST(listTrans);
}
else if (pg_strcasecmp(PREV_WD, "COMMIT") == 0) {
static const char* const listCommit[] = {"WORK", "TRANSACTION", "PREPARED", NULL};
COMPLETE_WITH_LIST(listCommit);
}
else if (pg_strcasecmp(PREV_WD, "RELEASE") == 0)
COMPLETE_WITH_CONST("SAVEPOINT");
else if (pg_strcasecmp(PREV_WD, "ROLLBACK") == 0) {
static const char* const listTrans[] = {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
COMPLETE_WITH_LIST(listTrans);
}
* 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)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
else if (pg_strcasecmp(PREV2_WD, "CLUSTER") == 0 && pg_strcasecmp(PREV_WD, "ON") != 0) {
COMPLETE_WITH_CONST("USING");
}
* If we have CLUSTER <sth> USING, then add the index as well.
*/
else if (pg_strcasecmp(PREV3_WD, "CLUSTER") == 0 && pg_strcasecmp(PREV_WD, "USING") == 0) {
completion_info_charp = PREV2_WD;
COMPLETE_WITH_QUERY(Query_for_index_of_table);
}
else if (pg_strcasecmp(PREV_WD, "COMMENT") == 0)
COMPLETE_WITH_CONST("ON");
else if (pg_strcasecmp(PREV2_WD, "COMMENT") == 0 && pg_strcasecmp(PREV_WD, "ON") == 0) {
static const char* const listComment[] = {
"CAST", "COLLATION", "CONVERSION", "DATABASE", "EXTENSION",
"FOREIGN DATA WRAPPER", "FOREIGN TABLE",
"SERVER", "INDEX", "LANGUAGE", "RULE", "SCHEMA", "SEQUENCE",
"TABLE", "TYPE", "VIEW", "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
"OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
"TABLESPACE", "TEXT SEARCH", "ROLE", NULL
};
COMPLETE_WITH_LIST(listComment);
} else if (pg_strcasecmp(PREV3_WD, "COMMENT") == 0 && pg_strcasecmp(PREV2_WD, "ON") == 0 &&
pg_strcasecmp(PREV_WD, "FOREIGN") == 0) {
static const char* const listTrans2[] = {"DATA WRAPPER", "TABLE", NULL};
COMPLETE_WITH_LIST(listTrans2);
} 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 listTrans2[] = {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
COMPLETE_WITH_LIST(listTrans2);
} 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) {
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(PREV5_WD, "COMMENT") == 0 && pg_strcasecmp(PREV4_WD, "ON") == 0) ||
(pg_strcasecmp(PREV6_WD, "COMMENT") == 0 && pg_strcasecmp(PREV5_WD, "ON") == 0))
COMPLETE_WITH_CONST("IS");
* 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))
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
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);
}
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)) {
completion_charp = "";
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);
}
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", "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);
}
else if (pg_strcasecmp(PREV_WD, "CSV") == 0 &&
(pg_strcasecmp(PREV3_WD, "FROM") == 0 || pg_strcasecmp(PREV3_WD, "TO") == 0)) {
static const char* const listCsv[] = {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL};
COMPLETE_WITH_LIST(listCsv);
}
else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "CAST") == 0) {
COMPLETE_WITH_CONST("(");
}
else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "CAST") == 0 &&
pg_strcasecmp(PREV2_WD, "(") == 0) {
COMPLETE_WITH_CONST("AS");
}
else if (pg_strcasecmp(PREV6_WD, "CREATE") == 0 && pg_strcasecmp(PREV5_WD, "CAST") == 0 &&
pg_strcasecmp(PREV4_WD, "(") == 0 && pg_strcasecmp(PREV2_WD, "AS") == 0) {
COMPLETE_WITH_CONST(")");
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "CAST") == 0 &&
pg_strcasecmp(PREV_WD, "(") != 0) {
static const char* const listCreateCastOptions[] = {"WITH FUNCTION", "WITHOUT FUNCTION", "WITH INOUT", NULL};
COMPLETE_WITH_LIST(listCreateCastOptions);
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "DATABASE") == 0) {
static const char* const listDatabase[] = {
"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);
else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "EXTENSION") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "EXTENSION") == 0) {
static const char* const listCreateExtension[] = {"WITH", "SCHEMA", "VERSION", "FROM", NULL};
COMPLETE_WITH_LIST(listCreateExtension);
}
else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "EXTENSION") == 0 &&
pg_strcasecmp(PREV_WD, "WITH") == 0) {
static const char* const listCreateExtensionWith[] = {"SCHEMA", "VERSION", "FROM", NULL};
COMPLETE_WITH_LIST(listCreateExtensionWith);
}
else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "FOREIGN") == 0) {
static const char* const listCreateForeign[] = {"DATA WRAPPER", "TABLE", NULL};
COMPLETE_WITH_LIST(listCreateForeign);
}
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 listCreateForeignDataWrapper[] = {"HANDLER", "VALIDATOR", NULL};
COMPLETE_WITH_LIST(listCreateForeignDataWrapper);
}
else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "UNIQUE") == 0)
COMPLETE_WITH_CONST("INDEX");
else if (pg_strcasecmp(PREV_WD, "INDEX") == 0 &&
(pg_strcasecmp(PREV2_WD, "CREATE") == 0 || pg_strcasecmp(PREV2_WD, "UNIQUE") == 0))
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, " UNION SELECT 'ON'"
" UNION SELECT 'CONCURRENTLY'");
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_tmf, NULL);
else if ((pg_strcasecmp(PREV3_WD, "INDEX") == 0 || pg_strcasecmp(PREV2_WD, "INDEX") == 0) &&
pg_strcasecmp(PREV_WD, "CONCURRENTLY") == 0)
COMPLETE_WITH_CONST("ON");
else if ((pg_strcasecmp(PREV3_WD, "CREATE") == 0 || pg_strcasecmp(PREV3_WD, "UNIQUE") == 0) &&
pg_strcasecmp(PREV2_WD, "INDEX") == 0) {
static const char* const listCreateIndex[] = {"CONCURRENTLY", "ON", NULL};
COMPLETE_WITH_LIST(listCreateIndex);
}
* Complete INDEX <name> ON <table> 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 listCreateIndex2[] = {"(", "USING", NULL};
COMPLETE_WITH_LIST(listCreateIndex2);
} 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)
COMPLETE_WITH_ATTR(PREV2_WD, "");
else if (pg_strcasecmp(PREV5_WD, "ON") == 0 && pg_strcasecmp(PREV3_WD, "USING") == 0 &&
pg_strcasecmp(PREV_WD, "(") == 0)
COMPLETE_WITH_ATTR(PREV4_WD, "");
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 &&
pg_strcasecmp(PREV6_WD, "POLICY") != 0)
COMPLETE_WITH_CONST("(");
else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "OR") == 0)
COMPLETE_WITH_CONST("REPLACE");
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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");
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "POLICY") == 0)
COMPLETE_WITH_CONST("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);
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);
}
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 <name> ON <table> 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);
}
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);
}
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");
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);
}
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);
}
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("(");
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "PUBLICATION") == 0) {
static const char * const createPub[] = {"FOR TABLE", "FOR ALL TABLES", "WITH (", NULL};
COMPLETE_WITH_LIST(createPub);
}
else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "PUBLICATION") == 0 &&
pg_strcasecmp(PREV_WD, "FOR") == 0) {
static const char * const createPub2[] = {"TABLE", "ALL TABLES", NULL};
COMPLETE_WITH_LIST(createPub2);
}
else if (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "PUBLICATION") == 0 &&
pg_strcasecmp(PREV2_WD, "FOR") == 0 && pg_strcasecmp(PREV_WD, "TABLE") == 0) {
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "SUBSCRIPTION") == 0) {
COMPLETE_WITH_CONST("CONNECTION");
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "RULE") == 0)
COMPLETE_WITH_CONST("AS");
else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "RULE") == 0 &&
pg_strcasecmp(PREV_WD, "AS") == 0)
COMPLETE_WITH_CONST("ON");
else if (pg_strcasecmp(PREV4_WD, "RULE") == 0 && pg_strcasecmp(PREV2_WD, "AS") == 0 &&
pg_strcasecmp(PREV_WD, "ON") == 0) {
static const char* const ruleEvents[] = {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
COMPLETE_WITH_LIST(ruleEvents);
}
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'))
COMPLETE_WITH_CONST("TO");
else if (pg_strcasecmp(PREV4_WD, "AS") == 0 && pg_strcasecmp(PREV3_WD, "ON") == 0 &&
pg_strcasecmp(PREV_WD, "TO") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
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);
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "SERVER") == 0) {
static const char* const listCreateServer[] = {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
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");
else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 &&
(pg_strcasecmp(PREV_WD, "TEMP") == 0 || pg_strcasecmp(PREV_WD, "TEMPORARY") == 0)) {
static const char* const listTemp[] = {"SEQUENCE", "TABLE", "VIEW", NULL};
COMPLETE_WITH_LIST(listTemp);
}
else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "UNLOGGED") == 0) {
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);
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "TABLESPACE") == 0) {
static const char* const listCreateTablespace[] = {"OWNER", "LOCATION", "RELATIVE LOCATION", NULL};
COMPLETE_WITH_LIST(listCreateTablespace);
}
else if (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "TABLESPACE") == 0 &&
pg_strcasecmp(PREV2_WD, "OWNER") == 0) {
static const char* const listCreateTablespaceOwner[] = {"LOCATION", "RELATIVE LOCATION", NULL};
COMPLETE_WITH_LIST(listCreateTablespaceOwner);
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "TEXT") == 0 &&
pg_strcasecmp(PREV_WD, "SEARCH") == 0) {
static const char* const listCreateTextSearch[] = {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
COMPLETE_WITH_LIST(listCreateTextSearch);
} else if (pg_strcasecmp(PREV4_WD, "TEXT") == 0 && pg_strcasecmp(PREV3_WD, "SEARCH") == 0 &&
pg_strcasecmp(PREV2_WD, "CONFIGURATION") == 0)
COMPLETE_WITH_CONST("(");
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "TRIGGER") == 0) {
static const char* const listCreateTrigger[] = {"BEFORE", "AFTER", "INSTEAD OF", NULL};
COMPLETE_WITH_LIST(listCreateTrigger);
}
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 listCreateTriggerEvents[] = {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
COMPLETE_WITH_LIST(listCreateTriggerEvents);
}
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 listCreateTriggerEvents[] = {"INSERT", "DELETE", "UPDATE", NULL};
COMPLETE_WITH_LIST(listCreateTriggerEvents);
}
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 listCreateTrigger2[] = {"ON", "OR", NULL};
COMPLETE_WITH_LIST(listCreateTrigger2);
}
* complete CREATE TRIGGER <name> 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)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
else if (pg_strcasecmp(PREV4_WD, "INSTEAD") == 0 && pg_strcasecmp(PREV3_WD, "OF") == 0 &&
pg_strcasecmp(PREV_WD, "ON") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
else if (pg_strcasecmp(PREV_WD, "EXECUTE") == 0 && PREV2_WD[0] != '\0')
COMPLETE_WITH_CONST("DIRECT");
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)) {
static const char* const listCreateRole[] = {
"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", "NOSYSADMIN",
"NOUSEFT", "NOVCADMIN", "OPRADMIN", "PASSWORD", "PERM SPACE", "PERSISTENCE",
"PGUSER", "POLADMIN", "PROFILE", "PROFILE DEFAULT", "REPLICATION",
"RESOURCE POOL", "ROLE", "SPILL SPACE", "SYSADMIN", "SYSID",
"TEMP SPACE", "UNENCRYPTED", "USEFT", "USER", "USER GROUP", "VALID",
"VCADMIN", "WITH", NULL
};
COMPLETE_WITH_LIST(listCreateRole);
}
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);
}
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)) {
static const char* const listCreateRoleWith[] = {
"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", "NOSYSADMIN",
"NOUSEFT", "NOVCADMIN", "OPRADMIN", "PASSWORD", "PERM SPACE", "PERSISTENCE",
"PGUSER", "POLADMIN", "PROFILE", "PROFILE DEFAULT", "REPLICATION",
"RESOURCE POOL", "ROLE", "SPILL SPACE", "SYSADMIN", "SYSID",
"TEMP SPACE", "UNENCRYPTED", "USEFT", "USER", "USER GROUP", "VALID",
"VCADMIN", NULL
};
COMPLETE_WITH_LIST(listCreateRoleWith);
}
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) {
static const char* const listCreateRoleWithValid[] = {"BEGIN", "UNTIL", NULL};
COMPLETE_WITH_LIST(listCreateRoleWithValid);
}
* complete CREATE ROLE,USER,GROUP <name> 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)) {
static const char* const listCreateRoleWithEncrypted[] = {"PASSWORD", "IDENTIFIED BY", NULL};
COMPLETE_WITH_LIST(listCreateRoleWithEncrypted);
}
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 listCreateRole3[] = {"GROUP", "ROLE", NULL};
COMPLETE_WITH_LIST(listCreateRole3);
}
else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "VIEW") == 0)
COMPLETE_WITH_CONST("AS");
else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "VIEW") == 0 &&
pg_strcasecmp(PREV_WD, "AS") == 0)
COMPLETE_WITH_CONST("SELECT");
else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "MATERIALIZED") == 0)
COMPLETE_WITH_CONST("VIEW");
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);
}
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)
COMPLETE_WITH_CONST("SELECT");
else if (pg_strcasecmp(PREV2_WD, "DECLARE") == 0) {
static const char* const listDeclare[] = {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
COMPLETE_WITH_LIST(listDeclare);
}
else if (pg_strcasecmp(PREV2_WD, "CURSOR") == 0) {
static const char* const listDeclareCursor[] = {
"BINARY", "SCROLL", "NO SCROLL","INSENSITIVE","FOR", NULL
};
COMPLETE_WITH_LIST(listDeclareCursor);
}
* 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))
COMPLETE_WITH_CONST("FROM");
else if (pg_strcasecmp(PREV2_WD, "DELETE") == 0 && pg_strcasecmp(PREV_WD, "FROM") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL);
else if (pg_strcasecmp(PREV3_WD, "DELETE") == 0 && pg_strcasecmp(PREV2_WD, "FROM") == 0) {
static const char* const listDelete[] = {"USING", "WHERE", "SET", NULL};
COMPLETE_WITH_LIST(listDelete);
}
else if (pg_strcasecmp(PREV_WD, "DISCARD") == 0) {
static const char* const listDiscard[] = {"ALL", "PLANS", "TEMP", NULL};
COMPLETE_WITH_LIST(listDiscard);
}
* Complete DO with LANGUAGE.
*/
else if (pg_strcasecmp(PREV_WD, "DO") == 0) {
static const char* const listDo[] = {"LANGUAGE", NULL};
COMPLETE_WITH_LIST(listDo);
}
else if (pg_strcasecmp(PREV3_WD, "DROP") == 0 && pg_strcasecmp(PREV2_WD, "AGGREGATE") == 0)
COMPLETE_WITH_CONST("(");
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, "PUBLICATION") == 0 ||
pg_strcasecmp(PREV2_WD, "SCHEMA") == 0 || pg_strcasecmp(PREV2_WD, "SEQUENCE") == 0 ||
pg_strcasecmp(PREV2_WD, "SERVER") == 0 || pg_strcasecmp(PREV2_WD, "SUBSCRIPTION") == 0 ||
pg_strcasecmp(PREV2_WD, "TABLE") == 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 &&
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) {
COMPLETE_WITH_CONST("(");
} else {
static const char* const listDropCr[] = {"CASCADE", "RESTRICT", NULL};
COMPLETE_WITH_LIST(listDropCr);
}
} else if (pg_strcasecmp(PREV2_WD, "DROP") == 0 && pg_strcasecmp(PREV_WD, "FOREIGN") == 0) {
static const char* const dropCreateForeign[] = {"DATA WRAPPER", "TABLE", NULL};
COMPLETE_WITH_LIST(dropCreateForeign);
} else if (pg_strcasecmp(PREV2_WD, "DROP") == 0 && pg_strcasecmp(PREV_WD, "MATERIALIZED") == 0) {
COMPLETE_WITH_CONST("VIEW");
} else if (pg_strcasecmp(PREV3_WD, "DROP") == 0 && pg_strcasecmp(PREV2_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV_WD, "VIEW") == 0) {
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) {
size_t tmpLength = strlen(Query_for_list_of_arguments) + strlen(PREV2_WD);
char *tmpBuf = (char *)pg_malloc(tmpLength);
int rc = sprintf_s(tmpBuf, tmpLength, Query_for_list_of_arguments, PREV2_WD);
securec_check_ss_c(rc,"","");
COMPLETE_WITH_QUERY(tmpBuf);
free(tmpBuf);
}
else if (pg_strcasecmp(PREV2_WD, "DROP") == 0 && pg_strcasecmp(PREV_WD, "OWNED") == 0)
COMPLETE_WITH_CONST("BY");
else if (pg_strcasecmp(PREV3_WD, "DROP") == 0 && pg_strcasecmp(PREV2_WD, "OWNED") == 0 &&
pg_strcasecmp(PREV_WD, "BY") == 0)
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 listAlterTextSearch[] = {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
COMPLETE_WITH_LIST(listAlterTextSearch);
}
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);
}
else if (pg_strcasecmp(PREV_WD, "EXECUTE") == 0 && PREV2_WD[0] == '\0')
COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
* Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
*/
else if (pg_strcasecmp(PREV_WD, "EXPLAIN") == 0) {
static const char* const listExplain[] = {
"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE",
"COSTS", "CPU", "DETAIL", "NODES", "NUM_NODES", "BUFFERS", "TIMING",
"PLAN", "FORMAT", "ANALYSE", "PERFORMANCE", NULL
};
COMPLETE_WITH_LIST(listExplain);
} else if (pg_strcasecmp(PREV2_WD, "EXPLAIN") == 0 && pg_strcasecmp(PREV_WD, "ANALYZE") == 0) {
static const char* const listExplain[] = {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
COMPLETE_WITH_LIST(listExplain);
} 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 listExplain[] = {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
COMPLETE_WITH_LIST(listExplain);
}
else if (pg_strcasecmp(PREV_WD, "FETCH") == 0 || pg_strcasecmp(PREV_WD, "MOVE") == 0) {
static const char* const listFetch1[] = {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
COMPLETE_WITH_LIST(listFetch1);
}
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);
}
* Complete FETCH <sth1> <sth2> 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 listFromin[] = {"FROM", "IN", NULL};
COMPLETE_WITH_LIST(listFromin);
}
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)
COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
else if (pg_strcasecmp(PREV3_WD, "CREATE") != 0 && pg_strcasecmp(PREV2_WD, "FOREIGN") == 0 &&
pg_strcasecmp(PREV_WD, "TABLE") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
else if (pg_strcasecmp(PREV_WD, "GRANT") == 0 || pg_strcasecmp(PREV_WD, "REVOKE") == 0) {
COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'SELECT'"
" UNION SELECT 'INSERT'"
" UNION SELECT 'UPDATE'"
" UNION SELECT 'DELETE'"
" UNION SELECT 'TRUNCATE'"
" UNION SELECT 'REFERENCES'"
" UNION SELECT 'TRIGGER'"
" UNION SELECT 'CREATE'"
" UNION SELECT 'CONNECT'"
" UNION SELECT 'TEMPORARY'"
" UNION SELECT 'EXECUTE'"
" UNION SELECT 'USAGE'"
" UNION SELECT 'ALL'"
" UNION SELECT 'ALTER'"
" UNION SELECT 'DROP'"
" UNION SELECT 'COMMENT'"
" UNION SELECT 'INDEX'"
" UNION SELECT 'VACUUM'"
" UNION SELECT 'READ'"
" UNION SELECT 'WRITE'");
}
* Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
* TO/FROM
*/
else if (pg_strcasecmp(PREV2_WD, "GRANT") == 0 || pg_strcasecmp(PREV2_WD, "REVOKE") == 0) {
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)
COMPLETE_WITH_CONST("ON");
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
COMPLETE_WITH_CONST("FROM");
}
}
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 <sth> ON with a list of tables, views, sequences,
* and indexes
*
* keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
* UNION; seems to work intuitively
*
* Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
* 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)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, " UNION SELECT 'DATABASE'"
" UNION SELECT 'DOMAIN'"
" UNION SELECT 'FOREIGN DATA WRAPPER'"
" UNION SELECT 'FOREIGN SERVER'"
" UNION SELECT 'FUNCTION'"
" UNION SELECT 'LANGUAGE'"
" UNION SELECT 'LARGE OBJECT'"
" UNION SELECT 'SCHEMA'"
" UNION SELECT 'TABLESPACE'"
" UNION SELECT 'TYPE'"
" UNION SELECT 'TABLE'"
" UNION SELECT 'DIRECTORY'"
" UNION SELECT 'NODE GROUP'"
" UNION SELECT 'DATA SOURCE'");
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 listPrivilegeForeign[] = {"DATA WRAPPER", "SERVER", NULL};
COMPLETE_WITH_LIST(listPrivilegeForeign);
}
else if ((pg_strcasecmp(PREV4_WD, "GRANT") == 0 || pg_strcasecmp(PREV4_WD, "REVOKE") == 0) &&
pg_strcasecmp(PREV2_WD, "ON") == 0) {
if (pg_strcasecmp(PREV_WD, "DATABASE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
else if (pg_strcasecmp(PREV_WD, "DOMAIN") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
else if (pg_strcasecmp(PREV_WD, "FUNCTION") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (pg_strcasecmp(PREV_WD, "LANGUAGE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
else if (pg_strcasecmp(PREV_WD, "SCHEMA") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
else if (pg_strcasecmp(PREV_WD, "TABLESPACE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
else if (pg_strcasecmp(PREV_WD, "TYPE") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
else if (pg_strcasecmp(PREV_WD, "DATA") == 0)
COMPLETE_WITH_CONST("SOURCE");
else if (pg_strcasecmp(PREV4_WD, "GRANT") == 0)
COMPLETE_WITH_CONST("TO");
else
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);
else if (pg_strcasecmp(PREV5_WD, "GRANT") == 0 && pg_strcasecmp(PREV3_WD, "ON") == 0) {
if (pg_strcasecmp(PREV_WD, "TO") == 0)
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) {
if (pg_strcasecmp(PREV_WD, "FROM") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
else
COMPLETE_WITH_CONST("FROM");
}
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");
}
else if (pg_strcasecmp(PREV3_WD, "GRANT") == 0 && pg_strcasecmp(PREV_WD, "TO") == 0) {
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
} else if (pg_strcasecmp(PREV3_WD, "REVOKE") == 0 && pg_strcasecmp(PREV_WD, "FROM") == 0) {
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
}
else if (pg_strcasecmp(PREV3_WD, "FROM") == 0 && pg_strcasecmp(PREV_WD, "GROUP") == 0)
COMPLETE_WITH_CONST("BY");
else if (pg_strcasecmp(PREV_WD, "INSERT") == 0)
COMPLETE_WITH_CONST("INTO");
else if (pg_strcasecmp(PREV2_WD, "INSERT") == 0 && pg_strcasecmp(PREV_WD, "INTO") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL);
else if (pg_strcasecmp(PREV4_WD, "INSERT") == 0 && pg_strcasecmp(PREV3_WD, "INTO") == 0 &&
pg_strcasecmp(PREV_WD, "(") == 0)
COMPLETE_WITH_ATTR(PREV2_WD, "");
* Complete INSERT INTO <table> 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 listInsert[] = {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
COMPLETE_WITH_LIST(listInsert);
}
* Complete INSERT INTO <table> (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 listInsert[] = {"SELECT", "TABLE", "VALUES", NULL};
COMPLETE_WITH_LIST(listInsert);
}
else if (pg_strcasecmp(PREV_WD, "VALUES") == 0 && pg_strcasecmp(PREV2_WD, "DEFAULT") != 0)
COMPLETE_WITH_CONST("(");
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, " UNION ALL SELECT 'ONLY'");
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)) {
static const char* const lockTableList[] = {"IN", "NOWAIT", NULL};
COMPLETE_WITH_LIST(lockTableList);
}
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 lockModes[] = {
"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(lockModes);
}
else if ((pg_strcasecmp(PREV_WD, "ACCESS") == 0 || pg_strcasecmp(PREV_WD, "ROW") == 0) &&
pg_strcasecmp(PREV2_WD, "IN") == 0 && (pg_strcasecmp(PREV4_WD, "LOCK") == 0 ||
(pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV5_WD, "LOCK") == 0))) {
static const char* const lockModesAccess[] = {"SHARE MODE", "EXCLUSIVE MODE", NULL};
COMPLETE_WITH_LIST(lockModesAccess);
}
else if (pg_strcasecmp(PREV_WD, "SHARE") == 0&& pg_strcasecmp(PREV2_WD, "IN") == 0 &&
(pg_strcasecmp(PREV4_WD, "LOCK") == 0 || (pg_strcasecmp(PREV4_WD, "TABLE") == 0 &&
pg_strcasecmp(PREV5_WD, "LOCK") == 0))) {
static const char* const lockModesAccess[] = {"UPDATE EXCLUSIVE MODE", "ROW EXCLUSIVE MODE", "MODE", NULL};
COMPLETE_WITH_LIST(lockModesAccess);
}
else if (pg_strcasecmp(PREV_WD, "NOTIFY") == 0)
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'");
else if (pg_strcasecmp(PREV_WD, "OPTIONS") == 0)
COMPLETE_WITH_CONST("(");
else if (pg_strcasecmp(PREV2_WD, "OWNER") == 0 && pg_strcasecmp(PREV_WD, "TO") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
else if (pg_strcasecmp(PREV3_WD, "FROM") == 0 && pg_strcasecmp(PREV_WD, "ORDER") == 0)
COMPLETE_WITH_CONST("BY");
else if (pg_strcasecmp(PREV4_WD, "FROM") == 0 && pg_strcasecmp(PREV2_WD, "ORDER") == 0 &&
pg_strcasecmp(PREV_WD, "BY") == 0)
COMPLETE_WITH_ATTR(PREV3_WD, "");
else if (pg_strcasecmp(PREV_WD, "AS") == 0 && pg_strcasecmp(PREV3_WD, "PREPARE") == 0) {
static const char* const listPrepare[] = {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
COMPLETE_WITH_LIST(listPrepare);
}
* PREPARE TRANSACTION is missing on purpose. It's intended for transaction
* managers, not for manual use in interactive sessions.
*/
else if (pg_strcasecmp(PREV_WD, "REASSIGN") == 0)
COMPLETE_WITH_CONST("OWNED");
else if (pg_strcasecmp(PREV_WD, "OWNED") == 0 && pg_strcasecmp(PREV2_WD, "REASSIGN") == 0)
COMPLETE_WITH_CONST("BY");
else if (pg_strcasecmp(PREV_WD, "BY") == 0 && pg_strcasecmp(PREV2_WD, "OWNED") == 0 &&
pg_strcasecmp(PREV3_WD, "REASSIGN") == 0)
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)
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)
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
else if (pg_strcasecmp(PREV_WD, "REFRESH") == 0) {
static const char* const refreshObject[] = {"MATERIALIZED VIEW", "INCREMENTAL MATERIALIZED VIEW", NULL};
COMPLETE_WITH_LIST(refreshObject);
}
else if (pg_strcasecmp(PREV2_WD, "REFRESH") == 0 && pg_strcasecmp(PREV_WD, "MATERIALIZED") == 0)
COMPLETE_WITH_CONST("VIEW");
else if (pg_strcasecmp(PREV3_WD, "REFRESH") == 0 && pg_strcasecmp(PREV2_WD, "MATERIALIZED") == 0 &&
pg_strcasecmp(PREV_WD, "VIEW") == 0)
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)
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(PREV_WD, "WITH") == 0) {
static const char *const listWithData[] = {
"NO DATA", "DATA", NULL};
COMPLETE_WITH_LIST(listWithData);
} 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)
COMPLETE_WITH_CONST("DATA");
else if (pg_strcasecmp(PREV_WD, "REINDEX") == 0) {
static const char* const listReindex[] = {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
COMPLETE_WITH_LIST(listReindex);
} else if (pg_strcasecmp(PREV2_WD, "REINDEX") == 0) {
if (pg_strcasecmp(PREV_WD, "TABLE") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'CONCURRENTLY'");
else if (pg_strcasecmp(PREV_WD, "INDEX") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, " UNION SELECT 'CONCURRENTLY'");
else if (pg_strcasecmp(PREV_WD, "SYSTEM") == 0 || pg_strcasecmp(PREV_WD, "DATABASE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_databases " UNION SELECT 'CONCURRENTLY'");
} else if (pg_strcasecmp(PREV3_WD, "REINDEX") == 0) {
if (pg_strcasecmp(PREV2_WD, "TABLE") == 0 && pg_strcasecmp(PREV_WD, "CONCURRENTLY") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
else if (pg_strcasecmp(PREV2_WD, "INDEX") == 0 && pg_strcasecmp(PREV_WD, "CONCURRENTLY") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
else if ((pg_strcasecmp(PREV2_WD, "SYSTEM") == 0 || pg_strcasecmp(PREV2_WD, "DATABASE") == 0) &&
pg_strcasecmp(PREV_WD, "CONCURRENTLY") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
}
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"};
COMPLETE_WITH_LIST(listSecurityLabelPreposition);
} else if (pg_strcasecmp(PREV4_WD, "SECURITY") == 0 && pg_strcasecmp(PREV3_WD, "LABEL") == 0 &&
pg_strcasecmp(PREV2_WD, "FOR") == 0)
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)) {
static const char* const listSecurityLabel[] = {
"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "MATERIALIZED VIEW", "COLUMN",
"AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT", NULL
};
COMPLETE_WITH_LIST(listSecurityLabel);
} else if (pg_strcasecmp(PREV5_WD, "SECURITY") == 0 && pg_strcasecmp(PREV4_WD, "LABEL") == 0 &&
pg_strcasecmp(PREV3_WD, "ON") == 0)
COMPLETE_WITH_CONST("IS");
else if ((pg_strcasecmp(PREV_WD, "SET") == 0 && pg_strcasecmp(PREV3_WD, "UPDATE") != 0) ||
pg_strcasecmp(PREV_WD, "RESET") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
else if (pg_strcasecmp(PREV_WD, "SHOW") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
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 myList[] = {"ISOLATION LEVEL", "READ", NULL};
COMPLETE_WITH_LIST(myList);
} 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)
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 myList[] = {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
COMPLETE_WITH_LIST(myList);
} 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 myList[] = {"UNCOMMITTED", "COMMITTED", NULL};
COMPLETE_WITH_LIST(myList);
} 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)
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 myList[] = {"ONLY", "WRITE", NULL};
COMPLETE_WITH_LIST(myList);
}
else if (pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "CONSTRAINTS") == 0) {
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, " UNION SELECT 'ALL'");
}
else if (pg_strcasecmp(PREV3_WD, "SET") == 0 && pg_strcasecmp(PREV2_WD, "CONSTRAINTS") == 0) {
static const char* const constraintList[] = {"DEFERRED", "IMMEDIATE", NULL};
COMPLETE_WITH_LIST(constraintList);
}
else if (pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "ROLE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
else if (pg_strcasecmp(PREV2_WD, "SET") == 0 &&
(pg_strcasecmp(PREV_WD, "SESSION") == 0 || pg_strcasecmp(PREV_WD, "LOCAL") == 0)) {
static const char* const myList[] = {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
COMPLETE_WITH_LIST(myList);
}
else if (pg_strcasecmp(PREV3_WD, "SET") == 0 && pg_strcasecmp(PREV2_WD, "SESSION") == 0 &&
pg_strcasecmp(PREV_WD, "AUTHORIZATION") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
else if (pg_strcasecmp(PREV2_WD, "RESET") == 0 && pg_strcasecmp(PREV_WD, "SESSION") == 0)
COMPLETE_WITH_CONST("AUTHORIZATION");
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] != ')' && pg_strcasecmp(PREV4_WD, "DOMAIN") != 0 &&
pg_strcasecmp(PREV_WD, "CONSTRAINTS") != 0)
COMPLETE_WITH_CONST("TO");
else if (pg_strcasecmp(PREV3_WD, "SET") == 0 && (pg_strcasecmp(PREV_WD, "TO") == 0 || strcmp(PREV_WD, "=") == 0)) {
if (pg_strcasecmp(PREV2_WD, "DateStyle") == 0) {
static const char* const myList[] = {
"ISO", "SQL", "Postgres", "German",
"YMD", "DMY", "MDY",
"US", "European", "NonEuropean",
"DEFAULT", NULL
};
COMPLETE_WITH_LIST(myList);
} else if (pg_strcasecmp(PREV2_WD, "IntervalStyle") == 0) {
static const char* const myList[] = {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
COMPLETE_WITH_LIST(myList);
} else if (pg_strcasecmp(PREV2_WD, "GEQO") == 0) {
static const char* const myList[] = {"ON", "OFF", "DEFAULT", NULL};
COMPLETE_WITH_LIST(myList);
} else {
static const char* const myList[] = {"DEFAULT", NULL};
COMPLETE_WITH_LIST(myList);
}
}
else if (pg_strcasecmp(PREV_WD, "START") == 0)
COMPLETE_WITH_CONST("TRANSACTION");
else if (pg_strcasecmp(PREV_WD, "TABLE") == 0 && PREV2_WD[0] == '\0')
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
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);
else if (pg_strcasecmp(PREV_WD, "UNLISTEN") == 0)
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 '*'");
else if (pg_strcasecmp(PREV_WD, "UPDATE") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
else if (pg_strcasecmp(PREV2_WD, "UPDATE") == 0)
COMPLETE_WITH_CONST("SET");
* If the previous word is SET (and it wasn't caught above as the _first_
* 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)
COMPLETE_WITH_ATTR(PREV2_WD, "");
else if (pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV4_WD, "UPDATE") == 0)
COMPLETE_WITH_CONST("=");
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)
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)
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)
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)
COMPLETE_WITH_CONST("SERVER");
* VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
* VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
*/
else if (pg_strcasecmp(PREV_WD, "VACUUM") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, " UNION SELECT 'FULL'"
" UNION SELECT 'FREEZE'"
" UNION SELECT 'ANALYZE'"
" 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 &&
(pg_strcasecmp(PREV2_WD, "FULL") == 0 || pg_strcasecmp(PREV2_WD, "FREEZE") == 0))
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))
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)
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)
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))
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
* 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')
COMPLETE_WITH_CONST("RECURSIVE");
else if (pg_strcasecmp(PREV_WD, "ANALYZE") == 0)
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);
}
else if (pg_strcasecmp(PREV_WD, "WHERE") == 0)
COMPLETE_WITH_ATTR(PREV2_WD, "");
else if (pg_strcasecmp(PREV_WD, "FROM") == 0 && pg_strcasecmp(PREV3_WD, "COPY") != 0 &&
pg_strcasecmp(PREV3_WD, "\\copy") != 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
else if (pg_strcasecmp(PREV_WD, "JOIN") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
else if (strcmp(PREV_WD, "\\connect") == 0 || strcmp(PREV_WD, "\\c") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
else if (strncmp(PREV_WD, "\\da", strlen("\\da")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
else if (strncmp(PREV_WD, "\\db", strlen("\\db")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
else if (strncmp(PREV_WD, "\\dD", strlen("\\dD")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
else if (strncmp(PREV_WD, "\\des", strlen("\\des")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_servers);
else if (strncmp(PREV_WD, "\\deu", strlen("\\deu")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
else if (strncmp(PREV_WD, "\\dew", strlen("\\dew")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
else if (strncmp(PREV_WD, "\\df", strlen("\\df")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (strncmp(PREV_WD, "\\dFd", strlen("\\dFd")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
else if (strncmp(PREV_WD, "\\dFp", strlen("\\dFp")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
else if (strncmp(PREV_WD, "\\dFt", strlen("\\dFt")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
else if (strncmp(PREV_WD, "\\dF", strlen("\\dF")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
else if (strncmp(PREV_WD, "\\di", strlen("\\di")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
else if (strncmp(PREV_WD, "\\dL", strlen("\\dL")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
else if (strncmp(PREV_WD, "\\dn", strlen("\\dn")) == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
else if (strncmp(PREV_WD, "\\dp", strlen("\\dp")) == 0 || strncmp(PREV_WD, "\\z", strlen("\\z")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
else if (strncmp(PREV_WD, "\\ds", strlen("\\ds")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
else if (strncmp(PREV_WD, "\\dt", strlen("\\dt")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
else if (strncmp(PREV_WD, "\\dT", strlen("\\dT")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
else if (strncmp(PREV_WD, "\\du", strlen("\\du")) == 0 || (strncmp(PREV_WD, "\\dg", strlen("\\dg")) == 0))
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
else if (strncmp(PREV_WD, "\\dv", strlen("\\dv")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
else if (strncmp(PREV_WD, "\\dm", strlen("\\dm")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
else if (strncmp(PREV_WD, "\\d", strlen("\\d")) == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
else if (strcmp(PREV_WD, "\\ef") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (strcmp(PREV_WD, "\\encoding") == 0)
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) {
static const char* const myList[] = {
"format", "border", "expanded",
"null", "fieldsep", "tuples_only", "title", "tableattr",
"linestyle", "pager", "recordsep", NULL
};
COMPLETE_WITH_LIST_CS(myList);
} else if (strcmp(PREV2_WD, "\\pset") == 0) {
if (strcmp(PREV_WD, "format") == 0) {
static const char* const myList[] = {"unaligned", "aligned", "wrapped", "html", "latex", "troff-ms", NULL};
COMPLETE_WITH_LIST_CS(myList);
} else if (strcmp(PREV_WD, "linestyle") == 0) {
static const char* const myList[] = {"ascii", "old-ascii", "unicode", NULL};
COMPLETE_WITH_LIST_CS(myList);
}
} else if (strcmp(PREV_WD, "\\set") == 0) {
matches = CompleteFromVariables(text, "", "");
} else if (strcmp(PREV_WD, "\\sf") == 0 || strcmp(PREV_WD, "\\sf+") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (strcmp(PREV_WD, "\\cd") == 0 || strcmp(PREV_WD, "\\e") == 0 || strcmp(PREV_WD, "\\edit") == 0 ||
strcmp(PREV_WD, "\\g") == 0 || strcmp(PREV_WD, "\\i") == 0 || strcmp(PREV_WD, "\\include") == 0 ||
strcmp(PREV_WD, "\\ir") == 0 || strcmp(PREV_WD, "\\include_relative") == 0 || strcmp(PREV_WD, "\\o") == 0 ||
strcmp(PREV_WD, "\\out") == 0 || strcmp(PREV_WD, "\\s") == 0 || strcmp(PREV_WD, "\\w") == 0 ||
strcmp(PREV_WD, "\\write") == 0) {
completion_charp = "\\";
matches = completion_matches(text, CompleteFromFiles);
}
* Finally, we look through the list of "things", such as TABLE, INDEX and
* check if that was the previous word. If so, execute the query to get a
* list of them.
*/
else {
int i;
for (i = 0; words_after_create[i].name; i++) {
if (pg_strcasecmp(PREV_WD, words_after_create[i].name) == 0) {
if (words_after_create[i].query) {
COMPLETE_WITH_QUERY(words_after_create[i].query);
}
else if (words_after_create[i].squery) {
COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery, NULL);
}
break;
}
}
}
* If we still don't have anything to match we have to fabricate some sort
* of default list. If we were to just return NULL, readline automatically
* attempts filename completion, and that's usually no good.
*/
if (matches == NULL) {
COMPLETE_WITH_CONST("");
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
rl_completion_append_character = '\0';
#endif
}
{
int i;
for (i = 0; i < (int)lengthof(previousWords); i++)
free(previousWords[i]);
}
return matches;
}
* This creates a list of matching things, according to a query pointed to
* by completion_charp.
* The query can be one of two kinds:
*
* 1. A simple query which must contain a %d and a %s, which will be replaced
* by the string length of the text and the text itself. The query may also
* have up to four more %s in it; the first two such will be replaced by the
* value of completion_info_charp, the next two by the value of
* completion_info_charp2.
*
* 2. A schema query used for completion of both schema and relation names.
* These are more complex and must contain in the following order:
* %d %s %d %s %d %s %s %d %s
* where %d is the string length of the text and %s the text itself.
*
* It is assumed that strings should be escaped to become SQL literals
* (that is, what is in the query is actually ... '%s' ...)
*
* See top of file for examples of both kinds of query.
*/
static char *_CompleteFromQuery(int isSchemaQuery, const char *text, int state)
{
static int listIndex, stringLength;
static PGresult *result = NULL;
EnableSqlModePipesAsConcat();
* If this is the first time for this completion, we fetch a list of our
* "things" from the backend.
*/
if (state == 0) {
PQExpBufferData queryBuffer;
char *eText = NULL;
char *eInfoCharp = NULL;
char *eInfoCharp2 = NULL;
listIndex = 0;
stringLength = strlen(text);
PQclear(result);
result = NULL;
readline_status = COMPLETE_QUERY;
eText = (char *)pg_malloc(stringLength * 2 + 1);
PQescapeString(eText, text, stringLength);
if (NULL != completion_info_charp) {
size_t charpLen;
charpLen = strlen(completion_info_charp);
eInfoCharp = (char *)pg_malloc(charpLen * 2 + 1);
PQescapeString(eInfoCharp, completion_info_charp, charpLen);
} else
eInfoCharp = NULL;
if (NULL != completion_info_charp2) {
size_t charpLen;
charpLen = strlen(completion_info_charp2);
eInfoCharp2 = (char *)pg_malloc(charpLen * 2 + 1);
PQescapeString(eInfoCharp2, completion_info_charp2, charpLen);
} else
eInfoCharp2 = NULL;
initPQExpBuffer(&queryBuffer);
if (isSchemaQuery) {
const char *qualresult = completion_squery->qualresult;
if (qualresult == NULL)
qualresult = completion_squery->result;
appendPQExpBuffer(&queryBuffer, "SELECT %s FROM %s WHERE ", completion_squery->result,
completion_squery->catname);
if (NULL != completion_squery->selcondition)
appendPQExpBuffer(&queryBuffer, "%s AND ", completion_squery->selcondition);
appendPQExpBuffer(&queryBuffer, "substring(%s,1,%d)='%s'", completion_squery->result, stringLength,
eText);
appendPQExpBuffer(&queryBuffer, " AND %s", completion_squery->viscondition);
* When fetching relation names, suppress system catalogs unless
* the input-so-far begins with "pg_". This is a compromise
* 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 && strncmp(text, "gs_", 3) != 0) {
appendPQExpBuffer(&queryBuffer, " AND c.relnamespace <> (SELECT oid FROM"
" pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
}
* Add in matching schema names, but only if there is more than
* one potential match among schema names.
*/
appendPQExpBuffer(&queryBuffer,
"\nUNION\n"
"SELECT pg_catalog.quote_ident(n.nspname) || '.' "
"FROM pg_catalog.pg_namespace n "
"WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
stringLength, eText);
appendPQExpBuffer(&queryBuffer,
" AND (SELECT pg_catalog.count(*)"
" FROM pg_catalog.pg_namespace"
" WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
stringLength, eText);
* Add in matching qualified names, but only if there is exactly
* one schema matching the input-so-far.
*/
appendPQExpBuffer(&queryBuffer,
"\nUNION\n"
"SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
"FROM %s, pg_catalog.pg_namespace n "
"WHERE %s = n.oid AND ",
qualresult, completion_squery->catname, completion_squery->nameSpace);
if (completion_squery->selcondition != NULL)
appendPQExpBuffer(&queryBuffer, "%s AND ", completion_squery->selcondition);
appendPQExpBuffer(&queryBuffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
qualresult, stringLength, eText);
* This condition exploits the single-matching-schema rule to
* speed up the query
*/
appendPQExpBuffer(&queryBuffer,
" AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
stringLength, eText);
appendPQExpBuffer(&queryBuffer,
" AND (SELECT pg_catalog.count(*)"
" FROM pg_catalog.pg_namespace"
" WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
stringLength, eText);
if (NULL != completion_charp)
appendPQExpBuffer(&queryBuffer, "\n%s", completion_charp);
} else {
appendPQExpBuffer(&queryBuffer, completion_charp, stringLength, eText, eInfoCharp, eInfoCharp,
eInfoCharp2, eInfoCharp2);
}
appendPQExpBuffer(&queryBuffer, "\nLIMIT %d", completion_max_records);
result = ExecQuery(queryBuffer.data);
termPQExpBuffer(&queryBuffer);
free(eText);
eText = NULL;
if (eInfoCharp != NULL) {
free(eInfoCharp);
eInfoCharp = NULL;
}
if (eInfoCharp2 != NULL) {
free(eInfoCharp2);
eInfoCharp2 = NULL;
}
}
if (readline_status == COMPLETE_QUERY && result && PQresultStatus(result) == PGRES_TUPLES_OK) {
const char *item = NULL;
while (listIndex < PQntuples(result) && (item = PQgetvalue(result, listIndex++, 0)))
if (pg_strncasecmp(text, item, stringLength) == 0) {
ResetSqlMode();
return pg_strdup(item);
}
}
PQclear(result);
result = NULL;
readline_status = WAIT_INPUT;
ResetSqlMode();
return NULL;
}
* This function returns in order one of a fixed, NULL pointer terminated list
* of strings (if matching). This can be used if there are only a fixed number
* SQL words that can appear at certain spot.
*/
static char *CompleteFromList(const char *text, int state)
{
static int stringLength, listIndex, matches;
static bool casesensitive = false;
const char *item = NULL;
psql_assert(completion_charpp);
if (state == 0) {
listIndex = 0;
stringLength = strlen(text);
casesensitive = completion_case_sensitive;
matches = 0;
}
while ((item = completion_charpp[listIndex++])) {
if (casesensitive && strncmp(text, item, stringLength) == 0) {
matches++;
return pg_strdup(item);
}
if (!casesensitive && pg_strncasecmp(text, item, stringLength) == 0) {
if (completion_case_sensitive)
return pg_strdup(item);
else
* If case insensitive matching was requested initially,
* adjust the case according to setting.
*/
return pg_strdup_keyword_case(item, text);
}
}
* No matches found. If we're not case insensitive already, lets switch to
* being case insensitive and try again
*/
if (casesensitive && matches == 0) {
casesensitive = false;
listIndex = 0;
state++;
return CompleteFromList(text, state);
}
return NULL;
}
* This function returns one fixed string the first time even if it doesn't
* match what's there, and nothing the second time. This should be used if
* there is only one possibility that can appear at a certain spot, so
* misspellings will be overwritten. The string to be passed must be in
* completion_charp.
*/
static char *CompleteFromConst(const char *text, int state)
{
psql_assert(completion_charp);
if (state == 0) {
if (completion_case_sensitive)
return pg_strdup(completion_charp);
else
* If case insensitive matching was requested initially, adjust
* the case according to setting.
*/
return pg_strdup_keyword_case(completion_charp, text);
} else
return NULL;
}
* This function supports completion with the name of a psql variable.
* The variable names can be prefixed and suffixed with additional text
* to support quoting usages.
*/
static char **CompleteFromVariables(const char *text, const char *prefix, const char *suffix)
{
char **matches = NULL;
int overhead = strlen(prefix) + strlen(suffix) + 1;
char **varnames = NULL;
int nvars = 0;
int maxvars = 100;
int i;
struct _variable *ptr = NULL;
int rc;
size_t sz = 0;
varnames = (char **)pg_malloc((maxvars + 1) * sizeof(char *));
ptr = (pset.vars != NULL) ? pset.vars->next : NULL;
for (; ptr != NULL; ptr = ptr->next) {
char *buffer = NULL;
if (nvars >= maxvars) {
maxvars *= 2;
varnames = (char **)psql_realloc(varnames, (maxvars + 1) * sizeof(char *), (maxvars + 1) * sizeof(char *));
if (varnames == NULL) {
psql_error("out of memory\n");
exit(EXIT_FAILURE);
}
}
sz = strlen(ptr->name) + overhead;
buffer = (char *)pg_malloc(sz);
rc = sprintf_s(buffer, sz, "%s%s%s", prefix, ptr->name, suffix);
check_sprintf_s(rc);
varnames[nvars++] = buffer;
}
varnames[nvars] = NULL;
COMPLETE_WITH_LIST_CS((const char * const *)varnames);
for (i = 0; i < nvars; i++) {
free(varnames[i]);
varnames[i] = NULL;
}
free(varnames);
varnames = NULL;
return matches;
}
* This function wraps rl_filename_completion_function() to strip quotes from
* the input before searching for matches and to quote any matches for which
* the consuming command will require it.
*/
static char *CompleteFromFiles(const char *text, int state)
{
static const char *unquotedText = NULL;
char *unquotedMatch = NULL;
char *ret = NULL;
if (state == 0) {
unquotedText = strtokx(text, "", NULL, "'", *completion_charp, false, true, pset.encoding);
if (NULL == unquotedText) {
psql_assert(!*text);
unquotedText = text;
}
}
unquotedMatch = filename_completion_function(unquotedText, state);
if (unquotedMatch != NULL) {
* Caller sets completion_charp to a zero- or one-character string
* containing the escape character. This is necessary since \copy has
* no escape character, but every other backslash command recognizes
* "\" as an escape character. Since we have only two callers, don't
* bother providing a macro to simplify this.
*/
ret = quote_if_needed(unquotedMatch, " \t\r\n\"`", '\'', *completion_charp, pset.encoding);
if (ret != NULL) {
free(unquotedMatch);
unquotedMatch = NULL;
} else
ret = unquotedMatch;
}
return ret;
}
* Make a pg_strdup copy of s and convert the case according to
* COMP_KEYWORD_CASE variable, using ref as the text that was already entered.
*/
static char *pg_strdup_keyword_case(const char *s, const char *ref)
{
char *ret = NULL;
char *p = NULL;
unsigned char first = ref[0];
int tocase;
const char *varval = NULL;
varval = GetVariable(pset.vars, "COMP_KEYWORD_CASE");
if (varval == NULL)
tocase = 0;
else if (strcmp(varval, "lower") == 0)
tocase = -2;
else if (strcmp(varval, "preserve-lower") == 0)
tocase = -1;
else if (strcmp(varval, "preserve-upper") == 0)
tocase = +1;
else if (strcmp(varval, "upper") == 0)
tocase = +2;
else
tocase = 0;
if (tocase == 0)
tocase = +1;
ret = pg_strdup(s);
if (tocase == -2 || ((tocase == -1 || tocase == +1) && islower(first)) || (tocase == -1 && !isalpha(first)))
for (p = ret; *p; p++)
*p = pg_tolower((unsigned char)*p);
else
for (p = ret; *p; p++)
*p = pg_toupper((unsigned char)*p);
return ret;
}
* Execute a query and report any errors. This should be the preferred way of
* talking to the database in this file.
*/
static PGresult *ExecQuery(const char *query)
{
PGresult *result = NULL;
if (query == NULL || pset.db == NULL || PQstatus(pset.db) != CONNECTION_OK)
return NULL;
result = PQexec(pset.db, query);
if (PQresultStatus(result) != PGRES_TUPLES_OK) {
PQclear(result);
result = NULL;
}
return result;
}
* Return the nwords word(s) before point. Words are returned right to left,
* that is, previousWords[0] gets the last word before point.
* If we run out of words, remaining array elements are set to empty strings.
* Each array element is filled with a malloc'd string.
*/
static void GetPreviousWords(int point, char **previousWords, int nwords)
{
char *buf = NULL;
int i;
errno_t rc = EOK;
* If we have anything in tab_completion_query_buf, paste it together with
* rl_line_buffer to construct the full query. Otherwise we can just use
* rl_line_buffer as the input string.
*/
if (tab_completion_query_buf && tab_completion_query_buf->len > 0) {
i = tab_completion_query_buf->len;
const int bufLen = point + i + 2;
buf = (char*)pg_malloc(bufLen);
rc = memcpy_s(buf, bufLen, tab_completion_query_buf->data, i);
securec_check_c(rc, "\0", "\0");
buf[i++] = '\n';
rc = memcpy_s(buf + i, bufLen, rl_line_buffer, point);
securec_check_c(rc, "\0", "\0");
i += point;
buf[i] = '\0';
point = i;
} else {
buf = rl_line_buffer;
}
for (i = point - 1; i >= 0; i--)
if (strchr(WORD_BREAKS, buf[i]))
break;
point = i;
while (nwords-- > 0) {
int start, end;
char *s = NULL;
end = -1;
for (i = point; i >= 0; i--) {
if (!isspace((unsigned char)buf[i])) {
end = i;
break;
}
}
* If no end found we return an empty string, because there is no word
* before the point
*/
if (end < 0) {
point = end;
s = pg_strdup("");
} else {
* Otherwise we now look for the start. The start is either the
* last character before any word-break character going backwards
* from the end, or it's simply character 0. We also handle open
* quotes and parentheses.
*/
bool inquotes = false;
int parentheses = 0;
for (start = end; start > 0; start--) {
if (buf[start] == '"')
inquotes = !inquotes;
if (!inquotes) {
if (buf[start] == ')')
parentheses++;
else if (buf[start] == '(') {
if (--parentheses <= 0)
break;
} else if (parentheses == 0 && strchr(WORD_BREAKS, buf[start - 1]))
break;
}
}
point = start - 1;
s = (char *)pg_malloc(end - start + 2);
rc = strncpy_s(s, end - start + 2, &buf[start], end - start + 1);
s[end - start + 1] = '\0';
securec_check_c(rc, "\0", "\0");
}
*previousWords++ = s;
}
if (buf != rl_line_buffer) {
free(buf);
}
}
#endif
* Since readline doesn't let us pass any state through to the tab completion
* callback, we have to use this global variable to let GetPreviousWords()
* get at the previous lines of the current command.
*/
PQExpBuffer tab_completion_query_buf = NULL;
* Initialize the readline library for our purposes.
*/
void initialize_readline(void)
{
rl_readline_name = (char *)pset.progname;
#ifdef HAVE_READLINE_READLINE_H
rl_attempted_completion_function = PsqlCompletion;
#else
rl_attempted_completion_function = NULL;
#endif
rl_basic_word_break_characters = WORD_BREAKS;
completion_max_records = 1000;
* There is a variable rl_completion_query_items for this but apparently
* it's not defined everywhere.
*/
}
#endif