/src/bin/psql/tab-complete.c
C | 4352 lines | 3625 code | 266 blank | 461 comment | 1092 complexity | bd95d0eaeff396c9dcede159ecb1fe98 MD5 | raw file
Possible License(s): AGPL-3.0
Large files files are truncated, but you can click here to view the full file
- /*
- * psql - the PostgreSQL interactive terminal
- *
- * Copyright (c) 2000-2014, PostgreSQL Global Development Group
- *
- * src/bin/psql/tab-complete.c
- */
- /*----------------------------------------------------------------------
- * This file implements a somewhat more sophisticated readline "TAB
- * completion" in psql. It is not intended to be AI, to replace
- * learning SQL, or to relieve you from thinking about what you're
- * doing. Also it does not always give you all the syntactically legal
- * completions, only those that are the most common or the ones that
- * the programmer felt most like implementing.
- *
- * CAVEAT: Tab completion causes queries to be sent to the backend.
- * The number of tuples returned gets limited, in most default
- * installations to 1000, but if you still don't like this prospect,
- * you can turn off tab completion in your ~/.inputrc (or else
- * ${INPUTRC}) file so:
- *
- * $if psql
- * set disable-completion on
- * $endif
- *
- * See `man 3 readline' or `info readline' for the full details. Also,
- * hence the
- *
- * BUGS:
- *
- * - If you split your queries across lines, this whole thing gets
- * confused. (To fix this, one would have to read psql's query
- * buffer rather than readline's line buffer, which would require
- * some major revisions of things.)
- *
- * - Table or attribute names with spaces in it may confuse it.
- *
- * - Quotes, parenthesis, and other funny characters are not handled
- * all that gracefully.
- *----------------------------------------------------------------------
- */
- #include "postgres_fe.h"
- #include "tab-complete.h"
- #include "input.h"
- /* If we don't have this, we might as well forget about the whole thing: */
- #ifdef USE_READLINE
- #include <ctype.h>
- #include "libpq-fe.h"
- #include "pqexpbuffer.h"
- #include "common.h"
- #include "settings.h"
- #include "stringutils.h"
- #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
- #define filename_completion_function rl_filename_completion_function
- #else
- /* missing in some header files */
- extern char *filename_completion_function();
- #endif
- #ifdef HAVE_RL_COMPLETION_MATCHES
- #define completion_matches rl_completion_matches
- #endif
- /* word break characters */
- #define WORD_BREAKS "\t\n@$><=;|&{() "
- /*
- * This struct is used to define "schema queries", which are custom-built
- * 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().
- */
- 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;
- /*
- * Selection condition --- only rows meeting this condition are candidates
- * to display. If catname mentions multiple tables, include the necessary
- * join condition here. For example, "c.relkind = 'r'". Write NULL (not
- * an empty string) if not needed.
- */
- 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;
- /*
- * Namespace --- name of field to join to pg_namespace.oid. For example,
- * "c.relnamespace".
- */
- 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;
- /*
- * 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;
- } SchemaQuery;
- /* Store maximum number of records we want from database queries
- * (implemented via SELECT ... LIMIT xx).
- */
- 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 *completion_charp; /* to pass a string */
- static const char *const * completion_charpp; /* to pass a list of strings */
- 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
- * string with
- * 1) The results from a query you pass it. (Perhaps one of those below?)
- * 2) The results from a schema query you pass it.
- * 3) The items from a null-pointer-terminated list.
- * 4) A string constant.
- * 5) The list of attributes of the given table (possibly schema-qualified).
- * 6/ The list of arguments to the given function (possibly schema-qualified).
- */
- #define COMPLETE_WITH_QUERY(query) \
- do { \
- completion_charp = query; \
- matches = completion_matches(text, complete_from_query); \
- } while (0)
- #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
- do { \
- completion_squery = &(query); \
- completion_charp = addon; \
- matches = completion_matches(text, complete_from_schema_query); \
- } while (0)
- #define COMPLETE_WITH_LIST_CS(list) \
- do { \
- completion_charpp = list; \
- completion_case_sensitive = true; \
- matches = completion_matches(text, complete_from_list); \
- } while (0)
- #define COMPLETE_WITH_LIST(list) \
- do { \
- completion_charpp = list; \
- completion_case_sensitive = false; \
- matches = completion_matches(text, complete_from_list); \
- } while (0)
- #define COMPLETE_WITH_CONST(string) \
- do { \
- completion_charp = string; \
- completion_case_sensitive = false; \
- matches = completion_matches(text, complete_from_const); \
- } while (0)
- #define COMPLETE_WITH_ATTR(relation, addon) \
- do { \
- char *_completion_schema; \
- char *_completion_table; \
- \
- _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- if (_completion_table == NULL) \
- { \
- completion_charp = Query_for_list_of_attributes addon; \
- completion_info_charp = relation; \
- } \
- else \
- { \
- completion_charp = Query_for_list_of_attributes_with_schema addon; \
- completion_info_charp = _completion_table; \
- completion_info_charp2 = _completion_schema; \
- } \
- matches = completion_matches(text, complete_from_query); \
- } while (0)
- #define COMPLETE_WITH_FUNCTION_ARG(function) \
- do { \
- char *_completion_schema; \
- char *_completion_function; \
- \
- _completion_schema = strtokx(function, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- _completion_function = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- if (_completion_function == NULL) \
- { \
- completion_charp = Query_for_list_of_arguments; \
- completion_info_charp = function; \
- } \
- else \
- { \
- completion_charp = Query_for_list_of_arguments_with_schema; \
- completion_info_charp = _completion_function; \
- completion_info_charp2 = _completion_schema; \
- } \
- matches = completion_matches(text, complete_from_query); \
- } while (0)
- /*
- * Assembly instructions for schema queries
- */
- static const SchemaQuery Query_for_list_of_aggregates = {
- /* catname */
- "pg_catalog.pg_proc p",
- /* selcondition */
- "p.proisagg",
- /* viscondition */
- "pg_catalog.pg_function_is_visible(p.oid)",
- /* namespace */
- "p.pronamespace",
- /* result */
- "pg_catalog.quote_ident(p.proname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_datatypes = {
- /* catname */
- "pg_catalog.pg_type t",
- /* selcondition --- ignore table rowtypes and array types */
- "(t.typrelid = 0 "
- " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
- "AND t.typname !~ '^_'",
- /* viscondition */
- "pg_catalog.pg_type_is_visible(t.oid)",
- /* namespace */
- "t.typnamespace",
- /* result */
- "pg_catalog.format_type(t.oid, NULL)",
- /* qualresult */
- "pg_catalog.quote_ident(t.typname)"
- };
- static const SchemaQuery Query_for_list_of_domains = {
- /* catname */
- "pg_catalog.pg_type t",
- /* selcondition */
- "t.typtype = 'd'",
- /* viscondition */
- "pg_catalog.pg_type_is_visible(t.oid)",
- /* namespace */
- "t.typnamespace",
- /* result */
- "pg_catalog.quote_ident(t.typname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_functions = {
- /* catname */
- "pg_catalog.pg_proc p",
- /* selcondition */
- NULL,
- /* viscondition */
- "pg_catalog.pg_function_is_visible(p.oid)",
- /* namespace */
- "p.pronamespace",
- /* result */
- "pg_catalog.quote_ident(p.proname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_indexes = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('i')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_sequences = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('S')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_foreign_tables = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('f')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_tables = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('r')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_constraints_with_schema = {
- /* catname */
- "pg_catalog.pg_constraint c",
- /* selcondition */
- "c.conrelid <> 0",
- /* viscondition */
- "true", /* there is no pg_constraint_is_visible */
- /* namespace */
- "c.connamespace",
- /* result */
- "pg_catalog.quote_ident(c.conname)",
- /* qualresult */
- NULL
- };
- /* Relations supporting INSERT, UPDATE or DELETE */
- static const SchemaQuery Query_for_list_of_updatables = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('r', 'f', 'v')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_relations = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- NULL,
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_tsvmf = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('r', 'S', 'v', 'm', 'f')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_tmf = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('r', 'm', 'f')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_tm = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('r', 'm')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_views = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('v')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- static const SchemaQuery Query_for_list_of_matviews = {
- /* catname */
- "pg_catalog.pg_class c",
- /* selcondition */
- "c.relkind IN ('m')",
- /* viscondition */
- "pg_catalog.pg_table_is_visible(c.oid)",
- /* namespace */
- "c.relnamespace",
- /* result */
- "pg_catalog.quote_ident(c.relname)",
- /* qualresult */
- NULL
- };
- /*
- * Queries to get lists of names of various kinds of things, possibly
- * restricted to names matching a partially entered name. In these queries,
- * the first %s will be replaced by the text entered so far (suitably escaped
- * to become a SQL literal string). %d will be replaced by the length of the
- * string (in unescaped form). A second and third %s, if present, will be
- * replaced by a suitably-escaped version of the string provided in
- * completion_info_charp. A fourth and fifth %s are similarly replaced by
- * completion_info_charp2.
- *
- * Beware that the allowed sequences of %s and %d are determined by
- * _complete_from_query().
- */
- #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_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_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_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_alter_system_set_vars \
- "SELECT name FROM "\
- " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
- " WHERE context != 'internal') 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_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'"
- /* 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)"
- /* 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)"
- /* the silly-looking length condition is just to eat up the current word */
- #define Query_for_constraint_of_table \
- "SELECT pg_catalog.quote_ident(conname) "\
- " FROM pg_catalog.pg_class c1, pg_catalog.pg_constraint con "\
- " WHERE c1.oid=conrelid and (%d = pg_catalog.length('%s'))"\
- " and pg_catalog.quote_ident(c1.relname)='%s'"\
- " and pg_catalog.pg_table_is_visible(c1.oid)"
- #define Query_for_all_table_constraints \
- "SELECT pg_catalog.quote_ident(conname) "\
- " FROM pg_catalog.pg_constraint c "\
- " WHERE c.conrelid <> 0 "
- /* the silly-looking length condition is just to eat up the current word */
- #define Query_for_constraint_of_type \
- "SELECT pg_catalog.quote_ident(conname) "\
- " FROM pg_catalog.pg_type t, pg_catalog.pg_constraint con "\
- " WHERE t.oid=contypid and (%d = pg_catalog.length('%s'))"\
- " and pg_catalog.quote_ident(t.typname)='%s'"\
- " and pg_catalog.pg_type_is_visible(t.oid)"
- /* the silly-looking length condition is just to eat up the current word */
- #define Query_for_list_of_tables_for_constraint \
- "SELECT pg_catalog.quote_ident(relname) "\
- " FROM pg_catalog.pg_class"\
- " WHERE (%d = pg_catalog.length('%s'))"\
- " AND oid IN "\
- " (SELECT conrelid FROM pg_catalog.pg_constraint "\
- " WHERE pg_catalog.quote_ident(conname)='%s')"
- /* the silly-looking length condition is just to eat up the current word */
- #define Query_for_rule_of_table \
- "SELECT pg_catalog.quote_ident(rulename) "\
- " FROM pg_catalog.pg_class c1, pg_catalog.pg_rewrite "\
- " WHERE c1.oid=ev_class and (%d = pg_catalog.length('%s'))"\
- " and pg_catalog.quote_ident(c1.relname)='%s'"\
- " and pg_catalog.pg_table_is_visible(c1.oid)"
- /* the silly-looking length condition is just to eat up the current word */
- #define Query_for_list_of_tables_for_rule \
- "SELECT pg_catalog.quote_ident(relname) "\
- " FROM pg_catalog.pg_class"\
- " WHERE (%d = pg_catalog.length('%s'))"\
- " AND oid IN "\
- " (SELECT ev_class FROM pg_catalog.pg_rewrite "\
- " WHERE pg_catalog.quote_ident(rulename)='%s')"
- /* the silly-looking length condition is just to eat up the current word */
- #define Query_for_trigger_of_table \
- "SELECT pg_catalog.quote_ident(tgname) "\
- " FROM pg_catalog.pg_class c1, pg_catalog.pg_trigger "\
- " WHERE c1.oid=tgrelid and (%d = pg_catalog.length('%s'))"\
- " and pg_catalog.quote_ident(c1.relname)='%s'"\
- " and pg_catalog.pg_table_is_visible(c1.oid)"\
- " and not tgisinternal"
- /* 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_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_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_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_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'"
- /* the silly-looking length condition is just to eat up the current word */
- #define Query_for_list_of_arguments \
- "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
- " FROM pg_catalog.pg_proc "\
- " WHERE (%d = pg_catalog.length('%s'))"\
- " AND (pg_catalog.quote_ident(proname)='%s'"\
- " OR '\"' || proname || '\"'='%s') "\
- " AND (pg_catalog.pg_function_is_visible(pg_proc.oid))"
- /* the silly-looking length condition is just to eat up the current word */
- #define Query_for_list_of_arguments_with_schema \
- "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
- " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
- " WHERE (%d = pg_catalog.length('%s'))"\
- " AND n.oid = p.pronamespace "\
- " AND (pg_catalog.quote_ident(proname)='%s' "\
- " OR '\"' || proname || '\"' ='%s') "\
- " AND (pg_catalog.quote_ident(nspname)='%s' "\
- " OR '\"' || nspname || '\"' ='%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_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_event_triggers \
- " SELECT pg_catalog.quote_ident(evtname) "\
- " FROM pg_catalog.pg_event_trigger "\
- " WHERE substring(pg_catalog.quote_ident(evtname),1,%d)='%s'"
- /*
- * This is a list of all "things" in Pgsql, which can show up after CREATE or
- * 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 bits32 flags; /* visibility flags, see below */
- } pgsql_thing_t;
- #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
- #define THING_NO_DROP (1 << 1) /* should not show up after DROP */
- #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
- static const pgsql_thing_t words_after_create[] = {
- {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
- {"CAST", NULL, NULL}, /* 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, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s'"},
- /*
- * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
- * to be used only by pg_dump.
- */
- {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
- {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
- {"DATABASE", Query_for_list_of_databases},
- {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
- {"DOMAIN", NULL, &Query_for_list_of_domains},
- {"EVENT TRIGGER", NULL, NULL},
- {"EXTENSION", Query_for_list_of_extensions},
- {"FOREIGN DATA WRAPPER", NULL, NULL},
- {"FOREIGN TABLE", NULL, NULL},
- {"FUNCTION", NULL, &Query_for_list_of_functions},
- {"GROUP", Query_for_list_of_roles},
- {"LANGUAGE", Query_for_list_of_languages},
- {"INDEX", NULL, &Query_for_list_of_indexes},
- {"MATERIALIZED VIEW", NULL, NULL},
- {"OPERATOR", NULL, NULL}, /* 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},
- {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
- {"SCHEMA", Query_for_list_of_schemas},
- {"SEQUENCE", NULL, &Query_for_list_of_sequences},
- {"SERVER", Query_for_list_of_servers},
- {"TABLE", NULL, &Query_for_list_of_tables},
- {"TABLESPACE", Query_for_list_of_tablespaces},
- {"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},
- {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s' AND NOT tgisinternal"},
- {"TYPE", NULL, &Query_for_list_of_datatypes},
- {"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},
- {"USER MAPPING FOR", NULL, NULL},
- {"VIEW", NULL, &Query_for_list_of_views},
- {NULL} /* 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 *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);
- #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);
- #endif
- /*
- * Initialize the readline library for our purposes.
- */
- void
- initialize_readline(void)
- {
- rl_readline_name = (char *) pset.progname;
- rl_attempted_completion_function = psql_completion;
- rl_basic_word_break_characters = WORD_BREAKS;
- completion_max_records = 1000;
- /*
- * There is a variable rl_completion_query_items for this but apparently
- * it's not defined everywhere.
- */
- }
- /*
- * The completion function.
- *
- * According to readline spec this gets passed the text entered so far and its
- * start and end positions in the readline buffer. The return value is some
- * partially obscure list format that can be generated by readline's
- * completion_matches() function, so we don't have to worry about it.
- */
- static char **
- psql_completion(const char *text, int start, int end)
- {
- /* This is the variable we'll return. */
- char **matches = NULL;
- /* This array will contain some scannage of the input line. */
- char *previous_words[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])
- 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", "IMPORT", "INSERT", "LISTEN", "LOAD", "LOCK",
- "MOVE", "NOTIFY", "PREPARE",
- "REASSIGN", "REFRESH", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
- "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
- "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
- NULL
- };
- static const char *const 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", "\\dx",
- "\\e", "\\echo", "\\ef", "\\encoding",
- "\\f", "\\g", "\\gset", "\\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", "\\watch", "\\z", "\\!", NULL
- };
- (void) end; /* not used */
- #ifdef HAVE_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",
- "EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
- "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR",
- "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "SYSTEM SET", "TABLE",
- "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
- "USER", "USER MAPPING FOR", "VIEW", NULL};
- COMPLETE_WITH_LIST(list_ALTER);
- }
- /* ALTER AGGREGATE,FUNCTION <name> */
- 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 <name> (...) */
- 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
- COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
- }
- /* ALTER SCHEMA <name> */
- 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 <name> */
- 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 <name> */
- 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 <name> */
- else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev2_wd, "DATABASE") == 0)
- {
- static const char *const list_ALTERDATABASE[] =
- {"RESET", "SET", "OWNER TO", "RENAME TO", "IS_TEMPLATE",
- "ALLOW_CONNECTIONS", "CONNECTION LIMIT", NULL};
- COMPLETE_WITH_LIST(list_ALTERDATABASE);
- }
- /* ALTER EVENT TRIGGER */
- else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev2_wd, "EVENT") == 0 &&
- pg_strcasecmp(prev_wd, "TRIGGER") == 0)
- {
- COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
- }
- /* ALTER EVENT TRIGGER <name> */
- else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev3_wd, "EVENT") == 0 &&
- pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
- {
- static const char *const list_ALTER_EVENT_TRIGGER[] =
- {"DISABLE", "ENABLE", "OWNER TO", "RENAME TO", NULL};
- COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER);
- }
- /* ALTER EVENT TRIGGER <name> ENABLE */
- else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev4_wd, "EVENT") == 0 &&
- pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
- pg_strcasecmp(prev_wd, "ENABLE") == 0)
- {
- static const char *const list_ALTER_EVENT_TRIGGER_ENABLE[] =
- {"REPLICA", "ALWAYS", NULL};
- COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER_ENABLE);
- }
- /* ALTER EXTENSION <name> */
- 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 <name> */
- 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 <name> */
- 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 <name> */
- 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 <name> 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 <name> 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 <foo> 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 <name> */
- 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 <oid> */
- 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 MATERIALIZED VIEW */
- else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
- pg_strcasecmp(prev_wd, "VIEW") == 0)
- {
- COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
- }
- /* ALTER USER,ROLE <name> */
- 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 <name> 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 <name> 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 <name> */
- 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 <sth> 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 <sth> DROP|RENAME|VALIDATE CONSTRAINT */
- else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev4_wd, "DOMAIN") == 0 &&
- (pg_strcasecmp(prev2_wd, "DROP") == 0 ||
- pg_strcasecmp(prev2_wd, "RENAME") == 0 ||
- pg_strcasecmp(prev2_wd, "VALIDATE") == 0) &&
- pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
- {
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
- }
- /* ALTER DOMAIN <sth> 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 <sth> RENAME CONSTRAINT <sth> */
- 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 <sth> 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 <name> */
- 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 <name> 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 <name> */
- 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 SYSTEM SET <name> */
- else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev2_wd, "SYSTEM") == 0 &&
- pg_strcasecmp(prev_wd, "SET") == 0)
- COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
- /* ALTER VIEW <name> */
- 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 MATERIALIZED VIEW <name> */
- else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
- pg_strcasecmp(prev2_wd, "VIEW") == 0)
- {
- static const char *const list_ALTERMATVIEW[] =
- {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
- COMPLETE_WITH_LIST(list_ALTERMATVIEW);
- }
- /* ALTER RULE <name>, add ON */
- else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev2_wd, "RULE") == 0)
- COMPLETE_WITH_CONST("ON");
- /* If we have ALTER RULE <name> ON, then add the correct tablename */
- else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev3_wd, "RULE") == 0 &&
- pg_strcasecmp(prev_wd, "ON") == 0)
- {
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
- }
- /* ALTER RULE <name> ON <name> */
- else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev4_wd, "RULE") == 0)
- COMPLETE_WITH_CONST("RENAME TO");
- /* ALTER TRIGGER <name>, 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 <sth> ON, then add the correct tablename
- */
- else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
- pg_strcasecmp(prev_wd, "ON") == 0)
- COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
- /* ALTER TRIGGER <name> ON <name> */
- else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
- pg_strcasecmp(prev2_wd, "ON") == 0)
- COMPLETE_WITH_CONST("RENAME TO");
- /*
- * If we detect ALTER TABLE <name>, suggest sub commands
- */
- else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev2_wd, "TABLE") == 0)
- {
- static const char *const list_ALTER2[] =
- {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
- "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
- "VALIDATE CONSTRAINT", "REPLICA IDENTITY", 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(prev5_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
- pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
- pg_strcasecmp(prev_wd, "RULE") == 0)
- {
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_rule_of_table);
- }
- else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
- pg_strcasecmp(prev3_wd, "ENABLE") == 0 &&
- pg_strcasecmp(prev_wd, "RULE") == 0)
- {
- completion_info_charp = prev4_wd;
- COMPLETE_WITH_QUERY(Query_for_rule_of_table);
- }
- else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
- pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
- pg_strcasecmp(prev_wd, "TRIGGER") == 0)
- {
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
- }
- else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
- pg_strcasecmp(prev3_wd, "ENABLE") == 0 &&
- pg_strcasecmp(prev_wd, "TRIGGER") == 0)
- {
- completion_info_charp = prev4_wd;
- COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
- }
- /* ALTER TABLE xxx INHERIT */
- else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
- pg_strcasecmp(prev_wd, "INHERIT") == 0)
- {
- COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
- }
- /* ALTER TABLE xxx NO INHERIT */
- else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
- pg_strcasecmp(prev2_wd, "NO") == 0 &&
- pg_strcasecmp(prev_wd, "INHERIT") == 0)
- {
- COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
- }
- /* ALTER TABLE xxx DISABLE */
- else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
- pg_strcasecmp(prev_wd, "DISABLE") == 0)
- {
- static const char *const list_ALTERDISABLE[] =
- {"RULE", "TRIGGER", NULL};
- COMPLETE_WITH_LIST(list_ALTERDISABLE);
- }
- else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
- pg_strcasecmp(prev2_wd, "DISABLE") == 0 &&
- pg_strcasecmp(prev_wd, "RULE") == 0)
- {
- completion_i…
Large files files are truncated, but you can click here to view the full file