diff --git a/src/bin/psql/tab-complete.cpp b/src/bin/psql/tab-complete.cpp index 274a1cda2..5c5a2cea5 100644 --- a/src/bin/psql/tab-complete.cpp +++ b/src/bin/psql/tab-complete.cpp @@ -20,9 +20,9 @@ * you can turn off tab completion in your ~/.inputrc (or else * ${INPUTRC}) file so: * - * $if psql - * set disable-completion on - * $endif + * $if psql + * set disable-completion on + * $endif * * See `man 3 readline' or `info readline' for the full details. Also, * hence the @@ -30,14 +30,14 @@ * 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.) + * 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. + * all that gracefully. * ---------------------------------------------------------------------- */ #include "settings.h" @@ -70,14 +70,14 @@ * to obtain possibly-schema-qualified names of database objects. There is * enough similarity in the structure that we don't want to repeat it each * time. So we put the components of each query into this struct and - * assemble them with the common boilerplate in _complete_from_query(). + * assemble them with the common boilerplate in _CompleteFromQuery(). */ typedef struct SchemaQuery { /* * Name of catalog or catalogs to be queried, with alias, eg. * "pg_catalog.pg_class c". Note that "pg_namespace n" will be added. */ - const char* catname; + const char *catname; /* * Selection condition --- only rows meeting this condition are candidates @@ -85,31 +85,31 @@ typedef struct SchemaQuery { * join condition here. For example, "c.relkind = 'r'". Write NULL (not * an empty string) if not needed. */ - const char* selcondition; + const char *selcondition; /* * Visibility condition --- which rows are visible without schema * qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)". */ - const char* viscondition; + const char *viscondition; /* * Namespace --- name of field to join to pg_namespace.oid. For example, * "c.relnamespace". */ - const char* nameSpace; + const char *nameSpace; /* * Result --- the appropriately-quoted name to return, in the case of an * unqualified name. For example, "pg_catalog.quote_ident(c.relname)". */ - const char* result; + const char *result; /* * In some cases a different result must be used for qualified names. * Enter that here, or write NULL if result can be used. */ - const char* qualresult; + const char *qualresult; } SchemaQuery; /* Store maximum number of records we want from database queries @@ -121,12 +121,12 @@ static int completion_max_records; * 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* const* completion_charpp; /* to pass a list of strings */ -static const char* completion_charp; /* to pass a string */ -static const char* completion_info_charp; /* to pass a second string */ -static const char* completion_info_charp2; /* to pass a third string */ -static const SchemaQuery* completion_squery; /* to pass a SchemaQuery */ -static bool completion_case_sensitive; /* completion is case sensitive */ +static const char * const * completion_charpp; /* to pass a list of strings */ +static const char *completion_charp; /* to pass a string */ +static const char *completion_info_charp; /* to pass a second string */ +static const char *completion_info_charp2; /* to pass a third string */ +static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */ +static bool completion_case_sensitive; /* completion is case sensitive */ /* * A few macros to ease typing. You can use these to complete the given @@ -137,44 +137,39 @@ static bool completion_case_sensitive; /* completion is case sensitive */ * 4) A string constant. * 5) The list of attributes of the given table (possibly schema-qualified). */ -#define COMPLETE_WITH_QUERY(query) \ - do { \ +#define COMPLETE_WITH_QUERY(query) do { \ completion_charp = query; \ - matches = completion_matches(text, complete_from_query); \ + matches = completion_matches(text, CompleteFromQuery); \ } while (0) -#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \ - do { \ +#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) do { \ completion_squery = &(query); \ completion_charp = addon; \ - matches = completion_matches(text, complete_from_schema_query); \ + matches = completion_matches(text, CompleteFromSchemaQuery); \ } while (0) -#define COMPLETE_WITH_LIST_CS(list) \ - do { \ +#define COMPLETE_WITH_LIST_CS(list) do { \ completion_charpp = list; \ completion_case_sensitive = true; \ - matches = completion_matches(text, complete_from_list); \ + matches = completion_matches(text, CompleteFromList); \ } while (0) -#define COMPLETE_WITH_LIST(list) \ - do { \ +#define COMPLETE_WITH_LIST(list) do { \ completion_charpp = list; \ completion_case_sensitive = false; \ - matches = completion_matches(text, complete_from_list); \ + matches = completion_matches(text, CompleteFromList); \ } while (0) -#define COMPLETE_WITH_CONST(string) \ - do { \ +#define COMPLETE_WITH_CONST(string) do { \ completion_charp = string; \ completion_case_sensitive = false; \ - matches = completion_matches(text, complete_from_const); \ + matches = completion_matches(text, CompleteFromConst); \ } while (0) #define COMPLETE_WITH_ATTR(relation, addon) \ do { \ - char* _completion_schema; \ - char* _completion_table; \ + 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); \ @@ -186,7 +181,7 @@ static bool completion_case_sensitive; /* completion is case sensitive */ completion_info_charp = _completion_table; \ completion_info_charp2 = _completion_schema; \ } \ - matches = completion_matches(text, complete_from_query); \ + matches = completion_matches(text, CompleteFromQuery); \ } while (0) /* @@ -196,7 +191,7 @@ static const SchemaQuery Query_for_list_of_aggregates = { /* catname */ "pg_catalog.pg_proc p", /* selcondition */ - "p.prokind", + "p.prokind = 'a'", /* viscondition */ "pg_catalog.pg_function_is_visible(p.oid)", /* namespace */ @@ -204,7 +199,8 @@ static const SchemaQuery Query_for_list_of_aggregates = { /* result */ "pg_catalog.quote_ident(p.proname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_datatypes = { /* catname */ @@ -220,7 +216,8 @@ static const SchemaQuery Query_for_list_of_datatypes = { /* result */ "pg_catalog.format_type(t.oid, NULL)", /* qualresult */ - "pg_catalog.quote_ident(t.typname)"}; + "pg_catalog.quote_ident(t.typname)" +}; static const SchemaQuery Query_for_list_of_domains = { /* catname */ @@ -234,7 +231,8 @@ static const SchemaQuery Query_for_list_of_domains = { /* result */ "pg_catalog.quote_ident(t.typname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_functions = { /* catname */ @@ -248,7 +246,8 @@ static const SchemaQuery Query_for_list_of_functions = { /* result */ "pg_catalog.quote_ident(p.proname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_indexes = { /* catname */ @@ -262,7 +261,8 @@ static const SchemaQuery Query_for_list_of_indexes = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_sequences = { /* catname */ @@ -276,7 +276,8 @@ static const SchemaQuery Query_for_list_of_sequences = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_foreign_tables = { /* catname */ @@ -290,7 +291,8 @@ static const SchemaQuery Query_for_list_of_foreign_tables = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_tables = { /* catname */ @@ -304,7 +306,8 @@ static const SchemaQuery Query_for_list_of_tables = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; /* The bit masks for the following three functions come from * src/include/catalog/pg_trigger.h. @@ -322,7 +325,8 @@ static const SchemaQuery Query_for_list_of_insertables = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_deletables = { /* catname */ @@ -337,7 +341,8 @@ static const SchemaQuery Query_for_list_of_deletables = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_updatables = { /* catname */ @@ -352,7 +357,8 @@ static const SchemaQuery Query_for_list_of_updatables = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_relations = { /* catname */ @@ -366,7 +372,8 @@ static const SchemaQuery Query_for_list_of_relations = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_tsvmf = { /* catname */ @@ -380,7 +387,8 @@ static const SchemaQuery Query_for_list_of_tsvmf = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_tmf = { /* catname */ @@ -408,7 +416,8 @@ static const SchemaQuery Query_for_list_of_tm = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_views = { /* catname */ @@ -422,7 +431,8 @@ static const SchemaQuery Query_for_list_of_views = { /* result */ "pg_catalog.quote_ident(c.relname)", /* qualresult */ - NULL}; + NULL +}; static const SchemaQuery Query_for_list_of_matviews = { /* catname */ @@ -450,187 +460,158 @@ static const SchemaQuery Query_for_list_of_matviews = { * completion_info_charp2. * * Beware that the allowed sequences of %s and %d are determined by - * _complete_from_query(). + * _CompleteFromQuery(). */ -#define Query_for_list_of_attributes \ - "SELECT pg_catalog.quote_ident(attname) " \ - " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c " \ - " WHERE c.oid = a.attrelid " \ - " AND a.attnum > 0 " \ - " AND NOT a.attisdropped " \ - " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' " \ - " AND (pg_catalog.quote_ident(relname)='%s' " \ - " OR '\"' || relname || '\"'='%s') " \ - " AND pg_catalog.pg_table_is_visible(c.oid)" +#define Query_for_list_of_attributes "SELECT pg_catalog.quote_ident(attname) " \ + " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c " \ + " WHERE c.oid = a.attrelid " \ + " AND a.attnum > 0 " \ + " AND NOT a.attisdropped " \ + " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' " \ + " AND (pg_catalog.quote_ident(relname)='%s' " \ + " OR '\"' || relname || '\"'='%s') " \ + " AND pg_catalog.pg_table_is_visible(c.oid)" -#define Query_for_list_of_attributes_with_schema \ - "SELECT pg_catalog.quote_ident(attname) " \ - " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n " \ - " WHERE c.oid = a.attrelid " \ - " AND n.oid = c.relnamespace " \ - " AND a.attnum > 0 " \ - " AND NOT a.attisdropped " \ - " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' " \ - " AND (pg_catalog.quote_ident(relname)='%s' " \ - " OR '\"' || relname || '\"' ='%s') " \ - " AND (pg_catalog.quote_ident(nspname)='%s' " \ - " OR '\"' || nspname || '\"' ='%s') " +#define Query_for_list_of_attributes_with_schema \ + "SELECT pg_catalog.quote_ident(attname) " \ + " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n " \ + " WHERE c.oid = a.attrelid " \ + " AND n.oid = c.relnamespace " \ + " AND a.attnum > 0 " \ + " AND NOT a.attisdropped " \ + " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' " \ + " AND (pg_catalog.quote_ident(relname)='%s' " \ + " OR '\"' || relname || '\"' ='%s') " \ + " AND (pg_catalog.quote_ident(nspname)='%s' " \ + " OR '\"' || nspname || '\"' ='%s') " -#define Query_for_list_of_template_databases \ - "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database " \ - " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate" +#define Query_for_list_of_template_databases "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database " \ + " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate" -#define Query_for_list_of_databases \ - "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database " \ - " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'" +#define Query_for_list_of_databases "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database " \ + " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'" -#define Query_for_list_of_tablespaces \ - "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace " \ - " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'" +#define Query_for_list_of_tablespaces "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace " \ + " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'" -#define Query_for_list_of_encodings \ - " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) " \ - " FROM pg_catalog.pg_conversion " \ - " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')" +#define Query_for_list_of_encodings " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) " \ + " FROM pg_catalog.pg_conversion " \ + " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')" -#define Query_for_list_of_languages \ - "SELECT pg_catalog.quote_ident(lanname) " \ - " FROM pg_catalog.pg_language " \ - " WHERE lanname != 'internal' " \ - " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'" +#define Query_for_list_of_languages "SELECT pg_catalog.quote_ident(lanname) " \ + " FROM pg_catalog.pg_language " \ + " WHERE lanname != 'internal' " \ + " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'" -#define Query_for_list_of_schemas \ - "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace " \ - " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'" +#define Query_for_list_of_schemas "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace " \ + " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'" -#define Query_for_list_of_set_vars \ - "SELECT name FROM " \ - " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings " \ - " WHERE context IN ('user', 'superuser') " \ - " UNION ALL SELECT 'constraints' " \ - " UNION ALL SELECT 'transaction' " \ - " UNION ALL SELECT 'session' " \ - " UNION ALL SELECT 'role' " \ - " UNION ALL SELECT 'tablespace' " \ - " UNION ALL SELECT 'all') ss " \ - " WHERE substring(name,1,%d)='%s'" +#define Query_for_list_of_set_vars "SELECT name FROM " \ + " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings " \ + " WHERE context IN ('user', 'superuser') " \ + " UNION ALL SELECT 'constraints' " \ + " UNION ALL SELECT 'transaction' " \ + " UNION ALL SELECT 'session' " \ + " UNION ALL SELECT 'role' " \ + " UNION ALL SELECT 'tablespace' " \ + " UNION ALL SELECT 'all') ss " \ + " WHERE substring(name,1,%d)='%s'" -#define Query_for_list_of_show_vars \ - "SELECT name FROM " \ - " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings " \ - " UNION ALL SELECT 'session authorization' " \ - " UNION ALL SELECT 'all') ss " \ - " WHERE substring(name,1,%d)='%s'" +#define Query_for_list_of_show_vars "SELECT name FROM " \ + " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings " \ + " UNION ALL SELECT 'session authorization' " \ + " UNION ALL SELECT 'all') ss " \ + " WHERE substring(name,1,%d)='%s'" -#define Query_for_list_of_roles \ - " SELECT pg_catalog.quote_ident(rolname) " \ - " FROM pg_catalog.pg_roles " \ - " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'" +#define Query_for_list_of_roles " SELECT pg_catalog.quote_ident(rolname) " \ + " FROM pg_catalog.pg_roles " \ + " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'" -#define Query_for_list_of_grant_roles \ - " SELECT pg_catalog.quote_ident(rolname) " \ - " FROM pg_catalog.pg_roles " \ - " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'" \ - " UNION ALL SELECT 'PUBLIC'" +#define Query_for_list_of_grant_roles " SELECT pg_catalog.quote_ident(rolname) " \ + " FROM pg_catalog.pg_roles " \ + " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'" \ + " UNION ALL SELECT 'PUBLIC'" /* the silly-looking length condition is just to eat up the current word */ -#define Query_for_table_owning_index \ - "SELECT pg_catalog.quote_ident(c1.relname) " \ - " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i" \ - " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid" \ - " and (%d = pg_catalog.length('%s'))" \ - " and pg_catalog.quote_ident(c2.relname)='%s'" \ - " and pg_catalog.pg_table_is_visible(c2.oid)" +#define Query_for_table_owning_index \ + "SELECT pg_catalog.quote_ident(c1.relname) " \ + " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i" \ + " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid" \ + " and (%d = pg_catalog.length('%s'))" \ + " and pg_catalog.quote_ident(c2.relname)='%s'" \ + " and pg_catalog.pg_table_is_visible(c2.oid)" /* the silly-looking length condition is just to eat up the current word */ -#define Query_for_index_of_table \ - "SELECT pg_catalog.quote_ident(c2.relname) " \ - " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i" \ - " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid" \ - " and (%d = pg_catalog.length('%s'))" \ - " and pg_catalog.quote_ident(c1.relname)='%s'" \ - " and pg_catalog.pg_table_is_visible(c2.oid)" +#define Query_for_index_of_table "SELECT pg_catalog.quote_ident(c2.relname) " \ + " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i" \ + " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid" \ + " and (%d = pg_catalog.length('%s'))" \ + " and pg_catalog.quote_ident(c1.relname)='%s'" \ + " and pg_catalog.pg_table_is_visible(c2.oid)" /* the silly-looking length condition is just to eat up the current word */ -#define Query_for_list_of_tables_for_trigger \ - "SELECT pg_catalog.quote_ident(relname) " \ - " FROM pg_catalog.pg_class" \ - " WHERE (%d = pg_catalog.length('%s'))" \ - " AND oid IN " \ - " (SELECT tgrelid FROM pg_catalog.pg_trigger " \ - " WHERE pg_catalog.quote_ident(tgname)='%s')" +#define Query_for_list_of_tables_for_trigger "SELECT pg_catalog.quote_ident(relname) " \ + " FROM pg_catalog.pg_class" \ + " WHERE (%d = pg_catalog.length('%s'))" \ + " AND oid IN " \ + " (SELECT tgrelid FROM pg_catalog.pg_trigger " \ + " WHERE pg_catalog.quote_ident(tgname)='%s')" -#define Query_for_list_of_ts_configurations \ - "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config " \ - " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'" +#define Query_for_list_of_ts_configurations "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config " \ + " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'" -#define Query_for_list_of_ts_dictionaries \ - "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict " \ - " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'" +#define Query_for_list_of_ts_dictionaries "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict " \ + " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'" -#define Query_for_list_of_ts_parsers \ - "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser " \ - " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'" +#define Query_for_list_of_ts_parsers "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser " \ + " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'" -#define Query_for_list_of_ts_templates \ - "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template " \ - " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'" +#define Query_for_list_of_ts_templates "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template " \ + " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'" -#define Query_for_list_of_fdws \ - " SELECT pg_catalog.quote_ident(fdwname) " \ - " FROM pg_catalog.pg_foreign_data_wrapper " \ - " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'" +#define Query_for_list_of_fdws " SELECT pg_catalog.quote_ident(fdwname) " \ + " FROM pg_catalog.pg_foreign_data_wrapper " \ + " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'" -#define Query_for_list_of_servers \ - " SELECT pg_catalog.quote_ident(srvname) " \ - " FROM pg_catalog.pg_foreign_server " \ - " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'" +#define Query_for_list_of_servers " SELECT pg_catalog.quote_ident(srvname) " \ + " FROM pg_catalog.pg_foreign_server " \ + " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'" -#define Query_for_list_of_user_mappings \ - " SELECT pg_catalog.quote_ident(usename) " \ - " FROM pg_catalog.pg_user_mappings " \ - " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'" +#define Query_for_list_of_user_mappings " SELECT pg_catalog.quote_ident(usename) " \ + " FROM pg_catalog.pg_user_mappings " \ + " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'" -#define Query_for_list_of_access_methods \ - " SELECT pg_catalog.quote_ident(amname) " \ - " FROM pg_catalog.pg_am " \ - " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'" +#define Query_for_list_of_access_methods " SELECT pg_catalog.quote_ident(amname) " \ + " FROM pg_catalog.pg_am " \ + " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'" -#define Query_for_list_of_arguments \ - " SELECT pg_catalog.oidvectortypes(proargtypes)||')' " \ - " FROM pg_catalog.pg_proc " \ - " WHERE proname='%s'" +#define Query_for_list_of_arguments " SELECT pg_catalog.oidvectortypes(proargtypes)||')' " \ + " FROM pg_catalog.pg_proc " \ + " WHERE proname='%s'" -#define Query_for_list_of_extensions \ - " SELECT pg_catalog.quote_ident(extname) " \ - " FROM pg_catalog.pg_extension " \ - " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'" +#define Query_for_list_of_extensions " SELECT pg_catalog.quote_ident(extname) " \ + " FROM pg_catalog.pg_extension " \ + " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'" -#define Query_for_list_of_available_extensions \ - " SELECT pg_catalog.quote_ident(name) " \ - " FROM pg_catalog.pg_available_extensions " \ - " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL" +#define Query_for_list_of_available_extensions " SELECT pg_catalog.quote_ident(name) " \ + " FROM pg_catalog.pg_available_extensions " \ + " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL" -#define Query_for_list_of_prepared_statements \ - " SELECT pg_catalog.quote_ident(name) " \ - " FROM pg_catalog.pg_prepared_statements " \ - " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'" +#define Query_for_list_of_prepared_statements " SELECT pg_catalog.quote_ident(name) " \ + " FROM pg_catalog.pg_prepared_statements " \ + " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'" #ifdef PGXC -#define Query_for_list_of_available_nodenames \ - " SELECT NODE_NAME " \ - " FROM PGXC_NODE" -#define Query_for_list_of_available_coordinators \ - " SELECT NODE_NAME " \ - " FROM PGXC_NODE" \ - " WHERE NODE_TYPE = 'C'" -#define Query_for_list_of_available_datanodes \ - " SELECT NODE_NAME " \ - " FROM PGXC_NODE" \ - " WHERE NODE_TYPE = 'D'" -#define Query_for_list_of_available_nodegroup_names \ - " SELECT GROUP_NAME " \ - " FROM PGXC_GROUP" +#define Query_for_list_of_available_nodenames " SELECT NODE_NAME " \ + " FROM PGXC_NODE" +#define Query_for_list_of_available_coordinators " SELECT NODE_NAME " \ + " FROM PGXC_NODE" \ + " WHERE NODE_TYPE = 'C'" +#define Query_for_list_of_available_datanodes " SELECT NODE_NAME " \ + " FROM PGXC_NODE" \ + " WHERE NODE_TYPE = 'D'" +#define Query_for_list_of_available_nodegroup_names " SELECT GROUP_NAME " \ + " FROM PGXC_GROUP" #endif /* @@ -638,9 +619,9 @@ static const SchemaQuery Query_for_list_of_matviews = { * DROP; and there is also a query to get a list of them. */ typedef struct { - const char* name; - const char* query; /* simple query, or NULL */ - const SchemaQuery* squery; /* schema query, or NULL */ + const char *name; + const char *query; /* simple query, or NULL */ + const SchemaQuery *squery; /* schema query, or NULL */ const bits32 flags; /* visibility flags, see below */ } pgsql_thing_t; @@ -651,16 +632,16 @@ typedef struct { static const pgsql_thing_t words_after_create[] = { {"AGGREGATE", NULL, &Query_for_list_of_aggregates, 0}, #ifdef PGXC - {"BARRIER", NULL, NULL, 0}, /* Comes barrier name next, so skip it */ + { "BARRIER", NULL, NULL, 0 }, /* Comes barrier name next, so skip it */ #endif - {"CAST", NULL, NULL, 0}, /* Casts have complex structures for names, so - * skip it */ + { "CAST", NULL, NULL, 0 }, /* Casts have complex structures for names, so + * skip it */ {"COLLATION", - "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding IN (-1, " + "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}, + NULL, + 0}, /* * CREATE CONSTRAINT TRIGGER is not supported here because it is designed @@ -668,10 +649,10 @@ static const pgsql_thing_t words_after_create[] = { */ {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW}, {"CONVERSION", - "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE " + "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE " "substring(pg_catalog.quote_ident(conname),1,%d)='%s'", - NULL, - 0}, + 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}, @@ -684,21 +665,21 @@ static const pgsql_thing_t words_after_create[] = { {"GROUP", Query_for_list_of_roles, NULL, 0}, {"LANGUAGE", Query_for_list_of_languages, NULL, 0}, {"INDEX", NULL, &Query_for_list_of_indexes, 0}, - {"MATERIALIZED VIEW", NULL, NULL}, + {"MATERIALIZED VIEW", NULL, &Query_for_list_of_matviews, 0}, #ifdef PGXC {"NODE", Query_for_list_of_available_nodenames, NULL, 0}, {"NODE GROUP", Query_for_list_of_available_nodegroup_names, NULL, 0}, #endif - {"OPERATOR", NULL, NULL, 0}, /* Querying for this is probably not such a - * good idea. */ - {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */ + { "OPERATOR", NULL, NULL, 0 }, /* Querying for this is probably not such a + * good idea. */ + { "OWNED", NULL, NULL, THING_NO_CREATE }, /* for DROP OWNED BY ... */ {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW}, {"ROLE", Query_for_list_of_roles, NULL, 0}, {"RULE", - "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE " + "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE " "substring(pg_catalog.quote_ident(rulename),1,%d)='%s'", - NULL, - 0}, + NULL, + 0}, {"SCHEMA", Query_for_list_of_schemas, NULL, 0}, {"SEQUENCE", NULL, &Query_for_list_of_sequences, 0}, #ifndef PGXC @@ -706,45 +687,45 @@ static const pgsql_thing_t words_after_create[] = { #endif {"TABLE", NULL, &Query_for_list_of_tables, 0}, {"TABLESPACE", Query_for_list_of_tablespaces, NULL, 0}, - {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */ + { "TEMP", NULL, NULL, THING_NO_DROP }, /* for CREATE TEMP TABLE ... */ {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW}, {"TEXT SEARCH", NULL, NULL, 0}, {"TRIGGER", - "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE " + "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE " "substring(pg_catalog.quote_ident(tgname),1,%d)='%s'", - NULL, - 0}, + NULL, + 0}, {"TYPE", NULL, &Query_for_list_of_datatypes, 0}, - {"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */ - {"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE - * ... */ + { "UNIQUE", NULL, NULL, THING_NO_DROP }, /* for CREATE UNIQUE INDEX ... */ + { "UNLOGGED", NULL, NULL, THING_NO_DROP }, /* for CREATE UNLOGGED TABLE + * ... */ {"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} /* end of list */ + { NULL, NULL, NULL, 0 } /* end of list */ }; /* Forward declaration of functions */ -static char **psql_completion(const char *text, int start, int end); -static char* create_command_generator(const char* text, int state); -static char* drop_command_generator(const char* text, int state); -static char* complete_from_query(const char* text, int state); -static char* complete_from_schema_query(const char* text, int state); -static char* _complete_from_query(int is_schema_query, const char* text, int state); -static char* complete_from_list(const char* text, int state); -static char* complete_from_const(const char* text, int state); -static char** complete_from_variables(const char* text, const char* prefix, const char* suffix); -static char* complete_from_files(const char* text, int state); +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 char *pg_strdup_keyword_case(const char *s, const char *ref); -static PGresult* exec_query(const char* query); -static void get_previous_words(int point, char** previous_words, int nwords); +static PGresult *ExecQuery(const char *query); +static void GetPreviousWords(int point, char **previousWords, int nwords); #ifdef NOT_USED -static char* quote_file_name(char* text, int match_type, char* quote_pointer); -static char* dequote_file_name(char* text, char quote_char); +static char *quote_file_name(char *text, int match_type, char *quote_pointer); +static char *dequote_file_name(char *text, char quote_char); #endif /* @@ -752,10 +733,10 @@ static char* dequote_file_name(char* text, char quote_char); */ void initialize_readline(void) { - rl_readline_name = (char*)pset.progname; + rl_readline_name = (char *)pset.progname; - /* psql_completion is deleted because it's too complex and not be used at all. */ - rl_attempted_completion_function = psql_completion; + /* PsqlCompletion is deleted because it's too complex and not be used at all. */ + rl_attempted_completion_function = PsqlCompletion; rl_basic_word_break_characters = WORD_BREAKS; @@ -781,23 +762,23 @@ void initialize_readline(void) * something of that sort. */ /* - * Common routine for create_command_generator and drop_command_generator. + * Common routine for CreateCommandGenerator and DropCommandGenerator. * Entries that have 'excluded' flags are not returned. */ -static char* create_or_drop_command_generator(const char* text, int state, bits32 excluded) +static char *create_or_DropCommandGenerator(const char *text, int state, bits32 excluded) { - static int list_index, string_length; - const char* name = NULL; + static int listIndex, stringLength; + const char *name = NULL; /* If this is the first time for this completion, init some values */ if (state == 0) { - list_index = 0; - string_length = strlen(text); + listIndex = 0; + stringLength = strlen(text); } /* find something that matches */ - while ((name = words_after_create[list_index++].name)) { - if ((pg_strncasecmp(name, text, string_length) == 0) && !(words_after_create[list_index - 1].flags & excluded)) + 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); } /* if nothing matches, return NULL */ @@ -808,28 +789,28 @@ static char* create_or_drop_command_generator(const char* text, int state, bits3 * This one gives you one from a list of things you can put after CREATE * as defined above. */ -static char* create_command_generator(const char* text, int state) +static char *CreateCommandGenerator(const char *text, int state) { - return create_or_drop_command_generator(text, state, THING_NO_CREATE); + 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* drop_command_generator(const char* text, int state) +static char *DropCommandGenerator(const char *text, int state) { - return create_or_drop_command_generator(text, state, THING_NO_DROP); + return create_or_DropCommandGenerator(text, state, THING_NO_DROP); } -/* The following two functions are wrappers for _complete_from_query */ -static char* complete_from_query(const char* text, int state) +/* The following two functions are wrappers for _CompleteFromQuery */ +static char *CompleteFromQuery(const char *text, int state) { - return _complete_from_query(0, text, state); + return _CompleteFromQuery(0, text, state); } -static char* complete_from_schema_query(const char* text, int state) +static char *CompleteFromSchemaQuery(const char *text, int state) { - return _complete_from_query(1, text, state); + return _CompleteFromQuery(1, text, state); } /* * The completion function. @@ -839,2362 +820,1876 @@ static char* complete_from_schema_query(const char* text, int state) * 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 ** -psql_completion(const char *text, int start, int end) +static char **PsqlCompletion(const char *text, int start, int end) { - /* This is the variable we'll return. */ - char **matches = NULL; + /* This is the variable we'll return. */ + char **matches = NULL; - /* This array will contain some scannage of the input line. */ - char *previous_words[6]; + /* This array will contain some scannage of the input line. */ + char *previousWords[6]; - /* For compactness, we use these macros to reference previous_words[]. */ -#define prev_wd (previous_words[0]) -#define prev2_wd (previous_words[1]) -#define prev3_wd (previous_words[2]) -#define prev4_wd (previous_words[3]) -#define prev5_wd (previous_words[4]) -#define prev6_wd (previous_words[5]) + /* For compactness, we use these macros to reference previousWords[]. */ +#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]) - static const char *const sql_commands[] = { - "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", - "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", - "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", - "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE", - "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", - "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START", - "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH", - NULL - }; + static const char *const sqlCommands[] = { + "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", + "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", + "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", + "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE", + "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", + "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START", + "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH", + NULL + }; - static const char *const backslash_commands[] = { - "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright", - "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df", - "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", - "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du", - "\\e", "\\echo", "\\ef", "\\encoding", - "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l", - "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink", - "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r", - "\\set", "\\sf", "\\t", "\\T", - "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL - }; + static const char *const backslashCommands[] = { + "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright", + "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df", + "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL", + "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du", + "\\e", "\\echo", "\\ef", "\\encoding", + "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l", + "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink", + "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r", + "\\set", "\\sf", "\\t", "\\T", + "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL + }; - (void) end; /* not used */ + (void)end; /* not used */ #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER - rl_completion_append_character = ' '; + rl_completion_append_character = ' '; #endif - /* Clear a few things. */ - 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. - */ - get_previous_words(start, previous_words, lengthof(previous_words)); - - /* If a backslash command was started, continue */ - if (text[0] == '\\') - COMPLETE_WITH_LIST_CS(backslash_commands); - - /* Variable interpolation */ - else if (text[0] == ':' && text[1] != ':') - { - if (text[1] == '\'') - matches = complete_from_variables(text, ":'", "'"); - else if (text[1] == '"') - matches = complete_from_variables(text, ":\"", "\""); - else - matches = complete_from_variables(text, ":", ""); - } - - /* If no previous word, suggest one of the basic sql commands */ - else if (prev_wd[0] == '\0') - COMPLETE_WITH_LIST(sql_commands); - -/* CREATE */ - /* complete with something you can create */ - else if (pg_strcasecmp(prev_wd, "CREATE") == 0) - matches = completion_matches(text, create_command_generator); - -/* DROP, but not DROP embedded in other commands */ - /* complete with something you can drop */ - else if (pg_strcasecmp(prev_wd, "DROP") == 0 && - prev2_wd[0] == '\0') - matches = completion_matches(text, drop_command_generator); - -/* ALTER */ - - /* - * 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 list_ALTER[] = - {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", - "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION", - "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR", - "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE", - "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", - "USER", "USER MAPPING FOR", "VIEW", NULL}; - - COMPLETE_WITH_LIST(list_ALTER); - } - /* ALTER AGGREGATE,FUNCTION */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 || - pg_strcasecmp(prev2_wd, "FUNCTION") == 0)) - COMPLETE_WITH_CONST("("); - /* ALTER AGGREGATE,FUNCTION (...) */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 || - pg_strcasecmp(prev3_wd, "FUNCTION") == 0)) - { - if (prev_wd[strlen(prev_wd) - 1] == ')') - { - static const char *const list_ALTERAGG[] = - {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERAGG); - } - else - { - char *tmp_buf = (char *)malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd)); - - sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd); - COMPLETE_WITH_QUERY(tmp_buf); - free(tmp_buf); - } - } - - /* ALTER SCHEMA */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "SCHEMA") == 0) - { - static const char *const list_ALTERGEN[] = - {"OWNER TO", "RENAME TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERGEN); - } - - /* ALTER COLLATION */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "COLLATION") == 0) - { - static const char *const list_ALTERGEN[] = - {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERGEN); - } - - /* ALTER CONVERSION */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "CONVERSION") == 0) - { - static const char *const list_ALTERGEN[] = - {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERGEN); - } - - /* ALTER DATABASE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "DATABASE") == 0) - { - static const char *const list_ALTERDATABASE[] = - {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDATABASE); - } - - /* ALTER EXTENSION */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "EXTENSION") == 0) - { - static const char *const list_ALTEREXTENSION[] = - {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTEREXTENSION); - } - - /* ALTER FOREIGN */ - else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const list_ALTER_FOREIGN[] = - {"DATA WRAPPER", "TABLE", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_FOREIGN); - } - - /* ALTER FOREIGN DATA WRAPPER */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev3_wd, "DATA") == 0 && - pg_strcasecmp(prev2_wd, "WRAPPER") == 0) - { - static const char *const list_ALTER_FDW[] = - {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_FDW); - } - - /* ALTER FOREIGN TABLE */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev2_wd, "TABLE") == 0) - { - static const char *const list_ALTER_FOREIGN_TABLE[] = - {"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE); - } - - /* ALTER INDEX */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "INDEX") == 0) - { - static const char *const list_ALTERINDEX[] = - {"OWNER TO", "RENAME TO", "SET", "RESET", NULL}; - - COMPLETE_WITH_LIST(list_ALTERINDEX); - } - /* ALTER INDEX SET */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "INDEX") == 0 && - pg_strcasecmp(prev_wd, "SET") == 0) - { - static const char *const list_ALTERINDEXSET[] = - {"(", "TABLESPACE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERINDEXSET); - } - /* ALTER INDEX RESET */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "INDEX") == 0 && - pg_strcasecmp(prev_wd, "RESET") == 0) - COMPLETE_WITH_CONST("("); - /* ALTER INDEX SET|RESET ( */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "INDEX") == 0 && - (pg_strcasecmp(prev2_wd, "SET") == 0 || - pg_strcasecmp(prev2_wd, "RESET") == 0) && - pg_strcasecmp(prev_wd, "(") == 0) - { - static const char *const list_INDEXOPTIONS[] = - {"fillfactor", "fastupdate", NULL}; - - COMPLETE_WITH_LIST(list_INDEXOPTIONS); - } - - /* ALTER LANGUAGE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "LANGUAGE") == 0) - { - static const char *const list_ALTERLANGUAGE[] = - {"OWNER TO", "RENAME TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERLANGUAGE); - } - - /* ALTER LARGE OBJECT */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "LARGE") == 0 && - pg_strcasecmp(prev2_wd, "OBJECT") == 0) - { - static const char *const list_ALTERLARGEOBJECT[] = - {"OWNER TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT); - } - - /* ALTER USER,ROLE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) && - (pg_strcasecmp(prev2_wd, "USER") == 0 || - pg_strcasecmp(prev2_wd, "ROLE") == 0)) - { - static const char *const list_ALTERUSER[] = - {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", - "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE", - "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION", - "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET", - "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL}; - - COMPLETE_WITH_LIST(list_ALTERUSER); - } - - /* ALTER USER,ROLE WITH */ - else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 && - (pg_strcasecmp(prev3_wd, "USER") == 0 || - pg_strcasecmp(prev3_wd, "ROLE") == 0) && - pg_strcasecmp(prev_wd, "WITH") == 0)) - { - /* Similar to the above, but don't complete "WITH" again. */ - static const char *const list_ALTERUSER_WITH[] = - {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", - "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE", - "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION", - "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET", - "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", NULL}; - - COMPLETE_WITH_LIST(list_ALTERUSER_WITH); - } - - /* complete ALTER USER,ROLE ENCRYPTED,UNENCRYPTED with PASSWORD */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) && - (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0)) - { - COMPLETE_WITH_CONST("PASSWORD"); - } - /* ALTER DEFAULT PRIVILEGES */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "DEFAULT") == 0 && - pg_strcasecmp(prev_wd, "PRIVILEGES") == 0) - { - static const char *const list_ALTER_DEFAULT_PRIVILEGES[] = - {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES); - } - /* ALTER DEFAULT PRIVILEGES FOR */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "DEFAULT") == 0 && - pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 && - pg_strcasecmp(prev_wd, "FOR") == 0) - { - static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] = - {"ROLE", "USER", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR); - } - /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */ - else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 && - pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 && - (pg_strcasecmp(prev3_wd, "FOR") == 0 || - pg_strcasecmp(prev3_wd, "IN") == 0)) - { - static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] = - {"GRANT", "REVOKE", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST); - } - /* ALTER DOMAIN */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "DOMAIN") == 0) - { - static const char *const list_ALTERDOMAIN[] = - {"ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDOMAIN); - } - /* ALTER DOMAIN DROP */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "DOMAIN") == 0 && - pg_strcasecmp(prev_wd, "DROP") == 0) - { - static const char *const list_ALTERDOMAIN2[] = - {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDOMAIN2); - } - /* ALTER DOMAIN RENAME */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "DOMAIN") == 0 && - pg_strcasecmp(prev_wd, "RENAME") == 0) - { - static const char *const list_ALTERDOMAIN[] = - {"CONSTRAINT", "TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDOMAIN); - } - /* ALTER DOMAIN RENAME CONSTRAINT */ - else if (pg_strcasecmp(prev5_wd, "DOMAIN") == 0 && - pg_strcasecmp(prev3_wd, "RENAME") == 0 && - pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) - COMPLETE_WITH_CONST("TO"); - - /* ALTER DOMAIN SET */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "DOMAIN") == 0 && - pg_strcasecmp(prev_wd, "SET") == 0) - { - static const char *const list_ALTERDOMAIN3[] = - {"DEFAULT", "NOT NULL", "SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDOMAIN3); - } - /* ALTER SEQUENCE */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "SEQUENCE") == 0) - { - static const char *const list_ALTERSEQUENCE[] = - {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE", - "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERSEQUENCE); - } - /* ALTER SEQUENCE NO */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 && - pg_strcasecmp(prev_wd, "NO") == 0) - { - static const char *const list_ALTERSEQUENCE2[] = - {"MINVALUE", "MAXVALUE", "CYCLE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERSEQUENCE2); - } - /* ALTER SERVER */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "SERVER") == 0) - { - static const char *const list_ALTER_SERVER[] = - {"VERSION", "OPTIONS", "OWNER TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTER_SERVER); - } - /* ALTER VIEW */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "VIEW") == 0) - { - static const char *const list_ALTERVIEW[] = - {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERVIEW); - } - /* ALTER TRIGGER , add ON */ - 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 ON, then add the correct tablename - */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - - /* ALTER TRIGGER ON */ - else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0) - COMPLETE_WITH_CONST("RENAME TO"); - - /* - * If we detect ALTER TABLE , suggest sub commands - */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TABLE") == 0) - { - static const char *const list_ALTER2[] = - {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT", - "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET", - "VALIDATE CONSTRAINT", NULL}; - - COMPLETE_WITH_LIST(list_ALTER2); - } - /* ALTER TABLE xxx ENABLE */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "ENABLE") == 0) - { - static const char *const list_ALTERENABLE[] = - {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL}; - - COMPLETE_WITH_LIST(list_ALTERENABLE); - } - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "ENABLE") == 0 && - (pg_strcasecmp(prev_wd, "REPLICA") == 0 || - pg_strcasecmp(prev_wd, "ALWAYS") == 0)) - { - static const char *const list_ALTERENABLE2[] = - {"RULE", "TRIGGER", NULL}; - - COMPLETE_WITH_LIST(list_ALTERENABLE2); - } - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "DISABLE") == 0) - { - static const char *const list_ALTERDISABLE[] = - {"RULE", "TRIGGER", NULL}; - - COMPLETE_WITH_LIST(list_ALTERDISABLE); - } - - /* ALTER TABLE xxx ALTER */ - 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'"); - - /* ALTER TABLE xxx RENAME */ - 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 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, ""); - - /* ALTER TABLE xxx RENAME yyy */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "RENAME") == 0 && - pg_strcasecmp(prev_wd, "CONSTRAINT") != 0 && - pg_strcasecmp(prev_wd, "TO") != 0) - COMPLETE_WITH_CONST("TO"); - - /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */ - else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "RENAME") == 0 && - (pg_strcasecmp(prev2_wd, "COLUMN") == 0 || - pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) && - pg_strcasecmp(prev_wd, "TO") != 0) - COMPLETE_WITH_CONST("TO"); - - /* If we have TABLE DROP, provide COLUMN or CONSTRAINT */ - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "DROP") == 0) - { - static const char *const list_TABLEDROP[] = - {"COLUMN", "CONSTRAINT", NULL}; - - COMPLETE_WITH_LIST(list_TABLEDROP); - } - /* If we have TABLE DROP COLUMN, provide list of columns */ - 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, ""); - /* ALTER TABLE ALTER [COLUMN] */ - else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "COLUMN") == 0) || - (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "ALTER") == 0)) - { - static const char *const list_COLUMNALTER[] = - {"TYPE", "SET", "RESET", "DROP", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNALTER); - } - /* ALTER TABLE ALTER [COLUMN] SET */ - else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "COLUMN") == 0) || - (pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "ALTER") == 0)) && - pg_strcasecmp(prev_wd, "SET") == 0) - { - static const char *const list_COLUMNSET[] = - {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNSET); - } - /* ALTER TABLE ALTER [COLUMN] SET ( */ - else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "COLUMN") == 0) || - pg_strcasecmp(prev4_wd, "ALTER") == 0) && - pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "(") == 0) - { - static const char *const list_COLUMNOPTIONS[] = - {"n_distinct", "n_distinct_inherited", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNOPTIONS); - } - /* ALTER TABLE ALTER [COLUMN] SET STORAGE */ - else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "COLUMN") == 0) || - pg_strcasecmp(prev4_wd, "ALTER") == 0) && - pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "STORAGE") == 0) - { - static const char *const list_COLUMNSTORAGE[] = - {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNSTORAGE); - } - /* ALTER TABLE ALTER [COLUMN] DROP */ - else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "COLUMN") == 0) || - (pg_strcasecmp(prev5_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "ALTER") == 0)) && - pg_strcasecmp(prev_wd, "DROP") == 0) - { - static const char *const list_COLUMNDROP[] = - {"DEFAULT", "NOT NULL", NULL}; - - COMPLETE_WITH_LIST(list_COLUMNDROP); - } - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "CLUSTER") == 0) - 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); - } - /* If we have TABLE SET, provide WITHOUT,TABLESPACE and SCHEMA */ - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "SET") == 0) - { - static const char *const list_TABLESET[] = - {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_TABLESET); - } - /* If we have TABLE SET TABLESPACE provide a list of tablespaces */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "TABLESPACE") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); - /* If we have TABLE SET WITHOUT provide CLUSTER or OIDS */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "WITHOUT") == 0) - { - static const char *const list_TABLESET2[] = - {"CLUSTER", "OIDS", NULL}; - - COMPLETE_WITH_LIST(list_TABLESET2); - } - /* ALTER TABLE RESET */ - else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev_wd, "RESET") == 0) - COMPLETE_WITH_CONST("("); - /* ALTER TABLE SET|RESET ( */ - else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && - (pg_strcasecmp(prev2_wd, "SET") == 0 || - pg_strcasecmp(prev2_wd, "RESET") == 0) && - pg_strcasecmp(prev_wd, "(") == 0) - { - static const char *const list_TABLEOPTIONS[] = - { - "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(list_TABLEOPTIONS); - } - - /* ALTER TABLESPACE with RENAME TO, OWNER TO, SET, RESET */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TABLESPACE") == 0) - { - static const char *const list_ALTERTSPC[] = - {"RENAME TO", "OWNER TO", "SET", "RESET", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTSPC); - } - /* ALTER TABLESPACE SET|RESET */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 && - (pg_strcasecmp(prev_wd, "SET") == 0 || - pg_strcasecmp(prev_wd, "RESET") == 0)) - COMPLETE_WITH_CONST("("); - /* ALTER TABLESPACE SET|RESET ( */ - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 && - (pg_strcasecmp(prev2_wd, "SET") == 0 || - pg_strcasecmp(prev2_wd, "RESET") == 0) && - pg_strcasecmp(prev_wd, "(") == 0) - { - static const char *const list_TABLESPACEOPTIONS[] = - {"seq_page_cost", "random_page_cost", NULL}; - - COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS); - } - - /* ALTER TEXT SEARCH */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TEXT") == 0 && - pg_strcasecmp(prev_wd, "SEARCH") == 0) - { - static const char *const list_ALTERTEXTSEARCH[] = - {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH); - } - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 || - pg_strcasecmp(prev2_wd, "PARSER") == 0)) - { - static const char *const list_ALTERTEXTSEARCH2[] = - {"RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2); - } - - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - pg_strcasecmp(prev2_wd, "DICTIONARY") == 0) - { - static const char *const list_ALTERTEXTSEARCH3[] = - {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3); - } - - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0) - { - static const char *const list_ALTERTEXTSEARCH4[] = - {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4); - } - - /* complete ALTER TYPE with actions */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "TYPE") == 0) - { - static const char *const list_ALTERTYPE[] = - {"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE", - "OWNER TO", "RENAME", "SET SCHEMA", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTYPE); - } - /* complete ALTER TYPE ADD with actions */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TYPE") == 0 && - pg_strcasecmp(prev_wd, "ADD") == 0) - { - static const char *const list_ALTERTYPE[] = - {"ATTRIBUTE", "VALUE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTYPE); - } - /* ALTER TYPE RENAME */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "TYPE") == 0 && - pg_strcasecmp(prev_wd, "RENAME") == 0) - { - static const char *const list_ALTERTYPE[] = - {"ATTRIBUTE", "TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTYPE); - } - /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */ - else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 && - pg_strcasecmp(prev3_wd, "RENAME") == 0 && - pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0) - COMPLETE_WITH_CONST("TO"); - - /* - * If we have TYPE ALTER/DROP/RENAME ATTRIBUTE, provide list of - * attributes - */ - else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 && - (pg_strcasecmp(prev2_wd, "ALTER") == 0 || - pg_strcasecmp(prev2_wd, "DROP") == 0 || - pg_strcasecmp(prev2_wd, "RENAME") == 0) && - pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0) - COMPLETE_WITH_ATTR(prev3_wd, ""); - /* ALTER TYPE ALTER ATTRIBUTE */ - else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)) - { - COMPLETE_WITH_CONST("TYPE"); - } - /* complete ALTER GROUP */ - else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - pg_strcasecmp(prev2_wd, "GROUP") == 0) - { - static const char *const list_ALTERGROUP[] = - {"ADD USER", "DROP USER", "RENAME TO", NULL}; - - COMPLETE_WITH_LIST(list_ALTERGROUP); - } - /* complete ALTER GROUP ADD|DROP with USER */ - else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 && - pg_strcasecmp(prev3_wd, "GROUP") == 0 && - (pg_strcasecmp(prev_wd, "ADD") == 0 || - pg_strcasecmp(prev_wd, "DROP") == 0)) - COMPLETE_WITH_CONST("USER"); - /* complete {ALTER} GROUP ADD|DROP USER with a user name */ - else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 && - (pg_strcasecmp(prev2_wd, "ADD") == 0 || - pg_strcasecmp(prev2_wd, "DROP") == 0) && - pg_strcasecmp(prev_wd, "USER") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_roles); - -/* BEGIN, END, ABORT */ - else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 || - pg_strcasecmp(prev_wd, "END") == 0 || - pg_strcasecmp(prev_wd, "ABORT") == 0) - { - static const char *const list_TRANS[] = - {"WORK", "TRANSACTION", NULL}; - - COMPLETE_WITH_LIST(list_TRANS); - } -/* COMMIT */ - else if (pg_strcasecmp(prev_wd, "COMMIT") == 0) - { - static const char *const list_COMMIT[] = - {"WORK", "TRANSACTION", "PREPARED", NULL}; - - COMPLETE_WITH_LIST(list_COMMIT); - } -/* RELEASE SAVEPOINT */ - else if (pg_strcasecmp(prev_wd, "RELEASE") == 0) - COMPLETE_WITH_CONST("SAVEPOINT"); -/* ROLLBACK*/ - else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0) - { - static const char *const list_TRANS[] = - {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL}; - - COMPLETE_WITH_LIST(list_TRANS); - } -/* CLUSTER */ - - /* - * If the previous word is CLUSTER and not without produce list of tables - */ - else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev2_wd, "WITHOUT") != 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - /* If we have CLUSTER , then add "USING" */ - else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev_wd, "ON") != 0) - { - COMPLETE_WITH_CONST("USING"); - } - - /* - * If we have CLUSTER USING, then add the index as well. - */ - else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 && - pg_strcasecmp(prev_wd, "USING") == 0) - { - completion_info_charp = prev2_wd; - COMPLETE_WITH_QUERY(Query_for_index_of_table); - } - -/* COMMENT */ - 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 list_COMMENT[] = - {"CAST", "COLLATION", "CONVERSION", "DATABASE", "EXTENSION", - "FOREIGN DATA WRAPPER", "FOREIGN TABLE", - "SERVER", "INDEX", "LANGUAGE", "RULE", "SCHEMA", "SEQUENCE", - "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION", - "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT", - "TABLESPACE", "TEXT SEARCH", "ROLE", NULL}; - - COMPLETE_WITH_LIST(list_COMMENT); - } - else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const list_TRANS2[] = - {"DATA WRAPPER", "TABLE", NULL}; - - COMPLETE_WITH_LIST(list_TRANS2); - } - else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "TEXT") == 0 && - pg_strcasecmp(prev_wd, "SEARCH") == 0) - { - static const char *const list_TRANS2[] = - {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL}; - - COMPLETE_WITH_LIST(list_TRANS2); - } - else if ((pg_strcasecmp(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"); - -/* COPY */ - - /* - * 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); - /* If we have COPY|BINARY , complete it with "TO" or "FROM" */ - else if (pg_strcasecmp(prev2_wd, "COPY") == 0 || - pg_strcasecmp(prev2_wd, "\\copy") == 0 || - pg_strcasecmp(prev2_wd, "BINARY") == 0) - { - static const char *const list_FROMTO[] = - {"FROM", "TO", NULL}; - - COMPLETE_WITH_LIST(list_FROMTO); - } - /* If we have COPY|BINARY FROM|TO, complete with filename */ - else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 || - pg_strcasecmp(prev3_wd, "\\copy") == 0 || - pg_strcasecmp(prev3_wd, "BINARY") == 0) && - (pg_strcasecmp(prev_wd, "FROM") == 0 || - pg_strcasecmp(prev_wd, "TO") == 0)) - { - completion_charp = ""; - matches = completion_matches(text, complete_from_files); - } - - /* Handle COPY|BINARY FROM|TO filename */ - else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 || - pg_strcasecmp(prev4_wd, "\\copy") == 0 || - pg_strcasecmp(prev4_wd, "BINARY") == 0) && - (pg_strcasecmp(prev2_wd, "FROM") == 0 || - pg_strcasecmp(prev2_wd, "TO") == 0)) - { - static const char *const list_COPY[] = - {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL}; - - COMPLETE_WITH_LIST(list_COPY); - } - - /* Handle COPY|BINARY FROM|TO filename CSV */ - else if (pg_strcasecmp(prev_wd, "CSV") == 0 && - (pg_strcasecmp(prev3_wd, "FROM") == 0 || - pg_strcasecmp(prev3_wd, "TO") == 0)) - { - static const char *const list_CSV[] = - {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL}; - - COMPLETE_WITH_LIST(list_CSV); - } - - /* CREATE DATABASE */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "DATABASE") == 0) - { - static const char *const list_DATABASE[] = - {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT", - NULL}; - - COMPLETE_WITH_LIST(list_DATABASE); - } - - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "DATABASE") == 0 && - pg_strcasecmp(prev_wd, "TEMPLATE") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_template_databases); - - /* CREATE EXTENSION */ - /* Complete with available extensions rather than installed ones. */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "EXTENSION") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions); - /* CREATE EXTENSION */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "EXTENSION") == 0) - COMPLETE_WITH_CONST("WITH SCHEMA"); - - /* CREATE FOREIGN */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const list_CREATE_FOREIGN[] = - {"DATA WRAPPER", "TABLE", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_FOREIGN); - } - - /* CREATE FOREIGN DATA WRAPPER */ - else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev3_wd, "DATA") == 0 && - pg_strcasecmp(prev2_wd, "WRAPPER") == 0) - { - static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] = - {"HANDLER", "VALIDATOR", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER); - } - - /* CREATE INDEX */ - /* First off we complete CREATE UNIQUE with "INDEX" */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "UNIQUE") == 0) - COMPLETE_WITH_CONST("INDEX"); - /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */ - else if (pg_strcasecmp(prev_wd, "INDEX") == 0 && - (pg_strcasecmp(prev2_wd, "CREATE") == 0 || - pg_strcasecmp(prev2_wd, "UNIQUE") == 0)) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, - " UNION SELECT 'ON'" - " UNION SELECT 'CONCURRENTLY'"); - /* Complete ... INDEX [] ON with a list of tables */ - else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 || - pg_strcasecmp(prev2_wd, "INDEX") == 0 || - pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) && - pg_strcasecmp(prev_wd, "ON") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - /* If we have CREATE|UNIQUE INDEX CONCURRENTLY, then add "ON" */ - else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 || - pg_strcasecmp(prev2_wd, "INDEX") == 0) && - pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0) - COMPLETE_WITH_CONST("ON"); - /* If we have CREATE|UNIQUE INDEX , then add "ON" or "CONCURRENTLY" */ - else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 || - pg_strcasecmp(prev3_wd, "UNIQUE") == 0) && - pg_strcasecmp(prev2_wd, "INDEX") == 0) - { - static const char *const list_CREATE_INDEX[] = - {"CONCURRENTLY", "ON", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_INDEX); - } - - /* - * Complete INDEX ON with a list of table columns (which - * should really be in parens) - */ - else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 || - pg_strcasecmp(prev3_wd, "INDEX") == 0 || - pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) && - pg_strcasecmp(prev2_wd, "ON") == 0) - { - static const char *const list_CREATE_INDEX2[] = - {"(", "USING", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_INDEX2); - } - else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 || - pg_strcasecmp(prev4_wd, "INDEX") == 0 || - pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "(") == 0) - COMPLETE_WITH_ATTR(prev2_wd, ""); - /* same if you put in USING */ - else if (pg_strcasecmp(prev5_wd, "ON") == 0 && - pg_strcasecmp(prev3_wd, "USING") == 0 && - pg_strcasecmp(prev_wd, "(") == 0) - COMPLETE_WITH_ATTR(prev4_wd, ""); - /* Complete USING with an index method */ - else if (pg_strcasecmp(prev_wd, "USING") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); - else if (pg_strcasecmp(prev4_wd, "ON") == 0 && - pg_strcasecmp(prev2_wd, "USING") == 0) - COMPLETE_WITH_CONST("("); - -/* CREATE RULE */ - /* Complete "CREATE RULE " with "AS" */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "RULE") == 0) - COMPLETE_WITH_CONST("AS"); - /* Complete "CREATE RULE AS with "ON" */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "RULE") == 0 && - pg_strcasecmp(prev_wd, "AS") == 0) - COMPLETE_WITH_CONST("ON"); - /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */ - else if (pg_strcasecmp(prev4_wd, "RULE") == 0 && - pg_strcasecmp(prev2_wd, "AS") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) - { - static const char *const rule_events[] = - {"SELECT", "UPDATE", "INSERT", "DELETE", NULL}; - - COMPLETE_WITH_LIST(rule_events); - } - /* Complete "AS ON " with a "TO" */ - else if (pg_strcasecmp(prev3_wd, "AS") == 0 && - pg_strcasecmp(prev2_wd, "ON") == 0 && - (pg_toupper((unsigned char) prev_wd[4]) == 'T' || - pg_toupper((unsigned char) prev_wd[5]) == 'T')) - COMPLETE_WITH_CONST("TO"); - /* Complete "AS ON TO" with a table name */ - else if (pg_strcasecmp(prev4_wd, "AS") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - -/* CREATE SERVER */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "SERVER") == 0) - { - static const char *const list_CREATE_SERVER[] = - {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL}; - - COMPLETE_WITH_LIST(list_CREATE_SERVER); - } - -/* CREATE TABLE */ - /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - (pg_strcasecmp(prev_wd, "TEMP") == 0 || - pg_strcasecmp(prev_wd, "TEMPORARY") == 0)) - { - static const char *const list_TEMP[] = - {"SEQUENCE", "TABLE", "VIEW", NULL}; - - COMPLETE_WITH_LIST(list_TEMP); - } - /* Complete "CREATE UNLOGGED" with TABLE */ - else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && - pg_strcasecmp(prev_wd, "UNLOGGED") == 0) - { - COMPLETE_WITH_CONST("TABLE"); - } - -/* CREATE TABLESPACE */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "TABLESPACE") == 0) - { - static const char *const list_CREATETABLESPACE[] = - {"OWNER", "LOCATION", NULL}; - - COMPLETE_WITH_LIST(list_CREATETABLESPACE); - } - /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */ - else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 && - pg_strcasecmp(prev2_wd, "OWNER") == 0) - { - COMPLETE_WITH_CONST("LOCATION"); - } - -/* CREATE TEXT SEARCH */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "TEXT") == 0 && - pg_strcasecmp(prev_wd, "SEARCH") == 0) - { - static const char *const list_CREATETEXTSEARCH[] = - {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL}; - - COMPLETE_WITH_LIST(list_CREATETEXTSEARCH); - } - else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0) - COMPLETE_WITH_CONST("("); - -/* CREATE TRIGGER */ - /* complete CREATE TRIGGER with BEFORE,AFTER */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "TRIGGER") == 0) - { - static const char *const list_CREATETRIGGER[] = - {"BEFORE", "AFTER", "INSTEAD OF", NULL}; - - COMPLETE_WITH_LIST(list_CREATETRIGGER); - } - /* complete CREATE TRIGGER BEFORE,AFTER with an event */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "TRIGGER") == 0 && - (pg_strcasecmp(prev_wd, "BEFORE") == 0 || - pg_strcasecmp(prev_wd, "AFTER") == 0)) - { - static const char *const list_CREATETRIGGER_EVENTS[] = - {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL}; - - COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS); - } - /* complete CREATE TRIGGER INSTEAD OF with an event */ - else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev2_wd, "INSTEAD") == 0 && - pg_strcasecmp(prev_wd, "OF") == 0) - { - static const char *const list_CREATETRIGGER_EVENTS[] = - {"INSERT", "DELETE", "UPDATE", NULL}; - - COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS); - } - /* complete CREATE TRIGGER BEFORE,AFTER sth with OR,ON */ - else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 && - pg_strcasecmp(prev4_wd, "TRIGGER") == 0 && - (pg_strcasecmp(prev2_wd, "BEFORE") == 0 || - pg_strcasecmp(prev2_wd, "AFTER") == 0)) || - (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 && - pg_strcasecmp(prev3_wd, "INSTEAD") == 0 && - pg_strcasecmp(prev2_wd, "OF") == 0)) - { - static const char *const list_CREATETRIGGER2[] = - {"ON", "OR", NULL}; - - COMPLETE_WITH_LIST(list_CREATETRIGGER2); - } - - /* - * complete CREATE TRIGGER BEFORE,AFTER event ON with a list of - * tables - */ - else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 && - (pg_strcasecmp(prev3_wd, "BEFORE") == 0 || - pg_strcasecmp(prev3_wd, "AFTER") == 0) && - pg_strcasecmp(prev_wd, "ON") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */ - else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 && - pg_strcasecmp(prev3_wd, "OF") == 0 && - pg_strcasecmp(prev_wd, "ON") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); - /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */ - else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 && - prev2_wd[0] != '\0') - COMPLETE_WITH_CONST("PROCEDURE"); - -/* CREATE ROLE,USER,GROUP */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) && - (pg_strcasecmp(prev2_wd, "ROLE") == 0 || - pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0)) - { - static const char *const list_CREATEROLE[] = - {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", - "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB", - "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN", - "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE", - "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL}; - - COMPLETE_WITH_LIST(list_CREATEROLE); - } - -/* CREATE ROLE,USER,GROUP WITH */ - else if ((pg_strcasecmp(prev4_wd, "CREATE") == 0 && - (pg_strcasecmp(prev3_wd, "ROLE") == 0 || - pg_strcasecmp(prev3_wd, "GROUP") == 0 || - pg_strcasecmp(prev3_wd, "USER") == 0) && - pg_strcasecmp(prev_wd, "WITH") == 0)) - { - /* Similar to the above, but don't complete "WITH" again. */ - static const char *const list_CREATEROLE_WITH[] = - {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", - "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB", - "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN", - "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE", - "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", NULL}; - - COMPLETE_WITH_LIST(list_CREATEROLE_WITH); - } - - /* - * complete CREATE ROLE,USER,GROUP ENCRYPTED,UNENCRYPTED with - * PASSWORD - */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - (pg_strcasecmp(prev3_wd, "ROLE") == 0 || - pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) && - (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0)) - { - COMPLETE_WITH_CONST("PASSWORD"); - } - /* complete CREATE ROLE,USER,GROUP IN with ROLE,GROUP */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - (pg_strcasecmp(prev3_wd, "ROLE") == 0 || - pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) && - pg_strcasecmp(prev_wd, "IN") == 0) - { - static const char *const list_CREATEROLE3[] = - {"GROUP", "ROLE", NULL}; - - COMPLETE_WITH_LIST(list_CREATEROLE3); - } - -/* CREATE VIEW */ - /* Complete CREATE VIEW with AS */ - else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && - pg_strcasecmp(prev2_wd, "VIEW") == 0) - COMPLETE_WITH_CONST("AS"); - /* Complete "CREATE VIEW AS with "SELECT" */ - else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 && - pg_strcasecmp(prev3_wd, "VIEW") == 0 && - pg_strcasecmp(prev_wd, "AS") == 0) - COMPLETE_WITH_CONST("SELECT"); - -/* DECLARE */ - else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0) - { - static const char *const list_DECLARE[] = - {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL}; - - COMPLETE_WITH_LIST(list_DECLARE); - } - -/* CURSOR */ - else if (pg_strcasecmp(prev_wd, "CURSOR") == 0) - { - static const char *const list_DECLARECURSOR[] = - {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL}; - - COMPLETE_WITH_LIST(list_DECLARECURSOR); - } - - -/* DELETE */ - - /* - * 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"); - /* Complete DELETE FROM with a list of tables */ - else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 && - pg_strcasecmp(prev_wd, "FROM") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL); - /* Complete DELETE FROM
*/ - else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 && - pg_strcasecmp(prev2_wd, "FROM") == 0) - { - static const char *const list_DELETE[] = - {"USING", "WHERE", "SET", NULL}; - - COMPLETE_WITH_LIST(list_DELETE); - } - /* XXX: implement tab completion for DELETE ... USING */ - -/* DISCARD */ - else if (pg_strcasecmp(prev_wd, "DISCARD") == 0) - { - static const char *const list_DISCARD[] = - {"ALL", "PLANS", "TEMP", NULL}; - - COMPLETE_WITH_LIST(list_DISCARD); - } - -/* DO */ - - /* - * Complete DO with LANGUAGE. - */ - else if (pg_strcasecmp(prev_wd, "DO") == 0) - { - static const char *const list_DO[] = - {"LANGUAGE", NULL}; - - COMPLETE_WITH_LIST(list_DO); - } - -/* DROP (when not the previous word) */ - /* DROP AGGREGATE */ - else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && - pg_strcasecmp(prev2_wd, "AGGREGATE") == 0) - COMPLETE_WITH_CONST("("); - - /* DROP object with CASCADE / RESTRICT */ - else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 && - (pg_strcasecmp(prev2_wd, "COLLATION") == 0 || - pg_strcasecmp(prev2_wd, "CONVERSION") == 0 || - pg_strcasecmp(prev2_wd, "DOMAIN") == 0 || - pg_strcasecmp(prev2_wd, "EXTENSION") == 0 || - pg_strcasecmp(prev2_wd, "FUNCTION") == 0 || - pg_strcasecmp(prev2_wd, "INDEX") == 0 || - pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 || - pg_strcasecmp(prev2_wd, "SCHEMA") == 0 || - pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 || - pg_strcasecmp(prev2_wd, "SERVER") == 0 || - pg_strcasecmp(prev2_wd, "TABLE") == 0 || - pg_strcasecmp(prev2_wd, "TYPE") == 0 || - pg_strcasecmp(prev2_wd, "VIEW") == 0)) || - (pg_strcasecmp(prev4_wd, "DROP") == 0 && - pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 && - prev_wd[strlen(prev_wd) - 1] == ')') || - (pg_strcasecmp(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 list_DROPCR[] = - {"CASCADE", "RESTRICT", NULL}; - - COMPLETE_WITH_LIST(list_DROPCR); - } - } - else if (pg_strcasecmp(prev2_wd, "DROP") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const drop_CREATE_FOREIGN[] = - {"DATA WRAPPER", "TABLE", NULL}; - - COMPLETE_WITH_LIST(drop_CREATE_FOREIGN); - } - 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) - { - char *tmp_buf = (char *)malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd)); - - sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd); - COMPLETE_WITH_QUERY(tmp_buf); - free(tmp_buf); - } - /* DROP OWNED BY */ - 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 list_ALTERTEXTSEARCH[] = - {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL}; - - COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH); - } - -/* EXECUTE, but not EXECUTE embedded in other commands */ - else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 && - prev2_wd[0] == '\0') - COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements); - -/* EXPLAIN */ - - /* - * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands - */ - else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0) - { - static const char *const list_EXPLAIN[] = - {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL}; - - COMPLETE_WITH_LIST(list_EXPLAIN); - } - else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 && - pg_strcasecmp(prev_wd, "ANALYZE") == 0) - { - static const char *const list_EXPLAIN[] = - {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL}; - - COMPLETE_WITH_LIST(list_EXPLAIN); - } - else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 && - pg_strcasecmp(prev_wd, "VERBOSE") == 0) || - (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 && - pg_strcasecmp(prev2_wd, "ANALYZE") == 0 && - pg_strcasecmp(prev_wd, "VERBOSE") == 0)) - { - static const char *const list_EXPLAIN[] = - {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL}; - - COMPLETE_WITH_LIST(list_EXPLAIN); - } - -/* FETCH && MOVE */ - /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */ - else if (pg_strcasecmp(prev_wd, "FETCH") == 0 || - pg_strcasecmp(prev_wd, "MOVE") == 0) - { - static const char *const list_FETCH1[] = - {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL}; - - COMPLETE_WITH_LIST(list_FETCH1); - } - /* Complete FETCH with one of ALL, NEXT, PRIOR */ - else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 || - pg_strcasecmp(prev2_wd, "MOVE") == 0) - { - static const char *const list_FETCH2[] = - {"ALL", "NEXT", "PRIOR", NULL}; - - COMPLETE_WITH_LIST(list_FETCH2); - } - - /* - * Complete FETCH with "FROM" or "IN". These are equivalent, - * but we may as well tab-complete both: perhaps some users prefer one - * variant or the other. - */ - else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 || - pg_strcasecmp(prev3_wd, "MOVE") == 0) - { - static const char *const list_FROMIN[] = - {"FROM", "IN", NULL}; - - COMPLETE_WITH_LIST(list_FROMIN); - } - -/* FOREIGN DATA WRAPPER */ - /* applies in ALTER/DROP FDW and in CREATE SERVER */ - else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 && - pg_strcasecmp(prev3_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev2_wd, "DATA") == 0 && - pg_strcasecmp(prev_wd, "WRAPPER") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_fdws); - -/* FOREIGN TABLE */ - else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 && - pg_strcasecmp(prev2_wd, "FOREIGN") == 0 && - pg_strcasecmp(prev_wd, "TABLE") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL); - -/* GRANT && REVOKE */ - /* Complete GRANT/REVOKE with a list of roles and privileges */ - else if (pg_strcasecmp(prev_wd, "GRANT") == 0 || - pg_strcasecmp(prev_wd, "REVOKE") == 0) - { - 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'"); - } - - /* - * Complete GRANT/REVOKE with "ON", GRANT/REVOKE 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 - || pg_strcasecmp(prev_wd, "ALL") == 0) - COMPLETE_WITH_CONST("ON"); - else - { - if (pg_strcasecmp(prev2_wd, "GRANT") == 0) - COMPLETE_WITH_CONST("TO"); - else - COMPLETE_WITH_CONST("FROM"); - } - } - - /* - * Complete GRANT/REVOKE 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_tsvf, - " 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'"); - else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 || - pg_strcasecmp(prev4_wd, "REVOKE") == 0) && - pg_strcasecmp(prev2_wd, "ON") == 0 && - pg_strcasecmp(prev_wd, "FOREIGN") == 0) - { - static const char *const list_privilege_foreign[] = - {"DATA WRAPPER", "SERVER", NULL}; - - COMPLETE_WITH_LIST(list_privilege_foreign); - } - - /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */ - else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 || - pg_strcasecmp(prev4_wd, "REVOKE") == 0) && - pg_strcasecmp(prev2_wd, "ON") == 0) - { - 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(prev4_wd, "GRANT") == 0) - COMPLETE_WITH_CONST("TO"); - else - COMPLETE_WITH_CONST("FROM"); - } - - /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */ - else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0) - { - 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"); - } - - /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */ - else if (pg_strcasecmp(prev3_wd, "GRANT") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) - { - COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); - } - else if (pg_strcasecmp(prev3_wd, "REVOKE") == 0 && - pg_strcasecmp(prev_wd, "FROM") == 0) - { - COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); - } - -/* GROUP BY */ - else if (pg_strcasecmp(prev3_wd, "FROM") == 0 && - pg_strcasecmp(prev_wd, "GROUP") == 0) - COMPLETE_WITH_CONST("BY"); - -/* INSERT */ - /* Complete INSERT with "INTO" */ - else if (pg_strcasecmp(prev_wd, "INSERT") == 0) - COMPLETE_WITH_CONST("INTO"); - /* Complete INSERT INTO with table names */ - else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 && - pg_strcasecmp(prev_wd, "INTO") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL); - /* Complete "INSERT INTO
(" with attribute names */ - else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 && - pg_strcasecmp(prev3_wd, "INTO") == 0 && - pg_strcasecmp(prev_wd, "(") == 0) - COMPLETE_WITH_ATTR(prev2_wd, ""); - - /* - * Complete INSERT INTO
with "(" or "VALUES" or "SELECT" or - * "TABLE" or "DEFAULT VALUES" - */ - else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 && - pg_strcasecmp(prev2_wd, "INTO") == 0) - { - static const char *const list_INSERT[] = - {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL}; - - COMPLETE_WITH_LIST(list_INSERT); - } - - /* - * Complete INSERT INTO
(attribs) with "VALUES" or "SELECT" or - * "TABLE" - */ - else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 && - pg_strcasecmp(prev3_wd, "INTO") == 0 && - prev_wd[strlen(prev_wd) - 1] == ')') - { - static const char *const list_INSERT[] = - {"SELECT", "TABLE", "VALUES", NULL}; - - COMPLETE_WITH_LIST(list_INSERT); - } - - /* Insert an open parenthesis after "VALUES" */ - else if (pg_strcasecmp(prev_wd, "VALUES") == 0 && - pg_strcasecmp(prev2_wd, "DEFAULT") != 0) - COMPLETE_WITH_CONST("("); - -/* LOCK */ - /* Complete LOCK [TABLE] with a list of tables */ - 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, ""); - - /* For the following, handle the case of a single table only for now */ - - /* Complete LOCK [TABLE]
with "IN" */ - else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 && - pg_strcasecmp(prev_wd, "TABLE") != 0) || - (pg_strcasecmp(prev2_wd, "TABLE") == 0 && - pg_strcasecmp(prev3_wd, "LOCK") == 0)) - COMPLETE_WITH_CONST("IN"); - - /* Complete LOCK [TABLE]
IN with a lock mode */ - else if (pg_strcasecmp(prev_wd, "IN") == 0 && - (pg_strcasecmp(prev3_wd, "LOCK") == 0 || - (pg_strcasecmp(prev3_wd, "TABLE") == 0 && - pg_strcasecmp(prev4_wd, "LOCK") == 0))) - { - static const char *const lock_modes[] = - {"ACCESS SHARE MODE", - "ROW SHARE MODE", "ROW EXCLUSIVE MODE", - "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE", - "SHARE ROW EXCLUSIVE MODE", - "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL}; - - COMPLETE_WITH_LIST(lock_modes); - } - -/* NOTIFY */ - 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'"); - -/* OPTIONS */ - else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0) - COMPLETE_WITH_CONST("("); - -/* OWNER TO - complete with available roles */ - else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 && - pg_strcasecmp(prev_wd, "TO") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_roles); - -/* ORDER BY */ - 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, ""); - -/* PREPARE xx AS */ - else if (pg_strcasecmp(prev_wd, "AS") == 0 && - pg_strcasecmp(prev3_wd, "PREPARE") == 0) - { - static const char *const list_PREPARE[] = - {"SELECT", "UPDATE", "INSERT", "DELETE", NULL}; - - COMPLETE_WITH_LIST(list_PREPARE); - } - -/* - * PREPARE TRANSACTION is missing on purpose. It's intended for transaction - * managers, not for manual use in interactive sessions. - */ - -/* REASSIGN OWNED BY xxx TO yyy */ - 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); - -/* REINDEX */ - else if (pg_strcasecmp(prev_wd, "REINDEX") == 0) - { - static const char *const list_REINDEX[] = - {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL}; - - COMPLETE_WITH_LIST(list_REINDEX); - } - else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0) - { - if (pg_strcasecmp(prev_wd, "TABLE") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - else if (pg_strcasecmp(prev_wd, "INDEX") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL); - else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 || - pg_strcasecmp(prev_wd, "DATABASE") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_databases); - } - -/* SECURITY LABEL */ - else if (pg_strcasecmp(prev_wd, "SECURITY") == 0) - COMPLETE_WITH_CONST("LABEL"); - else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 && - pg_strcasecmp(prev_wd, "LABEL") == 0) - { - static const char *const list_SECURITY_LABEL_preposition[] = - {"ON", "FOR"}; - - COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition); - } - else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 && - pg_strcasecmp(prev3_wd, "LABEL") == 0 && - pg_strcasecmp(prev2_wd, "FOR") == 0) - 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 list_SECURITY_LABEL[] = - {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", - "AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT", - NULL}; - - COMPLETE_WITH_LIST(list_SECURITY_LABEL); - } - else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 && - pg_strcasecmp(prev4_wd, "LABEL") == 0 && - pg_strcasecmp(prev3_wd, "ON") == 0) - COMPLETE_WITH_CONST("IS"); - -/* SELECT */ - /* naah . . . */ - -/* SET, RESET, SHOW */ - /* Complete with a variable name */ - else if ((pg_strcasecmp(prev_wd, "SET") == 0 && - pg_strcasecmp(prev3_wd, "UPDATE") != 0) || - pg_strcasecmp(prev_wd, "RESET") == 0) - 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); - /* Complete "SET TRANSACTION" */ - else if ((pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "TRANSACTION") == 0) - || (pg_strcasecmp(prev2_wd, "START") == 0 - && pg_strcasecmp(prev_wd, "TRANSACTION") == 0) - || (pg_strcasecmp(prev2_wd, "BEGIN") == 0 - && pg_strcasecmp(prev_wd, "WORK") == 0) - || (pg_strcasecmp(prev2_wd, "BEGIN") == 0 - && pg_strcasecmp(prev_wd, "TRANSACTION") == 0) - || (pg_strcasecmp(prev4_wd, "SESSION") == 0 - && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 - && pg_strcasecmp(prev2_wd, "AS") == 0 - && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)) - { - static const char *const my_list[] = - {"ISOLATION LEVEL", "READ", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if ((pg_strcasecmp(prev3_wd, "SET") == 0 - || pg_strcasecmp(prev3_wd, "BEGIN") == 0 - || pg_strcasecmp(prev3_wd, "START") == 0 - || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0 - && pg_strcasecmp(prev3_wd, "AS") == 0)) - && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 - || pg_strcasecmp(prev2_wd, "WORK") == 0) - && pg_strcasecmp(prev_wd, "ISOLATION") == 0) - COMPLETE_WITH_CONST("LEVEL"); - else if ((pg_strcasecmp(prev4_wd, "SET") == 0 - || pg_strcasecmp(prev4_wd, "BEGIN") == 0 - || pg_strcasecmp(prev4_wd, "START") == 0 - || pg_strcasecmp(prev4_wd, "AS") == 0) - && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0 - || pg_strcasecmp(prev3_wd, "WORK") == 0) - && pg_strcasecmp(prev2_wd, "ISOLATION") == 0 - && pg_strcasecmp(prev_wd, "LEVEL") == 0) - { - static const char *const my_list[] = - {"READ", "REPEATABLE", "SERIALIZABLE", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 || - pg_strcasecmp(prev4_wd, "WORK") == 0) && - pg_strcasecmp(prev3_wd, "ISOLATION") == 0 && - pg_strcasecmp(prev2_wd, "LEVEL") == 0 && - pg_strcasecmp(prev_wd, "READ") == 0) - { - static const char *const my_list[] = - {"UNCOMMITTED", "COMMITTED", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 || - pg_strcasecmp(prev4_wd, "WORK") == 0) && - pg_strcasecmp(prev3_wd, "ISOLATION") == 0 && - pg_strcasecmp(prev2_wd, "LEVEL") == 0 && - pg_strcasecmp(prev_wd, "REPEATABLE") == 0) - COMPLETE_WITH_CONST("READ"); - else if ((pg_strcasecmp(prev3_wd, "SET") == 0 || - pg_strcasecmp(prev3_wd, "BEGIN") == 0 || - pg_strcasecmp(prev3_wd, "START") == 0 || - pg_strcasecmp(prev3_wd, "AS") == 0) && - (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 || - pg_strcasecmp(prev2_wd, "WORK") == 0) && - pg_strcasecmp(prev_wd, "READ") == 0) - { - static const char *const my_list[] = - {"ONLY", "WRITE", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - /* Complete SET CONSTRAINTS with DEFERRED|IMMEDIATE */ - else if (pg_strcasecmp(prev3_wd, "SET") == 0 && - pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0) - { - static const char *const constraint_list[] = - {"DEFERRED", "IMMEDIATE", NULL}; - - COMPLETE_WITH_LIST(constraint_list); - } - /* Complete SET ROLE */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "ROLE") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_roles); - /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev_wd, "SESSION") == 0) - { - static const char *const my_list[] = - {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - /* Complete SET SESSION AUTHORIZATION with username */ - else if (pg_strcasecmp(prev3_wd, "SET") == 0 - && pg_strcasecmp(prev2_wd, "SESSION") == 0 - && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'"); - /* Complete RESET SESSION with AUTHORIZATION */ - else if (pg_strcasecmp(prev2_wd, "RESET") == 0 && - pg_strcasecmp(prev_wd, "SESSION") == 0) - COMPLETE_WITH_CONST("AUTHORIZATION"); - /* Complete SET with "TO" */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev4_wd, "UPDATE") != 0 && - pg_strcasecmp(prev_wd, "TABLESPACE") != 0 && - pg_strcasecmp(prev_wd, "SCHEMA") != 0 && - prev_wd[strlen(prev_wd) - 1] != ')' && - pg_strcasecmp(prev4_wd, "DOMAIN") != 0) - COMPLETE_WITH_CONST("TO"); - /* Suggest possible variable values */ - else if (pg_strcasecmp(prev3_wd, "SET") == 0 && - (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0)) - { - if (pg_strcasecmp(prev2_wd, "DateStyle") == 0) - { - static const char *const my_list[] = - {"ISO", "SQL", "Postgres", "German", - "YMD", "DMY", "MDY", - "US", "European", "NonEuropean", - "DEFAULT", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0) - { - static const char *const my_list[] = - {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else if (pg_strcasecmp(prev2_wd, "GEQO") == 0) - { - static const char *const my_list[] = - {"ON", "OFF", "DEFAULT", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - else - { - static const char *const my_list[] = - {"DEFAULT", NULL}; - - COMPLETE_WITH_LIST(my_list); - } - } - -/* START TRANSACTION */ - else if (pg_strcasecmp(prev_wd, "START") == 0) - COMPLETE_WITH_CONST("TRANSACTION"); - -/* TABLE, but not TABLE embedded in other commands */ - else if (pg_strcasecmp(prev_wd, "TABLE") == 0 && - prev2_wd[0] == '\0') - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL); - -/* TRUNCATE */ - else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); - -/* UNLISTEN */ - 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 '*'"); - -/* UPDATE */ - /* If prev. word is UPDATE suggest a list of tables */ - else if (pg_strcasecmp(prev_wd, "UPDATE") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL); - /* Complete UPDATE
with "SET" */ - else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0) - COMPLETE_WITH_CONST("SET"); - - /* - * 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, ""); - -/* UPDATE xx SET yy = */ - else if (pg_strcasecmp(prev2_wd, "SET") == 0 && - pg_strcasecmp(prev4_wd, "UPDATE") == 0) - COMPLETE_WITH_CONST("="); - -/* USER MAPPING */ - else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 || - pg_strcasecmp(prev3_wd, "CREATE") == 0 || - pg_strcasecmp(prev3_wd, "DROP") == 0) && - pg_strcasecmp(prev2_wd, "USER") == 0 && - pg_strcasecmp(prev_wd, "MAPPING") == 0) - 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_tables, - " UNION SELECT 'FULL'" - " UNION SELECT 'FREEZE'" - " UNION SELECT 'ANALYZE'" - " UNION SELECT 'VERBOSE'"); - else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 && - (pg_strcasecmp(prev_wd, "FULL") == 0 || - pg_strcasecmp(prev_wd, "FREEZE") == 0)) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, - " 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_tables, - " 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_tables, - " 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_tables, - " 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_tables, - " 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_tables, NULL); - -/* WITH [RECURSIVE] */ - - /* - * 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"); - -/* ANALYZE */ - /* If the previous word is ANALYZE, produce list of tables */ - else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tf, NULL); - -/* WHERE */ - /* Simple case of the word before the where being the table name */ - else if (pg_strcasecmp(prev_wd, "WHERE") == 0) - COMPLETE_WITH_ATTR(prev2_wd, ""); - -/* ... FROM ... */ -/* TODO: also include SRF ? */ - else if (pg_strcasecmp(prev_wd, "FROM") == 0 && - pg_strcasecmp(prev3_wd, "COPY") != 0 && - pg_strcasecmp(prev3_wd, "\\copy") != 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL); - -/* ... JOIN ... */ - else if (pg_strcasecmp(prev_wd, "JOIN") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL); - -/* Backslash commands */ -/* TODO: \dc \dd \dl */ - 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); - /* must be at end of \dF */ - 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_tsvf, 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); - - /* must be at end of \d list */ - 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(sql_commands); - 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 my_list[] = - {"format", "border", "expanded", - "null", "fieldsep", "tuples_only", "title", "tableattr", - "linestyle", "pager", "recordsep", NULL}; - - COMPLETE_WITH_LIST_CS(my_list); - } - else if (strcmp(prev2_wd, "\\pset") == 0) - { - if (strcmp(prev_wd, "format") == 0) - { - static const char *const my_list[] = - {"unaligned", "aligned", "wrapped", "html", "latex", - "troff-ms", NULL}; - - COMPLETE_WITH_LIST_CS(my_list); - } - else if (strcmp(prev_wd, "linestyle") == 0) - { - static const char *const my_list[] = - {"ascii", "old-ascii", "unicode", NULL}; - - COMPLETE_WITH_LIST_CS(my_list); - } - } - else if (strcmp(prev_wd, "\\set") == 0) - { - matches = complete_from_variables(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, complete_from_files); - } - - /* - * 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(""); + /* Clear a few things. */ + 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 a backslash command was started, continue */ + if (text[0] == '\\') + COMPLETE_WITH_LIST_CS(backslashCommands); + + /* Variable interpolation */ + else if (text[0] == ':' && text[1] != ':') { + if (text[1] == '\'') + matches = CompleteFromVariables(text, ":'", "'"); + else if (text[1] == '"') + matches = CompleteFromVariables(text, ":\"", "\""); + else + matches = CompleteFromVariables(text, ":", ""); + } + + /* If no previous word, suggest one of the basic sql commands */ + else if (PREV_WD[0] == '\0') + COMPLETE_WITH_LIST(sqlCommands); + + /* CREATE */ + /* complete with something you can create */ + else if (pg_strcasecmp(PREV_WD, "CREATE") == 0) + matches = completion_matches(text, CreateCommandGenerator); + + /* DROP, but not DROP embedded in other commands */ + /* complete with something you can drop */ + else if (pg_strcasecmp(PREV_WD, "DROP") == 0 && PREV2_WD[0] == '\0') + matches = completion_matches(text, DropCommandGenerator); + + /* ALTER */ + + /* + * 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", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", + "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION", + "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR", + "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE", + "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", + "USER", "USER MAPPING FOR", "VIEW", NULL}; + + COMPLETE_WITH_LIST(listAlter); + } + /* ALTER AGGREGATE,FUNCTION */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && + (pg_strcasecmp(PREV2_WD, "AGGREGATE") == 0 || pg_strcasecmp(PREV2_WD, "FUNCTION") == 0)) + COMPLETE_WITH_CONST("("); + /* ALTER AGGREGATE,FUNCTION (...) */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && + (pg_strcasecmp(PREV3_WD, "AGGREGATE") == 0 || pg_strcasecmp(PREV3_WD, "FUNCTION") == 0)) { + if (PREV_WD[strlen(PREV_WD) - 1] == ')') { + static const char *const listAlterAgg[] = { + "OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; + + COMPLETE_WITH_LIST(listAlterAgg); + } else { + char *tmpBuf = (char *)malloc(strlen(Query_for_list_of_arguments) + strlen(PREV2_WD)); + + sprintf(tmpBuf, Query_for_list_of_arguments, PREV2_WD); + COMPLETE_WITH_QUERY(tmpBuf); + free(tmpBuf); + } + } + + /* ALTER SCHEMA */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SCHEMA") == 0) { + static const char *const listAlterGen[] = { + "OWNER TO", "RENAME TO", NULL}; + + COMPLETE_WITH_LIST(listAlterGen); + } + + /* ALTER COLLATION */ + 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); + } + + /* ALTER CONVERSION */ + 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); + } + + /* ALTER DATABASE */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "DATABASE") == 0) { + static const char *const listAlterDatabase[] = { + "RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL}; + + COMPLETE_WITH_LIST(listAlterDatabase); + } + + /* ALTER EXTENSION */ + 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); + } + + /* ALTER FOREIGN */ + 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); + } + + /* ALTER FOREIGN DATA WRAPPER */ + else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "FOREIGN") == 0 && + pg_strcasecmp(PREV3_WD, "DATA") == 0 && pg_strcasecmp(PREV2_WD, "WRAPPER") == 0) { + static const char *const listAlterFdw[] = { + "HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL}; + + COMPLETE_WITH_LIST(listAlterFdw); + } + + /* ALTER FOREIGN TABLE */ + 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); + } + + /* ALTER INDEX */ + 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); + } + /* ALTER INDEX SET */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "INDEX") == 0 && + pg_strcasecmp(PREV_WD, "SET") == 0) { + static const char *const listAlterindexset[] = { + "(", "TABLESPACE", NULL}; + + COMPLETE_WITH_LIST(listAlterindexset); + } + /* ALTER INDEX RESET */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "INDEX") == 0 && + pg_strcasecmp(PREV_WD, "RESET") == 0) + COMPLETE_WITH_CONST("("); + /* ALTER INDEX SET|RESET ( */ + else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "INDEX") == 0 && + (pg_strcasecmp(PREV2_WD, "SET") == 0 || pg_strcasecmp(PREV2_WD, "RESET") == 0) && + pg_strcasecmp(PREV_WD, "(") == 0) { + static const char *const listIndexOptions[] = { + "fillfactor", "fastupdate", NULL}; + + COMPLETE_WITH_LIST(listIndexOptions); + } + + /* ALTER LANGUAGE */ + 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); + } + + /* ALTER LARGE OBJECT */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "LARGE") == 0 && + pg_strcasecmp(PREV2_WD, "OBJECT") == 0) { + static const char *const listAlterLargeObject[] = { + "OWNER TO", NULL}; + + COMPLETE_WITH_LIST(listAlterLargeObject); + } + + /* ALTER USER,ROLE */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && + !(pg_strcasecmp(PREV2_WD, "USER") == 0 && pg_strcasecmp(PREV_WD, "MAPPING") == 0) && + (pg_strcasecmp(PREV2_WD, "USER") == 0 || pg_strcasecmp(PREV2_WD, "ROLE") == 0)) { + static const char *const listAlterUser[] = { + "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", + "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE", + "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION", + "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET", + "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL}; + + COMPLETE_WITH_LIST(listAlterUser); + } + + /* ALTER USER,ROLE WITH */ + else if ((pg_strcasecmp(PREV4_WD, "ALTER") == 0 && + (pg_strcasecmp(PREV3_WD, "USER") == 0 || pg_strcasecmp(PREV3_WD, "ROLE") == 0) && + pg_strcasecmp(PREV_WD, "WITH") == 0)) { + /* Similar to the above, but don't complete "WITH" again. */ + static const char *const listAlterUserWith[] = { + "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", + "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE", + "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION", + "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET", + "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", NULL}; + + COMPLETE_WITH_LIST(listAlterUserWith); + } + + /* complete ALTER USER,ROLE ENCRYPTED,UNENCRYPTED with PASSWORD */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && + (pg_strcasecmp(PREV3_WD, "ROLE") == 0 || pg_strcasecmp(PREV3_WD, "USER") == 0) && + (pg_strcasecmp(PREV_WD, "ENCRYPTED") == 0 || pg_strcasecmp(PREV_WD, "UNENCRYPTED") == 0)) { + COMPLETE_WITH_CONST("PASSWORD"); + } + /* ALTER DEFAULT PRIVILEGES */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "DEFAULT") == 0 && + pg_strcasecmp(PREV_WD, "PRIVILEGES") == 0) { + static const char *const listAlterDefaultPrivileges[] = { + "FOR ROLE", "FOR USER", "IN SCHEMA", NULL}; + + COMPLETE_WITH_LIST(listAlterDefaultPrivileges); + } + /* ALTER DEFAULT PRIVILEGES FOR */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "DEFAULT") == 0 && + pg_strcasecmp(PREV2_WD, "PRIVILEGES") == 0 && pg_strcasecmp(PREV_WD, "FOR") == 0) { + static const char *const listAlterDefaultPrivileges_FOR[] = { + "ROLE", "USER", NULL}; + + COMPLETE_WITH_LIST(listAlterDefaultPrivileges_FOR); + } + /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */ + else if (pg_strcasecmp(PREV5_WD, "DEFAULT") == 0 && pg_strcasecmp(PREV4_WD, "PRIVILEGES") == 0 && + (pg_strcasecmp(PREV3_WD, "FOR") == 0 || pg_strcasecmp(PREV3_WD, "IN") == 0)) { + static const char *const listAlterDefaultPrivilegesRest[] = { + "GRANT", "REVOKE", NULL}; + + COMPLETE_WITH_LIST(listAlterDefaultPrivilegesRest); + } + /* ALTER DOMAIN */ + 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); + } + /* ALTER DOMAIN DROP */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "DOMAIN") == 0 && + pg_strcasecmp(PREV_WD, "DROP") == 0) { + static const char *const listAlterDomain2[] = { + "CONSTRAINT", "DEFAULT", "NOT NULL", NULL}; + + COMPLETE_WITH_LIST(listAlterDomain2); + } + /* ALTER DOMAIN RENAME */ + 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); + } + /* ALTER DOMAIN RENAME CONSTRAINT */ + else if (pg_strcasecmp(PREV5_WD, "DOMAIN") == 0 && pg_strcasecmp(PREV3_WD, "RENAME") == 0 && + pg_strcasecmp(PREV2_WD, "CONSTRAINT") == 0) + COMPLETE_WITH_CONST("TO"); + + /* ALTER DOMAIN SET */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "DOMAIN") == 0 && + pg_strcasecmp(PREV_WD, "SET") == 0) { + static const char *const listAlterDomain3[] = { + "DEFAULT", "NOT NULL", "SCHEMA", NULL}; + + COMPLETE_WITH_LIST(listAlterDomain3); + } + /* ALTER SEQUENCE */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SEQUENCE") == 0) { + static const char *const listAlterSequence[] = { + "INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE", + "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL}; + + COMPLETE_WITH_LIST(listAlterSequence); + } + /* ALTER SEQUENCE NO */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "SEQUENCE") == 0 && + pg_strcasecmp(PREV_WD, "NO") == 0) { + static const char *const listAlterSequencE2[] = { + "MINVALUE", "MAXVALUE", "CYCLE", NULL}; + + COMPLETE_WITH_LIST(listAlterSequencE2); + } + /* ALTER SERVER */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "SERVER") == 0) { + static const char *const listAlterServer[] = { + "VERSION", "OPTIONS", "OWNER TO", NULL}; + + COMPLETE_WITH_LIST(listAlterServer); + } + /* ALTER VIEW */ + 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); + } + /* ALTER TRIGGER , add ON */ + 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 ON, then add the correct tablename + */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TRIGGER") == 0 && + pg_strcasecmp(PREV_WD, "ON") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + + /* ALTER TRIGGER ON */ + else if (pg_strcasecmp(PREV4_WD, "TRIGGER") == 0 && pg_strcasecmp(PREV2_WD, "ON") == 0) + COMPLETE_WITH_CONST("RENAME TO"); + + /* + * If we detect ALTER TABLE , suggest sub commands + */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TABLE") == 0) { + 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); + } + /* ALTER TABLE xxx ENABLE */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TABLE") == 0 && + pg_strcasecmp(PREV_WD, "ENABLE") == 0) { + static const char *const 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); + } + + /* ALTER TABLE xxx ALTER */ + 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'"); + + /* ALTER TABLE xxx RENAME */ + 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 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, ""); + + /* ALTER TABLE xxx RENAME yyy */ + else if (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV2_WD, "RENAME") == 0 && + pg_strcasecmp(PREV_WD, "CONSTRAINT") != 0 && pg_strcasecmp(PREV_WD, "TO") != 0) + COMPLETE_WITH_CONST("TO"); + + /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */ + else if (pg_strcasecmp(PREV5_WD, "TABLE") == 0 && pg_strcasecmp(PREV3_WD, "RENAME") == 0 && + (pg_strcasecmp(PREV2_WD, "COLUMN") == 0 || pg_strcasecmp(PREV2_WD, "CONSTRAINT") == 0) && + pg_strcasecmp(PREV_WD, "TO") != 0) + COMPLETE_WITH_CONST("TO"); + + /* If we have TABLE DROP, provide COLUMN or CONSTRAINT */ + else if (pg_strcasecmp(PREV3_WD, "TABLE") == 0 && pg_strcasecmp(PREV_WD, "DROP") == 0) { + static const char *const listTableDrop[] = { + "COLUMN", "CONSTRAINT", NULL}; + + COMPLETE_WITH_LIST(listTableDrop); + } + /* If we have TABLE DROP COLUMN, provide list of columns */ + 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, ""); + /* ALTER TABLE ALTER [COLUMN] */ + else if ((pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "COLUMN") == 0) || + (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV2_WD, "ALTER") == 0)) { + static const char *const listColumnAlter[] = { + "TYPE", "SET", "RESET", "DROP", NULL}; + + COMPLETE_WITH_LIST(listColumnAlter); + } + /* ALTER TABLE ALTER [COLUMN] SET */ + else if (((pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "COLUMN") == 0) || + (pg_strcasecmp(PREV5_WD, "TABLE") == 0 && pg_strcasecmp(PREV3_WD, "ALTER") == 0)) && + pg_strcasecmp(PREV_WD, "SET") == 0) { + static const char *const listColumnSet[] = { + "(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL}; + + COMPLETE_WITH_LIST(listColumnSet); + } + /* ALTER TABLE ALTER [COLUMN] SET ( */ + else if (((pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "COLUMN") == 0) || + pg_strcasecmp(PREV4_WD, "ALTER") == 0) && + pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "(") == 0) { + static const char *const listColumnOptions[] = { + "n_distinct", "n_distinct_inherited", NULL}; + + COMPLETE_WITH_LIST(listColumnOptions); + } + /* ALTER TABLE ALTER [COLUMN] SET STORAGE */ + else if (((pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "COLUMN") == 0) || + pg_strcasecmp(PREV4_WD, "ALTER") == 0) && + pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "STORAGE") == 0) { + static const char *const listColumnStorage[] = { + "PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL}; + + COMPLETE_WITH_LIST(listColumnStorage); + } + /* ALTER TABLE ALTER [COLUMN] DROP */ + else if (((pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "COLUMN") == 0) || + (pg_strcasecmp(PREV5_WD, "TABLE") == 0 && pg_strcasecmp(PREV3_WD, "ALTER") == 0)) && + pg_strcasecmp(PREV_WD, "DROP") == 0) { + static const char *const 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); + } + /* If we have TABLE SET, provide WITHOUT,TABLESPACE and SCHEMA */ + 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); + } + /* If we have TABLE SET TABLESPACE provide a list of tablespaces */ + else if (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV2_WD, "SET") == 0 && + pg_strcasecmp(PREV_WD, "TABLESPACE") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); + /* If we have TABLE SET WITHOUT provide CLUSTER or OIDS */ + else if (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && pg_strcasecmp(PREV2_WD, "SET") == 0 && + pg_strcasecmp(PREV_WD, "WITHOUT") == 0) { + static const char *const listTableSet2[] = { + "CLUSTER", "OIDS", NULL}; + + COMPLETE_WITH_LIST(listTableSet2); + } + /* ALTER TABLE RESET */ + else if (pg_strcasecmp(PREV3_WD, "TABLE") == 0 && pg_strcasecmp(PREV_WD, "RESET") == 0) + COMPLETE_WITH_CONST("("); + /* ALTER TABLE SET|RESET ( */ + else if (pg_strcasecmp(PREV4_WD, "TABLE") == 0 && + (pg_strcasecmp(PREV2_WD, "SET") == 0 || pg_strcasecmp(PREV2_WD, "RESET") == 0) && + pg_strcasecmp(PREV_WD, "(") == 0) { + 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); + } + + /* ALTER TABLESPACE with RENAME TO, OWNER TO, SET, RESET */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TABLESPACE") == 0) { + static const char *const listAlterTspc[] = { + "RENAME TO", "OWNER TO", "SET", "RESET", NULL}; + + COMPLETE_WITH_LIST(listAlterTspc); + } + /* ALTER TABLESPACE SET|RESET */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TABLESPACE") == 0 && + (pg_strcasecmp(PREV_WD, "SET") == 0 || pg_strcasecmp(PREV_WD, "RESET") == 0)) + COMPLETE_WITH_CONST("("); + /* ALTER TABLESPACE SET|RESET ( */ + else if (pg_strcasecmp(PREV5_WD, "ALTER") == 0 && pg_strcasecmp(PREV4_WD, "TABLESPACE") == 0 && + (pg_strcasecmp(PREV2_WD, "SET") == 0 || pg_strcasecmp(PREV2_WD, "RESET") == 0) && + pg_strcasecmp(PREV_WD, "(") == 0) { + static const char *const listTablespaceOptions[] = { + "seq_page_cost", "random_page_cost", NULL}; + + COMPLETE_WITH_LIST(listTablespaceOptions); + } + + /* ALTER TEXT SEARCH */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "TEXT") == 0 && + pg_strcasecmp(PREV_WD, "SEARCH") == 0) { + static const char *const 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); + } + + /* complete ALTER TYPE with actions */ + 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); + } + /* complete ALTER TYPE ADD with actions */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TYPE") == 0 && + pg_strcasecmp(PREV_WD, "ADD") == 0) { + static const char *const listAlterType[] = { + "ATTRIBUTE", "VALUE", NULL}; + + COMPLETE_WITH_LIST(listAlterType); + } + /* ALTER TYPE RENAME */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "TYPE") == 0 && + pg_strcasecmp(PREV_WD, "RENAME") == 0) { + static const char *const listAlterType[] = { + "ATTRIBUTE", "TO", NULL}; + + COMPLETE_WITH_LIST(listAlterType); + } + /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */ + else if (pg_strcasecmp(PREV5_WD, "TYPE") == 0 && pg_strcasecmp(PREV3_WD, "RENAME") == 0 && + pg_strcasecmp(PREV2_WD, "ATTRIBUTE") == 0) + COMPLETE_WITH_CONST("TO"); + + /* + * If we have TYPE ALTER/DROP/RENAME ATTRIBUTE, provide list of + * attributes + */ + else if (pg_strcasecmp(PREV4_WD, "TYPE") == 0 && + (pg_strcasecmp(PREV2_WD, "ALTER") == 0 || pg_strcasecmp(PREV2_WD, "DROP") == 0 || + pg_strcasecmp(PREV2_WD, "RENAME") == 0) && + pg_strcasecmp(PREV_WD, "ATTRIBUTE") == 0) + COMPLETE_WITH_ATTR(PREV3_WD, ""); + /* ALTER TYPE ALTER ATTRIBUTE */ + else if ((pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "ATTRIBUTE") == 0)) { + COMPLETE_WITH_CONST("TYPE"); + } + /* complete ALTER GROUP */ + else if (pg_strcasecmp(PREV3_WD, "ALTER") == 0 && pg_strcasecmp(PREV2_WD, "GROUP") == 0) { + static const char *const listAlterGroup[] = { + "ADD USER", "DROP USER", "RENAME TO", NULL}; + + COMPLETE_WITH_LIST(listAlterGroup); + } + /* complete ALTER GROUP ADD|DROP with USER */ + else if (pg_strcasecmp(PREV4_WD, "ALTER") == 0 && pg_strcasecmp(PREV3_WD, "GROUP") == 0 && + (pg_strcasecmp(PREV_WD, "ADD") == 0 || pg_strcasecmp(PREV_WD, "DROP") == 0)) + COMPLETE_WITH_CONST("USER"); + /* complete {ALTER} GROUP ADD|DROP USER with a user name */ + else if (pg_strcasecmp(PREV4_WD, "GROUP") == 0 && + (pg_strcasecmp(PREV2_WD, "ADD") == 0 || pg_strcasecmp(PREV2_WD, "DROP") == 0) && + pg_strcasecmp(PREV_WD, "USER") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_roles); + + /* BEGIN, END, ABORT */ + else if (pg_strcasecmp(PREV_WD, "BEGIN") == 0 || pg_strcasecmp(PREV_WD, "END") == 0 || + pg_strcasecmp(PREV_WD, "ABORT") == 0) { + static const char *const listTrans[] = { + "WORK", "TRANSACTION", NULL}; + + COMPLETE_WITH_LIST(listTrans); + } + /* COMMIT */ + else if (pg_strcasecmp(PREV_WD, "COMMIT") == 0) { + static const char *const listCommit[] = { + "WORK", "TRANSACTION", "PREPARED", NULL}; + + COMPLETE_WITH_LIST(listCommit); + } + /* RELEASE SAVEPOINT */ + else if (pg_strcasecmp(PREV_WD, "RELEASE") == 0) + COMPLETE_WITH_CONST("SAVEPOINT"); + /* ROLLBACK */ + else if (pg_strcasecmp(PREV_WD, "ROLLBACK") == 0) { + static const char *const listTrans[] = { + "WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL}; + + COMPLETE_WITH_LIST(listTrans); + } + /* CLUSTER */ + + /* + * If the previous word is CLUSTER and not without produce list of tables + */ + else if (pg_strcasecmp(PREV_WD, "CLUSTER") == 0 && pg_strcasecmp(PREV2_WD, "WITHOUT") != 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + /* If we have CLUSTER , then add "USING" */ + else if (pg_strcasecmp(PREV2_WD, "CLUSTER") == 0 && pg_strcasecmp(PREV_WD, "ON") != 0) { + COMPLETE_WITH_CONST("USING"); + } + + /* + * If we have CLUSTER USING, then add the index as well. + */ + else if (pg_strcasecmp(PREV3_WD, "CLUSTER") == 0 && pg_strcasecmp(PREV_WD, "USING") == 0) { + completion_info_charp = PREV2_WD; + COMPLETE_WITH_QUERY(Query_for_index_of_table); + } + + /* COMMENT */ + 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", "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(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"); + + /* COPY */ + + /* + * 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); + /* If we have COPY|BINARY , complete it with "TO" or "FROM" */ + else if (pg_strcasecmp(PREV2_WD, "COPY") == 0 || pg_strcasecmp(PREV2_WD, "\\copy") == 0 || + pg_strcasecmp(PREV2_WD, "BINARY") == 0) { + static const char *const listFromTo[] = { + "FROM", "TO", NULL}; + + COMPLETE_WITH_LIST(listFromTo); + } + /* If we have COPY|BINARY FROM|TO, complete with filename */ + else if ((pg_strcasecmp(PREV3_WD, "COPY") == 0 || pg_strcasecmp(PREV3_WD, "\\copy") == 0 || + pg_strcasecmp(PREV3_WD, "BINARY") == 0) && + (pg_strcasecmp(PREV_WD, "FROM") == 0 || pg_strcasecmp(PREV_WD, "TO") == 0)) { + completion_charp = ""; + matches = completion_matches(text, CompleteFromFiles); + } + + /* Handle COPY|BINARY FROM|TO filename */ + else if ((pg_strcasecmp(PREV4_WD, "COPY") == 0 || pg_strcasecmp(PREV4_WD, "\\copy") == 0 || + pg_strcasecmp(PREV4_WD, "BINARY") == 0) && + (pg_strcasecmp(PREV2_WD, "FROM") == 0 || pg_strcasecmp(PREV2_WD, "TO") == 0)) { + static const char *const listCopy[] = { + "BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL}; + + COMPLETE_WITH_LIST(listCopy); + } + + /* Handle COPY|BINARY FROM|TO filename CSV */ + else if (pg_strcasecmp(PREV_WD, "CSV") == 0 && + (pg_strcasecmp(PREV3_WD, "FROM") == 0 || pg_strcasecmp(PREV3_WD, "TO") == 0)) { + static const char *const listCsv[] = { + "HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL}; + + COMPLETE_WITH_LIST(listCsv); + } + + /* CREATE DATABASE */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "DATABASE") == 0) { + static const char *const listDatabase[] = { + "OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT", + NULL}; + + COMPLETE_WITH_LIST(listDatabase); + } 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); + + /* CREATE EXTENSION */ + /* Complete with available extensions rather than installed ones. */ + else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "EXTENSION") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions); + /* CREATE EXTENSION */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "EXTENSION") == 0) + COMPLETE_WITH_CONST("WITH SCHEMA"); + + /* CREATE FOREIGN */ + else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "FOREIGN") == 0) { + static const char *const listCreateForeign[] = { + "DATA WRAPPER", "TABLE", NULL}; + + COMPLETE_WITH_LIST(listCreateForeign); + } + + /* CREATE FOREIGN DATA WRAPPER */ + else if (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "FOREIGN") == 0 && + pg_strcasecmp(PREV3_WD, "DATA") == 0 && pg_strcasecmp(PREV2_WD, "WRAPPER") == 0) { + static const char *const listCreateForeignDataWrapper[] = { + "HANDLER", "VALIDATOR", NULL}; + + COMPLETE_WITH_LIST(listCreateForeignDataWrapper); + } + + /* CREATE INDEX */ + /* First off we complete CREATE UNIQUE with "INDEX" */ + else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "UNIQUE") == 0) + COMPLETE_WITH_CONST("INDEX"); + /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */ + else if (pg_strcasecmp(PREV_WD, "INDEX") == 0 && + (pg_strcasecmp(PREV2_WD, "CREATE") == 0 || pg_strcasecmp(PREV2_WD, "UNIQUE") == 0)) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, " UNION SELECT 'ON'" + " UNION SELECT 'CONCURRENTLY'"); + /* Complete ... INDEX [] ON with a list of tables */ + else if ((pg_strcasecmp(PREV3_WD, "INDEX") == 0 || pg_strcasecmp(PREV2_WD, "INDEX") == 0 || + pg_strcasecmp(PREV2_WD, "CONCURRENTLY") == 0) && + pg_strcasecmp(PREV_WD, "ON") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + /* If we have CREATE|UNIQUE INDEX CONCURRENTLY, then add "ON" */ + else if ((pg_strcasecmp(PREV3_WD, "INDEX") == 0 || pg_strcasecmp(PREV2_WD, "INDEX") == 0) && + pg_strcasecmp(PREV_WD, "CONCURRENTLY") == 0) + COMPLETE_WITH_CONST("ON"); + /* If we have CREATE|UNIQUE INDEX , then add "ON" or "CONCURRENTLY" */ + else if ((pg_strcasecmp(PREV3_WD, "CREATE") == 0 || pg_strcasecmp(PREV3_WD, "UNIQUE") == 0) && + pg_strcasecmp(PREV2_WD, "INDEX") == 0) { + static const char *const listCreateIndex[] = { + "CONCURRENTLY", "ON", NULL}; + + COMPLETE_WITH_LIST(listCreateIndex); + } + + /* + * Complete INDEX ON
with a list of table columns (which + * should really be in parens) + */ + else if ((pg_strcasecmp(PREV4_WD, "INDEX") == 0 || pg_strcasecmp(PREV3_WD, "INDEX") == 0 || + pg_strcasecmp(PREV3_WD, "CONCURRENTLY") == 0) && + pg_strcasecmp(PREV2_WD, "ON") == 0) { + static const char *const 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, ""); + /* same if you put in USING */ + else if (pg_strcasecmp(PREV5_WD, "ON") == 0 && pg_strcasecmp(PREV3_WD, "USING") == 0 && + pg_strcasecmp(PREV_WD, "(") == 0) + COMPLETE_WITH_ATTR(PREV4_WD, ""); + /* Complete USING with an index method */ + else if (pg_strcasecmp(PREV_WD, "USING") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); + else if (pg_strcasecmp(PREV4_WD, "ON") == 0 && pg_strcasecmp(PREV2_WD, "USING") == 0) + COMPLETE_WITH_CONST("("); + + /* CREATE RULE */ + /* Complete "CREATE RULE " with "AS" */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "RULE") == 0) + COMPLETE_WITH_CONST("AS"); + /* Complete "CREATE RULE AS with "ON" */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "RULE") == 0 && + pg_strcasecmp(PREV_WD, "AS") == 0) + COMPLETE_WITH_CONST("ON"); + /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */ + else if (pg_strcasecmp(PREV4_WD, "RULE") == 0 && pg_strcasecmp(PREV2_WD, "AS") == 0 && + pg_strcasecmp(PREV_WD, "ON") == 0) { + static const char *const ruleEvents[] = { + "SELECT", "UPDATE", "INSERT", "DELETE", NULL}; + + COMPLETE_WITH_LIST(ruleEvents); + } + /* Complete "AS ON " with a "TO" */ + else if (pg_strcasecmp(PREV3_WD, "AS") == 0 && pg_strcasecmp(PREV2_WD, "ON") == 0 && + (pg_toupper((unsigned char)PREV_WD[4]) == 'T' || pg_toupper((unsigned char)PREV_WD[5]) == 'T')) + COMPLETE_WITH_CONST("TO"); + /* Complete "AS ON TO" with a table name */ + else if (pg_strcasecmp(PREV4_WD, "AS") == 0 && pg_strcasecmp(PREV3_WD, "ON") == 0 && + pg_strcasecmp(PREV_WD, "TO") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + + /* CREATE SERVER */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "SERVER") == 0) { + static const char *const list_CREATE_SERVER[] = { + "TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL}; + + COMPLETE_WITH_LIST(list_CREATE_SERVER); + } + + /* CREATE TABLE */ + /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */ + else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && + (pg_strcasecmp(PREV_WD, "TEMP") == 0 || pg_strcasecmp(PREV_WD, "TEMPORARY") == 0)) { + static const char *const listTemp[] = { + "SEQUENCE", "TABLE", "VIEW", NULL}; + + COMPLETE_WITH_LIST(listTemp); + } + /* Complete "CREATE UNLOGGED" with TABLE */ + else if (pg_strcasecmp(PREV2_WD, "CREATE") == 0 && pg_strcasecmp(PREV_WD, "UNLOGGED") == 0) { + COMPLETE_WITH_CONST("TABLE"); + } + + /* CREATE TABLESPACE */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "TABLESPACE") == 0) { + static const char *const listCreateTablespace[] = { + "OWNER", "LOCATION", NULL}; + + COMPLETE_WITH_LIST(listCreateTablespace); + } + /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */ + else if (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "TABLESPACE") == 0 && + pg_strcasecmp(PREV2_WD, "OWNER") == 0) { + COMPLETE_WITH_CONST("LOCATION"); + } + + /* CREATE TEXT SEARCH */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "TEXT") == 0 && + pg_strcasecmp(PREV_WD, "SEARCH") == 0) { + static const char *const 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("("); + + /* CREATE TRIGGER */ + /* complete CREATE TRIGGER with BEFORE,AFTER */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "TRIGGER") == 0) { + static const char *const listCreateTrigger[] = { + "BEFORE", "AFTER", "INSTEAD OF", NULL}; + + COMPLETE_WITH_LIST(listCreateTrigger); + } + /* complete CREATE TRIGGER BEFORE,AFTER with an event */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "TRIGGER") == 0 && + (pg_strcasecmp(PREV_WD, "BEFORE") == 0 || pg_strcasecmp(PREV_WD, "AFTER") == 0)) { + static const char *const listCreateTriggerEvents[] = { + "INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL}; + + COMPLETE_WITH_LIST(listCreateTriggerEvents); + } + /* complete CREATE TRIGGER INSTEAD OF with an event */ + else if (pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "TRIGGER") == 0 && + pg_strcasecmp(PREV2_WD, "INSTEAD") == 0 && pg_strcasecmp(PREV_WD, "OF") == 0) { + static const char *const listCreateTriggerEvents[] = { + "INSERT", "DELETE", "UPDATE", NULL}; + + COMPLETE_WITH_LIST(listCreateTriggerEvents); + } + /* complete CREATE TRIGGER BEFORE,AFTER sth with OR,ON */ + else if ((pg_strcasecmp(PREV5_WD, "CREATE") == 0 && pg_strcasecmp(PREV4_WD, "TRIGGER") == 0 && + (pg_strcasecmp(PREV2_WD, "BEFORE") == 0 || pg_strcasecmp(PREV2_WD, "AFTER") == 0)) || + (pg_strcasecmp(PREV5_WD, "TRIGGER") == 0 && pg_strcasecmp(PREV3_WD, "INSTEAD") == 0 && + pg_strcasecmp(PREV2_WD, "OF") == 0)) { + static const char *const listCreateTrigger2[] = { + "ON", "OR", NULL}; + + COMPLETE_WITH_LIST(listCreateTrigger2); + } + + /* + * complete CREATE TRIGGER BEFORE,AFTER event ON with a list of + * tables + */ + else if (pg_strcasecmp(PREV5_WD, "TRIGGER") == 0 && + (pg_strcasecmp(PREV3_WD, "BEFORE") == 0 || pg_strcasecmp(PREV3_WD, "AFTER") == 0) && + pg_strcasecmp(PREV_WD, "ON") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */ + else if (pg_strcasecmp(PREV4_WD, "INSTEAD") == 0 && pg_strcasecmp(PREV3_WD, "OF") == 0 && + pg_strcasecmp(PREV_WD, "ON") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); + /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */ + else if (pg_strcasecmp(PREV_WD, "EXECUTE") == 0 && PREV2_WD[0] != '\0') + COMPLETE_WITH_CONST("PROCEDURE"); + + /* CREATE ROLE,USER,GROUP */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && + !(pg_strcasecmp(PREV2_WD, "USER") == 0 && pg_strcasecmp(PREV_WD, "MAPPING") == 0) && + (pg_strcasecmp(PREV2_WD, "ROLE") == 0 || pg_strcasecmp(PREV2_WD, "GROUP") == 0 || + pg_strcasecmp(PREV2_WD, "USER") == 0)) { + static const char *const listCreateRole[] = { + "ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", + "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB", + "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN", + "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE", + "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL}; + + COMPLETE_WITH_LIST(listCreateRole); + } + + /* CREATE ROLE,USER,GROUP WITH */ + else if ((pg_strcasecmp(PREV4_WD, "CREATE") == 0 && + (pg_strcasecmp(PREV3_WD, "ROLE") == 0 || pg_strcasecmp(PREV3_WD, "GROUP") == 0 || + pg_strcasecmp(PREV3_WD, "USER") == 0) && + pg_strcasecmp(PREV_WD, "WITH") == 0)) { + /* Similar to the above, but don't complete "WITH" again. */ + static const char *const listCreateRoleWith[] = { + "ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER", + "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB", + "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN", + "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE", + "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", NULL}; + + COMPLETE_WITH_LIST(listCreateRoleWith); + } + + /* + * complete CREATE ROLE,USER,GROUP ENCRYPTED,UNENCRYPTED with + * PASSWORD + */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && + (pg_strcasecmp(PREV3_WD, "ROLE") == 0 || pg_strcasecmp(PREV3_WD, "GROUP") == 0 || + pg_strcasecmp(PREV3_WD, "USER") == 0) && + (pg_strcasecmp(PREV_WD, "ENCRYPTED") == 0 || pg_strcasecmp(PREV_WD, "UNENCRYPTED") == 0)) { + COMPLETE_WITH_CONST("PASSWORD"); + } + /* complete CREATE ROLE,USER,GROUP IN with ROLE,GROUP */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && + (pg_strcasecmp(PREV3_WD, "ROLE") == 0 || pg_strcasecmp(PREV3_WD, "GROUP") == 0 || + pg_strcasecmp(PREV3_WD, "USER") == 0) && + pg_strcasecmp(PREV_WD, "IN") == 0) { + static const char *const listCreateRole3[] = { + "GROUP", "ROLE", NULL}; + + COMPLETE_WITH_LIST(listCreateRole3); + } + + /* CREATE VIEW */ + /* Complete CREATE VIEW with AS */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") == 0 && pg_strcasecmp(PREV2_WD, "VIEW") == 0) + COMPLETE_WITH_CONST("AS"); + /* Complete "CREATE VIEW AS with "SELECT" */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") == 0 && pg_strcasecmp(PREV3_WD, "VIEW") == 0 && + pg_strcasecmp(PREV_WD, "AS") == 0) + COMPLETE_WITH_CONST("SELECT"); + + /* DECLARE */ + else if (pg_strcasecmp(PREV2_WD, "DECLARE") == 0) { + static const char *const listDeclare[] = { + "BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL}; + + COMPLETE_WITH_LIST(listDeclare); + } + + /* CURSOR */ + else if (pg_strcasecmp(PREV_WD, "CURSOR") == 0) { + static const char *const listDeclareCursor[] = { + "WITH HOLD", "WITHOUT HOLD", "FOR", NULL}; + + COMPLETE_WITH_LIST(listDeclareCursor); + } + + + /* DELETE */ + + /* + * 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"); + /* Complete DELETE FROM with a list of tables */ + else if (pg_strcasecmp(PREV2_WD, "DELETE") == 0 && pg_strcasecmp(PREV_WD, "FROM") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL); + /* Complete DELETE FROM
*/ + else if (pg_strcasecmp(PREV3_WD, "DELETE") == 0 && pg_strcasecmp(PREV2_WD, "FROM") == 0) { + static const char *const listDelete[] = { + "USING", "WHERE", "SET", NULL}; + + COMPLETE_WITH_LIST(listDelete); + } + /* XXX: implement tab completion for DELETE ... USING */ + + /* DISCARD */ + else if (pg_strcasecmp(PREV_WD, "DISCARD") == 0) { + static const char *const listDiscard[] = { + "ALL", "PLANS", "TEMP", NULL}; + + COMPLETE_WITH_LIST(listDiscard); + } + + /* DO */ + + /* + * Complete DO with LANGUAGE. + */ + else if (pg_strcasecmp(PREV_WD, "DO") == 0) { + static const char *const listDo[] = { + "LANGUAGE", NULL}; + + COMPLETE_WITH_LIST(listDo); + } + + /* DROP (when not the previous word) */ + /* DROP AGGREGATE */ + else if (pg_strcasecmp(PREV3_WD, "DROP") == 0 && pg_strcasecmp(PREV2_WD, "AGGREGATE") == 0) + COMPLETE_WITH_CONST("("); + + /* DROP object with CASCADE / RESTRICT */ + else if ((pg_strcasecmp(PREV3_WD, "DROP") == 0 && (pg_strcasecmp(PREV2_WD, "COLLATION") == 0 || + pg_strcasecmp(PREV2_WD, "CONVERSION") == 0 || pg_strcasecmp(PREV2_WD, "DOMAIN") == 0 || + pg_strcasecmp(PREV2_WD, "EXTENSION") == 0 || pg_strcasecmp(PREV2_WD, "FUNCTION") == 0 || + pg_strcasecmp(PREV2_WD, "INDEX") == 0 || pg_strcasecmp(PREV2_WD, "LANGUAGE") == 0 || + pg_strcasecmp(PREV2_WD, "SCHEMA") == 0 || pg_strcasecmp(PREV2_WD, "SEQUENCE") == 0 || + pg_strcasecmp(PREV2_WD, "SERVER") == 0 || pg_strcasecmp(PREV2_WD, "TABLE") == 0 || + pg_strcasecmp(PREV2_WD, "TYPE") == 0 || pg_strcasecmp(PREV2_WD, "VIEW") == 0)) || + (pg_strcasecmp(PREV4_WD, "DROP") == 0 && pg_strcasecmp(PREV3_WD, "AGGREGATE") == 0 && + PREV_WD[strlen(PREV_WD) - 1] == ')') || + (pg_strcasecmp(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(PREV4_WD, "DROP") == 0 && + (pg_strcasecmp(PREV3_WD, "AGGREGATE") == 0 || pg_strcasecmp(PREV3_WD, "FUNCTION") == 0) && + pg_strcasecmp(PREV_WD, "(") == 0) { + char *tmpBuf = (char *)malloc(strlen(Query_for_list_of_arguments) + strlen(PREV2_WD)); + + sprintf(tmpBuf, Query_for_list_of_arguments, PREV2_WD); + COMPLETE_WITH_QUERY(tmpBuf); + free(tmpBuf); + } + /* DROP OWNED BY */ + 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); + } + + /* EXECUTE, but not EXECUTE embedded in other commands */ + else if (pg_strcasecmp(PREV_WD, "EXECUTE") == 0 && PREV2_WD[0] == '\0') + COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements); + + /* EXPLAIN */ + + /* + * 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", 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); + } + + /* FETCH && MOVE */ + /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */ + else if (pg_strcasecmp(PREV_WD, "FETCH") == 0 || pg_strcasecmp(PREV_WD, "MOVE") == 0) { + static const char *const listFetch1[] = { + "ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL}; + + COMPLETE_WITH_LIST(listFetch1); + } + /* Complete FETCH with one of ALL, NEXT, PRIOR */ + else if (pg_strcasecmp(PREV2_WD, "FETCH") == 0 || pg_strcasecmp(PREV2_WD, "MOVE") == 0) { + static const char *const list_FETCH2[] = { + "ALL", "NEXT", "PRIOR", NULL}; + + COMPLETE_WITH_LIST(list_FETCH2); + } + + /* + * Complete FETCH with "FROM" or "IN". These are equivalent, + * but we may as well tab-complete both: perhaps some users prefer one + * variant or the other. + */ + else if (pg_strcasecmp(PREV3_WD, "FETCH") == 0 || pg_strcasecmp(PREV3_WD, "MOVE") == 0) { + static const char *const listFromin[] = { + "FROM", "IN", NULL}; + + COMPLETE_WITH_LIST(listFromin); + } + + /* FOREIGN DATA WRAPPER */ + /* applies in ALTER/DROP FDW and in CREATE SERVER */ + else if (pg_strcasecmp(PREV4_WD, "CREATE") != 0 && pg_strcasecmp(PREV3_WD, "FOREIGN") == 0 && + pg_strcasecmp(PREV2_WD, "DATA") == 0 && pg_strcasecmp(PREV_WD, "WRAPPER") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_fdws); + + /* FOREIGN TABLE */ + else if (pg_strcasecmp(PREV3_WD, "CREATE") != 0 && pg_strcasecmp(PREV2_WD, "FOREIGN") == 0 && + pg_strcasecmp(PREV_WD, "TABLE") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL); + + /* GRANT && REVOKE */ + /* Complete GRANT/REVOKE with a list of roles and privileges */ + else if (pg_strcasecmp(PREV_WD, "GRANT") == 0 || pg_strcasecmp(PREV_WD, "REVOKE") == 0) { + 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'"); + } + + /* + * Complete GRANT/REVOKE with "ON", GRANT/REVOKE 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 || pg_strcasecmp(PREV_WD, "ALL") == 0) + COMPLETE_WITH_CONST("ON"); + else { + if (pg_strcasecmp(PREV2_WD, "GRANT") == 0) + COMPLETE_WITH_CONST("TO"); + else + COMPLETE_WITH_CONST("FROM"); + } + } + + /* + * Complete GRANT/REVOKE 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'"); + 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); + } + + /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */ + else if ((pg_strcasecmp(PREV4_WD, "GRANT") == 0 || pg_strcasecmp(PREV4_WD, "REVOKE") == 0) && + pg_strcasecmp(PREV2_WD, "ON") == 0) { + 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(PREV4_WD, "GRANT") == 0) + COMPLETE_WITH_CONST("TO"); + else + COMPLETE_WITH_CONST("FROM"); + } + + /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */ + else if (pg_strcasecmp(PREV5_WD, "GRANT") == 0 && pg_strcasecmp(PREV3_WD, "ON") == 0) { + 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"); + } + + /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */ + else if (pg_strcasecmp(PREV3_WD, "GRANT") == 0 && pg_strcasecmp(PREV_WD, "TO") == 0) { + COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); + } else if (pg_strcasecmp(PREV3_WD, "REVOKE") == 0 && pg_strcasecmp(PREV_WD, "FROM") == 0) { + COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles); + } + + /* GROUP BY */ + else if (pg_strcasecmp(PREV3_WD, "FROM") == 0 && pg_strcasecmp(PREV_WD, "GROUP") == 0) + COMPLETE_WITH_CONST("BY"); + + /* INSERT */ + /* Complete INSERT with "INTO" */ + else if (pg_strcasecmp(PREV_WD, "INSERT") == 0) + COMPLETE_WITH_CONST("INTO"); + /* Complete INSERT INTO with table names */ + else if (pg_strcasecmp(PREV2_WD, "INSERT") == 0 && pg_strcasecmp(PREV_WD, "INTO") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL); + /* Complete "INSERT INTO
(" with attribute names */ + else if (pg_strcasecmp(PREV4_WD, "INSERT") == 0 && pg_strcasecmp(PREV3_WD, "INTO") == 0 && + pg_strcasecmp(PREV_WD, "(") == 0) + COMPLETE_WITH_ATTR(PREV2_WD, ""); + + /* + * Complete INSERT INTO
with "(" or "VALUES" or "SELECT" or + * "TABLE" or "DEFAULT VALUES" + */ + else if (pg_strcasecmp(PREV3_WD, "INSERT") == 0 && pg_strcasecmp(PREV2_WD, "INTO") == 0) { + static const char *const listInsert[] = { + "(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL}; + + COMPLETE_WITH_LIST(listInsert); + } + + /* + * Complete INSERT INTO
(attribs) with "VALUES" or "SELECT" or + * "TABLE" + */ + else if (pg_strcasecmp(PREV4_WD, "INSERT") == 0 && pg_strcasecmp(PREV3_WD, "INTO") == 0 && + PREV_WD[strlen(PREV_WD) - 1] == ')') { + static const char *const listInsert[] = { + "SELECT", "TABLE", "VALUES", NULL}; + + COMPLETE_WITH_LIST(listInsert); + } + + /* Insert an open parenthesis after "VALUES" */ + else if (pg_strcasecmp(PREV_WD, "VALUES") == 0 && pg_strcasecmp(PREV2_WD, "DEFAULT") != 0) + COMPLETE_WITH_CONST("("); + + /* LOCK */ + /* Complete LOCK [TABLE] with a list of tables */ + 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, ""); + + /* For the following, handle the case of a single table only for now */ + + /* Complete LOCK [TABLE]
with "IN" */ + else if ((pg_strcasecmp(PREV2_WD, "LOCK") == 0 && pg_strcasecmp(PREV_WD, "TABLE") != 0) || + (pg_strcasecmp(PREV2_WD, "TABLE") == 0 && pg_strcasecmp(PREV3_WD, "LOCK") == 0)) + COMPLETE_WITH_CONST("IN"); + + /* Complete LOCK [TABLE]
IN with a lock mode */ + else if (pg_strcasecmp(PREV_WD, "IN") == 0 && (pg_strcasecmp(PREV3_WD, "LOCK") == 0 || + (pg_strcasecmp(PREV3_WD, "TABLE") == 0 && pg_strcasecmp(PREV4_WD, "LOCK") == 0))) { + static const char *const 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); + } + + /* NOTIFY */ + 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'"); + + /* OPTIONS */ + else if (pg_strcasecmp(PREV_WD, "OPTIONS") == 0) + COMPLETE_WITH_CONST("("); + + /* OWNER TO - complete with available roles */ + else if (pg_strcasecmp(PREV2_WD, "OWNER") == 0 && pg_strcasecmp(PREV_WD, "TO") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_roles); + + /* ORDER BY */ + 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, ""); + + /* PREPARE xx AS */ + 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. + */ + + /* REASSIGN OWNED BY xxx TO yyy */ + 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); + + /* REINDEX */ + 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_tables, NULL); + else if (pg_strcasecmp(PREV_WD, "INDEX") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL); + else if (pg_strcasecmp(PREV_WD, "SYSTEM") == 0 || pg_strcasecmp(PREV_WD, "DATABASE") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_databases); + } + + /* SECURITY LABEL */ + else if (pg_strcasecmp(PREV_WD, "SECURITY") == 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", "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"); + + /* SELECT */ + /* naah . . . */ + + /* SET, RESET, SHOW */ + /* Complete with a variable name */ + else if ((pg_strcasecmp(PREV_WD, "SET") == 0 && pg_strcasecmp(PREV3_WD, "UPDATE") != 0) || + pg_strcasecmp(PREV_WD, "RESET") == 0) + 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); + /* Complete "SET TRANSACTION" */ + else if ((pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "TRANSACTION") == 0) || + (pg_strcasecmp(PREV2_WD, "START") == 0 && pg_strcasecmp(PREV_WD, "TRANSACTION") == 0) || + (pg_strcasecmp(PREV2_WD, "BEGIN") == 0 && pg_strcasecmp(PREV_WD, "WORK") == 0) || + (pg_strcasecmp(PREV2_WD, "BEGIN") == 0 && pg_strcasecmp(PREV_WD, "TRANSACTION") == 0) || + (pg_strcasecmp(PREV4_WD, "SESSION") == 0 && pg_strcasecmp(PREV3_WD, "CHARACTERISTICS") == 0 && + pg_strcasecmp(PREV2_WD, "AS") == 0 && pg_strcasecmp(PREV_WD, "TRANSACTION") == 0)) { + static const char *const 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); + } + /* Complete SET CONSTRAINTS with DEFERRED|IMMEDIATE */ + 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); + } + /* Complete SET ROLE */ + else if (pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "ROLE") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_roles); + /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */ + else if (pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV_WD, "SESSION") == 0) { + static const char *const myList[] = { + "AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL}; + + COMPLETE_WITH_LIST(myList); + } + /* Complete SET SESSION AUTHORIZATION with username */ + else if (pg_strcasecmp(PREV3_WD, "SET") == 0 && pg_strcasecmp(PREV2_WD, "SESSION") == 0 && + pg_strcasecmp(PREV_WD, "AUTHORIZATION") == 0) + COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'"); + /* Complete RESET SESSION with AUTHORIZATION */ + else if (pg_strcasecmp(PREV2_WD, "RESET") == 0 && pg_strcasecmp(PREV_WD, "SESSION") == 0) + COMPLETE_WITH_CONST("AUTHORIZATION"); + /* Complete SET with "TO" */ + else if (pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV4_WD, "UPDATE") != 0 && + pg_strcasecmp(PREV_WD, "TABLESPACE") != 0 && pg_strcasecmp(PREV_WD, "SCHEMA") != 0 && + PREV_WD[strlen(PREV_WD) - 1] != ')' && pg_strcasecmp(PREV4_WD, "DOMAIN") != 0) + COMPLETE_WITH_CONST("TO"); + /* Suggest possible variable values */ + else if (pg_strcasecmp(PREV3_WD, "SET") == 0 && (pg_strcasecmp(PREV_WD, "TO") == 0 || strcmp(PREV_WD, "=") == 0)) { + 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); + } + } + + /* START TRANSACTION */ + else if (pg_strcasecmp(PREV_WD, "START") == 0) + COMPLETE_WITH_CONST("TRANSACTION"); + + /* TABLE, but not TABLE embedded in other commands */ + else if (pg_strcasecmp(PREV_WD, "TABLE") == 0 && PREV2_WD[0] == '\0') + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL); + + /* TRUNCATE */ + else if (pg_strcasecmp(PREV_WD, "TRUNCATE") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + + /* UNLISTEN */ + 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 '*'"); + + /* UPDATE */ + /* If prev. word is UPDATE suggest a list of tables */ + else if (pg_strcasecmp(PREV_WD, "UPDATE") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL); + /* Complete UPDATE
with "SET" */ + else if (pg_strcasecmp(PREV2_WD, "UPDATE") == 0) + COMPLETE_WITH_CONST("SET"); + + /* + * 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, ""); + + /* UPDATE xx SET yy = */ + else if (pg_strcasecmp(PREV2_WD, "SET") == 0 && pg_strcasecmp(PREV4_WD, "UPDATE") == 0) + COMPLETE_WITH_CONST("="); + + /* USER MAPPING */ + else if ((pg_strcasecmp(PREV3_WD, "ALTER") == 0 || pg_strcasecmp(PREV3_WD, "CREATE") == 0 || + pg_strcasecmp(PREV3_WD, "DROP") == 0) && + pg_strcasecmp(PREV2_WD, "USER") == 0 && pg_strcasecmp(PREV_WD, "MAPPING") == 0) + 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_tables, " UNION SELECT 'FULL'" + " UNION SELECT 'FREEZE'" + " UNION SELECT 'ANALYZE'" + " UNION SELECT 'VERBOSE'"); + else if (pg_strcasecmp(PREV2_WD, "VACUUM") == 0 && + (pg_strcasecmp(PREV_WD, "FULL") == 0 || pg_strcasecmp(PREV_WD, "FREEZE") == 0)) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, " 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_tables, " 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_tables, " 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_tables, " 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_tables, " 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_tables, NULL); + + /* WITH [RECURSIVE] */ + + /* + * 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"); + + /* ANALYZE */ + /* If the previous word is ANALYZE, produce list of tables */ + else if (pg_strcasecmp(PREV_WD, "ANALYZE") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, NULL); + + /* WHERE */ + /* Simple case of the word before the where being the table name */ + else if (pg_strcasecmp(PREV_WD, "WHERE") == 0) + COMPLETE_WITH_ATTR(PREV2_WD, ""); + + /* ... FROM ... */ + /* TODO: also include SRF ? */ + else if (pg_strcasecmp(PREV_WD, "FROM") == 0 && pg_strcasecmp(PREV3_WD, "COPY") != 0 && + pg_strcasecmp(PREV3_WD, "\\copy") != 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL); + + /* ... JOIN ... */ + else if (pg_strcasecmp(PREV_WD, "JOIN") == 0) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL); + + /* Backslash commands */ + /* TODO: \dc \dd \dl */ + 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); + /* must be at end of \dF */ + 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); + + /* must be at end of \d list */ + 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(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'; + rl_completion_append_character = '\0'; #endif - } + } - /* free storage */ - { - int i; + /* free storage */ + { + int i; - for (i = 0; i < (int)lengthof(previous_words); i++) - free(previous_words[i]); - } + for (i = 0; i < (int)lengthof(previousWords); i++) + free(previousWords[i]); + } - /* Return our Grand List O' Matches */ - return matches; + /* Return our Grand List O' Matches */ + return matches; } /* @@ -3218,67 +2713,67 @@ psql_completion(const char *text, int start, int end) * * See top of file for examples of both kinds of query. */ -static char* _complete_from_query(int is_schema_query, const char* text, int state) +static char *_CompleteFromQuery(int isSchemaQuery, const char *text, int state) { - static int list_index, string_length; - static PGresult* result = NULL; + static int listIndex, stringLength; + static PGresult *result = NULL; /* * If this is the first time for this completion, we fetch a list of our * "things" from the backend. */ if (state == 0) { - PQExpBufferData query_buffer; - char* e_text = NULL; - char* e_info_charp = NULL; - char* e_info_charp2 = NULL; + PQExpBufferData queryBuffer; + char *eText = NULL; + char *eInfoCharp = NULL; + char *eInfoCharp2 = NULL; - list_index = 0; - string_length = strlen(text); + listIndex = 0; + stringLength = strlen(text); /* Free any prior result */ PQclear(result); result = NULL; /* Set up suitably-escaped copies of textual inputs */ - e_text = (char*)pg_malloc(string_length * 2 + 1); - PQescapeString(e_text, text, string_length); + eText = (char *)pg_malloc(stringLength * 2 + 1); + PQescapeString(eText, text, stringLength); if (NULL != completion_info_charp) { - size_t charp_len; + size_t charpLen; - charp_len = strlen(completion_info_charp); - e_info_charp = (char*)pg_malloc(charp_len * 2 + 1); - PQescapeString(e_info_charp, completion_info_charp, charp_len); + charpLen = strlen(completion_info_charp); + eInfoCharp = (char *)pg_malloc(charpLen * 2 + 1); + PQescapeString(eInfoCharp, completion_info_charp, charpLen); } else - e_info_charp = NULL; + eInfoCharp = NULL; if (NULL != completion_info_charp2) { - size_t charp_len; + size_t charpLen; - charp_len = strlen(completion_info_charp2); - e_info_charp2 = (char*)pg_malloc(charp_len * 2 + 1); - PQescapeString(e_info_charp2, completion_info_charp2, charp_len); + charpLen = strlen(completion_info_charp2); + eInfoCharp2 = (char *)pg_malloc(charpLen * 2 + 1); + PQescapeString(eInfoCharp2, completion_info_charp2, charpLen); } else - e_info_charp2 = NULL; + eInfoCharp2 = NULL; - initPQExpBuffer(&query_buffer); + initPQExpBuffer(&queryBuffer); - if (is_schema_query) { + if (isSchemaQuery) { /* completion_squery gives us the pieces to assemble */ - const char* qualresult = completion_squery->qualresult; + const char *qualresult = completion_squery->qualresult; if (qualresult == NULL) qualresult = completion_squery->result; /* Get unqualified names matching the input-so-far */ - appendPQExpBuffer( - &query_buffer, "SELECT %s FROM %s WHERE ", completion_squery->result, completion_squery->catname); + appendPQExpBuffer(&queryBuffer, "SELECT %s FROM %s WHERE ", completion_squery->result, + completion_squery->catname); if (NULL != completion_squery->selcondition) - appendPQExpBuffer(&query_buffer, "%s AND ", completion_squery->selcondition); - appendPQExpBuffer( - &query_buffer, "substring(%s,1,%d)='%s'", completion_squery->result, string_length, e_text); - appendPQExpBuffer(&query_buffer, " AND %s", completion_squery->viscondition); + 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 @@ -3287,8 +2782,7 @@ static char* _complete_from_query(int is_schema_query, const char* text, int sta * 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) { - appendPQExpBuffer(&query_buffer, - " AND c.relnamespace <> (SELECT oid FROM" + appendPQExpBuffer(&queryBuffer, " AND c.relnamespace <> (SELECT oid FROM" " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')"); } @@ -3296,97 +2790,82 @@ static char* _complete_from_query(int is_schema_query, const char* text, int sta * Add in matching schema names, but only if there is more than * one potential match among schema names. */ - appendPQExpBuffer(&query_buffer, + 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'", - string_length, - e_text); - appendPQExpBuffer(&query_buffer, + 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", - string_length, - e_text); + stringLength, eText); /* * Add in matching qualified names, but only if there is exactly * one schema matching the input-so-far. */ - appendPQExpBuffer(&query_buffer, + 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); + qualresult, completion_squery->catname, completion_squery->nameSpace); if (completion_squery->selcondition != NULL) - appendPQExpBuffer(&query_buffer, "%s AND ", completion_squery->selcondition); - appendPQExpBuffer(&query_buffer, - "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'", - qualresult, - string_length, - e_text); + 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(&query_buffer, + 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)", - string_length, - e_text); - appendPQExpBuffer(&query_buffer, + 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", - string_length, - e_text); + stringLength, eText); /* If an addon query was provided, use it */ if (NULL != completion_charp) - appendPQExpBuffer(&query_buffer, "\n%s", completion_charp); + appendPQExpBuffer(&queryBuffer, "\n%s", completion_charp); } else { /* completion_charp is an sprintf-style format string */ - appendPQExpBuffer(&query_buffer, - completion_charp, - string_length, - e_text, - e_info_charp, - e_info_charp, - e_info_charp2, - e_info_charp2); + appendPQExpBuffer(&queryBuffer, completion_charp, stringLength, eText, eInfoCharp, eInfoCharp, + eInfoCharp2, eInfoCharp2); } /* Limit the number of records in the result */ - appendPQExpBuffer(&query_buffer, "\nLIMIT %d", completion_max_records); + appendPQExpBuffer(&queryBuffer, "\nLIMIT %d", completion_max_records); - result = exec_query(query_buffer.data); + result = ExecQuery(queryBuffer.data); - termPQExpBuffer(&query_buffer); - free(e_text); - e_text = NULL; - if (e_info_charp != NULL) { - free(e_info_charp); - e_info_charp = NULL; + termPQExpBuffer(&queryBuffer); + free(eText); + eText = NULL; + if (eInfoCharp != NULL) { + free(eInfoCharp); + eInfoCharp = NULL; } - if (e_info_charp2 != NULL) { - free(e_info_charp2); - e_info_charp2 = NULL; + if (eInfoCharp2 != NULL) { + free(eInfoCharp2); + eInfoCharp2 = NULL; } } /* Find something that matches */ if (result && PQresultStatus(result) == PGRES_TUPLES_OK) { - const char* item = NULL; + const char *item = NULL; - while (list_index < PQntuples(result) && (item = PQgetvalue(result, list_index++, 0))) - if (pg_strncasecmp(text, item, string_length) == 0) + while (listIndex < PQntuples(result) && (item = PQgetvalue(result, listIndex++, 0))) + if (pg_strncasecmp(text, item, stringLength) == 0) return pg_strdup(item); } @@ -3402,32 +2881,32 @@ static char* _complete_from_query(int is_schema_query, const char* text, int sta * 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* complete_from_list(const char* text, int state) +static char *CompleteFromList(const char *text, int state) { - static int string_length, list_index, matches; + static int stringLength, listIndex, matches; static bool casesensitive = false; - const char* item = NULL; + const char *item = NULL; /* need to have a list */ psql_assert(completion_charpp); /* Initialization */ if (state == 0) { - list_index = 0; - string_length = strlen(text); + listIndex = 0; + stringLength = strlen(text); casesensitive = completion_case_sensitive; matches = 0; } - while ((item = completion_charpp[list_index++])) { + while ((item = completion_charpp[listIndex++])) { /* First pass is case sensitive */ - if (casesensitive && strncmp(text, item, string_length) == 0) { + if (casesensitive && strncmp(text, item, stringLength) == 0) { matches++; return pg_strdup(item); } /* Second pass is case insensitive, don't bother counting matches */ - if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0) { + if (!casesensitive && pg_strncasecmp(text, item, stringLength) == 0) { if (completion_case_sensitive) return pg_strdup(item); else @@ -3446,9 +2925,9 @@ static char* complete_from_list(const char* text, int state) */ if (casesensitive && matches == 0) { casesensitive = false; - list_index = 0; + listIndex = 0; state++; - return complete_from_list(text, state); + return CompleteFromList(text, state); } /* If no more matches, return null. */ @@ -3462,7 +2941,7 @@ static char* complete_from_list(const char* text, int state) * misspellings will be overwritten. The string to be passed must be in * completion_charp. */ -static char* complete_from_const(const char* text, int state) +static char *CompleteFromConst(const char *text, int state) { psql_assert(completion_charp); if (state == 0) { @@ -3484,27 +2963,27 @@ static char* complete_from_const(const char* text, int state) * The variable names can be prefixed and suffixed with additional text * to support quoting usages. */ -static char** complete_from_variables(const char* text, const char* prefix, const char* suffix) +static char **CompleteFromVariables(const char *text, const char *prefix, const char *suffix) { - char** matches = NULL; + char **matches = NULL; int overhead = strlen(prefix) + strlen(suffix) + 1; - char** varnames = NULL; + char **varnames = NULL; int nvars = 0; int maxvars = 100; int i; - struct _variable* ptr = NULL; + struct _variable *ptr = NULL; int rc; size_t sz = 0; - varnames = (char**)pg_malloc((maxvars + 1) * sizeof(char*)); + 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; + for (; ptr != NULL; ptr = ptr->next) { + char *buffer = NULL; if (nvars >= maxvars) { maxvars *= 2; - varnames = (char**)pg_realloc(varnames, (maxvars + 1) * sizeof(char*)); + varnames = (char **)pg_realloc(varnames, (maxvars + 1) * sizeof(char *)); if (varnames == NULL) { psql_error("out of memory\n"); exit(EXIT_FAILURE); @@ -3512,14 +2991,14 @@ static char** complete_from_variables(const char* text, const char* prefix, cons } sz = strlen(ptr->name) + overhead; - buffer = (char*)pg_malloc(sz); + 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); + COMPLETE_WITH_LIST_CS((const char * const *)varnames); for (i = 0; i < nvars; i++) { free(varnames[i]); @@ -3536,24 +3015,24 @@ static char** complete_from_variables(const char* text, const char* prefix, cons * the input before searching for matches and to quote any matches for which * the consuming command will require it. */ -static char* complete_from_files(const char* text, int state) +static char *CompleteFromFiles(const char *text, int state) { - static const char* unquoted_text = NULL; - char* unquoted_match = NULL; - char* ret = NULL; + static const char *unquotedText = NULL; + char *unquotedMatch = NULL; + char *ret = NULL; if (state == 0) { /* Initialization: stash the unquoted input. */ - unquoted_text = strtokx(text, "", NULL, "'", *completion_charp, false, true, pset.encoding); + unquotedText = strtokx(text, "", NULL, "'", *completion_charp, false, true, pset.encoding); /* expect a NULL return for the empty string only */ - if (NULL == unquoted_text) { + if (NULL == unquotedText) { psql_assert(!*text); - unquoted_text = text; + unquotedText = text; } } - unquoted_match = filename_completion_function(unquoted_text, state); - if (unquoted_match != NULL) { + 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 @@ -3561,12 +3040,12 @@ static char* complete_from_files(const char* text, int state) * "\" as an escape character. Since we have only two callers, don't * bother providing a macro to simplify this. */ - ret = quote_if_needed(unquoted_match, " \t\r\n\"`", '\'', *completion_charp, pset.encoding); + ret = quote_if_needed(unquotedMatch, " \t\r\n\"`", '\'', *completion_charp, pset.encoding); if (ret != NULL) { - free(unquoted_match); - unquoted_match = NULL; + free(unquotedMatch); + unquotedMatch = NULL; } else - ret = unquoted_match; + ret = unquotedMatch; } return ret; @@ -3578,13 +3057,13 @@ static char* complete_from_files(const char* text, int state) * 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) +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; + const char *varval = NULL; varval = GetVariable(pset.vars, "COMP_KEYWORD_CASE"); if (varval == NULL) @@ -3620,9 +3099,9 @@ static char* pg_strdup_keyword_case(const char* s, const char* ref) * Execute a query and report any errors. This should be the preferred way of * talking to the database in this file. */ -static PGresult* exec_query(const char* query) +static PGresult *ExecQuery(const char *query) { - PGresult* result = NULL; + PGresult *result = NULL; if (query == NULL || pset.db == NULL || PQstatus(pset.db) != CONNECTION_OK) return NULL; @@ -3639,13 +3118,13 @@ static PGresult* exec_query(const char* query) /* * Return the nwords word(s) before point. Words are returned right to left, - * that is, previous_words[0] gets the last word before point. + * 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 get_previous_words(int point, char** previous_words, int nwords) +static void GetPreviousWords(int point, char **previousWords, int nwords) { - const char* buf = rl_line_buffer; /* alias */ + const char *buf = rl_line_buffer; /* alias */ int i; errno_t rc = EOK; @@ -3657,7 +3136,7 @@ static void get_previous_words(int point, char** previous_words, int nwords) while (nwords-- > 0) { int start, end; - char* s = NULL; + char *s = NULL; /* now find the first non-space which then constitutes the end */ end = -1; @@ -3702,13 +3181,13 @@ static void get_previous_words(int point, char** previous_words, int nwords) point = start - 1; /* make a copy of chars from start to end inclusive */ - s = (char*)pg_malloc(end - start + 2); + 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"); } - *previous_words++ = s; + *previousWords++ = s; } } @@ -3719,9 +3198,9 @@ static void get_previous_words(int point, char** previous_words, int nwords) * psql internal. Currently disabled because it is reported not to * cooperate with certain versions of readline. */ -static char* quote_file_name(char* text, int match_type, char* quote_pointer) +static char *quote_file_name(char *text, int match_type, char *quote_pointer) { - char* s = NULL; + char *s = NULL; size_t length; int rc; @@ -3738,9 +3217,9 @@ static char* quote_file_name(char* text, int match_type, char* quote_pointer) return s; } -static char* dequote_file_name(char* text, char quote_char) +static char *dequote_file_name(char *text, char quote_char) { - char* s = NULL; + char *s = NULL; size_t length; errno_t rc = EOK;