2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2012, PostgreSQL Global Development Group
6 * src/bin/psql/tab-complete.c
9 /*----------------------------------------------------------------------
10 * This file implements a somewhat more sophisticated readline "TAB
11 * completion" in psql. It is not intended to be AI, to replace
12 * learning SQL, or to relieve you from thinking about what you're
13 * doing. Also it does not always give you all the syntactically legal
14 * completions, only those that are the most common or the ones that
15 * the programmer felt most like implementing.
17 * CAVEAT: Tab completion causes queries to be sent to the backend.
18 * The number of tuples returned gets limited, in most default
19 * installations to 1000, but if you still don't like this prospect,
20 * you can turn off tab completion in your ~/.inputrc (or else
21 * ${INPUTRC}) file so:
24 * set disable-completion on
27 * See `man 3 readline' or `info readline' for the full details. Also,
32 * - If you split your queries across lines, this whole thing gets
33 * confused. (To fix this, one would have to read psql's query
34 * buffer rather than readline's line buffer, which would require
35 * some major revisions of things.)
37 * - Table or attribute names with spaces in it may confuse it.
39 * - Quotes, parenthesis, and other funny characters are not handled
40 * all that gracefully.
41 *----------------------------------------------------------------------
44 #include "postgres_fe.h"
45 #include "tab-complete.h"
48 /* If we don't have this, we might as well forget about the whole thing: */
53 #include "pqexpbuffer.h"
56 #include "stringutils.h"
58 #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
59 #define filename_completion_function rl_filename_completion_function
61 /* missing in some header files */
62 extern char *filename_completion_function();
65 #ifdef HAVE_RL_COMPLETION_MATCHES
66 #define completion_matches rl_completion_matches
69 /* word break characters */
70 #define WORD_BREAKS "\t\n@$><=;|&{() "
73 * This struct is used to define "schema queries", which are custom-built
74 * to obtain possibly-schema-qualified names of database objects. There is
75 * enough similarity in the structure that we don't want to repeat it each
76 * time. So we put the components of each query into this struct and
77 * assemble them with the common boilerplate in _complete_from_query().
79 typedef struct SchemaQuery
82 * Name of catalog or catalogs to be queried, with alias, eg.
83 * "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
88 * Selection condition --- only rows meeting this condition are candidates
89 * to display. If catname mentions multiple tables, include the necessary
90 * join condition here. For example, "c.relkind = 'r'". Write NULL (not
91 * an empty string) if not needed.
93 const char *selcondition;
96 * Visibility condition --- which rows are visible without schema
97 * qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
99 const char *viscondition;
102 * Namespace --- name of field to join to pg_namespace.oid. For example,
105 const char *namespace;
108 * Result --- the appropriately-quoted name to return, in the case of an
109 * unqualified name. For example, "pg_catalog.quote_ident(c.relname)".
114 * In some cases a different result must be used for qualified names.
115 * Enter that here, or write NULL if result can be used.
117 const char *qualresult;
121 /* Store maximum number of records we want from database queries
122 * (implemented via SELECT ... LIMIT xx).
124 static int completion_max_records;
127 * Communication variables set by COMPLETE_WITH_FOO macros and then used by
128 * the completion callback functions. Ugly but there is no better way.
130 static const char *completion_charp; /* to pass a string */
131 static const char *const * completion_charpp; /* to pass a list of strings */
132 static const char *completion_info_charp; /* to pass a second string */
133 static const char *completion_info_charp2; /* to pass a third string */
134 static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
135 static bool completion_case_sensitive; /* completion is case sensitive */
138 * A few macros to ease typing. You can use these to complete the given
140 * 1) The results from a query you pass it. (Perhaps one of those below?)
141 * 2) The results from a schema query you pass it.
142 * 3) The items from a null-pointer-terminated list.
143 * 4) A string constant.
144 * 5) The list of attributes of the given table (possibly schema-qualified).
145 * 6/ The list of arguments to the given function (possibly schema-qualified).
147 #define COMPLETE_WITH_QUERY(query) \
149 completion_charp = query; \
150 matches = completion_matches(text, complete_from_query); \
153 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
155 completion_squery = &(query); \
156 completion_charp = addon; \
157 matches = completion_matches(text, complete_from_schema_query); \
160 #define COMPLETE_WITH_LIST_CS(list) \
162 completion_charpp = list; \
163 completion_case_sensitive = true; \
164 matches = completion_matches(text, complete_from_list); \
167 #define COMPLETE_WITH_LIST(list) \
169 completion_charpp = list; \
170 completion_case_sensitive = false; \
171 matches = completion_matches(text, complete_from_list); \
174 #define COMPLETE_WITH_CONST(string) \
176 completion_charp = string; \
177 completion_case_sensitive = false; \
178 matches = completion_matches(text, complete_from_const); \
181 #define COMPLETE_WITH_ATTR(relation, addon) \
183 char *_completion_schema; \
184 char *_completion_table; \
186 _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
187 false, false, pset.encoding); \
188 (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
189 false, false, pset.encoding); \
190 _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
191 false, false, pset.encoding); \
192 if (_completion_table == NULL) \
194 completion_charp = Query_for_list_of_attributes addon; \
195 completion_info_charp = relation; \
199 completion_charp = Query_for_list_of_attributes_with_schema addon; \
200 completion_info_charp = _completion_table; \
201 completion_info_charp2 = _completion_schema; \
203 matches = completion_matches(text, complete_from_query); \
206 #define COMPLETE_WITH_FUNCTION_ARG(function) \
208 char *_completion_schema; \
209 char *_completion_function; \
211 _completion_schema = strtokx(function, " \t\n\r", ".", "\"", 0, \
212 false, false, pset.encoding); \
213 (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
214 false, false, pset.encoding); \
215 _completion_function = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
216 false, false, pset.encoding); \
217 if (_completion_function == NULL) \
219 completion_charp = Query_for_list_of_arguments; \
220 completion_info_charp = function; \
224 completion_charp = Query_for_list_of_arguments_with_schema; \
225 completion_info_charp = _completion_function; \
226 completion_info_charp2 = _completion_schema; \
228 matches = completion_matches(text, complete_from_query); \
232 * Assembly instructions for schema queries
235 static const SchemaQuery Query_for_list_of_aggregates = {
237 "pg_catalog.pg_proc p",
241 "pg_catalog.pg_function_is_visible(p.oid)",
245 "pg_catalog.quote_ident(p.proname)",
250 static const SchemaQuery Query_for_list_of_datatypes = {
252 "pg_catalog.pg_type t",
253 /* selcondition --- ignore table rowtypes and array types */
255 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
256 "AND t.typname !~ '^_'",
258 "pg_catalog.pg_type_is_visible(t.oid)",
262 "pg_catalog.format_type(t.oid, NULL)",
264 "pg_catalog.quote_ident(t.typname)"
267 static const SchemaQuery Query_for_list_of_domains = {
269 "pg_catalog.pg_type t",
273 "pg_catalog.pg_type_is_visible(t.oid)",
277 "pg_catalog.quote_ident(t.typname)",
282 static const SchemaQuery Query_for_list_of_functions = {
284 "pg_catalog.pg_proc p",
288 "pg_catalog.pg_function_is_visible(p.oid)",
292 "pg_catalog.quote_ident(p.proname)",
297 static const SchemaQuery Query_for_list_of_indexes = {
299 "pg_catalog.pg_class c",
301 "c.relkind IN ('i')",
303 "pg_catalog.pg_table_is_visible(c.oid)",
307 "pg_catalog.quote_ident(c.relname)",
312 static const SchemaQuery Query_for_list_of_sequences = {
314 "pg_catalog.pg_class c",
316 "c.relkind IN ('S')",
318 "pg_catalog.pg_table_is_visible(c.oid)",
322 "pg_catalog.quote_ident(c.relname)",
327 static const SchemaQuery Query_for_list_of_foreign_tables = {
329 "pg_catalog.pg_class c",
331 "c.relkind IN ('f')",
333 "pg_catalog.pg_table_is_visible(c.oid)",
337 "pg_catalog.quote_ident(c.relname)",
342 static const SchemaQuery Query_for_list_of_tables = {
344 "pg_catalog.pg_class c",
346 "c.relkind IN ('r')",
348 "pg_catalog.pg_table_is_visible(c.oid)",
352 "pg_catalog.quote_ident(c.relname)",
357 /* The bit masks for the following three functions come from
358 * src/include/catalog/pg_trigger.h.
360 static const SchemaQuery Query_for_list_of_insertables = {
362 "pg_catalog.pg_class c",
364 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
365 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))",
367 "pg_catalog.pg_table_is_visible(c.oid)",
371 "pg_catalog.quote_ident(c.relname)",
376 static const SchemaQuery Query_for_list_of_deletables = {
378 "pg_catalog.pg_class c",
380 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
381 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))",
383 "pg_catalog.pg_table_is_visible(c.oid)",
387 "pg_catalog.quote_ident(c.relname)",
392 static const SchemaQuery Query_for_list_of_updatables = {
394 "pg_catalog.pg_class c",
396 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
397 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))",
399 "pg_catalog.pg_table_is_visible(c.oid)",
403 "pg_catalog.quote_ident(c.relname)",
408 static const SchemaQuery Query_for_list_of_relations = {
410 "pg_catalog.pg_class c",
414 "pg_catalog.pg_table_is_visible(c.oid)",
418 "pg_catalog.quote_ident(c.relname)",
423 static const SchemaQuery Query_for_list_of_tsvf = {
425 "pg_catalog.pg_class c",
427 "c.relkind IN ('r', 'S', 'v', 'f')",
429 "pg_catalog.pg_table_is_visible(c.oid)",
433 "pg_catalog.quote_ident(c.relname)",
438 static const SchemaQuery Query_for_list_of_tf = {
440 "pg_catalog.pg_class c",
442 "c.relkind IN ('r', 'f')",
444 "pg_catalog.pg_table_is_visible(c.oid)",
448 "pg_catalog.quote_ident(c.relname)",
453 static const SchemaQuery Query_for_list_of_views = {
455 "pg_catalog.pg_class c",
457 "c.relkind IN ('v')",
459 "pg_catalog.pg_table_is_visible(c.oid)",
463 "pg_catalog.quote_ident(c.relname)",
470 * Queries to get lists of names of various kinds of things, possibly
471 * restricted to names matching a partially entered name. In these queries,
472 * the first %s will be replaced by the text entered so far (suitably escaped
473 * to become a SQL literal string). %d will be replaced by the length of the
474 * string (in unescaped form). A second and third %s, if present, will be
475 * replaced by a suitably-escaped version of the string provided in
476 * completion_info_charp. A fourth and fifth %s are similarly replaced by
477 * completion_info_charp2.
479 * Beware that the allowed sequences of %s and %d are determined by
480 * _complete_from_query().
483 #define Query_for_list_of_attributes \
484 "SELECT pg_catalog.quote_ident(attname) "\
485 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
486 " WHERE c.oid = a.attrelid "\
487 " AND a.attnum > 0 "\
488 " AND NOT a.attisdropped "\
489 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
490 " AND (pg_catalog.quote_ident(relname)='%s' "\
491 " OR '\"' || relname || '\"'='%s') "\
492 " AND pg_catalog.pg_table_is_visible(c.oid)"
494 #define Query_for_list_of_attributes_with_schema \
495 "SELECT pg_catalog.quote_ident(attname) "\
496 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
497 " WHERE c.oid = a.attrelid "\
498 " AND n.oid = c.relnamespace "\
499 " AND a.attnum > 0 "\
500 " AND NOT a.attisdropped "\
501 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
502 " AND (pg_catalog.quote_ident(relname)='%s' "\
503 " OR '\"' || relname || '\"' ='%s') "\
504 " AND (pg_catalog.quote_ident(nspname)='%s' "\
505 " OR '\"' || nspname || '\"' ='%s') "
507 #define Query_for_list_of_template_databases \
508 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
509 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
511 #define Query_for_list_of_databases \
512 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
513 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
515 #define Query_for_list_of_tablespaces \
516 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
517 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
519 #define Query_for_list_of_encodings \
520 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
521 " FROM pg_catalog.pg_conversion "\
522 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
524 #define Query_for_list_of_languages \
525 "SELECT pg_catalog.quote_ident(lanname) "\
526 " FROM pg_catalog.pg_language "\
527 " WHERE lanname != 'internal' "\
528 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
530 #define Query_for_list_of_schemas \
531 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
532 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
534 #define Query_for_list_of_set_vars \
536 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
537 " WHERE context IN ('user', 'superuser') "\
538 " UNION ALL SELECT 'constraints' "\
539 " UNION ALL SELECT 'transaction' "\
540 " UNION ALL SELECT 'session' "\
541 " UNION ALL SELECT 'role' "\
542 " UNION ALL SELECT 'tablespace' "\
543 " UNION ALL SELECT 'all') ss "\
544 " WHERE substring(name,1,%d)='%s'"
546 #define Query_for_list_of_show_vars \
548 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
549 " UNION ALL SELECT 'session authorization' "\
550 " UNION ALL SELECT 'all') ss "\
551 " WHERE substring(name,1,%d)='%s'"
553 #define Query_for_list_of_roles \
554 " SELECT pg_catalog.quote_ident(rolname) "\
555 " FROM pg_catalog.pg_roles "\
556 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
558 #define Query_for_list_of_grant_roles \
559 " SELECT pg_catalog.quote_ident(rolname) "\
560 " FROM pg_catalog.pg_roles "\
561 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
562 " UNION ALL SELECT 'PUBLIC'"
564 /* the silly-looking length condition is just to eat up the current word */
565 #define Query_for_table_owning_index \
566 "SELECT pg_catalog.quote_ident(c1.relname) "\
567 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
568 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
569 " and (%d = pg_catalog.length('%s'))"\
570 " and pg_catalog.quote_ident(c2.relname)='%s'"\
571 " and pg_catalog.pg_table_is_visible(c2.oid)"
573 /* the silly-looking length condition is just to eat up the current word */
574 #define Query_for_index_of_table \
575 "SELECT pg_catalog.quote_ident(c2.relname) "\
576 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
577 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
578 " and (%d = pg_catalog.length('%s'))"\
579 " and pg_catalog.quote_ident(c1.relname)='%s'"\
580 " and pg_catalog.pg_table_is_visible(c2.oid)"
582 /* the silly-looking length condition is just to eat up the current word */
583 #define Query_for_constraint_of_table \
584 "SELECT pg_catalog.quote_ident(conname) "\
585 " FROM pg_catalog.pg_class c1, pg_catalog.pg_constraint con "\
586 " WHERE c1.oid=conrelid and (%d = pg_catalog.length('%s'))"\
587 " and pg_catalog.quote_ident(c1.relname)='%s'"\
588 " and pg_catalog.pg_table_is_visible(c1.oid)"
590 /* the silly-looking length condition is just to eat up the current word */
591 #define Query_for_list_of_tables_for_trigger \
592 "SELECT pg_catalog.quote_ident(relname) "\
593 " FROM pg_catalog.pg_class"\
594 " WHERE (%d = pg_catalog.length('%s'))"\
596 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
597 " WHERE pg_catalog.quote_ident(tgname)='%s')"
599 #define Query_for_list_of_ts_configurations \
600 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
601 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
603 #define Query_for_list_of_ts_dictionaries \
604 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
605 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
607 #define Query_for_list_of_ts_parsers \
608 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
609 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
611 #define Query_for_list_of_ts_templates \
612 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
613 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
615 #define Query_for_list_of_fdws \
616 " SELECT pg_catalog.quote_ident(fdwname) "\
617 " FROM pg_catalog.pg_foreign_data_wrapper "\
618 " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
620 #define Query_for_list_of_servers \
621 " SELECT pg_catalog.quote_ident(srvname) "\
622 " FROM pg_catalog.pg_foreign_server "\
623 " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
625 #define Query_for_list_of_user_mappings \
626 " SELECT pg_catalog.quote_ident(usename) "\
627 " FROM pg_catalog.pg_user_mappings "\
628 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
630 #define Query_for_list_of_access_methods \
631 " SELECT pg_catalog.quote_ident(amname) "\
632 " FROM pg_catalog.pg_am "\
633 " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
635 /* the silly-looking length condition is just to eat up the current word */
636 #define Query_for_list_of_arguments \
637 "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
638 " FROM pg_catalog.pg_proc "\
639 " WHERE (%d = pg_catalog.length('%s'))"\
640 " AND (pg_catalog.quote_ident(proname)='%s'"\
641 " OR '\"' || proname || '\"'='%s') "\
642 " AND (pg_catalog.pg_function_is_visible(pg_proc.oid))"
644 /* the silly-looking length condition is just to eat up the current word */
645 #define Query_for_list_of_arguments_with_schema \
646 "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
647 " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
648 " WHERE (%d = pg_catalog.length('%s'))"\
649 " AND n.oid = p.pronamespace "\
650 " AND (pg_catalog.quote_ident(proname)='%s' "\
651 " OR '\"' || proname || '\"' ='%s') "\
652 " AND (pg_catalog.quote_ident(nspname)='%s' "\
653 " OR '\"' || nspname || '\"' ='%s') "
655 #define Query_for_list_of_extensions \
656 " SELECT pg_catalog.quote_ident(extname) "\
657 " FROM pg_catalog.pg_extension "\
658 " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
660 #define Query_for_list_of_available_extensions \
661 " SELECT pg_catalog.quote_ident(name) "\
662 " FROM pg_catalog.pg_available_extensions "\
663 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
665 #define Query_for_list_of_prepared_statements \
666 " SELECT pg_catalog.quote_ident(name) "\
667 " FROM pg_catalog.pg_prepared_statements "\
668 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'"
671 * This is a list of all "things" in Pgsql, which can show up after CREATE or
672 * DROP; and there is also a query to get a list of them.
678 const char *query; /* simple query, or NULL */
679 const SchemaQuery *squery; /* schema query, or NULL */
680 const bits32 flags; /* visibility flags, see below */
683 #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
684 #define THING_NO_DROP (1 << 1) /* should not show up after DROP */
685 #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
687 static const pgsql_thing_t words_after_create[] = {
688 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
689 {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
691 {"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'"},
694 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
695 * to be used only by pg_dump.
697 {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
698 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
699 {"DATABASE", Query_for_list_of_databases},
700 {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
701 {"DOMAIN", NULL, &Query_for_list_of_domains},
702 {"EXTENSION", Query_for_list_of_extensions},
703 {"FOREIGN DATA WRAPPER", NULL, NULL},
704 {"FOREIGN TABLE", NULL, NULL},
705 {"FUNCTION", NULL, &Query_for_list_of_functions},
706 {"GROUP", Query_for_list_of_roles},
707 {"LANGUAGE", Query_for_list_of_languages},
708 {"INDEX", NULL, &Query_for_list_of_indexes},
709 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
711 {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */
712 {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
713 {"ROLE", Query_for_list_of_roles},
714 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
715 {"SCHEMA", Query_for_list_of_schemas},
716 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
717 {"SERVER", Query_for_list_of_servers},
718 {"TABLE", NULL, &Query_for_list_of_tables},
719 {"TABLESPACE", Query_for_list_of_tablespaces},
720 {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
721 {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
722 {"TEXT SEARCH", NULL, NULL},
723 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
724 {"TYPE", NULL, &Query_for_list_of_datatypes},
725 {"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
726 {"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE
728 {"USER", Query_for_list_of_roles},
729 {"USER MAPPING FOR", NULL, NULL},
730 {"VIEW", NULL, &Query_for_list_of_views},
731 {NULL} /* end of list */
735 /* Forward declaration of functions */
736 static char **psql_completion(char *text, int start, int end);
737 static char *create_command_generator(const char *text, int state);
738 static char *drop_command_generator(const char *text, int state);
739 static char *complete_from_query(const char *text, int state);
740 static char *complete_from_schema_query(const char *text, int state);
741 static char *_complete_from_query(int is_schema_query,
742 const char *text, int state);
743 static char *complete_from_list(const char *text, int state);
744 static char *complete_from_const(const char *text, int state);
745 static char **complete_from_variables(char *text,
746 const char *prefix, const char *suffix);
747 static char *complete_from_files(const char *text, int state);
749 static char *pg_strdup_keyword_case(const char *s, const char *ref);
750 static PGresult *exec_query(const char *query);
752 static void get_previous_words(int point, char **previous_words, int nwords);
755 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
756 static char *dequote_file_name(char *text, char quote_char);
761 * Initialize the readline library for our purposes.
764 initialize_readline(void)
766 rl_readline_name = (char *) pset.progname;
767 rl_attempted_completion_function = (void *) psql_completion;
769 rl_basic_word_break_characters = WORD_BREAKS;
771 completion_max_records = 1000;
774 * There is a variable rl_completion_query_items for this but apparently
775 * it's not defined everywhere.
781 * The completion function.
783 * According to readline spec this gets passed the text entered so far and its
784 * start and end positions in the readline buffer. The return value is some
785 * partially obscure list format that can be generated by readline's
786 * completion_matches() function, so we don't have to worry about it.
789 psql_completion(char *text, int start, int end)
791 /* This is the variable we'll return. */
792 char **matches = NULL;
794 /* This array will contain some scannage of the input line. */
795 char *previous_words[6];
797 /* For compactness, we use these macros to reference previous_words[]. */
798 #define prev_wd (previous_words[0])
799 #define prev2_wd (previous_words[1])
800 #define prev3_wd (previous_words[2])
801 #define prev4_wd (previous_words[3])
802 #define prev5_wd (previous_words[4])
803 #define prev6_wd (previous_words[5])
805 static const char *const sql_commands[] = {
806 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
807 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
808 "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
809 "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
810 "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
811 "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
812 "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
816 static const char *const backslash_commands[] = {
817 "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
818 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df",
819 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
820 "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
821 "\\e", "\\echo", "\\ef", "\\encoding",
822 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
823 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
824 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
825 "\\set", "\\sf", "\\t", "\\T",
826 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
829 (void) end; /* not used */
831 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
832 rl_completion_append_character = ' ';
835 /* Clear a few things. */
836 completion_charp = NULL;
837 completion_charpp = NULL;
838 completion_info_charp = NULL;
839 completion_info_charp2 = NULL;
842 * Scan the input line before our current position for the last few words.
843 * According to those we'll make some smart decisions on what the user is
844 * probably intending to type.
846 get_previous_words(start, previous_words, lengthof(previous_words));
848 /* If a backslash command was started, continue */
850 COMPLETE_WITH_LIST_CS(backslash_commands);
852 /* Variable interpolation */
853 else if (text[0] == ':' && text[1] != ':')
856 matches = complete_from_variables(text, ":'", "'");
857 else if (text[1] == '"')
858 matches = complete_from_variables(text, ":\"", "\"");
860 matches = complete_from_variables(text, ":", "");
863 /* If no previous word, suggest one of the basic sql commands */
864 else if (prev_wd[0] == '\0')
865 COMPLETE_WITH_LIST(sql_commands);
868 /* complete with something you can create */
869 else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
870 matches = completion_matches(text, create_command_generator);
872 /* DROP, but not DROP embedded in other commands */
873 /* complete with something you can drop */
874 else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
876 matches = completion_matches(text, drop_command_generator);
881 * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
882 * in ALTER TABLE sth ALTER
884 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
885 pg_strcasecmp(prev3_wd, "TABLE") != 0)
887 static const char *const list_ALTER[] =
888 {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
889 "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
890 "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR",
891 "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
892 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
893 "USER", "USER MAPPING FOR", "VIEW", NULL};
895 COMPLETE_WITH_LIST(list_ALTER);
897 /* ALTER AGGREGATE,FUNCTION <name> */
898 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
899 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
900 pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
901 COMPLETE_WITH_CONST("(");
902 /* ALTER AGGREGATE,FUNCTION <name> (...) */
903 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
904 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
905 pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
907 if (prev_wd[strlen(prev_wd) - 1] == ')')
909 static const char *const list_ALTERAGG[] =
910 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
912 COMPLETE_WITH_LIST(list_ALTERAGG);
915 COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
918 /* ALTER SCHEMA <name> */
919 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
920 pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
922 static const char *const list_ALTERGEN[] =
923 {"OWNER TO", "RENAME TO", NULL};
925 COMPLETE_WITH_LIST(list_ALTERGEN);
928 /* ALTER COLLATION <name> */
929 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
930 pg_strcasecmp(prev2_wd, "COLLATION") == 0)
932 static const char *const list_ALTERGEN[] =
933 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
935 COMPLETE_WITH_LIST(list_ALTERGEN);
938 /* ALTER CONVERSION <name> */
939 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
940 pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
942 static const char *const list_ALTERGEN[] =
943 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
945 COMPLETE_WITH_LIST(list_ALTERGEN);
948 /* ALTER DATABASE <name> */
949 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
950 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
952 static const char *const list_ALTERDATABASE[] =
953 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
955 COMPLETE_WITH_LIST(list_ALTERDATABASE);
958 /* ALTER EXTENSION <name> */
959 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
960 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
962 static const char *const list_ALTEREXTENSION[] =
963 {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
965 COMPLETE_WITH_LIST(list_ALTEREXTENSION);
969 else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
970 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
972 static const char *const list_ALTER_FOREIGN[] =
973 {"DATA WRAPPER", "TABLE", NULL};
975 COMPLETE_WITH_LIST(list_ALTER_FOREIGN);
978 /* ALTER FOREIGN DATA WRAPPER <name> */
979 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
980 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
981 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
982 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
984 static const char *const list_ALTER_FDW[] =
985 {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
987 COMPLETE_WITH_LIST(list_ALTER_FDW);
990 /* ALTER FOREIGN TABLE <name> */
991 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
992 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
993 pg_strcasecmp(prev2_wd, "TABLE") == 0)
995 static const char *const list_ALTER_FOREIGN_TABLE[] =
996 {"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL};
998 COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
1001 /* ALTER INDEX <name> */
1002 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1003 pg_strcasecmp(prev2_wd, "INDEX") == 0)
1005 static const char *const list_ALTERINDEX[] =
1006 {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
1008 COMPLETE_WITH_LIST(list_ALTERINDEX);
1010 /* ALTER INDEX <name> SET */
1011 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1012 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1013 pg_strcasecmp(prev_wd, "SET") == 0)
1015 static const char *const list_ALTERINDEXSET[] =
1016 {"(", "TABLESPACE", NULL};
1018 COMPLETE_WITH_LIST(list_ALTERINDEXSET);
1020 /* ALTER INDEX <name> RESET */
1021 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1022 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1023 pg_strcasecmp(prev_wd, "RESET") == 0)
1024 COMPLETE_WITH_CONST("(");
1025 /* ALTER INDEX <foo> SET|RESET ( */
1026 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1027 pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1028 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1029 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1030 pg_strcasecmp(prev_wd, "(") == 0)
1032 static const char *const list_INDEXOPTIONS[] =
1033 {"fillfactor", "fastupdate", NULL};
1035 COMPLETE_WITH_LIST(list_INDEXOPTIONS);
1038 /* ALTER LANGUAGE <name> */
1039 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1040 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
1042 static const char *const list_ALTERLANGUAGE[] =
1043 {"OWNER TO", "RENAME TO", NULL};
1045 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
1048 /* ALTER LARGE OBJECT <oid> */
1049 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1050 pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
1051 pg_strcasecmp(prev2_wd, "OBJECT") == 0)
1053 static const char *const list_ALTERLARGEOBJECT[] =
1056 COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
1059 /* ALTER USER,ROLE <name> */
1060 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1061 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1062 (pg_strcasecmp(prev2_wd, "USER") == 0 ||
1063 pg_strcasecmp(prev2_wd, "ROLE") == 0))
1065 static const char *const list_ALTERUSER[] =
1066 {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1067 "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
1068 "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
1069 "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
1070 "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL};
1072 COMPLETE_WITH_LIST(list_ALTERUSER);
1075 /* ALTER USER,ROLE <name> WITH */
1076 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1077 (pg_strcasecmp(prev3_wd, "USER") == 0 ||
1078 pg_strcasecmp(prev3_wd, "ROLE") == 0) &&
1079 pg_strcasecmp(prev_wd, "WITH") == 0))
1081 /* Similar to the above, but don't complete "WITH" again. */
1082 static const char *const list_ALTERUSER_WITH[] =
1083 {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1084 "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
1085 "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
1086 "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
1087 "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", NULL};
1089 COMPLETE_WITH_LIST(list_ALTERUSER_WITH);
1092 /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
1093 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1094 (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1095 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1097 COMPLETE_WITH_CONST("PASSWORD");
1099 /* ALTER DEFAULT PRIVILEGES */
1100 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1101 pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
1102 pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
1104 static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
1105 {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
1107 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
1109 /* ALTER DEFAULT PRIVILEGES FOR */
1110 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1111 pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
1112 pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
1113 pg_strcasecmp(prev_wd, "FOR") == 0)
1115 static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
1116 {"ROLE", "USER", NULL};
1118 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
1120 /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
1121 else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
1122 pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
1123 (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
1124 pg_strcasecmp(prev3_wd, "IN") == 0))
1126 static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
1127 {"GRANT", "REVOKE", NULL};
1129 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
1131 /* ALTER DOMAIN <name> */
1132 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1133 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
1135 static const char *const list_ALTERDOMAIN[] =
1136 {"ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT", NULL};
1138 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1140 /* ALTER DOMAIN <sth> DROP */
1141 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1142 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1143 pg_strcasecmp(prev_wd, "DROP") == 0)
1145 static const char *const list_ALTERDOMAIN2[] =
1146 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
1148 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
1150 /* ALTER DOMAIN <sth> RENAME */
1151 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1152 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1153 pg_strcasecmp(prev_wd, "RENAME") == 0)
1155 static const char *const list_ALTERDOMAIN[] =
1156 {"CONSTRAINT", "TO", NULL};
1158 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1160 /* ALTER DOMAIN <sth> RENAME CONSTRAINT <sth> */
1161 else if (pg_strcasecmp(prev5_wd, "DOMAIN") == 0 &&
1162 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1163 pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0)
1164 COMPLETE_WITH_CONST("TO");
1166 /* ALTER DOMAIN <sth> SET */
1167 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1168 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1169 pg_strcasecmp(prev_wd, "SET") == 0)
1171 static const char *const list_ALTERDOMAIN3[] =
1172 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
1174 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
1176 /* ALTER SEQUENCE <name> */
1177 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1178 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
1180 static const char *const list_ALTERSEQUENCE[] =
1181 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
1182 "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
1184 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
1186 /* ALTER SEQUENCE <name> NO */
1187 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1188 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
1189 pg_strcasecmp(prev_wd, "NO") == 0)
1191 static const char *const list_ALTERSEQUENCE2[] =
1192 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
1194 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
1196 /* ALTER SERVER <name> */
1197 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1198 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1200 static const char *const list_ALTER_SERVER[] =
1201 {"VERSION", "OPTIONS", "OWNER TO", NULL};
1203 COMPLETE_WITH_LIST(list_ALTER_SERVER);
1205 /* ALTER VIEW <name> */
1206 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1207 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1209 static const char *const list_ALTERVIEW[] =
1210 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1212 COMPLETE_WITH_LIST(list_ALTERVIEW);
1214 /* ALTER TRIGGER <name>, add ON */
1215 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1216 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1217 COMPLETE_WITH_CONST("ON");
1219 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1220 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
1222 completion_info_charp = prev2_wd;
1223 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1227 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1229 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1230 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1231 pg_strcasecmp(prev_wd, "ON") == 0)
1232 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1234 /* ALTER TRIGGER <name> ON <name> */
1235 else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1236 pg_strcasecmp(prev2_wd, "ON") == 0)
1237 COMPLETE_WITH_CONST("RENAME TO");
1240 * If we detect ALTER TABLE <name>, suggest sub commands
1242 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1243 pg_strcasecmp(prev2_wd, "TABLE") == 0)
1245 static const char *const list_ALTER2[] =
1246 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1247 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
1248 "VALIDATE CONSTRAINT", NULL};
1250 COMPLETE_WITH_LIST(list_ALTER2);
1252 /* ALTER TABLE xxx ENABLE */
1253 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1254 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1255 pg_strcasecmp(prev_wd, "ENABLE") == 0)
1257 static const char *const list_ALTERENABLE[] =
1258 {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
1260 COMPLETE_WITH_LIST(list_ALTERENABLE);
1262 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1263 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1264 (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
1265 pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1267 static const char *const list_ALTERENABLE2[] =
1268 {"RULE", "TRIGGER", NULL};
1270 COMPLETE_WITH_LIST(list_ALTERENABLE2);
1272 /* ALTER TABLE xxx INHERIT */
1273 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1274 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1275 pg_strcasecmp(prev_wd, "INHERIT") == 0)
1277 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1279 /* ALTER TABLE xxx NO INHERIT */
1280 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1281 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1282 pg_strcasecmp(prev2_wd, "NO") == 0 &&
1283 pg_strcasecmp(prev_wd, "INHERIT") == 0)
1285 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1287 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1288 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1289 pg_strcasecmp(prev_wd, "DISABLE") == 0)
1291 static const char *const list_ALTERDISABLE[] =
1292 {"RULE", "TRIGGER", NULL};
1294 COMPLETE_WITH_LIST(list_ALTERDISABLE);
1297 /* ALTER TABLE xxx ALTER */
1298 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1299 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1300 pg_strcasecmp(prev_wd, "ALTER") == 0)
1301 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
1303 /* ALTER TABLE xxx RENAME */
1304 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1305 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1306 pg_strcasecmp(prev_wd, "RENAME") == 0)
1307 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'");
1310 * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1313 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1314 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1315 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1316 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1317 COMPLETE_WITH_ATTR(prev3_wd, "");
1319 /* ALTER TABLE xxx RENAME yyy */
1320 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1321 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1322 pg_strcasecmp(prev_wd, "CONSTRAINT") != 0 &&
1323 pg_strcasecmp(prev_wd, "TO") != 0)
1324 COMPLETE_WITH_CONST("TO");
1326 /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */
1327 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1328 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1329 (pg_strcasecmp(prev2_wd, "COLUMN") == 0 ||
1330 pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) &&
1331 pg_strcasecmp(prev_wd, "TO") != 0)
1332 COMPLETE_WITH_CONST("TO");
1334 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1335 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1336 pg_strcasecmp(prev_wd, "DROP") == 0)
1338 static const char *const list_TABLEDROP[] =
1339 {"COLUMN", "CONSTRAINT", NULL};
1341 COMPLETE_WITH_LIST(list_TABLEDROP);
1343 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
1344 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1345 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1346 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1347 COMPLETE_WITH_ATTR(prev3_wd, "");
1348 /* If we have TABLE <sth> DROP CONSTRAINT, provide list of constraints */
1349 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1350 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1351 pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
1353 completion_info_charp = prev3_wd;
1354 COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
1356 /* ALTER TABLE ALTER [COLUMN] <foo> */
1357 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1358 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1359 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1360 pg_strcasecmp(prev2_wd, "ALTER") == 0))
1362 static const char *const list_COLUMNALTER[] =
1363 {"TYPE", "SET", "RESET", "DROP", NULL};
1365 COMPLETE_WITH_LIST(list_COLUMNALTER);
1367 /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1368 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1369 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1370 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1371 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1372 pg_strcasecmp(prev_wd, "SET") == 0)
1374 static const char *const list_COLUMNSET[] =
1375 {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1377 COMPLETE_WITH_LIST(list_COLUMNSET);
1379 /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1380 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1381 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1382 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1383 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1384 pg_strcasecmp(prev_wd, "(") == 0)
1386 static const char *const list_COLUMNOPTIONS[] =
1387 {"n_distinct", "n_distinct_inherited", NULL};
1389 COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1391 /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1392 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1393 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1394 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1395 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1396 pg_strcasecmp(prev_wd, "STORAGE") == 0)
1398 static const char *const list_COLUMNSTORAGE[] =
1399 {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1401 COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1403 /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1404 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1405 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1406 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1407 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1408 pg_strcasecmp(prev_wd, "DROP") == 0)
1410 static const char *const list_COLUMNDROP[] =
1411 {"DEFAULT", "NOT NULL", NULL};
1413 COMPLETE_WITH_LIST(list_COLUMNDROP);
1415 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1416 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1417 COMPLETE_WITH_CONST("ON");
1418 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1419 pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1420 pg_strcasecmp(prev_wd, "ON") == 0)
1422 completion_info_charp = prev3_wd;
1423 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1425 /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
1426 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1427 pg_strcasecmp(prev_wd, "SET") == 0)
1429 static const char *const list_TABLESET[] =
1430 {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
1432 COMPLETE_WITH_LIST(list_TABLESET);
1434 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1435 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1436 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1437 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1438 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1439 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1440 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1441 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1442 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1444 static const char *const list_TABLESET2[] =
1445 {"CLUSTER", "OIDS", NULL};
1447 COMPLETE_WITH_LIST(list_TABLESET2);
1449 /* ALTER TABLE <foo> RESET */
1450 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1451 pg_strcasecmp(prev_wd, "RESET") == 0)
1452 COMPLETE_WITH_CONST("(");
1453 /* ALTER TABLE <foo> SET|RESET ( */
1454 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1455 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1456 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1457 pg_strcasecmp(prev_wd, "(") == 0)
1459 static const char *const list_TABLEOPTIONS[] =
1461 "autovacuum_analyze_scale_factor",
1462 "autovacuum_analyze_threshold",
1463 "autovacuum_enabled",
1464 "autovacuum_freeze_max_age",
1465 "autovacuum_freeze_min_age",
1466 "autovacuum_freeze_table_age",
1467 "autovacuum_vacuum_cost_delay",
1468 "autovacuum_vacuum_cost_limit",
1469 "autovacuum_vacuum_scale_factor",
1470 "autovacuum_vacuum_threshold",
1472 "toast.autovacuum_enabled",
1473 "toast.autovacuum_freeze_max_age",
1474 "toast.autovacuum_freeze_min_age",
1475 "toast.autovacuum_freeze_table_age",
1476 "toast.autovacuum_vacuum_cost_delay",
1477 "toast.autovacuum_vacuum_cost_limit",
1478 "toast.autovacuum_vacuum_scale_factor",
1479 "toast.autovacuum_vacuum_threshold",
1483 COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1486 /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1487 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1488 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1490 static const char *const list_ALTERTSPC[] =
1491 {"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1493 COMPLETE_WITH_LIST(list_ALTERTSPC);
1495 /* ALTER TABLESPACE <foo> SET|RESET */
1496 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1497 pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1498 (pg_strcasecmp(prev_wd, "SET") == 0 ||
1499 pg_strcasecmp(prev_wd, "RESET") == 0))
1500 COMPLETE_WITH_CONST("(");
1501 /* ALTER TABLESPACE <foo> SET|RESET ( */
1502 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1503 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1504 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1505 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1506 pg_strcasecmp(prev_wd, "(") == 0)
1508 static const char *const list_TABLESPACEOPTIONS[] =
1509 {"seq_page_cost", "random_page_cost", NULL};
1511 COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1514 /* ALTER TEXT SEARCH */
1515 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1516 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1517 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1519 static const char *const list_ALTERTEXTSEARCH[] =
1520 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1522 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1524 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1525 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1526 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1527 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1528 pg_strcasecmp(prev2_wd, "PARSER") == 0))
1530 static const char *const list_ALTERTEXTSEARCH2[] =
1531 {"RENAME TO", "SET SCHEMA", NULL};
1533 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1536 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1537 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1538 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1539 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1541 static const char *const list_ALTERTEXTSEARCH3[] =
1542 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1544 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1547 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1548 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1549 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1550 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1552 static const char *const list_ALTERTEXTSEARCH4[] =
1553 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1555 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
1558 /* complete ALTER TYPE <foo> with actions */
1559 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1560 pg_strcasecmp(prev2_wd, "TYPE") == 0)
1562 static const char *const list_ALTERTYPE[] =
1563 {"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
1564 "OWNER TO", "RENAME", "SET SCHEMA", NULL};
1566 COMPLETE_WITH_LIST(list_ALTERTYPE);
1568 /* complete ALTER TYPE <foo> ADD with actions */
1569 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1570 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1571 pg_strcasecmp(prev_wd, "ADD") == 0)
1573 static const char *const list_ALTERTYPE[] =
1574 {"ATTRIBUTE", "VALUE", NULL};
1576 COMPLETE_WITH_LIST(list_ALTERTYPE);
1578 /* ALTER TYPE <foo> RENAME */
1579 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1580 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1581 pg_strcasecmp(prev_wd, "RENAME") == 0)
1583 static const char *const list_ALTERTYPE[] =
1584 {"ATTRIBUTE", "TO", NULL};
1586 COMPLETE_WITH_LIST(list_ALTERTYPE);
1588 /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */
1589 else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 &&
1590 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1591 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)
1592 COMPLETE_WITH_CONST("TO");
1595 * If we have TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list of
1598 else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 &&
1599 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1600 pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1601 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1602 pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0)
1603 COMPLETE_WITH_ATTR(prev3_wd, "");
1604 /* ALTER TYPE ALTER ATTRIBUTE <foo> */
1605 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1606 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0))
1608 COMPLETE_WITH_CONST("TYPE");
1610 /* complete ALTER GROUP <foo> */
1611 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1612 pg_strcasecmp(prev2_wd, "GROUP") == 0)
1614 static const char *const list_ALTERGROUP[] =
1615 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1617 COMPLETE_WITH_LIST(list_ALTERGROUP);
1619 /* complete ALTER GROUP <foo> ADD|DROP with USER */
1620 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1621 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1622 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1623 pg_strcasecmp(prev_wd, "DROP") == 0))
1624 COMPLETE_WITH_CONST("USER");
1625 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1626 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1627 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1628 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1629 pg_strcasecmp(prev_wd, "USER") == 0)
1630 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1632 /* BEGIN, END, ABORT */
1633 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1634 pg_strcasecmp(prev_wd, "END") == 0 ||
1635 pg_strcasecmp(prev_wd, "ABORT") == 0)
1637 static const char *const list_TRANS[] =
1638 {"WORK", "TRANSACTION", NULL};
1640 COMPLETE_WITH_LIST(list_TRANS);
1643 else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1645 static const char *const list_COMMIT[] =
1646 {"WORK", "TRANSACTION", "PREPARED", NULL};
1648 COMPLETE_WITH_LIST(list_COMMIT);
1650 /* RELEASE SAVEPOINT */
1651 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1652 COMPLETE_WITH_CONST("SAVEPOINT");
1654 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1656 static const char *const list_TRANS[] =
1657 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1659 COMPLETE_WITH_LIST(list_TRANS);
1664 * If the previous word is CLUSTER and not without produce list of tables
1666 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1667 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1668 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1669 /* If we have CLUSTER <sth>, then add "USING" */
1670 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1671 pg_strcasecmp(prev_wd, "ON") != 0)
1673 COMPLETE_WITH_CONST("USING");
1677 * If we have CLUSTER <sth> USING, then add the index as well.
1679 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1680 pg_strcasecmp(prev_wd, "USING") == 0)
1682 completion_info_charp = prev2_wd;
1683 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1687 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1688 COMPLETE_WITH_CONST("ON");
1689 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1690 pg_strcasecmp(prev_wd, "ON") == 0)
1692 static const char *const list_COMMENT[] =
1693 {"CAST", "COLLATION", "CONVERSION", "DATABASE", "EXTENSION",
1694 "FOREIGN DATA WRAPPER", "FOREIGN TABLE",
1695 "SERVER", "INDEX", "LANGUAGE", "RULE", "SCHEMA", "SEQUENCE",
1696 "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1697 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1698 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1700 COMPLETE_WITH_LIST(list_COMMENT);
1702 else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
1703 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1704 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1706 static const char *const list_TRANS2[] =
1707 {"DATA WRAPPER", "TABLE", NULL};
1709 COMPLETE_WITH_LIST(list_TRANS2);
1711 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1712 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1713 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1714 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1716 static const char *const list_TRANS2[] =
1717 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1719 COMPLETE_WITH_LIST(list_TRANS2);
1721 else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1722 pg_strcasecmp(prev3_wd, "ON") == 0) ||
1723 (pg_strcasecmp(prev5_wd, "COMMENT") == 0 &&
1724 pg_strcasecmp(prev4_wd, "ON") == 0) ||
1725 (pg_strcasecmp(prev6_wd, "COMMENT") == 0 &&
1726 pg_strcasecmp(prev5_wd, "ON") == 0))
1727 COMPLETE_WITH_CONST("IS");
1732 * If we have COPY [BINARY] (which you'd have to type yourself), offer
1733 * list of tables (Also cover the analogous backslash command)
1735 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1736 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1737 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1738 pg_strcasecmp(prev_wd, "BINARY") == 0))
1739 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1740 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1741 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1742 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1743 pg_strcasecmp(prev2_wd, "BINARY") == 0)
1745 static const char *const list_FROMTO[] =
1746 {"FROM", "TO", NULL};
1748 COMPLETE_WITH_LIST(list_FROMTO);
1750 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1751 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1752 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1753 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1754 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1755 pg_strcasecmp(prev_wd, "TO") == 0))
1757 completion_charp = "";
1758 matches = completion_matches(text, complete_from_files);
1761 /* Handle COPY|BINARY <sth> FROM|TO filename */
1762 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1763 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1764 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1765 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1766 pg_strcasecmp(prev2_wd, "TO") == 0))
1768 static const char *const list_COPY[] =
1769 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL};
1771 COMPLETE_WITH_LIST(list_COPY);
1774 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1775 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1776 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1777 pg_strcasecmp(prev3_wd, "TO") == 0))
1779 static const char *const list_CSV[] =
1780 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL};
1782 COMPLETE_WITH_LIST(list_CSV);
1785 /* CREATE DATABASE */
1786 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1787 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1789 static const char *const list_DATABASE[] =
1790 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1793 COMPLETE_WITH_LIST(list_DATABASE);
1796 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1797 pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1798 pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1799 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1801 /* CREATE EXTENSION */
1802 /* Complete with available extensions rather than installed ones. */
1803 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1804 pg_strcasecmp(prev_wd, "EXTENSION") == 0)
1805 COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
1806 /* CREATE EXTENSION <name> */
1807 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1808 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
1809 COMPLETE_WITH_CONST("WITH SCHEMA");
1811 /* CREATE FOREIGN */
1812 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1813 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1815 static const char *const list_CREATE_FOREIGN[] =
1816 {"DATA WRAPPER", "TABLE", NULL};
1818 COMPLETE_WITH_LIST(list_CREATE_FOREIGN);
1821 /* CREATE FOREIGN DATA WRAPPER */
1822 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1823 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1824 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1825 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1827 static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] =
1828 {"HANDLER", "VALIDATOR", NULL};
1830 COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER);
1834 /* First off we complete CREATE UNIQUE with "INDEX" */
1835 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1836 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1837 COMPLETE_WITH_CONST("INDEX");
1838 /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
1839 else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
1840 (pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
1841 pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
1842 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1843 " UNION SELECT 'ON'"
1844 " UNION SELECT 'CONCURRENTLY'");
1845 /* Complete ... INDEX [<name>] ON with a list of tables */
1846 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1847 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1848 pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
1849 pg_strcasecmp(prev_wd, "ON") == 0)
1850 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1851 /* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
1852 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1853 pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
1854 pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
1855 COMPLETE_WITH_CONST("ON");
1856 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
1857 else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1858 pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
1859 pg_strcasecmp(prev2_wd, "INDEX") == 0)
1861 static const char *const list_CREATE_INDEX[] =
1862 {"CONCURRENTLY", "ON", NULL};
1864 COMPLETE_WITH_LIST(list_CREATE_INDEX);
1868 * Complete INDEX <name> ON <table> with a list of table columns (which
1869 * should really be in parens)
1871 else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1872 pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1873 pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
1874 pg_strcasecmp(prev2_wd, "ON") == 0)
1876 static const char *const list_CREATE_INDEX2[] =
1877 {"(", "USING", NULL};
1879 COMPLETE_WITH_LIST(list_CREATE_INDEX2);
1881 else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
1882 pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1883 pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
1884 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1885 pg_strcasecmp(prev_wd, "(") == 0)
1886 COMPLETE_WITH_ATTR(prev2_wd, "");
1887 /* same if you put in USING */
1888 else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1889 pg_strcasecmp(prev3_wd, "USING") == 0 &&
1890 pg_strcasecmp(prev_wd, "(") == 0)
1891 COMPLETE_WITH_ATTR(prev4_wd, "");
1892 /* Complete USING with an index method */
1893 else if (pg_strcasecmp(prev_wd, "USING") == 0)
1894 COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
1895 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1896 pg_strcasecmp(prev2_wd, "USING") == 0)
1897 COMPLETE_WITH_CONST("(");
1900 /* Complete "CREATE RULE <sth>" with "AS" */
1901 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1902 pg_strcasecmp(prev2_wd, "RULE") == 0)
1903 COMPLETE_WITH_CONST("AS");
1904 /* Complete "CREATE RULE <sth> AS with "ON" */
1905 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1906 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1907 pg_strcasecmp(prev_wd, "AS") == 0)
1908 COMPLETE_WITH_CONST("ON");
1909 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1910 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1911 pg_strcasecmp(prev2_wd, "AS") == 0 &&
1912 pg_strcasecmp(prev_wd, "ON") == 0)
1914 static const char *const rule_events[] =
1915 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1917 COMPLETE_WITH_LIST(rule_events);
1919 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1920 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1921 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1922 (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1923 pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1924 COMPLETE_WITH_CONST("TO");
1925 /* Complete "AS ON <sth> TO" with a table name */
1926 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1927 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1928 pg_strcasecmp(prev_wd, "TO") == 0)
1929 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1931 /* CREATE SERVER <name> */
1932 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1933 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1935 static const char *const list_CREATE_SERVER[] =
1936 {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
1938 COMPLETE_WITH_LIST(list_CREATE_SERVER);
1942 /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
1943 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1944 (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
1945 pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
1947 static const char *const list_TEMP[] =
1948 {"SEQUENCE", "TABLE", "VIEW", NULL};
1950 COMPLETE_WITH_LIST(list_TEMP);
1952 /* Complete "CREATE UNLOGGED" with TABLE */
1953 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1954 pg_strcasecmp(prev_wd, "UNLOGGED") == 0)
1956 COMPLETE_WITH_CONST("TABLE");
1959 /* CREATE TABLESPACE */
1960 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1961 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1963 static const char *const list_CREATETABLESPACE[] =
1964 {"OWNER", "LOCATION", NULL};
1966 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1968 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1969 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1970 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1971 pg_strcasecmp(prev2_wd, "OWNER") == 0)
1973 COMPLETE_WITH_CONST("LOCATION");
1976 /* CREATE TEXT SEARCH */
1977 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1978 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1979 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1981 static const char *const list_CREATETEXTSEARCH[] =
1982 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1984 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
1986 else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1987 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1988 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1989 COMPLETE_WITH_CONST("(");
1991 /* CREATE TRIGGER */
1992 /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1993 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1994 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1996 static const char *const list_CREATETRIGGER[] =
1997 {"BEFORE", "AFTER", "INSTEAD OF", NULL};
1999 COMPLETE_WITH_LIST(list_CREATETRIGGER);
2001 /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
2002 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2003 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
2004 (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
2005 pg_strcasecmp(prev_wd, "AFTER") == 0))
2007 static const char *const list_CREATETRIGGER_EVENTS[] =
2008 {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
2010 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
2012 /* complete CREATE TRIGGER <name> INSTEAD OF with an event */
2013 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2014 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2015 pg_strcasecmp(prev2_wd, "INSTEAD") == 0 &&
2016 pg_strcasecmp(prev_wd, "OF") == 0)
2018 static const char *const list_CREATETRIGGER_EVENTS[] =
2019 {"INSERT", "DELETE", "UPDATE", NULL};
2021 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
2023 /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
2024 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2025 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2026 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2027 pg_strcasecmp(prev2_wd, "AFTER") == 0)) ||
2028 (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
2029 pg_strcasecmp(prev3_wd, "INSTEAD") == 0 &&
2030 pg_strcasecmp(prev2_wd, "OF") == 0))
2032 static const char *const list_CREATETRIGGER2[] =
2035 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
2039 * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
2042 else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
2043 (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
2044 pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
2045 pg_strcasecmp(prev_wd, "ON") == 0)
2046 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2047 /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
2048 else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 &&
2049 pg_strcasecmp(prev3_wd, "OF") == 0 &&
2050 pg_strcasecmp(prev_wd, "ON") == 0)
2051 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2052 /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
2053 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2054 prev2_wd[0] != '\0')
2055 COMPLETE_WITH_CONST("PROCEDURE");
2057 /* CREATE ROLE,USER,GROUP <name> */
2058 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2059 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
2060 (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
2061 pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
2063 static const char *const list_CREATEROLE[] =
2064 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
2065 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB",
2066 "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN",
2067 "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE",
2068 "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL};
2070 COMPLETE_WITH_LIST(list_CREATEROLE);
2073 /* CREATE ROLE,USER,GROUP <name> WITH */
2074 else if ((pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2075 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2076 pg_strcasecmp(prev3_wd, "GROUP") == 0 ||
2077 pg_strcasecmp(prev3_wd, "USER") == 0) &&
2078 pg_strcasecmp(prev_wd, "WITH") == 0))
2080 /* Similar to the above, but don't complete "WITH" again. */
2081 static const char *const list_CREATEROLE_WITH[] =
2082 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
2083 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB",
2084 "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN",
2085 "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE",
2086 "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", NULL};
2088 COMPLETE_WITH_LIST(list_CREATEROLE_WITH);
2092 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
2095 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2096 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2097 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
2098 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
2100 COMPLETE_WITH_CONST("PASSWORD");
2102 /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
2103 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2104 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2105 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
2106 pg_strcasecmp(prev_wd, "IN") == 0)
2108 static const char *const list_CREATEROLE3[] =
2109 {"GROUP", "ROLE", NULL};
2111 COMPLETE_WITH_LIST(list_CREATEROLE3);
2115 /* Complete CREATE VIEW <name> with AS */
2116 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2117 pg_strcasecmp(prev2_wd, "VIEW") == 0)
2118 COMPLETE_WITH_CONST("AS");
2119 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
2120 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2121 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2122 pg_strcasecmp(prev_wd, "AS") == 0)
2123 COMPLETE_WITH_CONST("SELECT");
2126 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
2128 static const char *const list_DECLARE[] =
2129 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
2131 COMPLETE_WITH_LIST(list_DECLARE);
2135 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
2137 static const char *const list_DECLARECURSOR[] =
2138 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
2140 COMPLETE_WITH_LIST(list_DECLARECURSOR);
2147 * Complete DELETE with FROM (only if the word before that is not "ON"
2148 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
2150 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
2151 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
2152 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2153 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2154 pg_strcasecmp(prev2_wd, "AFTER") == 0))
2155 COMPLETE_WITH_CONST("FROM");
2156 /* Complete DELETE FROM with a list of tables */
2157 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
2158 pg_strcasecmp(prev_wd, "FROM") == 0)
2159 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL);
2160 /* Complete DELETE FROM <table> */
2161 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
2162 pg_strcasecmp(prev2_wd, "FROM") == 0)
2164 static const char *const list_DELETE[] =
2165 {"USING", "WHERE", "SET", NULL};
2167 COMPLETE_WITH_LIST(list_DELETE);
2169 /* XXX: implement tab completion for DELETE ... USING */
2172 else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
2174 static const char *const list_DISCARD[] =
2175 {"ALL", "PLANS", "TEMP", NULL};
2177 COMPLETE_WITH_LIST(list_DISCARD);
2183 * Complete DO with LANGUAGE.
2185 else if (pg_strcasecmp(prev_wd, "DO") == 0)
2187 static const char *const list_DO[] =
2190 COMPLETE_WITH_LIST(list_DO);
2193 /* DROP (when not the previous word) */
2194 /* DROP AGGREGATE */
2195 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2196 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
2197 COMPLETE_WITH_CONST("(");
2199 /* DROP object with CASCADE / RESTRICT */
2200 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2201 (pg_strcasecmp(prev2_wd, "COLLATION") == 0 ||
2202 pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
2203 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
2204 pg_strcasecmp(prev2_wd, "EXTENSION") == 0 ||
2205 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
2206 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2207 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
2208 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
2209 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
2210 pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
2211 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
2212 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
2213 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
2214 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2215 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
2216 prev_wd[strlen(prev_wd) - 1] == ')') ||
2217 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2218 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2219 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2220 pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
2221 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2222 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2223 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2224 (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
2225 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
2226 pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
2227 pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
2230 if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2231 pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
2233 COMPLETE_WITH_CONST("(");
2237 static const char *const list_DROPCR[] =
2238 {"CASCADE", "RESTRICT", NULL};
2240 COMPLETE_WITH_LIST(list_DROPCR);
2243 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2244 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2246 static const char *const drop_CREATE_FOREIGN[] =
2247 {"DATA WRAPPER", "TABLE", NULL};
2249 COMPLETE_WITH_LIST(drop_CREATE_FOREIGN);
2251 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2252 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
2253 pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
2254 pg_strcasecmp(prev_wd, "(") == 0)
2255 COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
2257 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2258 pg_strcasecmp(prev_wd, "OWNED") == 0)
2259 COMPLETE_WITH_CONST("BY");
2260 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2261 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2262 pg_strcasecmp(prev_wd, "BY") == 0)
2263 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2264 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2265 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2266 pg_strcasecmp(prev_wd, "SEARCH") == 0)
2269 static const char *const list_ALTERTEXTSEARCH[] =
2270 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2272 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
2275 /* EXECUTE, but not EXECUTE embedded in other commands */
2276 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2277 prev2_wd[0] == '\0')
2278 COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
2283 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2285 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
2287 static const char *const list_EXPLAIN[] =
2288 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
2290 COMPLETE_WITH_LIST(list_EXPLAIN);
2292 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2293 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2295 static const char *const list_EXPLAIN[] =
2296 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
2298 COMPLETE_WITH_LIST(list_EXPLAIN);
2300 else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2301 pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
2302 (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
2303 pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
2304 pg_strcasecmp(prev_wd, "VERBOSE") == 0))
2306 static const char *const list_EXPLAIN[] =
2307 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
2309 COMPLETE_WITH_LIST(list_EXPLAIN);
2313 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
2314 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
2315 pg_strcasecmp(prev_wd, "MOVE") == 0)
2317 static const char *const list_FETCH1[] =
2318 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
2320 COMPLETE_WITH_LIST(list_FETCH1);
2322 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
2323 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
2324 pg_strcasecmp(prev2_wd, "MOVE") == 0)
2326 static const char *const list_FETCH2[] =
2327 {"ALL", "NEXT", "PRIOR", NULL};
2329 COMPLETE_WITH_LIST(list_FETCH2);
2333 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
2334 * but we may as well tab-complete both: perhaps some users prefer one
2335 * variant or the other.
2337 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
2338 pg_strcasecmp(prev3_wd, "MOVE") == 0)
2340 static const char *const list_FROMIN[] =
2341 {"FROM", "IN", NULL};
2343 COMPLETE_WITH_LIST(list_FROMIN);
2346 /* FOREIGN DATA WRAPPER */
2347 /* applies in ALTER/DROP FDW and in CREATE SERVER */
2348 else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
2349 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
2350 pg_strcasecmp(prev2_wd, "DATA") == 0 &&
2351 pg_strcasecmp(prev_wd, "WRAPPER") == 0)
2352 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2355 else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 &&
2356 pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
2357 pg_strcasecmp(prev_wd, "TABLE") == 0)
2358 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
2360 /* GRANT && REVOKE */
2361 /* Complete GRANT/REVOKE with a list of roles and privileges */
2362 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
2363 pg_strcasecmp(prev_wd, "REVOKE") == 0)
2365 COMPLETE_WITH_QUERY(Query_for_list_of_roles
2366 " UNION SELECT 'SELECT'"
2367 " UNION SELECT 'INSERT'"
2368 " UNION SELECT 'UPDATE'"
2369 " UNION SELECT 'DELETE'"
2370 " UNION SELECT 'TRUNCATE'"
2371 " UNION SELECT 'REFERENCES'"
2372 " UNION SELECT 'TRIGGER'"
2373 " UNION SELECT 'CREATE'"
2374 " UNION SELECT 'CONNECT'"
2375 " UNION SELECT 'TEMPORARY'"
2376 " UNION SELECT 'EXECUTE'"
2377 " UNION SELECT 'USAGE'"
2378 " UNION SELECT 'ALL'");
2382 * Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
2385 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2386 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
2388 if (pg_strcasecmp(prev_wd, "SELECT") == 0
2389 || pg_strcasecmp(prev_wd, "INSERT") == 0
2390 || pg_strcasecmp(prev_wd, "UPDATE") == 0
2391 || pg_strcasecmp(prev_wd, "DELETE") == 0
2392 || pg_strcasecmp(prev_wd, "TRUNCATE") == 0
2393 || pg_strcasecmp(prev_wd, "REFERENCES") == 0
2394 || pg_strcasecmp(prev_wd, "TRIGGER") == 0
2395 || pg_strcasecmp(prev_wd, "CREATE") == 0
2396 || pg_strcasecmp(prev_wd, "CONNECT") == 0
2397 || pg_strcasecmp(prev_wd, "TEMPORARY") == 0
2398 || pg_strcasecmp(prev_wd, "TEMP") == 0
2399 || pg_strcasecmp(prev_wd, "EXECUTE") == 0
2400 || pg_strcasecmp(prev_wd, "USAGE") == 0
2401 || pg_strcasecmp(prev_wd, "ALL") == 0)
2402 COMPLETE_WITH_CONST("ON");
2405 if (pg_strcasecmp(prev2_wd, "GRANT") == 0)
2406 COMPLETE_WITH_CONST("TO");
2408 COMPLETE_WITH_CONST("FROM");
2413 * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
2416 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
2417 * UNION; seems to work intuitively
2419 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
2420 * here will only work if the privilege list contains exactly one
2423 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
2424 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
2425 pg_strcasecmp(prev_wd, "ON") == 0)
2426 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf,
2427 " UNION SELECT 'DATABASE'"
2428 " UNION SELECT 'DOMAIN'"
2429 " UNION SELECT 'FOREIGN DATA WRAPPER'"
2430 " UNION SELECT 'FOREIGN SERVER'"
2431 " UNION SELECT 'FUNCTION'"
2432 " UNION SELECT 'LANGUAGE'"
2433 " UNION SELECT 'LARGE OBJECT'"
2434 " UNION SELECT 'SCHEMA'"
2435 " UNION SELECT 'TABLESPACE'"
2436 " UNION SELECT 'TYPE'");
2437 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2438 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2439 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2440 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2442 static const char *const list_privilege_foreign[] =
2443 {"DATA WRAPPER", "SERVER", NULL};
2445 COMPLETE_WITH_LIST(list_privilege_foreign);
2448 /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
2449 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2450 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2451 pg_strcasecmp(prev2_wd, "ON") == 0)
2453 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
2454 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2455 else if (pg_strcasecmp(prev_wd, "DOMAIN") == 0)
2456 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2457 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
2458 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2459 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
2460 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2461 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
2462 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2463 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
2464 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2465 else if (pg_strcasecmp(prev_wd, "TYPE") == 0)
2466 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2467 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
2468 COMPLETE_WITH_CONST("TO");
2470 COMPLETE_WITH_CONST("FROM");
2473 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
2474 else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
2475 pg_strcasecmp(prev3_wd, "ON") == 0)
2477 if (pg_strcasecmp(prev_wd, "TO") == 0)
2478 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2480 COMPLETE_WITH_CONST("TO");
2482 else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
2483 pg_strcasecmp(prev3_wd, "ON") == 0)
2485 if (pg_strcasecmp(prev_wd, "FROM") == 0)
2486 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2488 COMPLETE_WITH_CONST("FROM");
2491 /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */
2492 else if (pg_strcasecmp(prev3_wd, "GRANT") == 0 &&
2493 pg_strcasecmp(prev_wd, "TO") == 0)
2495 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2497 else if (pg_strcasecmp(prev3_wd, "REVOKE") == 0 &&
2498 pg_strcasecmp(prev_wd, "FROM") == 0)
2500 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2504 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2505 pg_strcasecmp(prev_wd, "GROUP") == 0)
2506 COMPLETE_WITH_CONST("BY");
2509 /* Complete INSERT with "INTO" */
2510 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
2511 COMPLETE_WITH_CONST("INTO");
2512 /* Complete INSERT INTO with table names */
2513 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
2514 pg_strcasecmp(prev_wd, "INTO") == 0)
2515 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL);
2516 /* Complete "INSERT INTO <table> (" with attribute names */
2517 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2518 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2519 pg_strcasecmp(prev_wd, "(") == 0)
2520 COMPLETE_WITH_ATTR(prev2_wd, "");
2523 * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
2524 * "TABLE" or "DEFAULT VALUES"
2526 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
2527 pg_strcasecmp(prev2_wd, "INTO") == 0)
2529 static const char *const list_INSERT[] =
2530 {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
2532 COMPLETE_WITH_LIST(list_INSERT);
2536 * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
2539 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2540 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2541 prev_wd[strlen(prev_wd) - 1] == ')')
2543 static const char *const list_INSERT[] =
2544 {"SELECT", "TABLE", "VALUES", NULL};
2546 COMPLETE_WITH_LIST(list_INSERT);
2549 /* Insert an open parenthesis after "VALUES" */
2550 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
2551 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
2552 COMPLETE_WITH_CONST("(");
2555 /* Complete LOCK [TABLE] with a list of tables */
2556 else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
2557 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2558 " UNION SELECT 'TABLE'");
2559 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2560 pg_strcasecmp(prev2_wd, "LOCK") == 0)
2561 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
2563 /* For the following, handle the case of a single table only for now */
2565 /* Complete LOCK [TABLE] <table> with "IN" */
2566 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
2567 pg_strcasecmp(prev_wd, "TABLE") != 0) ||
2568 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
2569 pg_strcasecmp(prev3_wd, "LOCK") == 0))
2570 COMPLETE_WITH_CONST("IN");
2572 /* Complete LOCK [TABLE] <table> IN with a lock mode */
2573 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
2574 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
2575 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
2576 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
2578 static const char *const lock_modes[] =
2579 {"ACCESS SHARE MODE",
2580 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
2581 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
2582 "SHARE ROW EXCLUSIVE MODE",
2583 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
2585 COMPLETE_WITH_LIST(lock_modes);
2589 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
2590 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'");
2593 else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
2594 COMPLETE_WITH_CONST("(");
2596 /* OWNER TO - complete with available roles */
2597 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
2598 pg_strcasecmp(prev_wd, "TO") == 0)
2599 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2602 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2603 pg_strcasecmp(prev_wd, "ORDER") == 0)
2604 COMPLETE_WITH_CONST("BY");
2605 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
2606 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
2607 pg_strcasecmp(prev_wd, "BY") == 0)
2608 COMPLETE_WITH_ATTR(prev3_wd, "");
2611 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
2612 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
2614 static const char *const list_PREPARE[] =
2615 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2617 COMPLETE_WITH_LIST(list_PREPARE);
2621 * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
2622 * managers, not for manual use in interactive sessions.
2625 /* REASSIGN OWNED BY xxx TO yyy */
2626 else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
2627 COMPLETE_WITH_CONST("OWNED");
2628 else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
2629 pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
2630 COMPLETE_WITH_CONST("BY");
2631 else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
2632 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2633 pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
2634 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2635 else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
2636 pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
2637 pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
2638 COMPLETE_WITH_CONST("TO");
2639 else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
2640 pg_strcasecmp(prev3_wd, "BY") == 0 &&
2641 pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
2642 pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
2643 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2646 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
2648 static const char *const list_REINDEX[] =
2649 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
2651 COMPLETE_WITH_LIST(list_REINDEX);
2653 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
2655 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
2656 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2657 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
2658 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2659 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
2660 pg_strcasecmp(prev_wd, "DATABASE") == 0)
2661 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2664 /* SECURITY LABEL */
2665 else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
2666 COMPLETE_WITH_CONST("LABEL");
2667 else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
2668 pg_strcasecmp(prev_wd, "LABEL") == 0)
2670 static const char *const list_SECURITY_LABEL_preposition[] =
2673 COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
2675 else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
2676 pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
2677 pg_strcasecmp(prev2_wd, "FOR") == 0)
2678 COMPLETE_WITH_CONST("ON");
2679 else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
2680 pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
2681 pg_strcasecmp(prev_wd, "ON") == 0) ||
2682 (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2683 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2684 pg_strcasecmp(prev3_wd, "FOR") == 0 &&
2685 pg_strcasecmp(prev_wd, "ON") == 0))
2687 static const char *const list_SECURITY_LABEL[] =
2688 {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN",
2689 "AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT",
2692 COMPLETE_WITH_LIST(list_SECURITY_LABEL);
2694 else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2695 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2696 pg_strcasecmp(prev3_wd, "ON") == 0)
2697 COMPLETE_WITH_CONST("IS");
2702 /* SET, RESET, SHOW */
2703 /* Complete with a variable name */
2704 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
2705 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
2706 pg_strcasecmp(prev_wd, "RESET") == 0)
2707 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
2708 else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
2709 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
2710 /* Complete "SET TRANSACTION" */
2711 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
2712 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2713 || (pg_strcasecmp(prev2_wd, "START") == 0
2714 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2715 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2716 && pg_strcasecmp(prev_wd, "WORK") == 0)
2717 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2718 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2719 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
2720 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
2721 && pg_strcasecmp(prev2_wd, "AS") == 0
2722 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
2724 static const char *const my_list[] =
2725 {"ISOLATION LEVEL", "READ", NULL};
2727 COMPLETE_WITH_LIST(my_list);
2729 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
2730 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
2731 || pg_strcasecmp(prev3_wd, "START") == 0
2732 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
2733 && pg_strcasecmp(prev3_wd, "AS") == 0))
2734 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
2735 || pg_strcasecmp(prev2_wd, "WORK") == 0)
2736 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
2737 COMPLETE_WITH_CONST("LEVEL");
2738 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
2739 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
2740 || pg_strcasecmp(prev4_wd, "START") == 0
2741 || pg_strcasecmp(prev4_wd, "AS") == 0)
2742 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
2743 || pg_strcasecmp(prev3_wd, "WORK") == 0)
2744 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
2745 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
2747 static const char *const my_list[] =
2748 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
2750 COMPLETE_WITH_LIST(my_list);
2752 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2753 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2754 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2755 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2756 pg_strcasecmp(prev_wd, "READ") == 0)
2758 static const char *const my_list[] =
2759 {"UNCOMMITTED", "COMMITTED", NULL};
2761 COMPLETE_WITH_LIST(my_list);
2763 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2764 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2765 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2766 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2767 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
2768 COMPLETE_WITH_CONST("READ");
2769 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
2770 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
2771 pg_strcasecmp(prev3_wd, "START") == 0 ||
2772 pg_strcasecmp(prev3_wd, "AS") == 0) &&
2773 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
2774 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
2775 pg_strcasecmp(prev_wd, "READ") == 0)
2777 static const char *const my_list[] =
2778 {"ONLY", "WRITE", NULL};
2780 COMPLETE_WITH_LIST(my_list);
2782 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
2783 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2784 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
2786 static const char *const constraint_list[] =
2787 {"DEFERRED", "IMMEDIATE", NULL};
2789 COMPLETE_WITH_LIST(constraint_list);
2791 /* Complete SET ROLE */
2792 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2793 pg_strcasecmp(prev_wd, "ROLE") == 0)
2794 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2795 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
2796 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2797 pg_strcasecmp(prev_wd, "SESSION") == 0)
2799 static const char *const my_list[] =
2800 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
2802 COMPLETE_WITH_LIST(my_list);
2804 /* Complete SET SESSION AUTHORIZATION with username */
2805 else if (pg_strcasecmp(prev3_wd, "SET") == 0
2806 && pg_strcasecmp(prev2_wd, "SESSION") == 0
2807 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
2808 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
2809 /* Complete RESET SESSION with AUTHORIZATION */
2810 else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
2811 pg_strcasecmp(prev_wd, "SESSION") == 0)
2812 COMPLETE_WITH_CONST("AUTHORIZATION");
2813 /* Complete SET <var> with "TO" */
2814 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2815 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
2816 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
2817 pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
2818 prev_wd[strlen(prev_wd) - 1] != ')' &&
2819 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
2820 COMPLETE_WITH_CONST("TO");
2821 /* Suggest possible variable values */
2822 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2823 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
2825 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
2827 static const char *const my_list[] =
2828 {"ISO", "SQL", "Postgres", "German",
2829 "YMD", "DMY", "MDY",
2830 "US", "European", "NonEuropean",
2833 COMPLETE_WITH_LIST(my_list);
2835 else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
2837 static const char *const my_list[] =
2838 {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
2840 COMPLETE_WITH_LIST(my_list);
2842 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
2844 static const char *const my_list[] =
2845 {"ON", "OFF", "DEFAULT", NULL};
2847 COMPLETE_WITH_LIST(my_list);
2851 static const char *const my_list[] =
2854 COMPLETE_WITH_LIST(my_list);
2858 /* START TRANSACTION */
2859 else if (pg_strcasecmp(prev_wd, "START") == 0)
2860 COMPLETE_WITH_CONST("TRANSACTION");
2862 /* TABLE, but not TABLE embedded in other commands */
2863 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2864 prev2_wd[0] == '\0')
2865 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
2868 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
2869 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2872 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
2873 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 '*'");
2876 /* If prev. word is UPDATE suggest a list of tables */
2877 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
2878 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
2879 /* Complete UPDATE <table> with "SET" */
2880 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
2881 COMPLETE_WITH_CONST("SET");
2884 * If the previous word is SET (and it wasn't caught above as the _first_
2885 * word) the word before it was (hopefully) a table name and we'll now
2886 * make a list of attributes.
2888 else if (pg_strcasecmp(prev_wd, "SET") == 0)
2889 COMPLETE_WITH_ATTR(prev2_wd, "");
2891 /* UPDATE xx SET yy = */
2892 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2893 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
2894 COMPLETE_WITH_CONST("=");
2897 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
2898 pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2899 pg_strcasecmp(prev3_wd, "DROP") == 0) &&
2900 pg_strcasecmp(prev2_wd, "USER") == 0 &&
2901 pg_strcasecmp(prev_wd, "MAPPING") == 0)
2902 COMPLETE_WITH_CONST("FOR");
2903 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2904 pg_strcasecmp(prev3_wd, "USER") == 0 &&
2905 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2906 pg_strcasecmp(prev_wd, "FOR") == 0)
2907 COMPLETE_WITH_QUERY(Query_for_list_of_roles
2908 " UNION SELECT 'CURRENT_USER'"
2909 " UNION SELECT 'PUBLIC'"
2910 " UNION SELECT 'USER'");
2911 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
2912 pg_strcasecmp(prev4_wd, "DROP") == 0) &&
2913 pg_strcasecmp(prev3_wd, "USER") == 0 &&
2914 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2915 pg_strcasecmp(prev_wd, "FOR") == 0)
2916 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2917 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
2918 pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
2919 pg_strcasecmp(prev5_wd, "DROP") == 0) &&
2920 pg_strcasecmp(prev4_wd, "USER") == 0 &&
2921 pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
2922 pg_strcasecmp(prev2_wd, "FOR") == 0)
2923 COMPLETE_WITH_CONST("SERVER");
2926 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
2927 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
2929 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
2930 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2931 " UNION SELECT 'FULL'"
2932 " UNION SELECT 'FREEZE'"
2933 " UNION SELECT 'ANALYZE'"
2934 " UNION SELECT 'VERBOSE'");
2935 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2936 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
2937 pg_strcasecmp(prev_wd, "FREEZE") == 0))
2938 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2939 " UNION SELECT 'ANALYZE'"
2940 " UNION SELECT 'VERBOSE'");
2941 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2942 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2943 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2944 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2945 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2946 " UNION SELECT 'VERBOSE'");
2947 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2948 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2949 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2950 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2951 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2952 " UNION SELECT 'ANALYZE'");
2953 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2954 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
2955 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2956 " UNION SELECT 'ANALYZE'");
2957 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2958 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2959 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2960 " UNION SELECT 'VERBOSE'");
2961 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2962 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
2963 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2964 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
2965 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2967 /* WITH [RECURSIVE] */
2970 * Only match when WITH is the first word, as WITH may appear in many
2973 else if (pg_strcasecmp(prev_wd, "WITH") == 0 &&
2974 prev2_wd[0] == '\0')
2975 COMPLETE_WITH_CONST("RECURSIVE");
2978 /* If the previous word is ANALYZE, produce list of tables */
2979 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2980 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tf, NULL);
2983 /* Simple case of the word before the where being the table name */
2984 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
2985 COMPLETE_WITH_ATTR(prev2_wd, "");
2988 /* TODO: also include SRF ? */
2989 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
2990 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
2991 pg_strcasecmp(prev3_wd, "\\copy") != 0)
2992 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2995 else if (pg_strcasecmp(prev_wd, "JOIN") == 0)
2996 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2998 /* Backslash commands */
2999 /* TODO: \dc \dd \dl */
3000 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
3001 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3003 else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
3004 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
3005 else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
3006 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
3007 else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
3008 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
3009 else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
3010 COMPLETE_WITH_QUERY(Query_for_list_of_servers);
3011 else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
3012 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3013 else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
3014 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
3016 else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
3017 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3018 else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
3019 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
3020 else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
3021 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
3022 else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
3023 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
3024 /* must be at end of \dF */
3025 else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
3026 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
3028 else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
3029 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
3030 else if (strncmp(prev_wd, "\\dL", strlen("\\dL")) == 0)
3031 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
3032 else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
3033 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3034 else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0
3035 || strncmp(prev_wd, "\\z", strlen("\\z")) == 0)
3036 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
3037 else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
3038 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
3039 else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
3040 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3041 else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
3042 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
3043 else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0
3044 || (strncmp(prev_wd, "\\dg", strlen("\\dg")) == 0))
3045 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3046 else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
3047 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
3049 /* must be at end of \d list */
3050 else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
3051 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3053 else if (strcmp(prev_wd, "\\ef") == 0)
3054 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3056 else if (strcmp(prev_wd, "\\encoding") == 0)
3057 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
3058 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
3059 COMPLETE_WITH_LIST(sql_commands);
3060 else if (strcmp(prev_wd, "\\password") == 0)
3061 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3062 else if (strcmp(prev_wd, "\\pset") == 0)
3064 static const char *const my_list[] =
3065 {"format", "border", "expanded",
3066 "null", "fieldsep", "tuples_only", "title", "tableattr",
3067 "linestyle", "pager", "recordsep", NULL};
3069 COMPLETE_WITH_LIST_CS(my_list);
3071 else if (strcmp(prev2_wd, "\\pset") == 0)
3073 if (strcmp(prev_wd, "format") == 0)
3075 static const char *const my_list[] =
3076 {"unaligned", "aligned", "wrapped", "html", "latex",
3079 COMPLETE_WITH_LIST_CS(my_list);
3081 else if (strcmp(prev_wd, "linestyle") == 0)
3083 static const char *const my_list[] =
3084 {"ascii", "old-ascii", "unicode", NULL};
3086 COMPLETE_WITH_LIST_CS(my_list);
3089 else if (strcmp(prev_wd, "\\set") == 0)
3091 matches = complete_from_variables(text, "", "");
3093 else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
3094 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3095 else if (strcmp(prev_wd, "\\cd") == 0 ||
3096 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
3097 strcmp(prev_wd, "\\g") == 0 ||
3098 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
3099 strcmp(prev_wd, "\\ir") == 0 || strcmp(prev_wd, "\\include_relative") == 0 ||
3100 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
3101 strcmp(prev_wd, "\\s") == 0 ||
3102 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
3105 completion_charp = "\\";
3106 matches = completion_matches(text, complete_from_files);
3110 * Finally, we look through the list of "things", such as TABLE, INDEX and
3111 * check if that was the previous word. If so, execute the query to get a
3118 for (i = 0; words_after_create[i].name; i++)
3120 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
3122 if (words_after_create[i].query)
3123 COMPLETE_WITH_QUERY(words_after_create[i].query);
3124 else if (words_after_create[i].squery)
3125 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
3133 * If we still don't have anything to match we have to fabricate some sort
3134 * of default list. If we were to just return NULL, readline automatically
3135 * attempts filename completion, and that's usually no good.
3137 if (matches == NULL)
3139 COMPLETE_WITH_CONST("");
3140 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
3141 rl_completion_append_character = '\0';
3149 for (i = 0; i < lengthof(previous_words); i++)
3150 free(previous_words[i]);
3153 /* Return our Grand List O' Matches */
3159 * GENERATOR FUNCTIONS
3161 * These functions do all the actual work of completing the input. They get
3162 * passed the text so far and the count how many times they have been called
3163 * so far with the same text.
3164 * If you read the above carefully, you'll see that these don't get called
3165 * directly but through the readline interface.
3166 * The return value is expected to be the full completion of the text, going
3167 * through a list each time, or NULL if there are no more matches. The string
3168 * will be free()'d by readline, so you must run it through strdup() or
3169 * something of that sort.
3173 * Common routine for create_command_generator and drop_command_generator.
3174 * Entries that have 'excluded' flags are not returned.
3177 create_or_drop_command_generator(const char *text, int state, bits32 excluded)
3179 static int list_index,
3183 /* If this is the first time for this completion, init some values */
3187 string_length = strlen(text);
3190 /* find something that matches */
3191 while ((name = words_after_create[list_index++].name))
3193 if ((pg_strncasecmp(name, text, string_length) == 0) &&
3194 !(words_after_create[list_index - 1].flags & excluded))
3195 return pg_strdup_keyword_case(name, text);
3197 /* if nothing matches, return NULL */
3202 * This one gives you one from a list of things you can put after CREATE
3206 create_command_generator(const char *text, int state)
3208 return create_or_drop_command_generator(text, state, THING_NO_CREATE);
3212 * This function gives you a list of things you can put after a DROP command.
3215 drop_command_generator(const char *text, int state)
3217 return create_or_drop_command_generator(text, state, THING_NO_DROP);
3220 /* The following two functions are wrappers for _complete_from_query */
3223 complete_from_query(const char *text, int state)
3225 return _complete_from_query(0, text, state);
3229 complete_from_schema_query(const char *text, int state)
3231 return _complete_from_query(1, text, state);
3236 * This creates a list of matching things, according to a query pointed to
3237 * by completion_charp.
3238 * The query can be one of two kinds:
3240 * 1. A simple query which must contain a %d and a %s, which will be replaced
3241 * by the string length of the text and the text itself. The query may also
3242 * have up to four more %s in it; the first two such will be replaced by the
3243 * value of completion_info_charp, the next two by the value of
3244 * completion_info_charp2.
3246 * 2. A schema query used for completion of both schema and relation names.
3247 * These are more complex and must contain in the following order:
3248 * %d %s %d %s %d %s %s %d %s
3249 * where %d is the string length of the text and %s the text itself.
3251 * It is assumed that strings should be escaped to become SQL literals
3252 * (that is, what is in the query is actually ... '%s' ...)
3254 * See top of file for examples of both kinds of query.
3257 _complete_from_query(int is_schema_query, const char *text, int state)
3259 static int list_index,
3261 static PGresult *result = NULL;
3264 * If this is the first time for this completion, we fetch a list of our
3265 * "things" from the backend.
3269 PQExpBufferData query_buffer;
3272 char *e_info_charp2;
3275 string_length = strlen(text);
3277 /* Free any prior result */
3281 /* Set up suitably-escaped copies of textual inputs */
3282 e_text = pg_malloc(string_length * 2 + 1);
3283 PQescapeString(e_text, text, string_length);
3285 if (completion_info_charp)
3289 charp_len = strlen(completion_info_charp);
3290 e_info_charp = pg_malloc(charp_len * 2 + 1);
3291 PQescapeString(e_info_charp, completion_info_charp,
3295 e_info_charp = NULL;
3297 if (completion_info_charp2)
3301 charp_len = strlen(completion_info_charp2);
3302 e_info_charp2 = pg_malloc(charp_len * 2 + 1);
3303 PQescapeString(e_info_charp2, completion_info_charp2,
3307 e_info_charp2 = NULL;
3309 initPQExpBuffer(&query_buffer);
3311 if (is_schema_query)
3313 /* completion_squery gives us the pieces to assemble */
3314 const char *qualresult = completion_squery->qualresult;
3316 if (qualresult == NULL)
3317 qualresult = completion_squery->result;
3319 /* Get unqualified names matching the input-so-far */
3320 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
3321 completion_squery->result,
3322 completion_squery->catname);
3323 if (completion_squery->selcondition)
3324 appendPQExpBuffer(&query_buffer, "%s AND ",
3325 completion_squery->selcondition);
3326 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
3327 completion_squery->result,
3328 string_length, e_text);
3329 appendPQExpBuffer(&query_buffer, " AND %s",
3330 completion_squery->viscondition);
3333 * When fetching relation names, suppress system catalogs unless
3334 * the input-so-far begins with "pg_". This is a compromise
3335 * between not offering system catalogs for completion at all, and
3336 * having them swamp the result when the input is just "p".
3338 if (strcmp(completion_squery->catname,
3339 "pg_catalog.pg_class c") == 0 &&
3340 strncmp(text, "pg_", 3) !=0)
3342 appendPQExpBuffer(&query_buffer,
3343 " AND c.relnamespace <> (SELECT oid FROM"
3344 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
3348 * Add in matching schema names, but only if there is more than
3349 * one potential match among schema names.
3351 appendPQExpBuffer(&query_buffer, "\nUNION\n"
3352 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
3353 "FROM pg_catalog.pg_namespace n "
3354 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
3355 string_length, e_text);
3356 appendPQExpBuffer(&query_buffer,
3357 " AND (SELECT pg_catalog.count(*)"
3358 " FROM pg_catalog.pg_namespace"
3359 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3360 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
3361 string_length, e_text);
3364 * Add in matching qualified names, but only if there is exactly
3365 * one schema matching the input-so-far.
3367 appendPQExpBuffer(&query_buffer, "\nUNION\n"
3368 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
3369 "FROM %s, pg_catalog.pg_namespace n "
3370 "WHERE %s = n.oid AND ",
3372 completion_squery->catname,
3373 completion_squery->namespace);
3374 if (completion_squery->selcondition)
3375 appendPQExpBuffer(&query_buffer, "%s AND ",
3376 completion_squery->selcondition);
3377 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
3379 string_length, e_text);
3382 * This condition exploits the single-matching-schema rule to
3383 * speed up the query
3385 appendPQExpBuffer(&query_buffer,
3386 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
3387 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
3388 string_length, e_text);
3389 appendPQExpBuffer(&query_buffer,
3390 " AND (SELECT pg_catalog.count(*)"
3391 " FROM pg_catalog.pg_namespace"
3392 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3393 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
3394 string_length, e_text);
3396 /* If an addon query was provided, use it */
3397 if (completion_charp)
3398 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
3402 /* completion_charp is an sprintf-style format string */
3403 appendPQExpBuffer(&query_buffer, completion_charp,
3404 string_length, e_text,
3405 e_info_charp, e_info_charp,
3406 e_info_charp2, e_info_charp2);
3409 /* Limit the number of records in the result */
3410 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
3411 completion_max_records);
3413 result = exec_query(query_buffer.data);
3415 termPQExpBuffer(&query_buffer);
3420 free(e_info_charp2);
3423 /* Find something that matches */
3424 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
3428 while (list_index < PQntuples(result) &&
3429 (item = PQgetvalue(result, list_index++, 0)))
3430 if (pg_strncasecmp(text, item, string_length) == 0)
3431 return pg_strdup(item);
3434 /* If nothing matches, free the db structure and return null */
3442 * This function returns in order one of a fixed, NULL pointer terminated list
3443 * of strings (if matching). This can be used if there are only a fixed number
3444 * SQL words that can appear at certain spot.
3447 complete_from_list(const char *text, int state)
3449 static int string_length,
3452 static bool casesensitive;
3455 /* need to have a list */
3456 psql_assert(completion_charpp);
3458 /* Initialization */
3462 string_length = strlen(text);
3463 casesensitive = completion_case_sensitive;
3467 while ((item = completion_charpp[list_index++]))
3469 /* First pass is case sensitive */
3470 if (casesensitive && strncmp(text, item, string_length) == 0)
3473 return pg_strdup(item);
3476 /* Second pass is case insensitive, don't bother counting matches */
3477 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
3479 if (completion_case_sensitive)
3480 return pg_strdup(item);
3484 * If case insensitive matching was requested initially,
3485 * adjust the case according to setting.
3487 return pg_strdup_keyword_case(item, text);
3492 * No matches found. If we're not case insensitive already, lets switch to
3493 * being case insensitive and try again
3495 if (casesensitive && matches == 0)
3497 casesensitive = false;
3500 return complete_from_list(text, state);
3503 /* If no more matches, return null. */
3509 * This function returns one fixed string the first time even if it doesn't
3510 * match what's there, and nothing the second time. This should be used if
3511 * there is only one possibility that can appear at a certain spot, so
3512 * misspellings will be overwritten. The string to be passed must be in
3516 complete_from_const(const char *text, int state)
3518 psql_assert(completion_charp);
3521 if (completion_case_sensitive)
3522 return pg_strdup(completion_charp);
3526 * If case insensitive matching was requested initially, adjust
3527 * the case according to setting.
3529 return pg_strdup_keyword_case(completion_charp, text);
3537 * This function supports completion with the name of a psql variable.
3538 * The variable names can be prefixed and suffixed with additional text
3539 * to support quoting usages.
3542 complete_from_variables(char *text, const char *prefix, const char *suffix)
3545 int overhead = strlen(prefix) + strlen(suffix) + 1;
3550 struct _variable *ptr;
3552 varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *));
3554 for (ptr = pset.vars->next; ptr; ptr = ptr->next)
3558 if (nvars >= maxvars)
3561 varnames = (char **) realloc(varnames,
3562 (maxvars + 1) * sizeof(char *));
3565 psql_error("out of memory\n");
3570 buffer = (char *) pg_malloc(strlen(ptr->name) + overhead);
3571 sprintf(buffer, "%s%s%s", prefix, ptr->name, suffix);
3572 varnames[nvars++] = buffer;
3575 varnames[nvars] = NULL;
3576 COMPLETE_WITH_LIST_CS((const char *const *) varnames);
3578 for (i = 0; i < nvars; i++)
3587 * This function wraps rl_filename_completion_function() to strip quotes from
3588 * the input before searching for matches and to quote any matches for which
3589 * the consuming command will require it.
3592 complete_from_files(const char *text, int state)
3594 static const char *unquoted_text;
3595 char *unquoted_match;
3600 /* Initialization: stash the unquoted input. */
3601 unquoted_text = strtokx(text, "", NULL, "'", *completion_charp,
3602 false, true, pset.encoding);
3603 /* expect a NULL return for the empty string only */
3606 psql_assert(!*text);
3607 unquoted_text = text;
3611 unquoted_match = filename_completion_function(unquoted_text, state);
3615 * Caller sets completion_charp to a zero- or one-character string
3616 * containing the escape character. This is necessary since \copy has
3617 * no escape character, but every other backslash command recognizes
3618 * "\" as an escape character. Since we have only two callers, don't
3619 * bother providing a macro to simplify this.
3621 ret = quote_if_needed(unquoted_match, " \t\r\n\"`",
3622 '\'', *completion_charp, pset.encoding);
3624 free(unquoted_match);
3626 ret = unquoted_match;
3633 /* HELPER FUNCTIONS */
3637 * Make a pg_strdup copy of s and convert the case according to
3638 * COMP_KEYWORD_CASE variable, using ref as the text that was already entered.
3641 pg_strdup_keyword_case(const char *s, const char *ref)
3645 unsigned char first = ref[0];
3649 varval = GetVariable(pset.vars, "COMP_KEYWORD_CASE");
3652 else if (strcmp(varval, "lower") == 0)
3654 else if (strcmp(varval, "preserve-lower") == 0)
3656 else if (strcmp(varval, "preserve-upper") == 0)
3658 else if (strcmp(varval, "upper") == 0)
3670 || ((tocase == -1 || tocase == +1) && islower(first))
3671 || (tocase == -1 && !isalpha(first))
3673 for (p = ret; *p; p++)
3674 *p = pg_tolower((unsigned char) *p);
3676 for (p = ret; *p; p++)
3677 *p = pg_toupper((unsigned char) *p);
3684 * Execute a query and report any errors. This should be the preferred way of
3685 * talking to the database in this file.
3688 exec_query(const char *query)
3692 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
3695 result = PQexec(pset.db, query);
3697 if (PQresultStatus(result) != PGRES_TUPLES_OK)
3700 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
3701 PQerrorMessage(pset.db), query);
3712 * Return the nwords word(s) before point. Words are returned right to left,
3713 * that is, previous_words[0] gets the last word before point.
3714 * If we run out of words, remaining array elements are set to empty strings.
3715 * Each array element is filled with a malloc'd string.
3718 get_previous_words(int point, char **previous_words, int nwords)
3720 const char *buf = rl_line_buffer; /* alias */
3723 /* first we look for a non-word char before the current point */
3724 for (i = point - 1; i >= 0; i--)
3725 if (strchr(WORD_BREAKS, buf[i]))
3729 while (nwords-- > 0)
3735 /* now find the first non-space which then constitutes the end */
3737 for (i = point; i >= 0; i--)
3739 if (!isspace((unsigned char) buf[i]))
3747 * If no end found we return an empty string, because there is no word
3758 * Otherwise we now look for the start. The start is either the
3759 * last character before any word-break character going backwards
3760 * from the end, or it's simply character 0. We also handle open
3761 * quotes and parentheses.
3763 bool inquotes = false;
3764 int parentheses = 0;
3766 for (start = end; start > 0; start--)
3768 if (buf[start] == '"')
3769 inquotes = !inquotes;
3772 if (buf[start] == ')')
3774 else if (buf[start] == '(')
3776 if (--parentheses <= 0)
3779 else if (parentheses == 0 &&
3780 strchr(WORD_BREAKS, buf[start - 1]))
3787 /* make a copy of chars from start to end inclusive */
3788 s = pg_malloc(end - start + 2);
3789 strlcpy(s, &buf[start], end - start + 2);
3792 *previous_words++ = s;
3799 * Surround a string with single quotes. This works for both SQL and
3800 * psql internal. Currently disabled because it is reported not to
3801 * cooperate with certain versions of readline.
3804 quote_file_name(char *text, int match_type, char *quote_pointer)
3809 (void) quote_pointer; /* not used */
3811 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
3812 s = pg_malloc(length);
3814 strcpy(s + 1, text);
3815 if (match_type == SINGLE_MATCH)
3816 s[length - 2] = '\'';
3817 s[length - 1] = '\0';
3822 dequote_file_name(char *text, char quote_char)
3828 return pg_strdup(text);
3830 length = strlen(text);
3831 s = pg_malloc(length - 2 + 1);
3832 strlcpy(s, text +1, length - 2 + 1);
3836 #endif /* NOT_USED */
3838 #endif /* USE_READLINE */