2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2015, 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 static const SchemaQuery Query_for_list_of_constraints_with_schema = {
359 "pg_catalog.pg_constraint c",
363 "true", /* there is no pg_constraint_is_visible */
367 "pg_catalog.quote_ident(c.conname)",
372 /* Relations supporting INSERT, UPDATE or DELETE */
373 static const SchemaQuery Query_for_list_of_updatables = {
375 "pg_catalog.pg_class c",
377 "c.relkind IN ('r', 'f', 'v')",
379 "pg_catalog.pg_table_is_visible(c.oid)",
383 "pg_catalog.quote_ident(c.relname)",
388 static const SchemaQuery Query_for_list_of_relations = {
390 "pg_catalog.pg_class c",
394 "pg_catalog.pg_table_is_visible(c.oid)",
398 "pg_catalog.quote_ident(c.relname)",
403 static const SchemaQuery Query_for_list_of_tsvmf = {
405 "pg_catalog.pg_class c",
407 "c.relkind IN ('r', 'S', 'v', 'm', 'f')",
409 "pg_catalog.pg_table_is_visible(c.oid)",
413 "pg_catalog.quote_ident(c.relname)",
418 static const SchemaQuery Query_for_list_of_tmf = {
420 "pg_catalog.pg_class c",
422 "c.relkind IN ('r', 'm', 'f')",
424 "pg_catalog.pg_table_is_visible(c.oid)",
428 "pg_catalog.quote_ident(c.relname)",
433 static const SchemaQuery Query_for_list_of_tm = {
435 "pg_catalog.pg_class c",
437 "c.relkind IN ('r', 'm')",
439 "pg_catalog.pg_table_is_visible(c.oid)",
443 "pg_catalog.quote_ident(c.relname)",
448 static const SchemaQuery Query_for_list_of_views = {
450 "pg_catalog.pg_class c",
452 "c.relkind IN ('v')",
454 "pg_catalog.pg_table_is_visible(c.oid)",
458 "pg_catalog.quote_ident(c.relname)",
463 static const SchemaQuery Query_for_list_of_matviews = {
465 "pg_catalog.pg_class c",
467 "c.relkind IN ('m')",
469 "pg_catalog.pg_table_is_visible(c.oid)",
473 "pg_catalog.quote_ident(c.relname)",
480 * Queries to get lists of names of various kinds of things, possibly
481 * restricted to names matching a partially entered name. In these queries,
482 * the first %s will be replaced by the text entered so far (suitably escaped
483 * to become a SQL literal string). %d will be replaced by the length of the
484 * string (in unescaped form). A second and third %s, if present, will be
485 * replaced by a suitably-escaped version of the string provided in
486 * completion_info_charp. A fourth and fifth %s are similarly replaced by
487 * completion_info_charp2.
489 * Beware that the allowed sequences of %s and %d are determined by
490 * _complete_from_query().
493 #define Query_for_list_of_attributes \
494 "SELECT pg_catalog.quote_ident(attname) "\
495 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
496 " WHERE c.oid = a.attrelid "\
497 " AND a.attnum > 0 "\
498 " AND NOT a.attisdropped "\
499 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
500 " AND (pg_catalog.quote_ident(relname)='%s' "\
501 " OR '\"' || relname || '\"'='%s') "\
502 " AND pg_catalog.pg_table_is_visible(c.oid)"
504 #define Query_for_list_of_attributes_with_schema \
505 "SELECT pg_catalog.quote_ident(attname) "\
506 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
507 " WHERE c.oid = a.attrelid "\
508 " AND n.oid = c.relnamespace "\
509 " AND a.attnum > 0 "\
510 " AND NOT a.attisdropped "\
511 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
512 " AND (pg_catalog.quote_ident(relname)='%s' "\
513 " OR '\"' || relname || '\"' ='%s') "\
514 " AND (pg_catalog.quote_ident(nspname)='%s' "\
515 " OR '\"' || nspname || '\"' ='%s') "
517 #define Query_for_list_of_template_databases \
518 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
519 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
521 #define Query_for_list_of_databases \
522 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
523 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
525 #define Query_for_list_of_tablespaces \
526 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
527 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
529 #define Query_for_list_of_encodings \
530 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
531 " FROM pg_catalog.pg_conversion "\
532 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
534 #define Query_for_list_of_languages \
535 "SELECT pg_catalog.quote_ident(lanname) "\
536 " FROM pg_catalog.pg_language "\
537 " WHERE lanname != 'internal' "\
538 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
540 #define Query_for_list_of_schemas \
541 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
542 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
544 #define Query_for_list_of_alter_system_set_vars \
546 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
547 " WHERE context != 'internal') ss "\
548 " WHERE substring(name,1,%d)='%s'"\
549 " UNION ALL SELECT 'all' ss"
551 #define Query_for_list_of_set_vars \
553 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
554 " WHERE context IN ('user', 'superuser') "\
555 " UNION ALL SELECT 'constraints' "\
556 " UNION ALL SELECT 'transaction' "\
557 " UNION ALL SELECT 'session' "\
558 " UNION ALL SELECT 'role' "\
559 " UNION ALL SELECT 'tablespace' "\
560 " UNION ALL SELECT 'all') ss "\
561 " WHERE substring(name,1,%d)='%s'"
563 #define Query_for_list_of_show_vars \
565 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
566 " UNION ALL SELECT 'session authorization' "\
567 " UNION ALL SELECT 'all') ss "\
568 " WHERE substring(name,1,%d)='%s'"
570 #define Query_for_list_of_roles \
571 " SELECT pg_catalog.quote_ident(rolname) "\
572 " FROM pg_catalog.pg_roles "\
573 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
575 #define Query_for_list_of_grant_roles \
576 " SELECT pg_catalog.quote_ident(rolname) "\
577 " FROM pg_catalog.pg_roles "\
578 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
579 " UNION ALL SELECT 'PUBLIC'"
581 /* the silly-looking length condition is just to eat up the current word */
582 #define Query_for_table_owning_index \
583 "SELECT pg_catalog.quote_ident(c1.relname) "\
584 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
585 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
586 " and (%d = pg_catalog.length('%s'))"\
587 " and pg_catalog.quote_ident(c2.relname)='%s'"\
588 " and pg_catalog.pg_table_is_visible(c2.oid)"
590 /* the silly-looking length condition is just to eat up the current word */
591 #define Query_for_index_of_table \
592 "SELECT pg_catalog.quote_ident(c2.relname) "\
593 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
594 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
595 " and (%d = pg_catalog.length('%s'))"\
596 " and pg_catalog.quote_ident(c1.relname)='%s'"\
597 " and pg_catalog.pg_table_is_visible(c2.oid)"
599 /* the silly-looking length condition is just to eat up the current word */
600 #define Query_for_constraint_of_table \
601 "SELECT pg_catalog.quote_ident(conname) "\
602 " FROM pg_catalog.pg_class c1, pg_catalog.pg_constraint con "\
603 " WHERE c1.oid=conrelid and (%d = pg_catalog.length('%s'))"\
604 " and pg_catalog.quote_ident(c1.relname)='%s'"\
605 " and pg_catalog.pg_table_is_visible(c1.oid)"
607 #define Query_for_all_table_constraints \
608 "SELECT pg_catalog.quote_ident(conname) "\
609 " FROM pg_catalog.pg_constraint c "\
610 " WHERE c.conrelid <> 0 "
612 /* the silly-looking length condition is just to eat up the current word */
613 #define Query_for_constraint_of_type \
614 "SELECT pg_catalog.quote_ident(conname) "\
615 " FROM pg_catalog.pg_type t, pg_catalog.pg_constraint con "\
616 " WHERE t.oid=contypid and (%d = pg_catalog.length('%s'))"\
617 " and pg_catalog.quote_ident(t.typname)='%s'"\
618 " and pg_catalog.pg_type_is_visible(t.oid)"
620 /* the silly-looking length condition is just to eat up the current word */
621 #define Query_for_list_of_tables_for_constraint \
622 "SELECT pg_catalog.quote_ident(relname) "\
623 " FROM pg_catalog.pg_class"\
624 " WHERE (%d = pg_catalog.length('%s'))"\
626 " (SELECT conrelid FROM pg_catalog.pg_constraint "\
627 " WHERE pg_catalog.quote_ident(conname)='%s')"
629 /* the silly-looking length condition is just to eat up the current word */
630 #define Query_for_rule_of_table \
631 "SELECT pg_catalog.quote_ident(rulename) "\
632 " FROM pg_catalog.pg_class c1, pg_catalog.pg_rewrite "\
633 " WHERE c1.oid=ev_class and (%d = pg_catalog.length('%s'))"\
634 " and pg_catalog.quote_ident(c1.relname)='%s'"\
635 " and pg_catalog.pg_table_is_visible(c1.oid)"
637 /* the silly-looking length condition is just to eat up the current word */
638 #define Query_for_list_of_tables_for_rule \
639 "SELECT pg_catalog.quote_ident(relname) "\
640 " FROM pg_catalog.pg_class"\
641 " WHERE (%d = pg_catalog.length('%s'))"\
643 " (SELECT ev_class FROM pg_catalog.pg_rewrite "\
644 " WHERE pg_catalog.quote_ident(rulename)='%s')"
646 /* the silly-looking length condition is just to eat up the current word */
647 #define Query_for_trigger_of_table \
648 "SELECT pg_catalog.quote_ident(tgname) "\
649 " FROM pg_catalog.pg_class c1, pg_catalog.pg_trigger "\
650 " WHERE c1.oid=tgrelid and (%d = pg_catalog.length('%s'))"\
651 " and pg_catalog.quote_ident(c1.relname)='%s'"\
652 " and pg_catalog.pg_table_is_visible(c1.oid)"\
653 " and not tgisinternal"
655 /* the silly-looking length condition is just to eat up the current word */
656 #define Query_for_list_of_tables_for_trigger \
657 "SELECT pg_catalog.quote_ident(relname) "\
658 " FROM pg_catalog.pg_class"\
659 " WHERE (%d = pg_catalog.length('%s'))"\
661 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
662 " WHERE pg_catalog.quote_ident(tgname)='%s')"
664 #define Query_for_list_of_ts_configurations \
665 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
666 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
668 #define Query_for_list_of_ts_dictionaries \
669 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
670 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
672 #define Query_for_list_of_ts_parsers \
673 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
674 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
676 #define Query_for_list_of_ts_templates \
677 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
678 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
680 #define Query_for_list_of_fdws \
681 " SELECT pg_catalog.quote_ident(fdwname) "\
682 " FROM pg_catalog.pg_foreign_data_wrapper "\
683 " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
685 #define Query_for_list_of_servers \
686 " SELECT pg_catalog.quote_ident(srvname) "\
687 " FROM pg_catalog.pg_foreign_server "\
688 " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
690 #define Query_for_list_of_user_mappings \
691 " SELECT pg_catalog.quote_ident(usename) "\
692 " FROM pg_catalog.pg_user_mappings "\
693 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
695 #define Query_for_list_of_access_methods \
696 " SELECT pg_catalog.quote_ident(amname) "\
697 " FROM pg_catalog.pg_am "\
698 " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
700 /* the silly-looking length condition is just to eat up the current word */
701 #define Query_for_list_of_arguments \
702 "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
703 " FROM pg_catalog.pg_proc "\
704 " WHERE (%d = pg_catalog.length('%s'))"\
705 " AND (pg_catalog.quote_ident(proname)='%s'"\
706 " OR '\"' || proname || '\"'='%s') "\
707 " AND (pg_catalog.pg_function_is_visible(pg_proc.oid))"
709 /* the silly-looking length condition is just to eat up the current word */
710 #define Query_for_list_of_arguments_with_schema \
711 "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
712 " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
713 " WHERE (%d = pg_catalog.length('%s'))"\
714 " AND n.oid = p.pronamespace "\
715 " AND (pg_catalog.quote_ident(proname)='%s' "\
716 " OR '\"' || proname || '\"' ='%s') "\
717 " AND (pg_catalog.quote_ident(nspname)='%s' "\
718 " OR '\"' || nspname || '\"' ='%s') "
720 #define Query_for_list_of_extensions \
721 " SELECT pg_catalog.quote_ident(extname) "\
722 " FROM pg_catalog.pg_extension "\
723 " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
725 #define Query_for_list_of_available_extensions \
726 " SELECT pg_catalog.quote_ident(name) "\
727 " FROM pg_catalog.pg_available_extensions "\
728 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
730 #define Query_for_list_of_prepared_statements \
731 " SELECT pg_catalog.quote_ident(name) "\
732 " FROM pg_catalog.pg_prepared_statements "\
733 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'"
735 #define Query_for_list_of_event_triggers \
736 " SELECT pg_catalog.quote_ident(evtname) "\
737 " FROM pg_catalog.pg_event_trigger "\
738 " WHERE substring(pg_catalog.quote_ident(evtname),1,%d)='%s'"
741 * This is a list of all "things" in Pgsql, which can show up after CREATE or
742 * DROP; and there is also a query to get a list of them.
748 const char *query; /* simple query, or NULL */
749 const SchemaQuery *squery; /* schema query, or NULL */
750 const bits32 flags; /* visibility flags, see below */
753 #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
754 #define THING_NO_DROP (1 << 1) /* should not show up after DROP */
755 #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
757 static const pgsql_thing_t words_after_create[] = {
758 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
759 {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
761 {"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'"},
764 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
765 * to be used only by pg_dump.
767 {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
768 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
769 {"DATABASE", Query_for_list_of_databases},
770 {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
771 {"DOMAIN", NULL, &Query_for_list_of_domains},
772 {"EVENT TRIGGER", NULL, NULL},
773 {"EXTENSION", Query_for_list_of_extensions},
774 {"FOREIGN DATA WRAPPER", NULL, NULL},
775 {"FOREIGN TABLE", NULL, NULL},
776 {"FUNCTION", NULL, &Query_for_list_of_functions},
777 {"GROUP", Query_for_list_of_roles},
778 {"LANGUAGE", Query_for_list_of_languages},
779 {"INDEX", NULL, &Query_for_list_of_indexes},
780 {"MATERIALIZED VIEW", NULL, NULL},
781 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
783 {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */
784 {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
785 {"POLICY", NULL, NULL},
786 {"ROLE", Query_for_list_of_roles},
787 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
788 {"SCHEMA", Query_for_list_of_schemas},
789 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
790 {"SERVER", Query_for_list_of_servers},
791 {"TABLE", NULL, &Query_for_list_of_tables},
792 {"TABLESPACE", Query_for_list_of_tablespaces},
793 {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
794 {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
795 {"TEXT SEARCH", NULL, NULL},
796 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s' AND NOT tgisinternal"},
797 {"TYPE", NULL, &Query_for_list_of_datatypes},
798 {"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
799 {"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE
801 {"USER", Query_for_list_of_roles},
802 {"USER MAPPING FOR", NULL, NULL},
803 {"VIEW", NULL, &Query_for_list_of_views},
804 {NULL} /* end of list */
808 /* Forward declaration of functions */
809 static char **psql_completion(const char *text, int start, int end);
810 static char *create_command_generator(const char *text, int state);
811 static char *drop_command_generator(const char *text, int state);
812 static char *complete_from_query(const char *text, int state);
813 static char *complete_from_schema_query(const char *text, int state);
814 static char *_complete_from_query(int is_schema_query,
815 const char *text, int state);
816 static char *complete_from_list(const char *text, int state);
817 static char *complete_from_const(const char *text, int state);
818 static void append_variable_names(char ***varnames, int *nvars,
819 int *maxvars, const char *varname,
820 const char *prefix, const char *suffix);
821 static char **complete_from_variables(const char *text,
822 const char *prefix, const char *suffix, bool need_value);
823 static char *complete_from_files(const char *text, int state);
825 static char *pg_strdup_keyword_case(const char *s, const char *ref);
826 static PGresult *exec_query(const char *query);
828 static void get_previous_words(int point, char **previous_words, int nwords);
831 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
832 static char *dequote_file_name(char *text, char quote_char);
837 * Initialize the readline library for our purposes.
840 initialize_readline(void)
842 rl_readline_name = (char *) pset.progname;
843 rl_attempted_completion_function = psql_completion;
845 rl_basic_word_break_characters = WORD_BREAKS;
847 completion_max_records = 1000;
850 * There is a variable rl_completion_query_items for this but apparently
851 * it's not defined everywhere.
857 * The completion function.
859 * According to readline spec this gets passed the text entered so far and its
860 * start and end positions in the readline buffer. The return value is some
861 * partially obscure list format that can be generated by readline's
862 * completion_matches() function, so we don't have to worry about it.
865 psql_completion(const char *text, int start, int end)
867 /* This is the variable we'll return. */
868 char **matches = NULL;
870 /* This array will contain some scannage of the input line. */
871 char *previous_words[6];
873 /* For compactness, we use these macros to reference previous_words[]. */
874 #define prev_wd (previous_words[0])
875 #define prev2_wd (previous_words[1])
876 #define prev3_wd (previous_words[2])
877 #define prev4_wd (previous_words[3])
878 #define prev5_wd (previous_words[4])
879 #define prev6_wd (previous_words[5])
881 static const char *const sql_commands[] = {
882 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
883 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
884 "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN",
885 "FETCH", "GRANT", "IMPORT", "INSERT", "LISTEN", "LOAD", "LOCK",
886 "MOVE", "NOTIFY", "PREPARE",
887 "REASSIGN", "REFRESH", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
888 "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
889 "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
893 static const char *const backslash_commands[] = {
894 "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
895 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df",
896 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
897 "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du", "\\dx",
898 "\\e", "\\echo", "\\ef", "\\encoding",
899 "\\f", "\\g", "\\gset", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
900 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
901 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
902 "\\set", "\\sf", "\\t", "\\T",
903 "\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!", NULL
906 (void) end; /* not used */
908 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
909 rl_completion_append_character = ' ';
912 /* Clear a few things. */
913 completion_charp = NULL;
914 completion_charpp = NULL;
915 completion_info_charp = NULL;
916 completion_info_charp2 = NULL;
919 * Scan the input line before our current position for the last few words.
920 * According to those we'll make some smart decisions on what the user is
921 * probably intending to type.
923 get_previous_words(start, previous_words, lengthof(previous_words));
925 /* If a backslash command was started, continue */
927 COMPLETE_WITH_LIST_CS(backslash_commands);
929 /* Variable interpolation */
930 else if (text[0] == ':' && text[1] != ':')
933 matches = complete_from_variables(text, ":'", "'", true);
934 else if (text[1] == '"')
935 matches = complete_from_variables(text, ":\"", "\"", true);
937 matches = complete_from_variables(text, ":", "", true);
940 /* If no previous word, suggest one of the basic sql commands */
941 else if (prev_wd[0] == '\0')
942 COMPLETE_WITH_LIST(sql_commands);
945 /* complete with something you can create */
946 else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
947 matches = completion_matches(text, create_command_generator);
949 /* DROP, but not DROP embedded in other commands */
950 /* complete with something you can drop */
951 else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
953 matches = completion_matches(text, drop_command_generator);
958 else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
959 pg_strcasecmp(prev_wd, "TABLE") == 0)
961 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
962 "UNION SELECT 'ALL IN TABLESPACE'");
966 * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
967 * in ALTER TABLE sth ALTER
969 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
970 pg_strcasecmp(prev3_wd, "TABLE") != 0)
972 static const char *const list_ALTER[] =
973 {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
974 "EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
975 "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR",
976 "POLICY", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "SYSTEM", "TABLE",
977 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
978 "USER", "USER MAPPING FOR", "VIEW", NULL};
980 COMPLETE_WITH_LIST(list_ALTER);
982 /* ALTER TABLE,INDEX,MATERIALIZED VIEW xxx ALL IN TABLESPACE xxx */
983 else if (pg_strcasecmp(prev4_wd, "ALL") == 0 &&
984 pg_strcasecmp(prev3_wd, "IN") == 0 &&
985 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
987 static const char *const list_ALTERALLINTSPC[] =
988 {"SET TABLESPACE", "OWNED BY", NULL};
990 COMPLETE_WITH_LIST(list_ALTERALLINTSPC);
992 /* ALTER TABLE,INDEX,MATERIALIZED VIEW xxx ALL IN TABLESPACE xxx OWNED BY */
993 else if (pg_strcasecmp(prev6_wd, "ALL") == 0 &&
994 pg_strcasecmp(prev5_wd, "IN") == 0 &&
995 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
996 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
997 pg_strcasecmp(prev4_wd, "BY") == 0)
999 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1001 /* ALTER AGGREGATE,FUNCTION <name> */
1002 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1003 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
1004 pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
1005 COMPLETE_WITH_CONST("(");
1006 /* ALTER AGGREGATE,FUNCTION <name> (...) */
1007 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1008 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
1009 pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
1011 if (prev_wd[strlen(prev_wd) - 1] == ')')
1013 static const char *const list_ALTERAGG[] =
1014 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1016 COMPLETE_WITH_LIST(list_ALTERAGG);
1019 COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
1022 /* ALTER SCHEMA <name> */
1023 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1024 pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
1026 static const char *const list_ALTERGEN[] =
1027 {"OWNER TO", "RENAME TO", NULL};
1029 COMPLETE_WITH_LIST(list_ALTERGEN);
1032 /* ALTER COLLATION <name> */
1033 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1034 pg_strcasecmp(prev2_wd, "COLLATION") == 0)
1036 static const char *const list_ALTERGEN[] =
1037 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1039 COMPLETE_WITH_LIST(list_ALTERGEN);
1042 /* ALTER CONVERSION <name> */
1043 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1044 pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
1046 static const char *const list_ALTERGEN[] =
1047 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1049 COMPLETE_WITH_LIST(list_ALTERGEN);
1052 /* ALTER DATABASE <name> */
1053 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1054 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1056 static const char *const list_ALTERDATABASE[] =
1057 {"RESET", "SET", "OWNER TO", "RENAME TO", "IS_TEMPLATE",
1058 "ALLOW_CONNECTIONS", "CONNECTION LIMIT", NULL};
1060 COMPLETE_WITH_LIST(list_ALTERDATABASE);
1063 /* ALTER EVENT TRIGGER */
1064 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1065 pg_strcasecmp(prev2_wd, "EVENT") == 0 &&
1066 pg_strcasecmp(prev_wd, "TRIGGER") == 0)
1068 COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
1071 /* ALTER EVENT TRIGGER <name> */
1072 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1073 pg_strcasecmp(prev3_wd, "EVENT") == 0 &&
1074 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1076 static const char *const list_ALTER_EVENT_TRIGGER[] =
1077 {"DISABLE", "ENABLE", "OWNER TO", "RENAME TO", NULL};
1079 COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER);
1082 /* ALTER EVENT TRIGGER <name> ENABLE */
1083 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1084 pg_strcasecmp(prev4_wd, "EVENT") == 0 &&
1085 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1086 pg_strcasecmp(prev_wd, "ENABLE") == 0)
1088 static const char *const list_ALTER_EVENT_TRIGGER_ENABLE[] =
1089 {"REPLICA", "ALWAYS", NULL};
1091 COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER_ENABLE);
1094 /* ALTER EXTENSION <name> */
1095 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1096 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
1098 static const char *const list_ALTEREXTENSION[] =
1099 {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
1101 COMPLETE_WITH_LIST(list_ALTEREXTENSION);
1105 else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
1106 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1108 static const char *const list_ALTER_FOREIGN[] =
1109 {"DATA WRAPPER", "TABLE", NULL};
1111 COMPLETE_WITH_LIST(list_ALTER_FOREIGN);
1114 /* ALTER FOREIGN DATA WRAPPER <name> */
1115 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1116 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1117 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1118 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1120 static const char *const list_ALTER_FDW[] =
1121 {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
1123 COMPLETE_WITH_LIST(list_ALTER_FDW);
1126 /* ALTER FOREIGN TABLE <name> */
1127 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1128 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
1129 pg_strcasecmp(prev2_wd, "TABLE") == 0)
1131 static const char *const list_ALTER_FOREIGN_TABLE[] =
1132 {"ADD", "ALTER", "DISABLE TRIGGER", "DROP", "ENABLE", "INHERIT",
1133 "NO INHERIT", "OPTIONS", "OWNER TO", "RENAME", "SET",
1134 "VALIDATE CONSTRAINT", NULL};
1136 COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
1140 else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
1141 pg_strcasecmp(prev_wd, "INDEX") == 0)
1143 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1144 "UNION SELECT 'ALL IN TABLESPACE'");
1146 /* ALTER INDEX <name> */
1147 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1148 pg_strcasecmp(prev2_wd, "INDEX") == 0)
1150 static const char *const list_ALTERINDEX[] =
1151 {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
1153 COMPLETE_WITH_LIST(list_ALTERINDEX);
1155 /* ALTER INDEX <name> SET */
1156 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1157 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1158 pg_strcasecmp(prev_wd, "SET") == 0)
1160 static const char *const list_ALTERINDEXSET[] =
1161 {"(", "TABLESPACE", NULL};
1163 COMPLETE_WITH_LIST(list_ALTERINDEXSET);
1165 /* ALTER INDEX <name> RESET */
1166 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1167 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1168 pg_strcasecmp(prev_wd, "RESET") == 0)
1169 COMPLETE_WITH_CONST("(");
1170 /* ALTER INDEX <foo> SET|RESET ( */
1171 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1172 pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1173 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1174 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1175 pg_strcasecmp(prev_wd, "(") == 0)
1177 static const char *const list_INDEXOPTIONS[] =
1178 {"fillfactor", "fastupdate", "gin_pending_list_limit", NULL};
1180 COMPLETE_WITH_LIST(list_INDEXOPTIONS);
1183 /* ALTER LANGUAGE <name> */
1184 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1185 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
1187 static const char *const list_ALTERLANGUAGE[] =
1188 {"OWNER TO", "RENAME TO", NULL};
1190 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
1193 /* ALTER LARGE OBJECT <oid> */
1194 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1195 pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
1196 pg_strcasecmp(prev2_wd, "OBJECT") == 0)
1198 static const char *const list_ALTERLARGEOBJECT[] =
1201 COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
1204 /* ALTER MATERIALIZED VIEW */
1205 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1206 pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
1207 pg_strcasecmp(prev_wd, "VIEW") == 0)
1209 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
1210 "UNION SELECT 'ALL IN TABLESPACE'");
1213 /* ALTER USER,ROLE <name> */
1214 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1215 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1216 (pg_strcasecmp(prev2_wd, "USER") == 0 ||
1217 pg_strcasecmp(prev2_wd, "ROLE") == 0))
1219 static const char *const list_ALTERUSER[] =
1220 {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
1221 "CREATEUSER", "ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS",
1222 "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT",
1223 "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
1224 "REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED",
1225 "VALID UNTIL", "WITH", NULL};
1227 COMPLETE_WITH_LIST(list_ALTERUSER);
1230 /* ALTER USER,ROLE <name> WITH */
1231 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1232 (pg_strcasecmp(prev3_wd, "USER") == 0 ||
1233 pg_strcasecmp(prev3_wd, "ROLE") == 0) &&
1234 pg_strcasecmp(prev_wd, "WITH") == 0))
1236 /* Similar to the above, but don't complete "WITH" again. */
1237 static const char *const list_ALTERUSER_WITH[] =
1238 {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
1239 "CREATEUSER", "ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS",
1240 "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT",
1241 "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
1242 "REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED",
1243 "VALID UNTIL", NULL};
1245 COMPLETE_WITH_LIST(list_ALTERUSER_WITH);
1248 /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
1249 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1250 (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1251 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1253 COMPLETE_WITH_CONST("PASSWORD");
1255 /* ALTER DEFAULT PRIVILEGES */
1256 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1257 pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
1258 pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
1260 static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
1261 {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
1263 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
1265 /* ALTER DEFAULT PRIVILEGES FOR */
1266 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1267 pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
1268 pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
1269 pg_strcasecmp(prev_wd, "FOR") == 0)
1271 static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
1272 {"ROLE", "USER", NULL};
1274 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
1276 /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
1277 else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
1278 pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
1279 (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
1280 pg_strcasecmp(prev3_wd, "IN") == 0))
1282 static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
1283 {"GRANT", "REVOKE", NULL};
1285 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
1287 /* ALTER DOMAIN <name> */
1288 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1289 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
1291 static const char *const list_ALTERDOMAIN[] =
1292 {"ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT", NULL};
1294 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1296 /* ALTER DOMAIN <sth> DROP */
1297 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1298 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1299 pg_strcasecmp(prev_wd, "DROP") == 0)
1301 static const char *const list_ALTERDOMAIN2[] =
1302 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
1304 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
1306 /* ALTER DOMAIN <sth> DROP|RENAME|VALIDATE CONSTRAINT */
1307 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1308 pg_strcasecmp(prev4_wd, "DOMAIN") == 0 &&
1309 (pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1310 pg_strcasecmp(prev2_wd, "RENAME") == 0 ||
1311 pg_strcasecmp(prev2_wd, "VALIDATE") == 0) &&
1312 pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
1314 completion_info_charp = prev3_wd;
1315 COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
1317 /* ALTER DOMAIN <sth> RENAME */
1318 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1319 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1320 pg_strcasecmp(prev_wd, "RENAME") == 0)
1322 static const char *const list_ALTERDOMAIN[] =
1323 {"CONSTRAINT", "TO", NULL};
1325 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1327 /* ALTER DOMAIN <sth> RENAME CONSTRAINT <sth> */
1328 else if (pg_strcasecmp(prev5_wd, "DOMAIN") == 0 &&
1329 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1330 pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0)
1331 COMPLETE_WITH_CONST("TO");
1333 /* ALTER DOMAIN <sth> SET */
1334 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1335 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1336 pg_strcasecmp(prev_wd, "SET") == 0)
1338 static const char *const list_ALTERDOMAIN3[] =
1339 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
1341 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
1343 /* ALTER SEQUENCE <name> */
1344 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1345 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
1347 static const char *const list_ALTERSEQUENCE[] =
1348 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
1349 "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
1351 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
1353 /* ALTER SEQUENCE <name> NO */
1354 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1355 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
1356 pg_strcasecmp(prev_wd, "NO") == 0)
1358 static const char *const list_ALTERSEQUENCE2[] =
1359 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
1361 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
1363 /* ALTER SERVER <name> */
1364 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1365 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1367 static const char *const list_ALTER_SERVER[] =
1368 {"VERSION", "OPTIONS", "OWNER TO", NULL};
1370 COMPLETE_WITH_LIST(list_ALTER_SERVER);
1372 /* ALTER SYSTEM SET, RESET, RESET ALL */
1373 else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
1374 pg_strcasecmp(prev_wd, "SYSTEM") == 0)
1376 static const char *const list_ALTERSYSTEM[] =
1377 {"SET", "RESET", NULL};
1379 COMPLETE_WITH_LIST(list_ALTERSYSTEM);
1381 /* ALTER SYSTEM SET|RESET <name> */
1382 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1383 pg_strcasecmp(prev2_wd, "SYSTEM") == 0 &&
1384 (pg_strcasecmp(prev_wd, "SET") == 0 ||
1385 pg_strcasecmp(prev_wd, "RESET") == 0))
1386 COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
1387 /* ALTER VIEW <name> */
1388 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1389 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1391 static const char *const list_ALTERVIEW[] =
1392 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1394 COMPLETE_WITH_LIST(list_ALTERVIEW);
1396 /* ALTER MATERIALIZED VIEW <name> */
1397 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1398 pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
1399 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1401 static const char *const list_ALTERMATVIEW[] =
1402 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1404 COMPLETE_WITH_LIST(list_ALTERMATVIEW);
1407 /* ALTER POLICY <name> ON */
1408 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1409 pg_strcasecmp(prev2_wd, "POLICY") == 0)
1410 COMPLETE_WITH_CONST("ON");
1411 /* ALTER POLICY <name> ON <table> */
1412 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1413 pg_strcasecmp(prev3_wd, "POLICY") == 0 &&
1414 pg_strcasecmp(prev_wd, "ON") == 0)
1415 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1416 /* ALTER POLICY <name> ON <table> - show options */
1417 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1418 pg_strcasecmp(prev4_wd, "POLICY") == 0 &&
1419 pg_strcasecmp(prev2_wd, "ON") == 0)
1421 static const char *const list_ALTERPOLICY[] =
1422 {"RENAME TO", "TO", "USING", "WITH CHECK", NULL};
1424 COMPLETE_WITH_LIST(list_ALTERPOLICY);
1426 /* ALTER POLICY <name> ON <table> TO <role> */
1427 else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
1428 pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
1429 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1430 pg_strcasecmp(prev_wd, "TO") == 0)
1431 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1432 /* ALTER POLICY <name> ON <table> USING ( */
1433 else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
1434 pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
1435 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1436 pg_strcasecmp(prev_wd, "USING") == 0)
1437 COMPLETE_WITH_CONST("(");
1438 /* ALTER POLICY <name> ON <table> WITH CHECK ( */
1439 else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 &&
1440 pg_strcasecmp(prev4_wd, "ON") == 0 &&
1441 pg_strcasecmp(prev2_wd, "WITH") == 0 &&
1442 pg_strcasecmp(prev_wd, "CHECK") == 0)
1443 COMPLETE_WITH_CONST("(");
1445 /* ALTER RULE <name>, add ON */
1446 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1447 pg_strcasecmp(prev2_wd, "RULE") == 0)
1448 COMPLETE_WITH_CONST("ON");
1450 /* If we have ALTER RULE <name> ON, then add the correct tablename */
1451 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1452 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1453 pg_strcasecmp(prev_wd, "ON") == 0)
1455 completion_info_charp = prev2_wd;
1456 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
1459 /* ALTER RULE <name> ON <name> */
1460 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1461 pg_strcasecmp(prev4_wd, "RULE") == 0)
1462 COMPLETE_WITH_CONST("RENAME TO");
1464 /* ALTER TRIGGER <name>, add ON */
1465 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1466 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1467 COMPLETE_WITH_CONST("ON");
1469 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1470 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
1472 completion_info_charp = prev2_wd;
1473 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1477 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1479 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1480 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1481 pg_strcasecmp(prev_wd, "ON") == 0)
1482 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1484 /* ALTER TRIGGER <name> ON <name> */
1485 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1486 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1487 pg_strcasecmp(prev2_wd, "ON") == 0)
1488 COMPLETE_WITH_CONST("RENAME TO");
1491 * If we detect ALTER TABLE <name>, suggest sub commands
1493 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1494 pg_strcasecmp(prev2_wd, "TABLE") == 0)
1496 static const char *const list_ALTER2[] =
1497 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1498 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
1499 "VALIDATE CONSTRAINT", "REPLICA IDENTITY", NULL};
1501 COMPLETE_WITH_LIST(list_ALTER2);
1503 /* ALTER TABLE xxx ENABLE */
1504 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1505 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1506 pg_strcasecmp(prev_wd, "ENABLE") == 0)
1508 static const char *const list_ALTERENABLE[] =
1509 {"ALWAYS", "REPLICA", "ROW LEVEL SECURITY", "RULE", "TRIGGER", NULL};
1511 COMPLETE_WITH_LIST(list_ALTERENABLE);
1513 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1514 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1515 (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
1516 pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1518 static const char *const list_ALTERENABLE2[] =
1519 {"RULE", "TRIGGER", NULL};
1521 COMPLETE_WITH_LIST(list_ALTERENABLE2);
1523 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1524 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1525 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1526 pg_strcasecmp(prev_wd, "RULE") == 0)
1528 completion_info_charp = prev3_wd;
1529 COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1531 else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
1532 pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1533 pg_strcasecmp(prev3_wd, "ENABLE") == 0 &&
1534 pg_strcasecmp(prev_wd, "RULE") == 0)
1536 completion_info_charp = prev4_wd;
1537 COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1539 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1540 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1541 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1542 pg_strcasecmp(prev_wd, "TRIGGER") == 0)
1544 completion_info_charp = prev3_wd;
1545 COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1547 else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
1548 pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1549 pg_strcasecmp(prev3_wd, "ENABLE") == 0 &&
1550 pg_strcasecmp(prev_wd, "TRIGGER") == 0)
1552 completion_info_charp = prev4_wd;
1553 COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1555 /* ALTER TABLE xxx INHERIT */
1556 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1557 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1558 pg_strcasecmp(prev_wd, "INHERIT") == 0)
1560 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1562 /* ALTER TABLE xxx NO INHERIT */
1563 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1564 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1565 pg_strcasecmp(prev2_wd, "NO") == 0 &&
1566 pg_strcasecmp(prev_wd, "INHERIT") == 0)
1568 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1570 /* ALTER TABLE xxx DISABLE */
1571 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1572 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1573 pg_strcasecmp(prev_wd, "DISABLE") == 0)
1575 static const char *const list_ALTERDISABLE[] =
1576 {"ROW LEVEL SECURITY", "RULE", "TRIGGER", NULL};
1578 COMPLETE_WITH_LIST(list_ALTERDISABLE);
1580 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1581 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1582 pg_strcasecmp(prev2_wd, "DISABLE") == 0 &&
1583 pg_strcasecmp(prev_wd, "RULE") == 0)
1585 completion_info_charp = prev3_wd;
1586 COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1588 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1589 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1590 pg_strcasecmp(prev2_wd, "DISABLE") == 0 &&
1591 pg_strcasecmp(prev_wd, "TRIGGER") == 0)
1593 completion_info_charp = prev3_wd;
1594 COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1596 else if (pg_strcasecmp(prev4_wd, "DISABLE") == 0 &&
1597 pg_strcasecmp(prev3_wd, "ROW") == 0 &&
1598 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1599 pg_strcasecmp(prev_wd, "SECURITY") == 0)
1601 static const char *const list_DISABLERLS[] =
1604 COMPLETE_WITH_LIST(list_DISABLERLS);
1607 /* ALTER TABLE xxx ALTER */
1608 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1609 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1610 pg_strcasecmp(prev_wd, "ALTER") == 0)
1611 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT'");
1613 /* ALTER TABLE xxx RENAME */
1614 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1615 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1616 pg_strcasecmp(prev_wd, "RENAME") == 0)
1617 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'");
1620 * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1623 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1624 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1625 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1626 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1627 COMPLETE_WITH_ATTR(prev3_wd, "");
1629 /* ALTER TABLE xxx RENAME yyy */
1630 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1631 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1632 pg_strcasecmp(prev_wd, "CONSTRAINT") != 0 &&
1633 pg_strcasecmp(prev_wd, "TO") != 0)
1634 COMPLETE_WITH_CONST("TO");
1636 /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */
1637 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1638 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1639 (pg_strcasecmp(prev2_wd, "COLUMN") == 0 ||
1640 pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) &&
1641 pg_strcasecmp(prev_wd, "TO") != 0)
1642 COMPLETE_WITH_CONST("TO");
1644 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1645 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1646 pg_strcasecmp(prev_wd, "DROP") == 0)
1648 static const char *const list_TABLEDROP[] =
1649 {"COLUMN", "CONSTRAINT", NULL};
1651 COMPLETE_WITH_LIST(list_TABLEDROP);
1653 /* If we have ALTER TABLE <sth> DROP COLUMN, provide list of columns */
1654 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1655 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1656 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1657 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1658 COMPLETE_WITH_ATTR(prev3_wd, "");
1661 * If we have ALTER TABLE <sth> ALTER|DROP|RENAME|VALIDATE CONSTRAINT,
1662 * provide list of constraints
1664 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1665 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1666 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1667 pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1668 pg_strcasecmp(prev2_wd, "RENAME") == 0 ||
1669 pg_strcasecmp(prev2_wd, "VALIDATE") == 0) &&
1670 pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
1672 completion_info_charp = prev3_wd;
1673 COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
1675 /* ALTER TABLE ALTER [COLUMN] <foo> */
1676 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1677 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1678 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1679 pg_strcasecmp(prev2_wd, "ALTER") == 0))
1681 static const char *const list_COLUMNALTER[] =
1682 {"TYPE", "SET", "RESET", "DROP", NULL};
1684 COMPLETE_WITH_LIST(list_COLUMNALTER);
1686 /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1687 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1688 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1689 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1690 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1691 pg_strcasecmp(prev_wd, "SET") == 0)
1693 static const char *const list_COLUMNSET[] =
1694 {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1696 COMPLETE_WITH_LIST(list_COLUMNSET);
1698 /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1699 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1700 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1701 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1702 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1703 pg_strcasecmp(prev_wd, "(") == 0)
1705 static const char *const list_COLUMNOPTIONS[] =
1706 {"n_distinct", "n_distinct_inherited", NULL};
1708 COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1710 /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1711 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1712 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1713 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1714 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1715 pg_strcasecmp(prev_wd, "STORAGE") == 0)
1717 static const char *const list_COLUMNSTORAGE[] =
1718 {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1720 COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1722 /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1723 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1724 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1725 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1726 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1727 pg_strcasecmp(prev_wd, "DROP") == 0)
1729 static const char *const list_COLUMNDROP[] =
1730 {"DEFAULT", "NOT NULL", NULL};
1732 COMPLETE_WITH_LIST(list_COLUMNDROP);
1734 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1735 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1736 COMPLETE_WITH_CONST("ON");
1737 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1738 pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1739 pg_strcasecmp(prev_wd, "ON") == 0)
1741 completion_info_charp = prev3_wd;
1742 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1744 /* If we have TABLE <sth> SET, provide list of attributes and '(' */
1745 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1746 pg_strcasecmp(prev_wd, "SET") == 0)
1748 static const char *const list_TABLESET[] =
1749 {"(", "LOGGED", "SCHEMA", "TABLESPACE", "UNLOGGED", "WITH", "WITHOUT", NULL};
1751 COMPLETE_WITH_LIST(list_TABLESET);
1753 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1754 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1755 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1756 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1757 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1758 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1759 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1760 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1761 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1763 static const char *const list_TABLESET2[] =
1764 {"CLUSTER", "OIDS", NULL};
1766 COMPLETE_WITH_LIST(list_TABLESET2);
1768 /* ALTER TABLE <foo> RESET */
1769 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1770 pg_strcasecmp(prev_wd, "RESET") == 0)
1771 COMPLETE_WITH_CONST("(");
1772 /* ALTER TABLE <foo> SET|RESET ( */
1773 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1774 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1775 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1776 pg_strcasecmp(prev_wd, "(") == 0)
1778 static const char *const list_TABLEOPTIONS[] =
1780 "autovacuum_analyze_scale_factor",
1781 "autovacuum_analyze_threshold",
1782 "autovacuum_enabled",
1783 "autovacuum_freeze_max_age",
1784 "autovacuum_freeze_min_age",
1785 "autovacuum_freeze_table_age",
1786 "autovacuum_multixact_freeze_max_age",
1787 "autovacuum_multixact_freeze_min_age",
1788 "autovacuum_multixact_freeze_table_age",
1789 "autovacuum_vacuum_cost_delay",
1790 "autovacuum_vacuum_cost_limit",
1791 "autovacuum_vacuum_scale_factor",
1792 "autovacuum_vacuum_threshold",
1794 "log_autovacuum_min_duration",
1795 "toast.autovacuum_enabled",
1796 "toast.autovacuum_freeze_max_age",
1797 "toast.autovacuum_freeze_min_age",
1798 "toast.autovacuum_freeze_table_age",
1799 "toast.autovacuum_multixact_freeze_max_age",
1800 "toast.autovacuum_multixact_freeze_min_age",
1801 "toast.autovacuum_multixact_freeze_table_age",
1802 "toast.autovacuum_vacuum_cost_delay",
1803 "toast.autovacuum_vacuum_cost_limit",
1804 "toast.autovacuum_vacuum_scale_factor",
1805 "toast.autovacuum_vacuum_threshold",
1806 "toast.log_autovacuum_min_duration",
1807 "user_catalog_table",
1811 COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1813 else if (pg_strcasecmp(prev4_wd, "REPLICA") == 0 &&
1814 pg_strcasecmp(prev3_wd, "IDENTITY") == 0 &&
1815 pg_strcasecmp(prev2_wd, "USING") == 0 &&
1816 pg_strcasecmp(prev_wd, "INDEX") == 0)
1818 completion_info_charp = prev5_wd;
1819 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1821 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1822 pg_strcasecmp(prev3_wd, "REPLICA") == 0 &&
1823 pg_strcasecmp(prev2_wd, "IDENTITY") == 0 &&
1824 pg_strcasecmp(prev_wd, "USING") == 0)
1826 COMPLETE_WITH_CONST("INDEX");
1828 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1829 pg_strcasecmp(prev2_wd, "REPLICA") == 0 &&
1830 pg_strcasecmp(prev_wd, "IDENTITY") == 0)
1832 static const char *const list_REPLICAID[] =
1833 {"FULL", "NOTHING", "DEFAULT", "USING", NULL};
1835 COMPLETE_WITH_LIST(list_REPLICAID);
1837 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1838 pg_strcasecmp(prev_wd, "REPLICA") == 0)
1840 COMPLETE_WITH_CONST("IDENTITY");
1843 /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1844 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1845 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1847 static const char *const list_ALTERTSPC[] =
1848 {"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1850 COMPLETE_WITH_LIST(list_ALTERTSPC);
1852 /* ALTER TABLESPACE <foo> SET|RESET */
1853 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1854 pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1855 (pg_strcasecmp(prev_wd, "SET") == 0 ||
1856 pg_strcasecmp(prev_wd, "RESET") == 0))
1857 COMPLETE_WITH_CONST("(");
1858 /* ALTER TABLESPACE <foo> SET|RESET ( */
1859 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1860 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1861 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1862 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1863 pg_strcasecmp(prev_wd, "(") == 0)
1865 static const char *const list_TABLESPACEOPTIONS[] =
1866 {"seq_page_cost", "random_page_cost", NULL};
1868 COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1871 /* ALTER TEXT SEARCH */
1872 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1873 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1874 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1876 static const char *const list_ALTERTEXTSEARCH[] =
1877 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1879 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1881 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1882 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1883 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1884 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1885 pg_strcasecmp(prev2_wd, "PARSER") == 0))
1887 static const char *const list_ALTERTEXTSEARCH2[] =
1888 {"RENAME TO", "SET SCHEMA", NULL};
1890 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1893 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1894 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1895 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1896 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1898 static const char *const list_ALTERTEXTSEARCH3[] =
1899 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1901 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1904 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1905 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1906 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1907 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1909 static const char *const list_ALTERTEXTSEARCH4[] =
1910 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1912 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
1915 /* complete ALTER TYPE <foo> with actions */
1916 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1917 pg_strcasecmp(prev2_wd, "TYPE") == 0)
1919 static const char *const list_ALTERTYPE[] =
1920 {"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
1921 "OWNER TO", "RENAME", "SET SCHEMA", NULL};
1923 COMPLETE_WITH_LIST(list_ALTERTYPE);
1925 /* complete ALTER TYPE <foo> ADD with actions */
1926 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1927 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1928 pg_strcasecmp(prev_wd, "ADD") == 0)
1930 static const char *const list_ALTERTYPE[] =
1931 {"ATTRIBUTE", "VALUE", NULL};
1933 COMPLETE_WITH_LIST(list_ALTERTYPE);
1935 /* ALTER TYPE <foo> RENAME */
1936 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1937 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1938 pg_strcasecmp(prev_wd, "RENAME") == 0)
1940 static const char *const list_ALTERTYPE[] =
1941 {"ATTRIBUTE", "TO", NULL};
1943 COMPLETE_WITH_LIST(list_ALTERTYPE);
1945 /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */
1946 else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 &&
1947 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1948 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)
1949 COMPLETE_WITH_CONST("TO");
1952 * If we have TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list of
1955 else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 &&
1956 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1957 pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1958 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1959 pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0)
1960 COMPLETE_WITH_ATTR(prev3_wd, "");
1961 /* ALTER TYPE ALTER ATTRIBUTE <foo> */
1962 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1963 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0))
1965 COMPLETE_WITH_CONST("TYPE");
1967 /* complete ALTER GROUP <foo> */
1968 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1969 pg_strcasecmp(prev2_wd, "GROUP") == 0)
1971 static const char *const list_ALTERGROUP[] =
1972 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1974 COMPLETE_WITH_LIST(list_ALTERGROUP);
1976 /* complete ALTER GROUP <foo> ADD|DROP with USER */
1977 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1978 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1979 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1980 pg_strcasecmp(prev_wd, "DROP") == 0))
1981 COMPLETE_WITH_CONST("USER");
1982 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1983 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1984 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1985 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1986 pg_strcasecmp(prev_wd, "USER") == 0)
1987 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1989 /* BEGIN, END, ABORT */
1990 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1991 pg_strcasecmp(prev_wd, "END") == 0 ||
1992 pg_strcasecmp(prev_wd, "ABORT") == 0)
1994 static const char *const list_TRANS[] =
1995 {"WORK", "TRANSACTION", NULL};
1997 COMPLETE_WITH_LIST(list_TRANS);
2000 else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
2002 static const char *const list_COMMIT[] =
2003 {"WORK", "TRANSACTION", "PREPARED", NULL};
2005 COMPLETE_WITH_LIST(list_COMMIT);
2007 /* RELEASE SAVEPOINT */
2008 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
2009 COMPLETE_WITH_CONST("SAVEPOINT");
2011 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
2013 static const char *const list_TRANS[] =
2014 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
2016 COMPLETE_WITH_LIST(list_TRANS);
2021 * If the previous word is CLUSTER and not WITHOUT produce list of tables
2023 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
2024 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
2025 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "UNION SELECT 'VERBOSE'");
2028 * If the previous words are CLUSTER VERBOSE produce list of tables
2030 else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2031 pg_strcasecmp(prev2_wd, "CLUSTER") == 0)
2032 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
2034 /* If we have CLUSTER <sth>, then add "USING" */
2035 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
2036 pg_strcasecmp(prev_wd, "ON") != 0 &&
2037 pg_strcasecmp(prev_wd, "VERBOSE") != 0)
2039 COMPLETE_WITH_CONST("USING");
2041 /* If we have CLUSTER VERBOSE <sth>, then add "USING" */
2042 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
2043 pg_strcasecmp(prev2_wd, "VERBOSE") == 0)
2045 COMPLETE_WITH_CONST("USING");
2049 * If we have CLUSTER <sth> USING, then add the index as well.
2051 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
2052 pg_strcasecmp(prev_wd, "USING") == 0)
2054 completion_info_charp = prev2_wd;
2055 COMPLETE_WITH_QUERY(Query_for_index_of_table);
2059 * If we have CLUSTER VERBOSE <sth> USING, then add the index as well.
2061 else if (pg_strcasecmp(prev4_wd, "CLUSTER") == 0 &&
2062 pg_strcasecmp(prev3_wd, "VERBOSE") == 0 &&
2063 pg_strcasecmp(prev_wd, "USING") == 0)
2065 completion_info_charp = prev2_wd;
2066 COMPLETE_WITH_QUERY(Query_for_index_of_table);
2070 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
2071 COMPLETE_WITH_CONST("ON");
2072 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
2073 pg_strcasecmp(prev_wd, "ON") == 0)
2075 static const char *const list_COMMENT[] =
2076 {"CAST", "COLLATION", "CONVERSION", "DATABASE", "EVENT TRIGGER", "EXTENSION",
2077 "FOREIGN DATA WRAPPER", "FOREIGN TABLE",
2078 "SERVER", "INDEX", "LANGUAGE", "POLICY", "RULE", "SCHEMA", "SEQUENCE",
2079 "TABLE", "TYPE", "VIEW", "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
2080 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
2081 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
2083 COMPLETE_WITH_LIST(list_COMMENT);
2085 else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
2086 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2087 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2089 static const char *const list_TRANS2[] =
2090 {"DATA WRAPPER", "TABLE", NULL};
2092 COMPLETE_WITH_LIST(list_TRANS2);
2094 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2095 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2096 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2097 pg_strcasecmp(prev_wd, "SEARCH") == 0)
2099 static const char *const list_TRANS2[] =
2100 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2102 COMPLETE_WITH_LIST(list_TRANS2);
2104 else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
2105 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2106 pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
2108 COMPLETE_WITH_QUERY(Query_for_all_table_constraints);
2110 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2111 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2112 pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0)
2114 COMPLETE_WITH_CONST("ON");
2116 else if (pg_strcasecmp(prev5_wd, "COMMENT") == 0 &&
2117 pg_strcasecmp(prev4_wd, "ON") == 0 &&
2118 pg_strcasecmp(prev3_wd, "CONSTRAINT") == 0 &&
2119 pg_strcasecmp(prev_wd, "ON") == 0)
2121 completion_info_charp = prev2_wd;
2122 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint);
2124 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2125 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2126 pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
2127 pg_strcasecmp(prev_wd, "VIEW") == 0)
2129 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
2131 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2132 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2133 pg_strcasecmp(prev2_wd, "EVENT") == 0 &&
2134 pg_strcasecmp(prev_wd, "TRIGGER") == 0)
2136 COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
2138 else if (((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2139 pg_strcasecmp(prev3_wd, "ON") == 0) ||
2140 (pg_strcasecmp(prev5_wd, "COMMENT") == 0 &&
2141 pg_strcasecmp(prev4_wd, "ON") == 0) ||
2142 (pg_strcasecmp(prev6_wd, "COMMENT") == 0 &&
2143 pg_strcasecmp(prev5_wd, "ON") == 0)) &&
2144 pg_strcasecmp(prev_wd, "IS") != 0)
2145 COMPLETE_WITH_CONST("IS");
2150 * If we have COPY [BINARY] (which you'd have to type yourself), offer
2151 * list of tables (Also cover the analogous backslash command)
2153 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
2154 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
2155 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
2156 pg_strcasecmp(prev_wd, "BINARY") == 0))
2157 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2158 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
2159 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
2160 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
2161 pg_strcasecmp(prev2_wd, "BINARY") == 0)
2163 static const char *const list_FROMTO[] =
2164 {"FROM", "TO", NULL};
2166 COMPLETE_WITH_LIST(list_FROMTO);
2168 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
2169 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
2170 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
2171 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
2172 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
2173 pg_strcasecmp(prev_wd, "TO") == 0))
2175 completion_charp = "";
2176 matches = completion_matches(text, complete_from_files);
2179 /* Handle COPY|BINARY <sth> FROM|TO filename */
2180 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
2181 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
2182 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
2183 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
2184 pg_strcasecmp(prev2_wd, "TO") == 0))
2186 static const char *const list_COPY[] =
2187 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL};
2189 COMPLETE_WITH_LIST(list_COPY);
2192 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
2193 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
2194 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
2195 pg_strcasecmp(prev3_wd, "TO") == 0))
2197 static const char *const list_CSV[] =
2198 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL};
2200 COMPLETE_WITH_LIST(list_CSV);
2203 /* CREATE DATABASE */
2204 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2205 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
2207 static const char *const list_DATABASE[] =
2208 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "IS_TEMPLATE",
2209 "ALLOW_CONNECTIONS", "CONNECTION LIMIT", "LC_COLLATE", "LC_CTYPE",
2212 COMPLETE_WITH_LIST(list_DATABASE);
2215 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2216 pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
2217 pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
2218 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
2220 /* CREATE EXTENSION */
2221 /* Complete with available extensions rather than installed ones. */
2222 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2223 pg_strcasecmp(prev_wd, "EXTENSION") == 0)
2224 COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
2225 /* CREATE EXTENSION <name> */
2226 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2227 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
2228 COMPLETE_WITH_CONST("WITH SCHEMA");
2230 /* CREATE FOREIGN */
2231 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2232 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2234 static const char *const list_CREATE_FOREIGN[] =
2235 {"DATA WRAPPER", "TABLE", NULL};
2237 COMPLETE_WITH_LIST(list_CREATE_FOREIGN);
2240 /* CREATE FOREIGN DATA WRAPPER */
2241 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2242 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2243 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2244 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
2246 static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] =
2247 {"HANDLER", "VALIDATOR", NULL};
2249 COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER);
2253 /* First off we complete CREATE UNIQUE with "INDEX" */
2254 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2255 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
2256 COMPLETE_WITH_CONST("INDEX");
2257 /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
2258 else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
2259 (pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
2260 pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
2261 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
2262 " UNION SELECT 'ON'"
2263 " UNION SELECT 'CONCURRENTLY'");
2264 /* Complete ... INDEX [<name>] ON with a list of tables */
2265 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2266 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2267 pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
2268 pg_strcasecmp(prev_wd, "ON") == 0)
2269 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
2270 /* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
2271 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2272 pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
2273 pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
2274 COMPLETE_WITH_CONST("ON");
2275 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
2276 else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2277 pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
2278 pg_strcasecmp(prev2_wd, "INDEX") == 0)
2280 static const char *const list_CREATE_INDEX[] =
2281 {"CONCURRENTLY", "ON", NULL};
2283 COMPLETE_WITH_LIST(list_CREATE_INDEX);
2287 * Complete INDEX <name> ON <table> with a list of table columns (which
2288 * should really be in parens)
2290 else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
2291 pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2292 pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
2293 pg_strcasecmp(prev2_wd, "ON") == 0)
2295 static const char *const list_CREATE_INDEX2[] =
2296 {"(", "USING", NULL};
2298 COMPLETE_WITH_LIST(list_CREATE_INDEX2);
2300 else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
2301 pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
2302 pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
2303 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2304 pg_strcasecmp(prev_wd, "(") == 0)
2305 COMPLETE_WITH_ATTR(prev2_wd, "");
2306 /* same if you put in USING */
2307 else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
2308 pg_strcasecmp(prev3_wd, "USING") == 0 &&
2309 pg_strcasecmp(prev_wd, "(") == 0)
2310 COMPLETE_WITH_ATTR(prev4_wd, "");
2311 /* Complete USING with an index method */
2312 else if ((pg_strcasecmp(prev6_wd, "INDEX") == 0 ||
2313 pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
2314 pg_strcasecmp(prev4_wd, "INDEX") == 0) &&
2315 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2316 pg_strcasecmp(prev_wd, "USING") == 0)
2317 COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
2318 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
2319 (!(pg_strcasecmp(prev6_wd, "POLICY") == 0) &&
2320 !(pg_strcasecmp(prev4_wd, "FOR") == 0)) &&
2321 pg_strcasecmp(prev2_wd, "USING") == 0)
2322 COMPLETE_WITH_CONST("(");
2325 /* Complete "CREATE POLICY <name> ON" */
2326 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2327 pg_strcasecmp(prev2_wd, "POLICY") == 0)
2328 COMPLETE_WITH_CONST("ON");
2329 /* Complete "CREATE POLICY <name> ON <table>" */
2330 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2331 pg_strcasecmp(prev3_wd, "POLICY") == 0 &&
2332 pg_strcasecmp(prev_wd, "ON") == 0)
2333 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2334 /* Complete "CREATE POLICY <name> ON <table> FOR|TO|USING|WITH CHECK" */
2335 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2336 pg_strcasecmp(prev4_wd, "POLICY") == 0 &&
2337 pg_strcasecmp(prev2_wd, "ON") == 0)
2339 static const char *const list_POLICYOPTIONS[] =
2340 {"FOR", "TO", "USING", "WITH CHECK", NULL};
2342 COMPLETE_WITH_LIST(list_POLICYOPTIONS);
2346 * Complete "CREATE POLICY <name> ON <table> FOR
2347 * ALL|SELECT|INSERT|UPDATE|DELETE"
2349 else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 &&
2350 pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
2351 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2352 pg_strcasecmp(prev_wd, "FOR") == 0)
2354 static const char *const list_POLICYCMDS[] =
2355 {"ALL", "SELECT", "INSERT", "UPDATE", "DELETE", NULL};
2357 COMPLETE_WITH_LIST(list_POLICYCMDS);
2359 /* Complete "CREATE POLICY <name> ON <table> FOR INSERT TO|WITH CHECK" */
2360 else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 &&
2361 pg_strcasecmp(prev4_wd, "ON") == 0 &&
2362 pg_strcasecmp(prev2_wd, "FOR") == 0 &&
2363 pg_strcasecmp(prev_wd, "INSERT") == 0)
2365 static const char *const list_POLICYOPTIONS[] =
2366 {"TO", "WITH CHECK", NULL};
2368 COMPLETE_WITH_LIST(list_POLICYOPTIONS);
2372 * Complete "CREATE POLICY <name> ON <table> FOR SELECT TO|USING" Complete
2373 * "CREATE POLICY <name> ON <table> FOR DELETE TO|USING"
2375 else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 &&
2376 pg_strcasecmp(prev4_wd, "ON") == 0 &&
2377 pg_strcasecmp(prev2_wd, "FOR") == 0 &&
2378 (pg_strcasecmp(prev_wd, "SELECT") == 0 ||
2379 pg_strcasecmp(prev_wd, "DELETE") == 0))
2381 static const char *const list_POLICYOPTIONS[] =
2382 {"TO", "USING", NULL};
2384 COMPLETE_WITH_LIST(list_POLICYOPTIONS);
2388 * Complete "CREATE POLICY <name> ON <table> FOR ALL TO|USING|WITH CHECK"
2389 * Complete "CREATE POLICY <name> ON <table> FOR UPDATE TO|USING|WITH
2392 else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 &&
2393 pg_strcasecmp(prev4_wd, "ON") == 0 &&
2394 pg_strcasecmp(prev2_wd, "FOR") == 0 &&
2395 (pg_strcasecmp(prev_wd, "ALL") == 0 ||
2396 pg_strcasecmp(prev_wd, "UPDATE") == 0))
2398 static const char *const list_POLICYOPTIONS[] =
2399 {"TO", "USING", "WITH CHECK", NULL};
2401 COMPLETE_WITH_LIST(list_POLICYOPTIONS);
2403 /* Complete "CREATE POLICY <name> ON <table> TO <role>" */
2404 else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 &&
2405 pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
2406 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2407 pg_strcasecmp(prev_wd, "TO") == 0)
2408 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2409 /* Complete "CREATE POLICY <name> ON <table> USING (" */
2410 else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 &&
2411 pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
2412 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2413 pg_strcasecmp(prev_wd, "USING") == 0)
2414 COMPLETE_WITH_CONST("(");
2417 /* Complete "CREATE RULE <sth>" with "AS" */
2418 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2419 pg_strcasecmp(prev2_wd, "RULE") == 0)
2420 COMPLETE_WITH_CONST("AS");
2421 /* Complete "CREATE RULE <sth> AS with "ON" */
2422 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2423 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
2424 pg_strcasecmp(prev_wd, "AS") == 0)
2425 COMPLETE_WITH_CONST("ON");
2426 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
2427 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
2428 pg_strcasecmp(prev2_wd, "AS") == 0 &&
2429 pg_strcasecmp(prev_wd, "ON") == 0)
2431 static const char *const rule_events[] =
2432 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2434 COMPLETE_WITH_LIST(rule_events);
2436 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
2437 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
2438 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2439 (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
2440 pg_toupper((unsigned char) prev_wd[5]) == 'T'))
2441 COMPLETE_WITH_CONST("TO");
2442 /* Complete "AS ON <sth> TO" with a table name */
2443 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
2444 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2445 pg_strcasecmp(prev_wd, "TO") == 0)
2446 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2448 /* CREATE SERVER <name> */
2449 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2450 pg_strcasecmp(prev2_wd, "SERVER") == 0)
2452 static const char *const list_CREATE_SERVER[] =
2453 {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
2455 COMPLETE_WITH_LIST(list_CREATE_SERVER);
2459 /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
2460 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2461 (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
2462 pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
2464 static const char *const list_TEMP[] =
2465 {"SEQUENCE", "TABLE", "VIEW", NULL};
2467 COMPLETE_WITH_LIST(list_TEMP);
2469 /* Complete "CREATE UNLOGGED" with TABLE */
2470 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2471 pg_strcasecmp(prev_wd, "UNLOGGED") == 0)
2473 static const char *const list_UNLOGGED[] =
2474 {"TABLE", "MATERIALIZED VIEW", NULL};
2476 COMPLETE_WITH_LIST(list_UNLOGGED);
2479 /* CREATE TABLESPACE */
2480 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2481 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
2483 static const char *const list_CREATETABLESPACE[] =
2484 {"OWNER", "LOCATION", NULL};
2486 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
2488 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
2489 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2490 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
2491 pg_strcasecmp(prev2_wd, "OWNER") == 0)
2493 COMPLETE_WITH_CONST("LOCATION");
2496 /* CREATE TEXT SEARCH */
2497 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2498 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2499 pg_strcasecmp(prev_wd, "SEARCH") == 0)
2501 static const char *const list_CREATETEXTSEARCH[] =
2502 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2504 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
2506 else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2507 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2508 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
2509 COMPLETE_WITH_CONST("(");
2511 /* CREATE TRIGGER */
2512 /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
2513 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2514 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
2516 static const char *const list_CREATETRIGGER[] =
2517 {"BEFORE", "AFTER", "INSTEAD OF", NULL};
2519 COMPLETE_WITH_LIST(list_CREATETRIGGER);
2521 /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
2522 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2523 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
2524 (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
2525 pg_strcasecmp(prev_wd, "AFTER") == 0))
2527 static const char *const list_CREATETRIGGER_EVENTS[] =
2528 {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
2530 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
2532 /* complete CREATE TRIGGER <name> INSTEAD OF with an event */
2533 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2534 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2535 pg_strcasecmp(prev2_wd, "INSTEAD") == 0 &&
2536 pg_strcasecmp(prev_wd, "OF") == 0)
2538 static const char *const list_CREATETRIGGER_EVENTS[] =
2539 {"INSERT", "DELETE", "UPDATE", NULL};
2541 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
2543 /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
2544 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2545 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2546 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2547 pg_strcasecmp(prev2_wd, "AFTER") == 0)) ||
2548 (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
2549 pg_strcasecmp(prev3_wd, "INSTEAD") == 0 &&
2550 pg_strcasecmp(prev2_wd, "OF") == 0))
2552 static const char *const list_CREATETRIGGER2[] =
2555 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
2559 * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
2562 else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
2563 (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
2564 pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
2565 pg_strcasecmp(prev_wd, "ON") == 0)
2566 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2567 /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
2568 else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 &&
2569 pg_strcasecmp(prev3_wd, "OF") == 0 &&
2570 pg_strcasecmp(prev_wd, "ON") == 0)
2571 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2572 /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
2573 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2574 prev2_wd[0] != '\0')
2575 COMPLETE_WITH_CONST("PROCEDURE");
2577 /* CREATE ROLE,USER,GROUP <name> */
2578 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2579 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
2580 (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
2581 pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
2583 static const char *const list_CREATEROLE[] =
2584 {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
2585 "CREATEUSER", "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
2586 "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT",
2587 "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
2588 "REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED",
2589 "VALID UNTIL", "WITH", NULL};
2591 COMPLETE_WITH_LIST(list_CREATEROLE);
2594 /* CREATE ROLE,USER,GROUP <name> WITH */
2595 else if ((pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2596 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2597 pg_strcasecmp(prev3_wd, "GROUP") == 0 ||
2598 pg_strcasecmp(prev3_wd, "USER") == 0) &&
2599 pg_strcasecmp(prev_wd, "WITH") == 0))
2601 /* Similar to the above, but don't complete "WITH" again. */
2602 static const char *const list_CREATEROLE_WITH[] =
2603 {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
2604 "CREATEUSER", "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
2605 "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT",
2606 "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
2607 "REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED",
2608 "VALID UNTIL", NULL};
2610 COMPLETE_WITH_LIST(list_CREATEROLE_WITH);
2614 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
2617 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2618 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2619 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
2620 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
2622 COMPLETE_WITH_CONST("PASSWORD");
2624 /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
2625 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2626 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2627 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
2628 pg_strcasecmp(prev_wd, "IN") == 0)
2630 static const char *const list_CREATEROLE3[] =
2631 {"GROUP", "ROLE", NULL};
2633 COMPLETE_WITH_LIST(list_CREATEROLE3);
2637 /* Complete CREATE VIEW <name> with AS */
2638 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2639 pg_strcasecmp(prev2_wd, "VIEW") == 0)
2640 COMPLETE_WITH_CONST("AS");
2641 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
2642 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2643 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2644 pg_strcasecmp(prev_wd, "AS") == 0)
2645 COMPLETE_WITH_CONST("SELECT");
2647 /* CREATE MATERIALIZED VIEW */
2648 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2649 pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
2650 COMPLETE_WITH_CONST("VIEW");
2651 /* Complete CREATE MATERIALIZED VIEW <name> with AS */
2652 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2653 pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
2654 pg_strcasecmp(prev2_wd, "VIEW") == 0)
2655 COMPLETE_WITH_CONST("AS");
2656 /* Complete "CREATE MATERIALIZED VIEW <sth> AS with "SELECT" */
2657 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2658 pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
2659 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2660 pg_strcasecmp(prev_wd, "AS") == 0)
2661 COMPLETE_WITH_CONST("SELECT");
2663 /* CREATE EVENT TRIGGER */
2664 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2665 pg_strcasecmp(prev_wd, "EVENT") == 0)
2666 COMPLETE_WITH_CONST("TRIGGER");
2667 /* Complete CREATE EVENT TRIGGER <name> with ON */
2668 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2669 pg_strcasecmp(prev3_wd, "EVENT") == 0 &&
2670 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
2671 COMPLETE_WITH_CONST("ON");
2672 /* Complete CREATE EVENT TRIGGER <name> ON with event_type */
2673 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2674 pg_strcasecmp(prev4_wd, "EVENT") == 0 &&
2675 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
2676 pg_strcasecmp(prev_wd, "ON") == 0)
2678 static const char *const list_CREATE_EVENT_TRIGGER_ON[] =
2679 {"ddl_command_start", "ddl_command_end", "sql_drop", NULL};
2681 COMPLETE_WITH_LIST(list_CREATE_EVENT_TRIGGER_ON);
2685 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
2687 static const char *const list_DECLARE[] =
2688 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
2690 COMPLETE_WITH_LIST(list_DECLARE);
2694 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
2696 static const char *const list_DECLARECURSOR[] =
2697 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
2699 COMPLETE_WITH_LIST(list_DECLARECURSOR);
2706 * Complete DELETE with FROM (only if the word before that is not "ON"
2707 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
2709 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
2710 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
2711 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2712 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2713 pg_strcasecmp(prev2_wd, "AFTER") == 0))
2714 COMPLETE_WITH_CONST("FROM");
2715 /* Complete DELETE FROM with a list of tables */
2716 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
2717 pg_strcasecmp(prev_wd, "FROM") == 0)
2718 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
2719 /* Complete DELETE FROM <table> */
2720 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
2721 pg_strcasecmp(prev2_wd, "FROM") == 0)
2723 static const char *const list_DELETE[] =
2724 {"USING", "WHERE", "SET", NULL};
2726 COMPLETE_WITH_LIST(list_DELETE);
2728 /* XXX: implement tab completion for DELETE ... USING */
2731 else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
2733 static const char *const list_DISCARD[] =
2734 {"ALL", "PLANS", "SEQUENCES", "TEMP", NULL};
2736 COMPLETE_WITH_LIST(list_DISCARD);
2742 * Complete DO with LANGUAGE.
2744 else if (pg_strcasecmp(prev_wd, "DO") == 0)
2746 static const char *const list_DO[] =
2749 COMPLETE_WITH_LIST(list_DO);
2752 /* DROP (when not the previous word) */
2753 /* DROP AGGREGATE */
2754 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2755 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
2756 COMPLETE_WITH_CONST("(");
2758 /* DROP object with CASCADE / RESTRICT */
2759 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2760 (pg_strcasecmp(prev2_wd, "COLLATION") == 0 ||
2761 pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
2762 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
2763 pg_strcasecmp(prev2_wd, "EXTENSION") == 0 ||
2764 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
2765 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2766 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
2767 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
2768 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
2769 pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
2770 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
2771 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
2772 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
2773 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2774 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
2775 prev_wd[strlen(prev_wd) - 1] == ')') ||
2776 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2777 pg_strcasecmp(prev3_wd, "EVENT") == 0 &&
2778 pg_strcasecmp(prev2_wd, "TRIGGER") == 0) ||
2779 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2780 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2781 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2782 pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
2783 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2784 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2785 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2786 (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
2787 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
2788 pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
2789 pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
2792 if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2793 pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
2795 COMPLETE_WITH_CONST("(");
2799 static const char *const list_DROPCR[] =
2800 {"CASCADE", "RESTRICT", NULL};
2802 COMPLETE_WITH_LIST(list_DROPCR);
2805 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2806 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2808 static const char *const drop_CREATE_FOREIGN[] =
2809 {"DATA WRAPPER", "TABLE", NULL};
2811 COMPLETE_WITH_LIST(drop_CREATE_FOREIGN);
2814 /* DROP MATERIALIZED VIEW */
2815 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2816 pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
2818 COMPLETE_WITH_CONST("VIEW");
2820 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2821 pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
2822 pg_strcasecmp(prev_wd, "VIEW") == 0)
2824 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
2827 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2828 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
2829 pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
2830 pg_strcasecmp(prev_wd, "(") == 0)
2831 COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
2833 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2834 pg_strcasecmp(prev_wd, "OWNED") == 0)
2835 COMPLETE_WITH_CONST("BY");
2836 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2837 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2838 pg_strcasecmp(prev_wd, "BY") == 0)
2839 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2840 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2841 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2842 pg_strcasecmp(prev_wd, "SEARCH") == 0)
2845 static const char *const list_ALTERTEXTSEARCH[] =
2846 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2848 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
2852 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2853 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
2855 COMPLETE_WITH_CONST("ON");
2857 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2858 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
2859 pg_strcasecmp(prev_wd, "ON") == 0)
2861 completion_info_charp = prev2_wd;
2862 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
2864 else if (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2865 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2866 pg_strcasecmp(prev2_wd, "ON") == 0)
2868 static const char *const list_DROPCR[] =
2869 {"CASCADE", "RESTRICT", NULL};
2871 COMPLETE_WITH_LIST(list_DROPCR);
2874 /* DROP EVENT TRIGGER */
2875 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2876 pg_strcasecmp(prev_wd, "EVENT") == 0)
2878 COMPLETE_WITH_CONST("TRIGGER");
2880 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2881 pg_strcasecmp(prev2_wd, "EVENT") == 0 &&
2882 pg_strcasecmp(prev_wd, "TRIGGER") == 0)
2884 COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
2887 /* DROP POLICY <name> ON */
2888 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2889 pg_strcasecmp(prev2_wd, "POLICY") == 0)
2890 COMPLETE_WITH_CONST("ON");
2891 /* DROP POLICY <name> ON <table> */
2892 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2893 pg_strcasecmp(prev3_wd, "POLICY") == 0 &&
2894 pg_strcasecmp(prev_wd, "ON") == 0)
2895 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2898 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2899 pg_strcasecmp(prev2_wd, "RULE") == 0)
2901 COMPLETE_WITH_CONST("ON");
2903 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2904 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
2905 pg_strcasecmp(prev_wd, "ON") == 0)
2907 completion_info_charp = prev2_wd;
2908 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
2910 else if (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2911 pg_strcasecmp(prev4_wd, "RULE") == 0 &&
2912 pg_strcasecmp(prev2_wd, "ON") == 0)
2914 static const char *const list_DROPCR[] =
2915 {"CASCADE", "RESTRICT", NULL};
2917 COMPLETE_WITH_LIST(list_DROPCR);
2920 /* EXECUTE, but not EXECUTE embedded in other commands */
2921 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2922 prev2_wd[0] == '\0')
2923 COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
2928 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2930 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
2932 static const char *const list_EXPLAIN[] =
2933 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
2935 COMPLETE_WITH_LIST(list_EXPLAIN);
2937 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2938 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2940 static const char *const list_EXPLAIN[] =
2941 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
2943 COMPLETE_WITH_LIST(list_EXPLAIN);
2945 else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2946 pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
2947 (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
2948 pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
2949 pg_strcasecmp(prev_wd, "VERBOSE") == 0))
2951 static const char *const list_EXPLAIN[] =
2952 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
2954 COMPLETE_WITH_LIST(list_EXPLAIN);
2958 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
2959 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
2960 pg_strcasecmp(prev_wd, "MOVE") == 0)
2962 static const char *const list_FETCH1[] =
2963 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
2965 COMPLETE_WITH_LIST(list_FETCH1);
2967 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
2968 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
2969 pg_strcasecmp(prev2_wd, "MOVE") == 0)
2971 static const char *const list_FETCH2[] =
2972 {"ALL", "NEXT", "PRIOR", NULL};
2974 COMPLETE_WITH_LIST(list_FETCH2);
2978 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
2979 * but we may as well tab-complete both: perhaps some users prefer one
2980 * variant or the other.
2982 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
2983 pg_strcasecmp(prev3_wd, "MOVE") == 0)
2985 static const char *const list_FROMIN[] =
2986 {"FROM", "IN", NULL};
2988 COMPLETE_WITH_LIST(list_FROMIN);
2991 /* FOREIGN DATA WRAPPER */
2992 /* applies in ALTER/DROP FDW and in CREATE SERVER */
2993 else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
2994 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
2995 pg_strcasecmp(prev2_wd, "DATA") == 0 &&
2996 pg_strcasecmp(prev_wd, "WRAPPER") == 0)
2997 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
3000 else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 &&
3001 pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
3002 pg_strcasecmp(prev_wd, "TABLE") == 0)
3003 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
3005 /* GRANT && REVOKE */
3006 /* Complete GRANT/REVOKE with a list of roles and privileges */
3007 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
3008 pg_strcasecmp(prev_wd, "REVOKE") == 0)
3010 COMPLETE_WITH_QUERY(Query_for_list_of_roles
3011 " UNION SELECT 'SELECT'"
3012 " UNION SELECT 'INSERT'"
3013 " UNION SELECT 'UPDATE'"
3014 " UNION SELECT 'DELETE'"
3015 " UNION SELECT 'TRUNCATE'"
3016 " UNION SELECT 'REFERENCES'"
3017 " UNION SELECT 'TRIGGER'"
3018 " UNION SELECT 'CREATE'"
3019 " UNION SELECT 'CONNECT'"
3020 " UNION SELECT 'TEMPORARY'"
3021 " UNION SELECT 'EXECUTE'"
3022 " UNION SELECT 'USAGE'"
3023 " UNION SELECT 'ALL'");
3027 * Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
3030 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
3031 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
3033 if (pg_strcasecmp(prev_wd, "SELECT") == 0
3034 || pg_strcasecmp(prev_wd, "INSERT") == 0
3035 || pg_strcasecmp(prev_wd, "UPDATE") == 0
3036 || pg_strcasecmp(prev_wd, "DELETE") == 0
3037 || pg_strcasecmp(prev_wd, "TRUNCATE") == 0
3038 || pg_strcasecmp(prev_wd, "REFERENCES") == 0
3039 || pg_strcasecmp(prev_wd, "TRIGGER") == 0
3040 || pg_strcasecmp(prev_wd, "CREATE") == 0
3041 || pg_strcasecmp(prev_wd, "CONNECT") == 0
3042 || pg_strcasecmp(prev_wd, "TEMPORARY") == 0
3043 || pg_strcasecmp(prev_wd, "TEMP") == 0
3044 || pg_strcasecmp(prev_wd, "EXECUTE") == 0
3045 || pg_strcasecmp(prev_wd, "USAGE") == 0
3046 || pg_strcasecmp(prev_wd, "ALL") == 0)
3047 COMPLETE_WITH_CONST("ON");
3050 if (pg_strcasecmp(prev2_wd, "GRANT") == 0)
3051 COMPLETE_WITH_CONST("TO");
3053 COMPLETE_WITH_CONST("FROM");
3058 * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
3061 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
3062 * UNION; seems to work intuitively
3064 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
3065 * here will only work if the privilege list contains exactly one
3068 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
3069 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
3070 pg_strcasecmp(prev_wd, "ON") == 0)
3071 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
3072 " UNION SELECT 'DATABASE'"
3073 " UNION SELECT 'DOMAIN'"
3074 " UNION SELECT 'FOREIGN DATA WRAPPER'"
3075 " UNION SELECT 'FOREIGN SERVER'"
3076 " UNION SELECT 'FUNCTION'"
3077 " UNION SELECT 'LANGUAGE'"
3078 " UNION SELECT 'LARGE OBJECT'"
3079 " UNION SELECT 'SCHEMA'"
3080 " UNION SELECT 'TABLESPACE'"
3081 " UNION SELECT 'TYPE'");
3082 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
3083 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
3084 pg_strcasecmp(prev2_wd, "ON") == 0 &&
3085 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
3087 static const char *const list_privilege_foreign[] =
3088 {"DATA WRAPPER", "SERVER", NULL};
3090 COMPLETE_WITH_LIST(list_privilege_foreign);
3093 /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
3094 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
3095 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
3096 pg_strcasecmp(prev2_wd, "ON") == 0)
3098 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
3099 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3100 else if (pg_strcasecmp(prev_wd, "DOMAIN") == 0)
3101 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
3102 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
3103 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3104 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
3105 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
3106 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
3107 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3108 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
3109 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
3110 else if (pg_strcasecmp(prev_wd, "TYPE") == 0)
3111 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
3112 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
3113 COMPLETE_WITH_CONST("TO");
3115 COMPLETE_WITH_CONST("FROM");
3118 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
3119 else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
3120 pg_strcasecmp(prev3_wd, "ON") == 0)
3122 if (pg_strcasecmp(prev_wd, "TO") == 0)
3123 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
3125 COMPLETE_WITH_CONST("TO");
3127 else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
3128 pg_strcasecmp(prev3_wd, "ON") == 0)
3130 if (pg_strcasecmp(prev_wd, "FROM") == 0)
3131 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
3133 COMPLETE_WITH_CONST("FROM");
3136 /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */
3137 else if (pg_strcasecmp(prev3_wd, "GRANT") == 0 &&
3138 pg_strcasecmp(prev_wd, "TO") == 0)
3140 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
3142 else if (pg_strcasecmp(prev3_wd, "REVOKE") == 0 &&
3143 pg_strcasecmp(prev_wd, "FROM") == 0)
3145 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
3149 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
3150 pg_strcasecmp(prev_wd, "GROUP") == 0)
3151 COMPLETE_WITH_CONST("BY");
3153 /* IMPORT FOREIGN SCHEMA */
3154 else if (pg_strcasecmp(prev_wd, "IMPORT") == 0)
3155 COMPLETE_WITH_CONST("FOREIGN SCHEMA");
3156 else if (pg_strcasecmp(prev2_wd, "IMPORT") == 0 &&
3157 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
3158 COMPLETE_WITH_CONST("SCHEMA");
3161 /* Complete INSERT with "INTO" */
3162 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
3163 COMPLETE_WITH_CONST("INTO");
3164 /* Complete INSERT INTO with table names */
3165 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
3166 pg_strcasecmp(prev_wd, "INTO") == 0)
3167 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
3168 /* Complete "INSERT INTO <table> (" with attribute names */
3169 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
3170 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
3171 pg_strcasecmp(prev_wd, "(") == 0)
3172 COMPLETE_WITH_ATTR(prev2_wd, "");
3175 * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
3176 * "TABLE" or "DEFAULT VALUES"
3178 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
3179 pg_strcasecmp(prev2_wd, "INTO") == 0)
3181 static const char *const list_INSERT[] =
3182 {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
3184 COMPLETE_WITH_LIST(list_INSERT);
3188 * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
3191 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
3192 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
3193 prev_wd[strlen(prev_wd) - 1] == ')')
3195 static const char *const list_INSERT[] =
3196 {"SELECT", "TABLE", "VALUES", NULL};
3198 COMPLETE_WITH_LIST(list_INSERT);
3201 /* Insert an open parenthesis after "VALUES" */
3202 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
3203 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
3204 COMPLETE_WITH_CONST("(");
3207 /* Complete LOCK [TABLE] with a list of tables */
3208 else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
3209 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
3210 " UNION SELECT 'TABLE'");
3211 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
3212 pg_strcasecmp(prev2_wd, "LOCK") == 0)
3213 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
3215 /* For the following, handle the case of a single table only for now */
3217 /* Complete LOCK [TABLE] <table> with "IN" */
3218 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
3219 pg_strcasecmp(prev_wd, "TABLE") != 0) ||
3220 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
3221 pg_strcasecmp(prev3_wd, "LOCK") == 0))
3222 COMPLETE_WITH_CONST("IN");
3224 /* Complete LOCK [TABLE] <table> IN with a lock mode */
3225 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
3226 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
3227 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
3228 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
3230 static const char *const lock_modes[] =
3231 {"ACCESS SHARE MODE",
3232 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
3233 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
3234 "SHARE ROW EXCLUSIVE MODE",
3235 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
3237 COMPLETE_WITH_LIST(lock_modes);
3241 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
3242 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'");
3245 else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
3246 COMPLETE_WITH_CONST("(");
3248 /* OWNER TO - complete with available roles */
3249 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
3250 pg_strcasecmp(prev_wd, "TO") == 0)
3251 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3254 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
3255 pg_strcasecmp(prev_wd, "ORDER") == 0)
3256 COMPLETE_WITH_CONST("BY");
3257 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
3258 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
3259 pg_strcasecmp(prev_wd, "BY") == 0)
3260 COMPLETE_WITH_ATTR(prev3_wd, "");
3263 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
3264 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
3266 static const char *const list_PREPARE[] =
3267 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
3269 COMPLETE_WITH_LIST(list_PREPARE);
3273 * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
3274 * managers, not for manual use in interactive sessions.
3277 /* REASSIGN OWNED BY xxx TO yyy */
3278 else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
3279 COMPLETE_WITH_CONST("OWNED");
3280 else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
3281 pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
3282 COMPLETE_WITH_CONST("BY");
3283 else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
3284 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
3285 pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
3286 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3287 else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
3288 pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
3289 pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
3290 COMPLETE_WITH_CONST("TO");
3291 else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
3292 pg_strcasecmp(prev3_wd, "BY") == 0 &&
3293 pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
3294 pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
3295 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3297 /* REFRESH MATERIALIZED VIEW */
3298 else if (pg_strcasecmp(prev_wd, "REFRESH") == 0)
3299 COMPLETE_WITH_CONST("MATERIALIZED VIEW");
3300 else if (pg_strcasecmp(prev2_wd, "REFRESH") == 0 &&
3301 pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
3302 COMPLETE_WITH_CONST("VIEW");
3303 else if (pg_strcasecmp(prev3_wd, "REFRESH") == 0 &&
3304 pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
3305 pg_strcasecmp(prev_wd, "VIEW") == 0)
3306 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
3307 " UNION SELECT 'CONCURRENTLY'");
3308 else if (pg_strcasecmp(prev4_wd, "REFRESH") == 0 &&
3309 pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
3310 pg_strcasecmp(prev2_wd, "VIEW") == 0 &&
3311 pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
3312 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
3313 else if (pg_strcasecmp(prev4_wd, "REFRESH") == 0 &&
3314 pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
3315 pg_strcasecmp(prev2_wd, "VIEW") == 0)
3316 COMPLETE_WITH_CONST("WITH");
3317 else if (pg_strcasecmp(prev5_wd, "REFRESH") == 0 &&
3318 pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
3319 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
3320 pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0)
3321 COMPLETE_WITH_CONST("WITH DATA");
3322 else if (pg_strcasecmp(prev5_wd, "REFRESH") == 0 &&
3323 pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
3324 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
3325 pg_strcasecmp(prev_wd, "WITH") == 0)
3327 static const char *const list_WITH_DATA[] =
3328 {"NO DATA", "DATA", NULL};
3330 COMPLETE_WITH_LIST(list_WITH_DATA);
3332 else if (pg_strcasecmp(prev6_wd, "REFRESH") == 0 &&
3333 pg_strcasecmp(prev5_wd, "MATERIALIZED") == 0 &&
3334 pg_strcasecmp(prev4_wd, "VIEW") == 0 &&
3335 pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0 &&
3336 pg_strcasecmp(prev_wd, "WITH") == 0)
3337 COMPLETE_WITH_CONST("DATA");
3338 else if (pg_strcasecmp(prev6_wd, "REFRESH") == 0 &&
3339 pg_strcasecmp(prev5_wd, "MATERIALIZED") == 0 &&
3340 pg_strcasecmp(prev4_wd, "VIEW") == 0 &&
3341 pg_strcasecmp(prev2_wd, "WITH") == 0 &&
3342 pg_strcasecmp(prev_wd, "NO") == 0)
3343 COMPLETE_WITH_CONST("DATA");
3346 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
3348 static const char *const list_REINDEX[] =
3349 {"TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE", NULL};
3351 COMPLETE_WITH_LIST(list_REINDEX);
3353 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
3355 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
3356 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
3357 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
3358 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
3359 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
3360 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3361 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
3362 pg_strcasecmp(prev_wd, "DATABASE") == 0)
3363 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3366 /* SECURITY LABEL */
3367 else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
3368 COMPLETE_WITH_CONST("LABEL");
3369 else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
3370 pg_strcasecmp(prev_wd, "LABEL") == 0)
3372 static const char *const list_SECURITY_LABEL_preposition[] =
3375 COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
3377 else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
3378 pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
3379 pg_strcasecmp(prev2_wd, "FOR") == 0)
3380 COMPLETE_WITH_CONST("ON");
3381 else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
3382 pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
3383 pg_strcasecmp(prev_wd, "ON") == 0) ||
3384 (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
3385 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
3386 pg_strcasecmp(prev3_wd, "FOR") == 0 &&
3387 pg_strcasecmp(prev_wd, "ON") == 0))
3389 static const char *const list_SECURITY_LABEL[] =
3390 {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW",
3391 "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "DOMAIN",
3392 "LARGE OBJECT", NULL};
3394 COMPLETE_WITH_LIST(list_SECURITY_LABEL);
3396 else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
3397 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
3398 pg_strcasecmp(prev3_wd, "ON") == 0)
3399 COMPLETE_WITH_CONST("IS");
3404 /* SET, RESET, SHOW */
3405 /* Complete with a variable name */
3406 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
3407 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
3408 pg_strcasecmp(prev_wd, "RESET") == 0)
3409 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
3410 else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
3411 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
3412 /* Complete "SET TRANSACTION" */
3413 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
3414 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
3415 || (pg_strcasecmp(prev2_wd, "START") == 0
3416 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
3417 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
3418 && pg_strcasecmp(prev_wd, "WORK") == 0)
3419 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
3420 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
3421 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
3422 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
3423 && pg_strcasecmp(prev2_wd, "AS") == 0
3424 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
3426 static const char *const my_list[] =
3427 {"ISOLATION LEVEL", "READ", NULL};
3429 COMPLETE_WITH_LIST(my_list);
3431 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
3432 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
3433 || pg_strcasecmp(prev3_wd, "START") == 0
3434 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
3435 && pg_strcasecmp(prev3_wd, "AS") == 0))
3436 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
3437 || pg_strcasecmp(prev2_wd, "WORK") == 0)
3438 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
3439 COMPLETE_WITH_CONST("LEVEL");
3440 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
3441 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
3442 || pg_strcasecmp(prev4_wd, "START") == 0
3443 || pg_strcasecmp(prev4_wd, "AS") == 0)
3444 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
3445 || pg_strcasecmp(prev3_wd, "WORK") == 0)
3446 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
3447 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
3449 static const char *const my_list[] =
3450 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
3452 COMPLETE_WITH_LIST(my_list);
3454 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
3455 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
3456 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
3457 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
3458 pg_strcasecmp(prev_wd, "READ") == 0)
3460 static const char *const my_list[] =
3461 {"UNCOMMITTED", "COMMITTED", NULL};
3463 COMPLETE_WITH_LIST(my_list);
3465 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
3466 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
3467 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
3468 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
3469 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
3470 COMPLETE_WITH_CONST("READ");
3471 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
3472 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
3473 pg_strcasecmp(prev3_wd, "START") == 0 ||
3474 pg_strcasecmp(prev3_wd, "AS") == 0) &&
3475 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
3476 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
3477 pg_strcasecmp(prev_wd, "READ") == 0)
3479 static const char *const my_list[] =
3480 {"ONLY", "WRITE", NULL};
3482 COMPLETE_WITH_LIST(my_list);
3484 /* SET CONSTRAINTS */
3485 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3486 pg_strcasecmp(prev_wd, "CONSTRAINTS") == 0)
3488 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, "UNION SELECT 'ALL'");
3490 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
3491 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
3492 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
3494 static const char *const constraint_list[] =
3495 {"DEFERRED", "IMMEDIATE", NULL};
3497 COMPLETE_WITH_LIST(constraint_list);
3499 /* Complete SET ROLE */
3500 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3501 pg_strcasecmp(prev_wd, "ROLE") == 0)
3502 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3503 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
3504 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3505 pg_strcasecmp(prev_wd, "SESSION") == 0)
3507 static const char *const my_list[] =
3508 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
3510 COMPLETE_WITH_LIST(my_list);
3512 /* Complete SET SESSION AUTHORIZATION with username */
3513 else if (pg_strcasecmp(prev3_wd, "SET") == 0
3514 && pg_strcasecmp(prev2_wd, "SESSION") == 0
3515 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
3516 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
3517 /* Complete RESET SESSION with AUTHORIZATION */
3518 else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
3519 pg_strcasecmp(prev_wd, "SESSION") == 0)
3520 COMPLETE_WITH_CONST("AUTHORIZATION");
3521 /* Complete SET <var> with "TO" */
3522 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3523 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
3524 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
3525 pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
3526 prev_wd[strlen(prev_wd) - 1] != ')' &&
3527 prev_wd[strlen(prev_wd) - 1] != '=' &&
3528 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
3529 COMPLETE_WITH_CONST("TO");
3530 /* Suggest possible variable values */
3531 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
3532 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
3534 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
3536 static const char *const my_list[] =
3537 {"ISO", "SQL", "Postgres", "German",
3538 "YMD", "DMY", "MDY",
3539 "US", "European", "NonEuropean",
3542 COMPLETE_WITH_LIST(my_list);
3544 else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
3546 static const char *const my_list[] =
3547 {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
3549 COMPLETE_WITH_LIST(my_list);
3551 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
3553 static const char *const my_list[] =
3554 {"ON", "OFF", "DEFAULT", NULL};
3556 COMPLETE_WITH_LIST(my_list);
3558 else if (pg_strcasecmp(prev2_wd, "search_path") == 0)
3560 COMPLETE_WITH_QUERY(Query_for_list_of_schemas
3561 " AND nspname not like 'pg\\_toast%%' "
3562 " AND nspname not like 'pg\\_temp%%' "
3563 " UNION SELECT 'DEFAULT' ");
3567 static const char *const my_list[] =
3570 COMPLETE_WITH_LIST(my_list);
3574 /* START TRANSACTION */
3575 else if (pg_strcasecmp(prev_wd, "START") == 0)
3576 COMPLETE_WITH_CONST("TRANSACTION");
3578 /* TABLE, but not TABLE embedded in other commands */
3579 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
3580 prev2_wd[0] == '\0')
3581 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3584 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
3585 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3588 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
3589 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 '*'");
3592 /* If prev. word is UPDATE suggest a list of tables */
3593 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
3594 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
3595 /* Complete UPDATE <table> with "SET" */
3596 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
3597 COMPLETE_WITH_CONST("SET");
3600 * If the previous word is SET (and it wasn't caught above as the _first_
3601 * word) the word before it was (hopefully) a table name and we'll now
3602 * make a list of attributes.
3604 else if (pg_strcasecmp(prev_wd, "SET") == 0)
3605 COMPLETE_WITH_ATTR(prev2_wd, "");
3607 /* UPDATE xx SET yy = */
3608 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3609 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
3610 COMPLETE_WITH_CONST("=");
3613 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
3614 pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
3615 pg_strcasecmp(prev3_wd, "DROP") == 0) &&
3616 pg_strcasecmp(prev2_wd, "USER") == 0 &&
3617 pg_strcasecmp(prev_wd, "MAPPING") == 0)
3618 COMPLETE_WITH_CONST("FOR");
3619 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
3620 pg_strcasecmp(prev3_wd, "USER") == 0 &&
3621 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
3622 pg_strcasecmp(prev_wd, "FOR") == 0)
3623 COMPLETE_WITH_QUERY(Query_for_list_of_roles
3624 " UNION SELECT 'CURRENT_USER'"
3625 " UNION SELECT 'PUBLIC'"
3626 " UNION SELECT 'USER'");
3627 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
3628 pg_strcasecmp(prev4_wd, "DROP") == 0) &&
3629 pg_strcasecmp(prev3_wd, "USER") == 0 &&
3630 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
3631 pg_strcasecmp(prev_wd, "FOR") == 0)
3632 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3633 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
3634 pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
3635 pg_strcasecmp(prev5_wd, "DROP") == 0) &&
3636 pg_strcasecmp(prev4_wd, "USER") == 0 &&
3637 pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
3638 pg_strcasecmp(prev2_wd, "FOR") == 0)
3639 COMPLETE_WITH_CONST("SERVER");
3642 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
3643 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
3645 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
3646 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3647 " UNION SELECT 'FULL'"
3648 " UNION SELECT 'FREEZE'"
3649 " UNION SELECT 'ANALYZE'"
3650 " UNION SELECT 'VERBOSE'");
3651 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3652 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
3653 pg_strcasecmp(prev_wd, "FREEZE") == 0))
3654 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3655 " UNION SELECT 'ANALYZE'"
3656 " UNION SELECT 'VERBOSE'");
3657 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
3658 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
3659 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
3660 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
3661 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3662 " UNION SELECT 'VERBOSE'");
3663 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
3664 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
3665 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
3666 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
3667 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3668 " UNION SELECT 'ANALYZE'");
3669 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3670 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
3671 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3672 " UNION SELECT 'ANALYZE'");
3673 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3674 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
3675 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3676 " UNION SELECT 'VERBOSE'");
3677 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
3678 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
3679 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
3680 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
3681 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
3683 /* WITH [RECURSIVE] */
3686 * Only match when WITH is the first word, as WITH may appear in many
3689 else if (pg_strcasecmp(prev_wd, "WITH") == 0 &&
3690 prev2_wd[0] == '\0')
3691 COMPLETE_WITH_CONST("RECURSIVE");
3694 /* If the previous word is ANALYZE, produce list of tables */
3695 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
3696 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, NULL);
3699 /* Simple case of the word before the where being the table name */
3700 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
3701 COMPLETE_WITH_ATTR(prev2_wd, "");
3704 /* TODO: also include SRF ? */
3705 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
3706 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
3707 pg_strcasecmp(prev3_wd, "\\copy") != 0)
3708 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3711 else if (pg_strcasecmp(prev_wd, "JOIN") == 0)
3712 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3714 /* Backslash commands */
3715 /* TODO: \dc \dd \dl */
3716 else if (strcmp(prev_wd, "\\?") == 0)
3718 static const char *const my_list[] =
3719 {"commands", "options", "variables", NULL};
3721 COMPLETE_WITH_LIST_CS(my_list);
3723 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
3725 if (!recognized_connection_string(text))
3726 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3728 else if (strcmp(prev2_wd, "\\connect") == 0 || strcmp(prev2_wd, "\\c") == 0)
3730 if (!recognized_connection_string(prev_wd))
3731 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3733 else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
3734 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
3735 else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
3736 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
3737 else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
3738 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
3739 else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
3740 COMPLETE_WITH_QUERY(Query_for_list_of_servers);
3741 else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
3742 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3743 else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
3744 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
3746 else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
3747 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3748 else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
3749 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
3750 else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
3751 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
3752 else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
3753 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
3754 /* must be at end of \dF */
3755 else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
3756 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
3758 else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
3759 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
3760 else if (strncmp(prev_wd, "\\dL", strlen("\\dL")) == 0)
3761 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
3762 else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
3763 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3764 else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0
3765 || strncmp(prev_wd, "\\z", strlen("\\z")) == 0)
3766 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3767 else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
3768 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
3769 else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
3770 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3771 else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
3772 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
3773 else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0
3774 || (strncmp(prev_wd, "\\dg", strlen("\\dg")) == 0))
3775 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3776 else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
3777 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
3778 else if (strncmp(prev_wd, "\\dx", strlen("\\dx")) == 0)
3779 COMPLETE_WITH_QUERY(Query_for_list_of_extensions);
3780 else if (strncmp(prev_wd, "\\dm", strlen("\\dm")) == 0)
3781 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
3783 /* must be at end of \d list */
3784 else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
3785 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3787 else if (strcmp(prev_wd, "\\ef") == 0)
3788 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3790 else if (strcmp(prev_wd, "\\encoding") == 0)
3791 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
3792 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
3793 COMPLETE_WITH_LIST(sql_commands);
3794 else if (strcmp(prev_wd, "\\password") == 0)
3795 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3796 else if (strcmp(prev_wd, "\\pset") == 0)
3798 static const char *const my_list[] =
3799 {"border", "columns", "expanded", "fieldsep", "fieldsep_zero",
3800 "footer", "format", "linestyle", "null", "numericlocale",
3801 "pager", "recordsep", "recordsep_zero", "tableattr", "title",
3802 "tuples_only", "unicode_border_linestyle",
3803 "unicode_column_linestyle", "unicode_header_linestyle", NULL};
3805 COMPLETE_WITH_LIST_CS(my_list);
3807 else if (strcmp(prev2_wd, "\\pset") == 0)
3809 if (strcmp(prev_wd, "format") == 0)
3811 static const char *const my_list[] =
3812 {"unaligned", "aligned", "wrapped", "html", "asciidoc",
3813 "latex", "latex-longtable", "troff-ms", NULL};
3815 COMPLETE_WITH_LIST_CS(my_list);
3817 else if (strcmp(prev_wd, "linestyle") == 0)
3819 static const char *const my_list[] =
3820 {"ascii", "old-ascii", "unicode", NULL};
3822 COMPLETE_WITH_LIST_CS(my_list);
3824 else if (strcmp(prev_wd, "unicode_border_linestyle") == 0 ||
3825 strcmp(prev_wd, "unicode_column_linestyle") == 0 ||
3826 strcmp(prev_wd, "unicode_header_linestyle") == 0)
3828 static const char *const my_list[] =
3829 {"single", "double", NULL};
3831 COMPLETE_WITH_LIST_CS(my_list);
3835 else if (strcmp(prev_wd, "\\unset") == 0)
3837 matches = complete_from_variables(text, "", "", true);
3839 else if (strcmp(prev_wd, "\\set") == 0)
3841 matches = complete_from_variables(text, "", "", false);
3843 else if (strcmp(prev2_wd, "\\set") == 0)
3845 static const char *const boolean_value_list[] =
3846 {"on", "off", NULL};
3848 if (strcmp(prev_wd, "AUTOCOMMIT") == 0)
3849 COMPLETE_WITH_LIST_CS(boolean_value_list);
3850 else if (strcmp(prev_wd, "COMP_KEYWORD_CASE") == 0)
3852 static const char *const my_list[] =
3853 {"lower", "upper", "preserve-lower", "preserve-upper", NULL};
3855 COMPLETE_WITH_LIST_CS(my_list);
3857 else if (strcmp(prev_wd, "ECHO") == 0)
3859 static const char *const my_list[] =
3860 {"errors", "queries", "all", "none", NULL};
3862 COMPLETE_WITH_LIST_CS(my_list);
3864 else if (strcmp(prev_wd, "ECHO_HIDDEN") == 0)
3866 static const char *const my_list[] =
3867 {"noexec", "off", "on", NULL};
3869 COMPLETE_WITH_LIST_CS(my_list);
3871 else if (strcmp(prev_wd, "HISTCONTROL") == 0)
3873 static const char *const my_list[] =
3874 {"ignorespace", "ignoredups", "ignoreboth", "none", NULL};
3876 COMPLETE_WITH_LIST_CS(my_list);
3878 else if (strcmp(prev_wd, "ON_ERROR_ROLLBACK") == 0)
3880 static const char *const my_list[] =
3881 {"on", "off", "interactive", NULL};
3883 COMPLETE_WITH_LIST_CS(my_list);
3885 else if (strcmp(prev_wd, "ON_ERROR_STOP") == 0)
3886 COMPLETE_WITH_LIST_CS(boolean_value_list);
3887 else if (strcmp(prev_wd, "QUIET") == 0)
3888 COMPLETE_WITH_LIST_CS(boolean_value_list);
3889 else if (strcmp(prev_wd, "SINGLELINE") == 0)
3890 COMPLETE_WITH_LIST_CS(boolean_value_list);
3891 else if (strcmp(prev_wd, "SINGLESTEP") == 0)
3892 COMPLETE_WITH_LIST_CS(boolean_value_list);
3893 else if (strcmp(prev_wd, "VERBOSITY") == 0)
3895 static const char *const my_list[] =
3896 {"default", "verbose", "terse", NULL};
3898 COMPLETE_WITH_LIST_CS(my_list);
3901 else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
3902 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3903 else if (strcmp(prev_wd, "\\cd") == 0 ||
3904 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
3905 strcmp(prev_wd, "\\g") == 0 ||
3906 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
3907 strcmp(prev_wd, "\\ir") == 0 || strcmp(prev_wd, "\\include_relative") == 0 ||
3908 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
3909 strcmp(prev_wd, "\\s") == 0 ||
3910 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0 ||
3911 strcmp(prev_wd, "\\lo_import") == 0
3914 completion_charp = "\\";
3915 matches = completion_matches(text, complete_from_files);
3919 * Finally, we look through the list of "things", such as TABLE, INDEX and
3920 * check if that was the previous word. If so, execute the query to get a
3927 for (i = 0; words_after_create[i].name; i++)
3929 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
3931 if (words_after_create[i].query)
3932 COMPLETE_WITH_QUERY(words_after_create[i].query);
3933 else if (words_after_create[i].squery)
3934 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
3942 * If we still don't have anything to match we have to fabricate some sort
3943 * of default list. If we were to just return NULL, readline automatically
3944 * attempts filename completion, and that's usually no good.
3946 if (matches == NULL)
3948 COMPLETE_WITH_CONST("");
3949 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
3950 rl_completion_append_character = '\0';
3958 for (i = 0; i < lengthof(previous_words); i++)
3959 free(previous_words[i]);
3962 /* Return our Grand List O' Matches */
3968 * GENERATOR FUNCTIONS
3970 * These functions do all the actual work of completing the input. They get
3971 * passed the text so far and the count how many times they have been called
3972 * so far with the same text.
3973 * If you read the above carefully, you'll see that these don't get called
3974 * directly but through the readline interface.
3975 * The return value is expected to be the full completion of the text, going
3976 * through a list each time, or NULL if there are no more matches. The string
3977 * will be free()'d by readline, so you must run it through strdup() or
3978 * something of that sort.
3982 * Common routine for create_command_generator and drop_command_generator.
3983 * Entries that have 'excluded' flags are not returned.
3986 create_or_drop_command_generator(const char *text, int state, bits32 excluded)
3988 static int list_index,
3992 /* If this is the first time for this completion, init some values */
3996 string_length = strlen(text);
3999 /* find something that matches */
4000 while ((name = words_after_create[list_index++].name))
4002 if ((pg_strncasecmp(name, text, string_length) == 0) &&
4003 !(words_after_create[list_index - 1].flags & excluded))
4004 return pg_strdup_keyword_case(name, text);
4006 /* if nothing matches, return NULL */
4011 * This one gives you one from a list of things you can put after CREATE
4015 create_command_generator(const char *text, int state)
4017 return create_or_drop_command_generator(text, state, THING_NO_CREATE);
4021 * This function gives you a list of things you can put after a DROP command.
4024 drop_command_generator(const char *text, int state)
4026 return create_or_drop_command_generator(text, state, THING_NO_DROP);
4029 /* The following two functions are wrappers for _complete_from_query */
4032 complete_from_query(const char *text, int state)
4034 return _complete_from_query(0, text, state);
4038 complete_from_schema_query(const char *text, int state)
4040 return _complete_from_query(1, text, state);
4045 * This creates a list of matching things, according to a query pointed to
4046 * by completion_charp.
4047 * The query can be one of two kinds:
4049 * 1. A simple query which must contain a %d and a %s, which will be replaced
4050 * by the string length of the text and the text itself. The query may also
4051 * have up to four more %s in it; the first two such will be replaced by the
4052 * value of completion_info_charp, the next two by the value of
4053 * completion_info_charp2.
4055 * 2. A schema query used for completion of both schema and relation names.
4056 * These are more complex and must contain in the following order:
4057 * %d %s %d %s %d %s %s %d %s
4058 * where %d is the string length of the text and %s the text itself.
4060 * It is assumed that strings should be escaped to become SQL literals
4061 * (that is, what is in the query is actually ... '%s' ...)
4063 * See top of file for examples of both kinds of query.
4066 _complete_from_query(int is_schema_query, const char *text, int state)
4068 static int list_index,
4070 static PGresult *result = NULL;
4073 * If this is the first time for this completion, we fetch a list of our
4074 * "things" from the backend.
4078 PQExpBufferData query_buffer;
4081 char *e_info_charp2;
4084 string_length = strlen(text);
4086 /* Free any prior result */
4090 /* Set up suitably-escaped copies of textual inputs */
4091 e_text = pg_malloc(string_length * 2 + 1);
4092 PQescapeString(e_text, text, string_length);
4094 if (completion_info_charp)
4098 charp_len = strlen(completion_info_charp);
4099 e_info_charp = pg_malloc(charp_len * 2 + 1);
4100 PQescapeString(e_info_charp, completion_info_charp,
4104 e_info_charp = NULL;
4106 if (completion_info_charp2)
4110 charp_len = strlen(completion_info_charp2);
4111 e_info_charp2 = pg_malloc(charp_len * 2 + 1);
4112 PQescapeString(e_info_charp2, completion_info_charp2,
4116 e_info_charp2 = NULL;
4118 initPQExpBuffer(&query_buffer);
4120 if (is_schema_query)
4122 /* completion_squery gives us the pieces to assemble */
4123 const char *qualresult = completion_squery->qualresult;
4125 if (qualresult == NULL)
4126 qualresult = completion_squery->result;
4128 /* Get unqualified names matching the input-so-far */
4129 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
4130 completion_squery->result,
4131 completion_squery->catname);
4132 if (completion_squery->selcondition)
4133 appendPQExpBuffer(&query_buffer, "%s AND ",
4134 completion_squery->selcondition);
4135 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
4136 completion_squery->result,
4137 string_length, e_text);
4138 appendPQExpBuffer(&query_buffer, " AND %s",
4139 completion_squery->viscondition);
4142 * When fetching relation names, suppress system catalogs unless
4143 * the input-so-far begins with "pg_". This is a compromise
4144 * between not offering system catalogs for completion at all, and
4145 * having them swamp the result when the input is just "p".
4147 if (strcmp(completion_squery->catname,
4148 "pg_catalog.pg_class c") == 0 &&
4149 strncmp(text, "pg_", 3) !=0)
4151 appendPQExpBufferStr(&query_buffer,
4152 " AND c.relnamespace <> (SELECT oid FROM"
4153 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
4157 * Add in matching schema names, but only if there is more than
4158 * one potential match among schema names.
4160 appendPQExpBuffer(&query_buffer, "\nUNION\n"
4161 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
4162 "FROM pg_catalog.pg_namespace n "
4163 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
4164 string_length, e_text);
4165 appendPQExpBuffer(&query_buffer,
4166 " AND (SELECT pg_catalog.count(*)"
4167 " FROM pg_catalog.pg_namespace"
4168 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
4169 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
4170 string_length, e_text);
4173 * Add in matching qualified names, but only if there is exactly
4174 * one schema matching the input-so-far.
4176 appendPQExpBuffer(&query_buffer, "\nUNION\n"
4177 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
4178 "FROM %s, pg_catalog.pg_namespace n "
4179 "WHERE %s = n.oid AND ",
4181 completion_squery->catname,
4182 completion_squery->namespace);
4183 if (completion_squery->selcondition)
4184 appendPQExpBuffer(&query_buffer, "%s AND ",
4185 completion_squery->selcondition);
4186 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
4188 string_length, e_text);
4191 * This condition exploits the single-matching-schema rule to
4192 * speed up the query
4194 appendPQExpBuffer(&query_buffer,
4195 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
4196 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
4197 string_length, e_text);
4198 appendPQExpBuffer(&query_buffer,
4199 " AND (SELECT pg_catalog.count(*)"
4200 " FROM pg_catalog.pg_namespace"
4201 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
4202 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
4203 string_length, e_text);
4205 /* If an addon query was provided, use it */
4206 if (completion_charp)
4207 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
4211 /* completion_charp is an sprintf-style format string */
4212 appendPQExpBuffer(&query_buffer, completion_charp,
4213 string_length, e_text,
4214 e_info_charp, e_info_charp,
4215 e_info_charp2, e_info_charp2);
4218 /* Limit the number of records in the result */
4219 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
4220 completion_max_records);
4222 result = exec_query(query_buffer.data);
4224 termPQExpBuffer(&query_buffer);
4229 free(e_info_charp2);
4232 /* Find something that matches */
4233 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
4237 while (list_index < PQntuples(result) &&
4238 (item = PQgetvalue(result, list_index++, 0)))
4239 if (pg_strncasecmp(text, item, string_length) == 0)
4240 return pg_strdup(item);
4243 /* If nothing matches, free the db structure and return null */
4251 * This function returns in order one of a fixed, NULL pointer terminated list
4252 * of strings (if matching). This can be used if there are only a fixed number
4253 * SQL words that can appear at certain spot.
4256 complete_from_list(const char *text, int state)
4258 static int string_length,
4261 static bool casesensitive;
4264 /* need to have a list */
4265 Assert(completion_charpp != NULL);
4267 /* Initialization */
4271 string_length = strlen(text);
4272 casesensitive = completion_case_sensitive;
4276 while ((item = completion_charpp[list_index++]))
4278 /* First pass is case sensitive */
4279 if (casesensitive && strncmp(text, item, string_length) == 0)
4282 return pg_strdup(item);
4285 /* Second pass is case insensitive, don't bother counting matches */
4286 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
4288 if (completion_case_sensitive)
4289 return pg_strdup(item);
4293 * If case insensitive matching was requested initially,
4294 * adjust the case according to setting.
4296 return pg_strdup_keyword_case(item, text);
4301 * No matches found. If we're not case insensitive already, lets switch to
4302 * being case insensitive and try again
4304 if (casesensitive && matches == 0)
4306 casesensitive = false;
4309 return complete_from_list(text, state);
4312 /* If no more matches, return null. */
4318 * This function returns one fixed string the first time even if it doesn't
4319 * match what's there, and nothing the second time. This should be used if
4320 * there is only one possibility that can appear at a certain spot, so
4321 * misspellings will be overwritten. The string to be passed must be in
4325 complete_from_const(const char *text, int state)
4327 Assert(completion_charp != NULL);
4330 if (completion_case_sensitive)
4331 return pg_strdup(completion_charp);
4335 * If case insensitive matching was requested initially, adjust
4336 * the case according to setting.
4338 return pg_strdup_keyword_case(completion_charp, text);
4346 * This function appends the variable name with prefix and suffix to
4347 * the variable names array.
4350 append_variable_names(char ***varnames, int *nvars,
4351 int *maxvars, const char *varname,
4352 const char *prefix, const char *suffix)
4354 if (*nvars >= *maxvars)
4357 *varnames = (char **) pg_realloc(*varnames,
4358 ((*maxvars) + 1) * sizeof(char *));
4361 (*varnames)[(*nvars)++] = psprintf("%s%s%s", prefix, varname, suffix);
4366 * This function supports completion with the name of a psql variable.
4367 * The variable names can be prefixed and suffixed with additional text
4368 * to support quoting usages. If need_value is true, only the variables
4369 * that have the set values are picked up.
4372 complete_from_variables(const char *text, const char *prefix, const char *suffix,
4380 struct _variable *ptr;
4382 static const char *const known_varnames[] = {
4383 "AUTOCOMMIT", "COMP_KEYWORD_CASE", "DBNAME", "ECHO", "ECHO_HIDDEN",
4384 "ENCODING", "FETCH_COUNT", "HISTCONTROL", "HISTFILE", "HISTSIZE",
4385 "HOST", "IGNOREEOF", "LASTOID", "ON_ERROR_ROLLBACK", "ON_ERROR_STOP",
4386 "PORT", "PROMPT1", "PROMPT2", "PROMPT3", "QUIET", "SINGLELINE",
4387 "SINGLESTEP", "USER", "VERBOSITY", NULL
4390 varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *));
4394 for (i = 0; known_varnames[i] && nvars < maxvars; i++)
4395 append_variable_names(&varnames, &nvars, &maxvars,
4396 known_varnames[i], prefix, suffix);
4399 for (ptr = pset.vars->next; ptr; ptr = ptr->next)
4401 if (need_value && !(ptr->value))
4403 for (i = 0; known_varnames[i]; i++) /* remove duplicate entry */
4405 if (strcmp(ptr->name, known_varnames[i]) == 0)
4408 append_variable_names(&varnames, &nvars, &maxvars, ptr->name,
4412 varnames[nvars] = NULL;
4413 COMPLETE_WITH_LIST_CS((const char *const *) varnames);
4415 for (i = 0; i < nvars; i++)
4424 * This function wraps rl_filename_completion_function() to strip quotes from
4425 * the input before searching for matches and to quote any matches for which
4426 * the consuming command will require it.
4429 complete_from_files(const char *text, int state)
4431 static const char *unquoted_text;
4432 char *unquoted_match;
4437 /* Initialization: stash the unquoted input. */
4438 unquoted_text = strtokx(text, "", NULL, "'", *completion_charp,
4439 false, true, pset.encoding);
4440 /* expect a NULL return for the empty string only */
4443 Assert(*text == '\0');
4444 unquoted_text = text;
4448 unquoted_match = filename_completion_function(unquoted_text, state);
4452 * Caller sets completion_charp to a zero- or one-character string
4453 * containing the escape character. This is necessary since \copy has
4454 * no escape character, but every other backslash command recognizes
4455 * "\" as an escape character. Since we have only two callers, don't
4456 * bother providing a macro to simplify this.
4458 ret = quote_if_needed(unquoted_match, " \t\r\n\"`",
4459 '\'', *completion_charp, pset.encoding);
4461 free(unquoted_match);
4463 ret = unquoted_match;
4470 /* HELPER FUNCTIONS */
4474 * Make a pg_strdup copy of s and convert the case according to
4475 * COMP_KEYWORD_CASE setting, using ref as the text that was already entered.
4478 pg_strdup_keyword_case(const char *s, const char *ref)
4482 unsigned char first = ref[0];
4486 if (pset.comp_case == PSQL_COMP_CASE_LOWER ||
4487 ((pset.comp_case == PSQL_COMP_CASE_PRESERVE_LOWER ||
4488 pset.comp_case == PSQL_COMP_CASE_PRESERVE_UPPER) && islower(first)) ||
4489 (pset.comp_case == PSQL_COMP_CASE_PRESERVE_LOWER && !isalpha(first)))
4491 for (p = ret; *p; p++)
4492 *p = pg_tolower((unsigned char) *p);
4496 for (p = ret; *p; p++)
4497 *p = pg_toupper((unsigned char) *p);
4505 * Execute a query and report any errors. This should be the preferred way of
4506 * talking to the database in this file.
4509 exec_query(const char *query)
4513 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
4516 result = PQexec(pset.db, query);
4518 if (PQresultStatus(result) != PGRES_TUPLES_OK)
4521 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
4522 PQerrorMessage(pset.db), query);
4533 * Return the nwords word(s) before point. Words are returned right to left,
4534 * that is, previous_words[0] gets the last word before point.
4535 * If we run out of words, remaining array elements are set to empty strings.
4536 * Each array element is filled with a malloc'd string.
4539 get_previous_words(int point, char **previous_words, int nwords)
4541 const char *buf = rl_line_buffer; /* alias */
4544 /* first we look for a non-word char before the current point */
4545 for (i = point - 1; i >= 0; i--)
4546 if (strchr(WORD_BREAKS, buf[i]))
4550 while (nwords-- > 0)
4556 /* now find the first non-space which then constitutes the end */
4558 for (i = point; i >= 0; i--)
4560 if (!isspace((unsigned char) buf[i]))
4568 * If no end found we return an empty string, because there is no word
4579 * Otherwise we now look for the start. The start is either the
4580 * last character before any word-break character going backwards
4581 * from the end, or it's simply character 0. We also handle open
4582 * quotes and parentheses.
4584 bool inquotes = false;
4585 int parentheses = 0;
4587 for (start = end; start > 0; start--)
4589 if (buf[start] == '"')
4590 inquotes = !inquotes;
4593 if (buf[start] == ')')
4595 else if (buf[start] == '(')
4597 if (--parentheses <= 0)
4600 else if (parentheses == 0 &&
4601 strchr(WORD_BREAKS, buf[start - 1]))
4608 /* make a copy of chars from start to end inclusive */
4609 s = pg_malloc(end - start + 2);
4610 strlcpy(s, &buf[start], end - start + 2);
4613 *previous_words++ = s;
4620 * Surround a string with single quotes. This works for both SQL and
4621 * psql internal. Currently disabled because it is reported not to
4622 * cooperate with certain versions of readline.
4625 quote_file_name(char *text, int match_type, char *quote_pointer)
4630 (void) quote_pointer; /* not used */
4632 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
4633 s = pg_malloc(length);
4635 strcpy(s + 1, text);
4636 if (match_type == SINGLE_MATCH)
4637 s[length - 2] = '\'';
4638 s[length - 1] = '\0';
4643 dequote_file_name(char *text, char quote_char)
4649 return pg_strdup(text);
4651 length = strlen(text);
4652 s = pg_malloc(length - 2 + 1);
4653 strlcpy(s, text +1, length - 2 + 1);
4657 #endif /* NOT_USED */
4659 #endif /* USE_READLINE */