2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2013, 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 /* The bit masks for the following three functions come from
373 * src/include/catalog/pg_trigger.h.
375 static const SchemaQuery Query_for_list_of_insertables = {
377 "pg_catalog.pg_class c",
379 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
380 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))",
382 "pg_catalog.pg_table_is_visible(c.oid)",
386 "pg_catalog.quote_ident(c.relname)",
391 static const SchemaQuery Query_for_list_of_deletables = {
393 "pg_catalog.pg_class c",
395 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
396 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))",
398 "pg_catalog.pg_table_is_visible(c.oid)",
402 "pg_catalog.quote_ident(c.relname)",
407 static const SchemaQuery Query_for_list_of_updatables = {
409 "pg_catalog.pg_class c",
411 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
412 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))",
414 "pg_catalog.pg_table_is_visible(c.oid)",
418 "pg_catalog.quote_ident(c.relname)",
423 static const SchemaQuery Query_for_list_of_relations = {
425 "pg_catalog.pg_class c",
429 "pg_catalog.pg_table_is_visible(c.oid)",
433 "pg_catalog.quote_ident(c.relname)",
438 static const SchemaQuery Query_for_list_of_tsvmf = {
440 "pg_catalog.pg_class c",
442 "c.relkind IN ('r', 'S', 'v', 'm', 'f')",
444 "pg_catalog.pg_table_is_visible(c.oid)",
448 "pg_catalog.quote_ident(c.relname)",
453 static const SchemaQuery Query_for_list_of_tmf = {
455 "pg_catalog.pg_class c",
457 "c.relkind IN ('r', 'm', 'f')",
459 "pg_catalog.pg_table_is_visible(c.oid)",
463 "pg_catalog.quote_ident(c.relname)",
468 static const SchemaQuery Query_for_list_of_tm = {
470 "pg_catalog.pg_class c",
472 "c.relkind IN ('r', 'm')",
474 "pg_catalog.pg_table_is_visible(c.oid)",
478 "pg_catalog.quote_ident(c.relname)",
483 static const SchemaQuery Query_for_list_of_views = {
485 "pg_catalog.pg_class c",
487 "c.relkind IN ('v')",
489 "pg_catalog.pg_table_is_visible(c.oid)",
493 "pg_catalog.quote_ident(c.relname)",
498 static const SchemaQuery Query_for_list_of_matviews = {
500 "pg_catalog.pg_class c",
502 "c.relkind IN ('m')",
504 "pg_catalog.pg_table_is_visible(c.oid)",
508 "pg_catalog.quote_ident(c.relname)",
515 * Queries to get lists of names of various kinds of things, possibly
516 * restricted to names matching a partially entered name. In these queries,
517 * the first %s will be replaced by the text entered so far (suitably escaped
518 * to become a SQL literal string). %d will be replaced by the length of the
519 * string (in unescaped form). A second and third %s, if present, will be
520 * replaced by a suitably-escaped version of the string provided in
521 * completion_info_charp. A fourth and fifth %s are similarly replaced by
522 * completion_info_charp2.
524 * Beware that the allowed sequences of %s and %d are determined by
525 * _complete_from_query().
528 #define Query_for_list_of_attributes \
529 "SELECT pg_catalog.quote_ident(attname) "\
530 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
531 " WHERE c.oid = a.attrelid "\
532 " AND a.attnum > 0 "\
533 " AND NOT a.attisdropped "\
534 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
535 " AND (pg_catalog.quote_ident(relname)='%s' "\
536 " OR '\"' || relname || '\"'='%s') "\
537 " AND pg_catalog.pg_table_is_visible(c.oid)"
539 #define Query_for_list_of_attributes_with_schema \
540 "SELECT pg_catalog.quote_ident(attname) "\
541 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
542 " WHERE c.oid = a.attrelid "\
543 " AND n.oid = c.relnamespace "\
544 " AND a.attnum > 0 "\
545 " AND NOT a.attisdropped "\
546 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
547 " AND (pg_catalog.quote_ident(relname)='%s' "\
548 " OR '\"' || relname || '\"' ='%s') "\
549 " AND (pg_catalog.quote_ident(nspname)='%s' "\
550 " OR '\"' || nspname || '\"' ='%s') "
552 #define Query_for_list_of_template_databases \
553 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
554 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
556 #define Query_for_list_of_databases \
557 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
558 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
560 #define Query_for_list_of_tablespaces \
561 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
562 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
564 #define Query_for_list_of_encodings \
565 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
566 " FROM pg_catalog.pg_conversion "\
567 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
569 #define Query_for_list_of_languages \
570 "SELECT pg_catalog.quote_ident(lanname) "\
571 " FROM pg_catalog.pg_language "\
572 " WHERE lanname != 'internal' "\
573 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
575 #define Query_for_list_of_schemas \
576 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
577 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
579 #define Query_for_list_of_set_vars \
581 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
582 " WHERE context IN ('user', 'superuser') "\
583 " UNION ALL SELECT 'constraints' "\
584 " UNION ALL SELECT 'transaction' "\
585 " UNION ALL SELECT 'session' "\
586 " UNION ALL SELECT 'role' "\
587 " UNION ALL SELECT 'tablespace' "\
588 " UNION ALL SELECT 'all') ss "\
589 " WHERE substring(name,1,%d)='%s'"
591 #define Query_for_list_of_show_vars \
593 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
594 " UNION ALL SELECT 'session authorization' "\
595 " UNION ALL SELECT 'all') ss "\
596 " WHERE substring(name,1,%d)='%s'"
598 #define Query_for_list_of_roles \
599 " SELECT pg_catalog.quote_ident(rolname) "\
600 " FROM pg_catalog.pg_roles "\
601 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
603 #define Query_for_list_of_grant_roles \
604 " SELECT pg_catalog.quote_ident(rolname) "\
605 " FROM pg_catalog.pg_roles "\
606 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
607 " UNION ALL SELECT 'PUBLIC'"
609 /* the silly-looking length condition is just to eat up the current word */
610 #define Query_for_table_owning_index \
611 "SELECT pg_catalog.quote_ident(c1.relname) "\
612 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
613 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
614 " and (%d = pg_catalog.length('%s'))"\
615 " and pg_catalog.quote_ident(c2.relname)='%s'"\
616 " and pg_catalog.pg_table_is_visible(c2.oid)"
618 /* the silly-looking length condition is just to eat up the current word */
619 #define Query_for_index_of_table \
620 "SELECT pg_catalog.quote_ident(c2.relname) "\
621 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
622 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
623 " and (%d = pg_catalog.length('%s'))"\
624 " and pg_catalog.quote_ident(c1.relname)='%s'"\
625 " and pg_catalog.pg_table_is_visible(c2.oid)"
627 /* the silly-looking length condition is just to eat up the current word */
628 #define Query_for_constraint_of_table \
629 "SELECT pg_catalog.quote_ident(conname) "\
630 " FROM pg_catalog.pg_class c1, pg_catalog.pg_constraint con "\
631 " WHERE c1.oid=conrelid and (%d = pg_catalog.length('%s'))"\
632 " and pg_catalog.quote_ident(c1.relname)='%s'"\
633 " and pg_catalog.pg_table_is_visible(c1.oid)"
635 #define Query_for_all_table_constraints \
636 "SELECT pg_catalog.quote_ident(conname) "\
637 " FROM pg_catalog.pg_constraint c "\
638 " WHERE c.conrelid <> 0 "
640 /* the silly-looking length condition is just to eat up the current word */
641 #define Query_for_constraint_of_type \
642 "SELECT pg_catalog.quote_ident(conname) "\
643 " FROM pg_catalog.pg_type t, pg_catalog.pg_constraint con "\
644 " WHERE t.oid=contypid and (%d = pg_catalog.length('%s'))"\
645 " and pg_catalog.quote_ident(t.typname)='%s'"\
646 " and pg_catalog.pg_type_is_visible(t.oid)"
648 /* the silly-looking length condition is just to eat up the current word */
649 #define Query_for_list_of_tables_for_constraint \
650 "SELECT pg_catalog.quote_ident(relname) "\
651 " FROM pg_catalog.pg_class"\
652 " WHERE (%d = pg_catalog.length('%s'))"\
654 " (SELECT conrelid FROM pg_catalog.pg_constraint "\
655 " WHERE pg_catalog.quote_ident(conname)='%s')"
657 /* the silly-looking length condition is just to eat up the current word */
658 #define Query_for_list_of_tables_for_rule \
659 "SELECT pg_catalog.quote_ident(relname) "\
660 " FROM pg_catalog.pg_class"\
661 " WHERE (%d = pg_catalog.length('%s'))"\
663 " (SELECT ev_class FROM pg_catalog.pg_rewrite "\
664 " WHERE pg_catalog.quote_ident(rulename)='%s')"
666 /* the silly-looking length condition is just to eat up the current word */
667 #define Query_for_list_of_tables_for_trigger \
668 "SELECT pg_catalog.quote_ident(relname) "\
669 " FROM pg_catalog.pg_class"\
670 " WHERE (%d = pg_catalog.length('%s'))"\
672 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
673 " WHERE pg_catalog.quote_ident(tgname)='%s')"
675 #define Query_for_list_of_ts_configurations \
676 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
677 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
679 #define Query_for_list_of_ts_dictionaries \
680 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
681 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
683 #define Query_for_list_of_ts_parsers \
684 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
685 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
687 #define Query_for_list_of_ts_templates \
688 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
689 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
691 #define Query_for_list_of_fdws \
692 " SELECT pg_catalog.quote_ident(fdwname) "\
693 " FROM pg_catalog.pg_foreign_data_wrapper "\
694 " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
696 #define Query_for_list_of_servers \
697 " SELECT pg_catalog.quote_ident(srvname) "\
698 " FROM pg_catalog.pg_foreign_server "\
699 " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
701 #define Query_for_list_of_user_mappings \
702 " SELECT pg_catalog.quote_ident(usename) "\
703 " FROM pg_catalog.pg_user_mappings "\
704 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
706 #define Query_for_list_of_access_methods \
707 " SELECT pg_catalog.quote_ident(amname) "\
708 " FROM pg_catalog.pg_am "\
709 " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
711 /* the silly-looking length condition is just to eat up the current word */
712 #define Query_for_list_of_arguments \
713 "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
714 " FROM pg_catalog.pg_proc "\
715 " WHERE (%d = pg_catalog.length('%s'))"\
716 " AND (pg_catalog.quote_ident(proname)='%s'"\
717 " OR '\"' || proname || '\"'='%s') "\
718 " AND (pg_catalog.pg_function_is_visible(pg_proc.oid))"
720 /* the silly-looking length condition is just to eat up the current word */
721 #define Query_for_list_of_arguments_with_schema \
722 "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
723 " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
724 " WHERE (%d = pg_catalog.length('%s'))"\
725 " AND n.oid = p.pronamespace "\
726 " AND (pg_catalog.quote_ident(proname)='%s' "\
727 " OR '\"' || proname || '\"' ='%s') "\
728 " AND (pg_catalog.quote_ident(nspname)='%s' "\
729 " OR '\"' || nspname || '\"' ='%s') "
731 #define Query_for_list_of_extensions \
732 " SELECT pg_catalog.quote_ident(extname) "\
733 " FROM pg_catalog.pg_extension "\
734 " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
736 #define Query_for_list_of_available_extensions \
737 " SELECT pg_catalog.quote_ident(name) "\
738 " FROM pg_catalog.pg_available_extensions "\
739 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
741 #define Query_for_list_of_prepared_statements \
742 " SELECT pg_catalog.quote_ident(name) "\
743 " FROM pg_catalog.pg_prepared_statements "\
744 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'"
747 * This is a list of all "things" in Pgsql, which can show up after CREATE or
748 * DROP; and there is also a query to get a list of them.
754 const char *query; /* simple query, or NULL */
755 const SchemaQuery *squery; /* schema query, or NULL */
756 const bits32 flags; /* visibility flags, see below */
759 #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
760 #define THING_NO_DROP (1 << 1) /* should not show up after DROP */
761 #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
763 static const pgsql_thing_t words_after_create[] = {
764 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
765 {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
767 {"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'"},
770 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
771 * to be used only by pg_dump.
773 {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
774 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
775 {"DATABASE", Query_for_list_of_databases},
776 {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
777 {"DOMAIN", NULL, &Query_for_list_of_domains},
778 {"EXTENSION", Query_for_list_of_extensions},
779 {"FOREIGN DATA WRAPPER", NULL, NULL},
780 {"FOREIGN TABLE", NULL, NULL},
781 {"FUNCTION", NULL, &Query_for_list_of_functions},
782 {"GROUP", Query_for_list_of_roles},
783 {"LANGUAGE", Query_for_list_of_languages},
784 {"INDEX", NULL, &Query_for_list_of_indexes},
785 {"MATERIALIZED VIEW", NULL, NULL},
786 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
788 {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */
789 {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
790 {"ROLE", Query_for_list_of_roles},
791 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
792 {"SCHEMA", Query_for_list_of_schemas},
793 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
794 {"SERVER", Query_for_list_of_servers},
795 {"TABLE", NULL, &Query_for_list_of_tables},
796 {"TABLESPACE", Query_for_list_of_tablespaces},
797 {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
798 {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
799 {"TEXT SEARCH", NULL, NULL},
800 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
801 {"TYPE", NULL, &Query_for_list_of_datatypes},
802 {"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
803 {"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE
805 {"USER", Query_for_list_of_roles},
806 {"USER MAPPING FOR", NULL, NULL},
807 {"VIEW", NULL, &Query_for_list_of_views},
808 {NULL} /* end of list */
812 /* Forward declaration of functions */
813 static char **psql_completion(char *text, int start, int end);
814 static char *create_command_generator(const char *text, int state);
815 static char *drop_command_generator(const char *text, int state);
816 static char *complete_from_query(const char *text, int state);
817 static char *complete_from_schema_query(const char *text, int state);
818 static char *_complete_from_query(int is_schema_query,
819 const char *text, int state);
820 static char *complete_from_list(const char *text, int state);
821 static char *complete_from_const(const char *text, int state);
822 static char **complete_from_variables(char *text,
823 const char *prefix, const char *suffix);
824 static char *complete_from_files(const char *text, int state);
826 static char *pg_strdup_keyword_case(const char *s, const char *ref);
827 static PGresult *exec_query(const char *query);
829 static void get_previous_words(int point, char **previous_words, int nwords);
832 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
833 static char *dequote_file_name(char *text, char quote_char);
838 * Initialize the readline library for our purposes.
841 initialize_readline(void)
843 rl_readline_name = (char *) pset.progname;
844 rl_attempted_completion_function = (void *) psql_completion;
846 rl_basic_word_break_characters = WORD_BREAKS;
848 completion_max_records = 1000;
851 * There is a variable rl_completion_query_items for this but apparently
852 * it's not defined everywhere.
858 * The completion function.
860 * According to readline spec this gets passed the text entered so far and its
861 * start and end positions in the readline buffer. The return value is some
862 * partially obscure list format that can be generated by readline's
863 * completion_matches() function, so we don't have to worry about it.
866 psql_completion(char *text, int start, int end)
868 /* This is the variable we'll return. */
869 char **matches = NULL;
871 /* This array will contain some scannage of the input line. */
872 char *previous_words[6];
874 /* For compactness, we use these macros to reference previous_words[]. */
875 #define prev_wd (previous_words[0])
876 #define prev2_wd (previous_words[1])
877 #define prev3_wd (previous_words[2])
878 #define prev4_wd (previous_words[3])
879 #define prev5_wd (previous_words[4])
880 #define prev6_wd (previous_words[5])
882 static const char *const sql_commands[] = {
883 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
884 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
885 "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
886 "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "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, ":'", "'");
934 else if (text[1] == '"')
935 matches = complete_from_variables(text, ":\"", "\"");
937 matches = complete_from_variables(text, ":", "");
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 * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
959 * in ALTER TABLE sth ALTER
961 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
962 pg_strcasecmp(prev3_wd, "TABLE") != 0)
964 static const char *const list_ALTER[] =
965 {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
966 "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
967 "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR",
968 "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
969 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
970 "USER", "USER MAPPING FOR", "VIEW", NULL};
972 COMPLETE_WITH_LIST(list_ALTER);
974 /* ALTER AGGREGATE,FUNCTION <name> */
975 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
976 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
977 pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
978 COMPLETE_WITH_CONST("(");
979 /* ALTER AGGREGATE,FUNCTION <name> (...) */
980 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
981 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
982 pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
984 if (prev_wd[strlen(prev_wd) - 1] == ')')
986 static const char *const list_ALTERAGG[] =
987 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
989 COMPLETE_WITH_LIST(list_ALTERAGG);
992 COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
995 /* ALTER SCHEMA <name> */
996 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
997 pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
999 static const char *const list_ALTERGEN[] =
1000 {"OWNER TO", "RENAME TO", NULL};
1002 COMPLETE_WITH_LIST(list_ALTERGEN);
1005 /* ALTER COLLATION <name> */
1006 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1007 pg_strcasecmp(prev2_wd, "COLLATION") == 0)
1009 static const char *const list_ALTERGEN[] =
1010 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1012 COMPLETE_WITH_LIST(list_ALTERGEN);
1015 /* ALTER CONVERSION <name> */
1016 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1017 pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
1019 static const char *const list_ALTERGEN[] =
1020 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1022 COMPLETE_WITH_LIST(list_ALTERGEN);
1025 /* ALTER DATABASE <name> */
1026 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1027 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1029 static const char *const list_ALTERDATABASE[] =
1030 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
1032 COMPLETE_WITH_LIST(list_ALTERDATABASE);
1035 /* ALTER EXTENSION <name> */
1036 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1037 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
1039 static const char *const list_ALTEREXTENSION[] =
1040 {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
1042 COMPLETE_WITH_LIST(list_ALTEREXTENSION);
1046 else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
1047 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1049 static const char *const list_ALTER_FOREIGN[] =
1050 {"DATA WRAPPER", "TABLE", NULL};
1052 COMPLETE_WITH_LIST(list_ALTER_FOREIGN);
1055 /* ALTER FOREIGN DATA WRAPPER <name> */
1056 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1057 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1058 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1059 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1061 static const char *const list_ALTER_FDW[] =
1062 {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
1064 COMPLETE_WITH_LIST(list_ALTER_FDW);
1067 /* ALTER FOREIGN TABLE <name> */
1068 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1069 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
1070 pg_strcasecmp(prev2_wd, "TABLE") == 0)
1072 static const char *const list_ALTER_FOREIGN_TABLE[] =
1073 {"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL};
1075 COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
1078 /* ALTER INDEX <name> */
1079 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1080 pg_strcasecmp(prev2_wd, "INDEX") == 0)
1082 static const char *const list_ALTERINDEX[] =
1083 {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
1085 COMPLETE_WITH_LIST(list_ALTERINDEX);
1087 /* ALTER INDEX <name> SET */
1088 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1089 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1090 pg_strcasecmp(prev_wd, "SET") == 0)
1092 static const char *const list_ALTERINDEXSET[] =
1093 {"(", "TABLESPACE", NULL};
1095 COMPLETE_WITH_LIST(list_ALTERINDEXSET);
1097 /* ALTER INDEX <name> RESET */
1098 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1099 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1100 pg_strcasecmp(prev_wd, "RESET") == 0)
1101 COMPLETE_WITH_CONST("(");
1102 /* ALTER INDEX <foo> SET|RESET ( */
1103 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1104 pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1105 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1106 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1107 pg_strcasecmp(prev_wd, "(") == 0)
1109 static const char *const list_INDEXOPTIONS[] =
1110 {"fillfactor", "fastupdate", NULL};
1112 COMPLETE_WITH_LIST(list_INDEXOPTIONS);
1115 /* ALTER LANGUAGE <name> */
1116 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1117 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
1119 static const char *const list_ALTERLANGUAGE[] =
1120 {"OWNER TO", "RENAME TO", NULL};
1122 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
1125 /* ALTER LARGE OBJECT <oid> */
1126 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1127 pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
1128 pg_strcasecmp(prev2_wd, "OBJECT") == 0)
1130 static const char *const list_ALTERLARGEOBJECT[] =
1133 COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
1136 /* ALTER MATERIALIZED VIEW */
1137 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1138 pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
1139 pg_strcasecmp(prev_wd, "VIEW") == 0)
1141 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
1144 /* ALTER USER,ROLE <name> */
1145 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1146 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1147 (pg_strcasecmp(prev2_wd, "USER") == 0 ||
1148 pg_strcasecmp(prev2_wd, "ROLE") == 0))
1150 static const char *const list_ALTERUSER[] =
1151 {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1152 "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
1153 "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
1154 "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
1155 "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL};
1157 COMPLETE_WITH_LIST(list_ALTERUSER);
1160 /* ALTER USER,ROLE <name> WITH */
1161 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1162 (pg_strcasecmp(prev3_wd, "USER") == 0 ||
1163 pg_strcasecmp(prev3_wd, "ROLE") == 0) &&
1164 pg_strcasecmp(prev_wd, "WITH") == 0))
1166 /* Similar to the above, but don't complete "WITH" again. */
1167 static const char *const list_ALTERUSER_WITH[] =
1168 {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1169 "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
1170 "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
1171 "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
1172 "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", NULL};
1174 COMPLETE_WITH_LIST(list_ALTERUSER_WITH);
1177 /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
1178 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1179 (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1180 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1182 COMPLETE_WITH_CONST("PASSWORD");
1184 /* ALTER DEFAULT PRIVILEGES */
1185 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1186 pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
1187 pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
1189 static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
1190 {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
1192 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
1194 /* ALTER DEFAULT PRIVILEGES FOR */
1195 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1196 pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
1197 pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
1198 pg_strcasecmp(prev_wd, "FOR") == 0)
1200 static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
1201 {"ROLE", "USER", NULL};
1203 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
1205 /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
1206 else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
1207 pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
1208 (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
1209 pg_strcasecmp(prev3_wd, "IN") == 0))
1211 static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
1212 {"GRANT", "REVOKE", NULL};
1214 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
1216 /* ALTER DOMAIN <name> */
1217 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1218 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
1220 static const char *const list_ALTERDOMAIN[] =
1221 {"ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT", NULL};
1223 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1225 /* ALTER DOMAIN <sth> DROP */
1226 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1227 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1228 pg_strcasecmp(prev_wd, "DROP") == 0)
1230 static const char *const list_ALTERDOMAIN2[] =
1231 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
1233 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
1235 /* ALTER DOMAIN <sth> DROP|RENAME|VALIDATE CONSTRAINT */
1236 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1237 pg_strcasecmp(prev4_wd, "DOMAIN") == 0 &&
1238 (pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1239 pg_strcasecmp(prev2_wd, "RENAME") == 0 ||
1240 pg_strcasecmp(prev2_wd, "VALIDATE") == 0) &&
1241 pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
1243 completion_info_charp = prev3_wd;
1244 COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
1246 /* ALTER DOMAIN <sth> RENAME */
1247 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1248 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1249 pg_strcasecmp(prev_wd, "RENAME") == 0)
1251 static const char *const list_ALTERDOMAIN[] =
1252 {"CONSTRAINT", "TO", NULL};
1254 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1256 /* ALTER DOMAIN <sth> RENAME CONSTRAINT <sth> */
1257 else if (pg_strcasecmp(prev5_wd, "DOMAIN") == 0 &&
1258 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1259 pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0)
1260 COMPLETE_WITH_CONST("TO");
1262 /* ALTER DOMAIN <sth> SET */
1263 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1264 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1265 pg_strcasecmp(prev_wd, "SET") == 0)
1267 static const char *const list_ALTERDOMAIN3[] =
1268 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
1270 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
1272 /* ALTER SEQUENCE <name> */
1273 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1274 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
1276 static const char *const list_ALTERSEQUENCE[] =
1277 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
1278 "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
1280 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
1282 /* ALTER SEQUENCE <name> NO */
1283 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1284 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
1285 pg_strcasecmp(prev_wd, "NO") == 0)
1287 static const char *const list_ALTERSEQUENCE2[] =
1288 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
1290 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
1292 /* ALTER SERVER <name> */
1293 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1294 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1296 static const char *const list_ALTER_SERVER[] =
1297 {"VERSION", "OPTIONS", "OWNER TO", NULL};
1299 COMPLETE_WITH_LIST(list_ALTER_SERVER);
1301 /* ALTER VIEW <name> */
1302 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1303 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1305 static const char *const list_ALTERVIEW[] =
1306 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1308 COMPLETE_WITH_LIST(list_ALTERVIEW);
1310 /* ALTER MATERIALIZED VIEW <name> */
1311 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1312 pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
1313 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1315 static const char *const list_ALTERMATVIEW[] =
1316 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1318 COMPLETE_WITH_LIST(list_ALTERMATVIEW);
1321 /* ALTER RULE <name>, add ON */
1322 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1323 pg_strcasecmp(prev2_wd, "RULE") == 0)
1324 COMPLETE_WITH_CONST("ON");
1326 /* If we have ALTER RULE <name> ON, then add the correct tablename */
1327 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1328 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1329 pg_strcasecmp(prev_wd, "ON") == 0)
1331 completion_info_charp = prev2_wd;
1332 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
1335 /* ALTER RULE <name> ON <name> */
1336 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1337 pg_strcasecmp(prev4_wd, "RULE") == 0)
1338 COMPLETE_WITH_CONST("RENAME TO");
1340 /* ALTER TRIGGER <name>, add ON */
1341 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1342 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1343 COMPLETE_WITH_CONST("ON");
1345 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1346 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
1348 completion_info_charp = prev2_wd;
1349 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1353 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1355 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1356 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1357 pg_strcasecmp(prev_wd, "ON") == 0)
1358 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1360 /* ALTER TRIGGER <name> ON <name> */
1361 else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1362 pg_strcasecmp(prev2_wd, "ON") == 0)
1363 COMPLETE_WITH_CONST("RENAME TO");
1366 * If we detect ALTER TABLE <name>, suggest sub commands
1368 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1369 pg_strcasecmp(prev2_wd, "TABLE") == 0)
1371 static const char *const list_ALTER2[] =
1372 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1373 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
1374 "VALIDATE CONSTRAINT", NULL};
1376 COMPLETE_WITH_LIST(list_ALTER2);
1378 /* ALTER TABLE xxx ENABLE */
1379 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1380 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1381 pg_strcasecmp(prev_wd, "ENABLE") == 0)
1383 static const char *const list_ALTERENABLE[] =
1384 {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
1386 COMPLETE_WITH_LIST(list_ALTERENABLE);
1388 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1389 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1390 (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
1391 pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1393 static const char *const list_ALTERENABLE2[] =
1394 {"RULE", "TRIGGER", NULL};
1396 COMPLETE_WITH_LIST(list_ALTERENABLE2);
1398 /* ALTER TABLE xxx INHERIT */
1399 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1400 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1401 pg_strcasecmp(prev_wd, "INHERIT") == 0)
1403 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1405 /* ALTER TABLE xxx NO INHERIT */
1406 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1407 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1408 pg_strcasecmp(prev2_wd, "NO") == 0 &&
1409 pg_strcasecmp(prev_wd, "INHERIT") == 0)
1411 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1413 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1414 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1415 pg_strcasecmp(prev_wd, "DISABLE") == 0)
1417 static const char *const list_ALTERDISABLE[] =
1418 {"RULE", "TRIGGER", NULL};
1420 COMPLETE_WITH_LIST(list_ALTERDISABLE);
1423 /* ALTER TABLE xxx ALTER */
1424 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1425 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1426 pg_strcasecmp(prev_wd, "ALTER") == 0)
1427 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
1429 /* ALTER TABLE xxx RENAME */
1430 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1431 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1432 pg_strcasecmp(prev_wd, "RENAME") == 0)
1433 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'");
1436 * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1439 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1440 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1441 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1442 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1443 COMPLETE_WITH_ATTR(prev3_wd, "");
1445 /* ALTER TABLE xxx RENAME yyy */
1446 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1447 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1448 pg_strcasecmp(prev_wd, "CONSTRAINT") != 0 &&
1449 pg_strcasecmp(prev_wd, "TO") != 0)
1450 COMPLETE_WITH_CONST("TO");
1452 /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */
1453 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1454 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1455 (pg_strcasecmp(prev2_wd, "COLUMN") == 0 ||
1456 pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) &&
1457 pg_strcasecmp(prev_wd, "TO") != 0)
1458 COMPLETE_WITH_CONST("TO");
1460 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1461 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1462 pg_strcasecmp(prev_wd, "DROP") == 0)
1464 static const char *const list_TABLEDROP[] =
1465 {"COLUMN", "CONSTRAINT", NULL};
1467 COMPLETE_WITH_LIST(list_TABLEDROP);
1469 /* If we have ALTER TABLE <sth> DROP COLUMN, provide list of columns */
1470 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1471 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1472 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1473 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1474 COMPLETE_WITH_ATTR(prev3_wd, "");
1477 * If we have ALTER TABLE <sth> DROP|RENAME|VALIDATE CONSTRAINT, provide
1478 * list of constraints
1480 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1481 pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1482 (pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1483 pg_strcasecmp(prev2_wd, "RENAME") == 0 ||
1484 pg_strcasecmp(prev2_wd, "VALIDATE") == 0) &&
1485 pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
1487 completion_info_charp = prev3_wd;
1488 COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
1490 /* ALTER TABLE ALTER [COLUMN] <foo> */
1491 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1492 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1493 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1494 pg_strcasecmp(prev2_wd, "ALTER") == 0))
1496 static const char *const list_COLUMNALTER[] =
1497 {"TYPE", "SET", "RESET", "DROP", NULL};
1499 COMPLETE_WITH_LIST(list_COLUMNALTER);
1501 /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1502 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1503 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1504 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1505 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1506 pg_strcasecmp(prev_wd, "SET") == 0)
1508 static const char *const list_COLUMNSET[] =
1509 {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1511 COMPLETE_WITH_LIST(list_COLUMNSET);
1513 /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1514 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1515 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1516 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1517 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1518 pg_strcasecmp(prev_wd, "(") == 0)
1520 static const char *const list_COLUMNOPTIONS[] =
1521 {"n_distinct", "n_distinct_inherited", NULL};
1523 COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1525 /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1526 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1527 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1528 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1529 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1530 pg_strcasecmp(prev_wd, "STORAGE") == 0)
1532 static const char *const list_COLUMNSTORAGE[] =
1533 {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1535 COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1537 /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1538 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1539 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1540 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1541 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1542 pg_strcasecmp(prev_wd, "DROP") == 0)
1544 static const char *const list_COLUMNDROP[] =
1545 {"DEFAULT", "NOT NULL", NULL};
1547 COMPLETE_WITH_LIST(list_COLUMNDROP);
1549 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1550 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1551 COMPLETE_WITH_CONST("ON");
1552 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1553 pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1554 pg_strcasecmp(prev_wd, "ON") == 0)
1556 completion_info_charp = prev3_wd;
1557 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1559 /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
1560 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1561 pg_strcasecmp(prev_wd, "SET") == 0)
1563 static const char *const list_TABLESET[] =
1564 {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
1566 COMPLETE_WITH_LIST(list_TABLESET);
1568 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1569 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1570 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1571 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1572 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1573 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1574 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1575 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1576 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1578 static const char *const list_TABLESET2[] =
1579 {"CLUSTER", "OIDS", NULL};
1581 COMPLETE_WITH_LIST(list_TABLESET2);
1583 /* ALTER TABLE <foo> RESET */
1584 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1585 pg_strcasecmp(prev_wd, "RESET") == 0)
1586 COMPLETE_WITH_CONST("(");
1587 /* ALTER TABLE <foo> SET|RESET ( */
1588 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1589 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1590 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1591 pg_strcasecmp(prev_wd, "(") == 0)
1593 static const char *const list_TABLEOPTIONS[] =
1595 "autovacuum_analyze_scale_factor",
1596 "autovacuum_analyze_threshold",
1597 "autovacuum_enabled",
1598 "autovacuum_freeze_max_age",
1599 "autovacuum_freeze_min_age",
1600 "autovacuum_freeze_table_age",
1601 "autovacuum_vacuum_cost_delay",
1602 "autovacuum_vacuum_cost_limit",
1603 "autovacuum_vacuum_scale_factor",
1604 "autovacuum_vacuum_threshold",
1606 "toast.autovacuum_enabled",
1607 "toast.autovacuum_freeze_max_age",
1608 "toast.autovacuum_freeze_min_age",
1609 "toast.autovacuum_freeze_table_age",
1610 "toast.autovacuum_vacuum_cost_delay",
1611 "toast.autovacuum_vacuum_cost_limit",
1612 "toast.autovacuum_vacuum_scale_factor",
1613 "toast.autovacuum_vacuum_threshold",
1617 COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1620 /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1621 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1622 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1624 static const char *const list_ALTERTSPC[] =
1625 {"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1627 COMPLETE_WITH_LIST(list_ALTERTSPC);
1629 /* ALTER TABLESPACE <foo> SET|RESET */
1630 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1631 pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1632 (pg_strcasecmp(prev_wd, "SET") == 0 ||
1633 pg_strcasecmp(prev_wd, "RESET") == 0))
1634 COMPLETE_WITH_CONST("(");
1635 /* ALTER TABLESPACE <foo> SET|RESET ( */
1636 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1637 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1638 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1639 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1640 pg_strcasecmp(prev_wd, "(") == 0)
1642 static const char *const list_TABLESPACEOPTIONS[] =
1643 {"seq_page_cost", "random_page_cost", NULL};
1645 COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1648 /* ALTER TEXT SEARCH */
1649 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1650 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1651 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1653 static const char *const list_ALTERTEXTSEARCH[] =
1654 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1656 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1658 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1659 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1660 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1661 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1662 pg_strcasecmp(prev2_wd, "PARSER") == 0))
1664 static const char *const list_ALTERTEXTSEARCH2[] =
1665 {"RENAME TO", "SET SCHEMA", NULL};
1667 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1670 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1671 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1672 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1673 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1675 static const char *const list_ALTERTEXTSEARCH3[] =
1676 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1678 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1681 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1682 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1683 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1684 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1686 static const char *const list_ALTERTEXTSEARCH4[] =
1687 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1689 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
1692 /* complete ALTER TYPE <foo> with actions */
1693 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1694 pg_strcasecmp(prev2_wd, "TYPE") == 0)
1696 static const char *const list_ALTERTYPE[] =
1697 {"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
1698 "OWNER TO", "RENAME", "SET SCHEMA", NULL};
1700 COMPLETE_WITH_LIST(list_ALTERTYPE);
1702 /* complete ALTER TYPE <foo> ADD with actions */
1703 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1704 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1705 pg_strcasecmp(prev_wd, "ADD") == 0)
1707 static const char *const list_ALTERTYPE[] =
1708 {"ATTRIBUTE", "VALUE", NULL};
1710 COMPLETE_WITH_LIST(list_ALTERTYPE);
1712 /* ALTER TYPE <foo> RENAME */
1713 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1714 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1715 pg_strcasecmp(prev_wd, "RENAME") == 0)
1717 static const char *const list_ALTERTYPE[] =
1718 {"ATTRIBUTE", "TO", NULL};
1720 COMPLETE_WITH_LIST(list_ALTERTYPE);
1722 /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */
1723 else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 &&
1724 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1725 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)
1726 COMPLETE_WITH_CONST("TO");
1729 * If we have TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list of
1732 else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 &&
1733 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1734 pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1735 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1736 pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0)
1737 COMPLETE_WITH_ATTR(prev3_wd, "");
1738 /* ALTER TYPE ALTER ATTRIBUTE <foo> */
1739 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1740 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0))
1742 COMPLETE_WITH_CONST("TYPE");
1744 /* complete ALTER GROUP <foo> */
1745 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1746 pg_strcasecmp(prev2_wd, "GROUP") == 0)
1748 static const char *const list_ALTERGROUP[] =
1749 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1751 COMPLETE_WITH_LIST(list_ALTERGROUP);
1753 /* complete ALTER GROUP <foo> ADD|DROP with USER */
1754 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1755 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1756 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1757 pg_strcasecmp(prev_wd, "DROP") == 0))
1758 COMPLETE_WITH_CONST("USER");
1759 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1760 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1761 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1762 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1763 pg_strcasecmp(prev_wd, "USER") == 0)
1764 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1766 /* BEGIN, END, ABORT */
1767 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1768 pg_strcasecmp(prev_wd, "END") == 0 ||
1769 pg_strcasecmp(prev_wd, "ABORT") == 0)
1771 static const char *const list_TRANS[] =
1772 {"WORK", "TRANSACTION", NULL};
1774 COMPLETE_WITH_LIST(list_TRANS);
1777 else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1779 static const char *const list_COMMIT[] =
1780 {"WORK", "TRANSACTION", "PREPARED", NULL};
1782 COMPLETE_WITH_LIST(list_COMMIT);
1784 /* RELEASE SAVEPOINT */
1785 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1786 COMPLETE_WITH_CONST("SAVEPOINT");
1788 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1790 static const char *const list_TRANS[] =
1791 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1793 COMPLETE_WITH_LIST(list_TRANS);
1798 * If the previous word is CLUSTER and not WITHOUT produce list of tables
1800 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1801 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1802 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "UNION SELECT 'VERBOSE'");
1805 * If the previous words are CLUSTER VERBOSE produce list of tables
1807 else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1808 pg_strcasecmp(prev2_wd, "CLUSTER") == 0)
1809 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
1811 /* If we have CLUSTER <sth>, then add "USING" */
1812 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1813 pg_strcasecmp(prev_wd, "ON") != 0 &&
1814 pg_strcasecmp(prev_wd, "VERBOSE") != 0)
1816 COMPLETE_WITH_CONST("USING");
1818 /* If we have CLUSTER VERBOSE <sth>, then add "USING" */
1819 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1820 pg_strcasecmp(prev2_wd, "VERBOSE") == 0)
1822 COMPLETE_WITH_CONST("USING");
1826 * If we have CLUSTER <sth> USING, then add the index as well.
1828 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1829 pg_strcasecmp(prev_wd, "USING") == 0)
1831 completion_info_charp = prev2_wd;
1832 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1836 * If we have CLUSTER VERBOSE <sth> USING, then add the index as well.
1838 else if (pg_strcasecmp(prev4_wd, "CLUSTER") == 0 &&
1839 pg_strcasecmp(prev3_wd, "VERBOSE") == 0 &&
1840 pg_strcasecmp(prev_wd, "USING") == 0)
1842 completion_info_charp = prev2_wd;
1843 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1847 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1848 COMPLETE_WITH_CONST("ON");
1849 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1850 pg_strcasecmp(prev_wd, "ON") == 0)
1852 static const char *const list_COMMENT[] =
1853 {"CAST", "COLLATION", "CONVERSION", "DATABASE", "EXTENSION",
1854 "FOREIGN DATA WRAPPER", "FOREIGN TABLE",
1855 "SERVER", "INDEX", "LANGUAGE", "RULE", "SCHEMA", "SEQUENCE",
1856 "TABLE", "TYPE", "VIEW", "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1857 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1858 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1860 COMPLETE_WITH_LIST(list_COMMENT);
1862 else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
1863 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1864 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1866 static const char *const list_TRANS2[] =
1867 {"DATA WRAPPER", "TABLE", NULL};
1869 COMPLETE_WITH_LIST(list_TRANS2);
1871 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1872 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1873 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1874 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1876 static const char *const list_TRANS2[] =
1877 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1879 COMPLETE_WITH_LIST(list_TRANS2);
1881 else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
1882 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1883 pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
1885 COMPLETE_WITH_QUERY(Query_for_all_table_constraints);
1887 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1888 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1889 pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0)
1891 COMPLETE_WITH_CONST("ON");
1893 else if (pg_strcasecmp(prev5_wd, "COMMENT") == 0 &&
1894 pg_strcasecmp(prev4_wd, "ON") == 0 &&
1895 pg_strcasecmp(prev3_wd, "CONSTRAINT") == 0 &&
1896 pg_strcasecmp(prev_wd, "ON") == 0)
1898 completion_info_charp = prev2_wd;
1899 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint);
1901 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1902 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1903 pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
1904 pg_strcasecmp(prev_wd, "VIEW") == 0)
1906 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
1908 else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1909 pg_strcasecmp(prev3_wd, "ON") == 0) ||
1910 (pg_strcasecmp(prev5_wd, "COMMENT") == 0 &&
1911 pg_strcasecmp(prev4_wd, "ON") == 0) ||
1912 (pg_strcasecmp(prev6_wd, "COMMENT") == 0 &&
1913 pg_strcasecmp(prev5_wd, "ON") == 0))
1914 COMPLETE_WITH_CONST("IS");
1919 * If we have COPY [BINARY] (which you'd have to type yourself), offer
1920 * list of tables (Also cover the analogous backslash command)
1922 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1923 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1924 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1925 pg_strcasecmp(prev_wd, "BINARY") == 0))
1926 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1927 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1928 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1929 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1930 pg_strcasecmp(prev2_wd, "BINARY") == 0)
1932 static const char *const list_FROMTO[] =
1933 {"FROM", "TO", NULL};
1935 COMPLETE_WITH_LIST(list_FROMTO);
1937 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1938 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1939 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1940 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1941 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1942 pg_strcasecmp(prev_wd, "TO") == 0))
1944 completion_charp = "";
1945 matches = completion_matches(text, complete_from_files);
1948 /* Handle COPY|BINARY <sth> FROM|TO filename */
1949 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1950 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1951 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1952 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1953 pg_strcasecmp(prev2_wd, "TO") == 0))
1955 static const char *const list_COPY[] =
1956 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL};
1958 COMPLETE_WITH_LIST(list_COPY);
1961 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1962 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1963 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1964 pg_strcasecmp(prev3_wd, "TO") == 0))
1966 static const char *const list_CSV[] =
1967 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL};
1969 COMPLETE_WITH_LIST(list_CSV);
1972 /* CREATE DATABASE */
1973 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1974 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1976 static const char *const list_DATABASE[] =
1977 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1980 COMPLETE_WITH_LIST(list_DATABASE);
1983 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1984 pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1985 pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1986 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1988 /* CREATE EXTENSION */
1989 /* Complete with available extensions rather than installed ones. */
1990 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1991 pg_strcasecmp(prev_wd, "EXTENSION") == 0)
1992 COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
1993 /* CREATE EXTENSION <name> */
1994 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1995 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
1996 COMPLETE_WITH_CONST("WITH SCHEMA");
1998 /* CREATE FOREIGN */
1999 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2000 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2002 static const char *const list_CREATE_FOREIGN[] =
2003 {"DATA WRAPPER", "TABLE", NULL};
2005 COMPLETE_WITH_LIST(list_CREATE_FOREIGN);
2008 /* CREATE FOREIGN DATA WRAPPER */
2009 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2010 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2011 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2012 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
2014 static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] =
2015 {"HANDLER", "VALIDATOR", NULL};
2017 COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER);
2021 /* First off we complete CREATE UNIQUE with "INDEX" */
2022 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2023 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
2024 COMPLETE_WITH_CONST("INDEX");
2025 /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
2026 else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
2027 (pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
2028 pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
2029 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
2030 " UNION SELECT 'ON'"
2031 " UNION SELECT 'CONCURRENTLY'");
2032 /* Complete ... INDEX [<name>] ON with a list of tables */
2033 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2034 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2035 pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
2036 pg_strcasecmp(prev_wd, "ON") == 0)
2037 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
2038 /* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
2039 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2040 pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
2041 pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
2042 COMPLETE_WITH_CONST("ON");
2043 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
2044 else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2045 pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
2046 pg_strcasecmp(prev2_wd, "INDEX") == 0)
2048 static const char *const list_CREATE_INDEX[] =
2049 {"CONCURRENTLY", "ON", NULL};
2051 COMPLETE_WITH_LIST(list_CREATE_INDEX);
2055 * Complete INDEX <name> ON <table> with a list of table columns (which
2056 * should really be in parens)
2058 else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
2059 pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2060 pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
2061 pg_strcasecmp(prev2_wd, "ON") == 0)
2063 static const char *const list_CREATE_INDEX2[] =
2064 {"(", "USING", NULL};
2066 COMPLETE_WITH_LIST(list_CREATE_INDEX2);
2068 else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
2069 pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
2070 pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
2071 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2072 pg_strcasecmp(prev_wd, "(") == 0)
2073 COMPLETE_WITH_ATTR(prev2_wd, "");
2074 /* same if you put in USING */
2075 else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
2076 pg_strcasecmp(prev3_wd, "USING") == 0 &&
2077 pg_strcasecmp(prev_wd, "(") == 0)
2078 COMPLETE_WITH_ATTR(prev4_wd, "");
2079 /* Complete USING with an index method */
2080 else if (pg_strcasecmp(prev_wd, "USING") == 0)
2081 COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
2082 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
2083 pg_strcasecmp(prev2_wd, "USING") == 0)
2084 COMPLETE_WITH_CONST("(");
2087 /* Complete "CREATE RULE <sth>" with "AS" */
2088 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2089 pg_strcasecmp(prev2_wd, "RULE") == 0)
2090 COMPLETE_WITH_CONST("AS");
2091 /* Complete "CREATE RULE <sth> AS with "ON" */
2092 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2093 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
2094 pg_strcasecmp(prev_wd, "AS") == 0)
2095 COMPLETE_WITH_CONST("ON");
2096 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
2097 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
2098 pg_strcasecmp(prev2_wd, "AS") == 0 &&
2099 pg_strcasecmp(prev_wd, "ON") == 0)
2101 static const char *const rule_events[] =
2102 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2104 COMPLETE_WITH_LIST(rule_events);
2106 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
2107 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
2108 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2109 (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
2110 pg_toupper((unsigned char) prev_wd[5]) == 'T'))
2111 COMPLETE_WITH_CONST("TO");
2112 /* Complete "AS ON <sth> TO" with a table name */
2113 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
2114 pg_strcasecmp(prev3_wd, "ON") == 0 &&
2115 pg_strcasecmp(prev_wd, "TO") == 0)
2116 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2118 /* CREATE SERVER <name> */
2119 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2120 pg_strcasecmp(prev2_wd, "SERVER") == 0)
2122 static const char *const list_CREATE_SERVER[] =
2123 {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
2125 COMPLETE_WITH_LIST(list_CREATE_SERVER);
2129 /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
2130 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2131 (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
2132 pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
2134 static const char *const list_TEMP[] =
2135 {"SEQUENCE", "TABLE", "VIEW", NULL};
2137 COMPLETE_WITH_LIST(list_TEMP);
2139 /* Complete "CREATE UNLOGGED" with TABLE */
2140 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2141 pg_strcasecmp(prev_wd, "UNLOGGED") == 0)
2143 static const char *const list_UNLOGGED[] =
2144 {"TABLE", "MATERIALIZED VIEW", NULL};
2146 COMPLETE_WITH_LIST(list_UNLOGGED);
2149 /* CREATE TABLESPACE */
2150 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2151 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
2153 static const char *const list_CREATETABLESPACE[] =
2154 {"OWNER", "LOCATION", NULL};
2156 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
2158 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
2159 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2160 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
2161 pg_strcasecmp(prev2_wd, "OWNER") == 0)
2163 COMPLETE_WITH_CONST("LOCATION");
2166 /* CREATE TEXT SEARCH */
2167 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2168 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2169 pg_strcasecmp(prev_wd, "SEARCH") == 0)
2171 static const char *const list_CREATETEXTSEARCH[] =
2172 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2174 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
2176 else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2177 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2178 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
2179 COMPLETE_WITH_CONST("(");
2181 /* CREATE TRIGGER */
2182 /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
2183 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2184 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
2186 static const char *const list_CREATETRIGGER[] =
2187 {"BEFORE", "AFTER", "INSTEAD OF", NULL};
2189 COMPLETE_WITH_LIST(list_CREATETRIGGER);
2191 /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
2192 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2193 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
2194 (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
2195 pg_strcasecmp(prev_wd, "AFTER") == 0))
2197 static const char *const list_CREATETRIGGER_EVENTS[] =
2198 {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
2200 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
2202 /* complete CREATE TRIGGER <name> INSTEAD OF with an event */
2203 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2204 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2205 pg_strcasecmp(prev2_wd, "INSTEAD") == 0 &&
2206 pg_strcasecmp(prev_wd, "OF") == 0)
2208 static const char *const list_CREATETRIGGER_EVENTS[] =
2209 {"INSERT", "DELETE", "UPDATE", NULL};
2211 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
2213 /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
2214 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2215 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2216 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2217 pg_strcasecmp(prev2_wd, "AFTER") == 0)) ||
2218 (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
2219 pg_strcasecmp(prev3_wd, "INSTEAD") == 0 &&
2220 pg_strcasecmp(prev2_wd, "OF") == 0))
2222 static const char *const list_CREATETRIGGER2[] =
2225 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
2229 * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
2232 else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
2233 (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
2234 pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
2235 pg_strcasecmp(prev_wd, "ON") == 0)
2236 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2237 /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
2238 else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 &&
2239 pg_strcasecmp(prev3_wd, "OF") == 0 &&
2240 pg_strcasecmp(prev_wd, "ON") == 0)
2241 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2242 /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
2243 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2244 prev2_wd[0] != '\0')
2245 COMPLETE_WITH_CONST("PROCEDURE");
2247 /* CREATE ROLE,USER,GROUP <name> */
2248 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2249 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
2250 (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
2251 pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
2253 static const char *const list_CREATEROLE[] =
2254 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
2255 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB",
2256 "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN",
2257 "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE",
2258 "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL};
2260 COMPLETE_WITH_LIST(list_CREATEROLE);
2263 /* CREATE ROLE,USER,GROUP <name> WITH */
2264 else if ((pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2265 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2266 pg_strcasecmp(prev3_wd, "GROUP") == 0 ||
2267 pg_strcasecmp(prev3_wd, "USER") == 0) &&
2268 pg_strcasecmp(prev_wd, "WITH") == 0))
2270 /* Similar to the above, but don't complete "WITH" again. */
2271 static const char *const list_CREATEROLE_WITH[] =
2272 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
2273 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB",
2274 "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN",
2275 "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE",
2276 "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", NULL};
2278 COMPLETE_WITH_LIST(list_CREATEROLE_WITH);
2282 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
2285 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2286 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2287 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
2288 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
2290 COMPLETE_WITH_CONST("PASSWORD");
2292 /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
2293 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2294 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2295 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
2296 pg_strcasecmp(prev_wd, "IN") == 0)
2298 static const char *const list_CREATEROLE3[] =
2299 {"GROUP", "ROLE", NULL};
2301 COMPLETE_WITH_LIST(list_CREATEROLE3);
2305 /* Complete CREATE VIEW <name> with AS */
2306 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2307 pg_strcasecmp(prev2_wd, "VIEW") == 0)
2308 COMPLETE_WITH_CONST("AS");
2309 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
2310 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2311 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2312 pg_strcasecmp(prev_wd, "AS") == 0)
2313 COMPLETE_WITH_CONST("SELECT");
2315 /* CREATE MATERIALIZED VIEW */
2316 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2317 pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
2318 COMPLETE_WITH_CONST("VIEW");
2319 /* Complete CREATE MATERIALIZED VIEW <name> with AS */
2320 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2321 pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
2322 pg_strcasecmp(prev2_wd, "VIEW") == 0)
2323 COMPLETE_WITH_CONST("AS");
2324 /* Complete "CREATE MATERIALIZED VIEW <sth> AS with "SELECT" */
2325 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2326 pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
2327 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2328 pg_strcasecmp(prev_wd, "AS") == 0)
2329 COMPLETE_WITH_CONST("SELECT");
2332 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
2334 static const char *const list_DECLARE[] =
2335 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
2337 COMPLETE_WITH_LIST(list_DECLARE);
2341 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
2343 static const char *const list_DECLARECURSOR[] =
2344 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
2346 COMPLETE_WITH_LIST(list_DECLARECURSOR);
2353 * Complete DELETE with FROM (only if the word before that is not "ON"
2354 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
2356 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
2357 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
2358 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2359 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2360 pg_strcasecmp(prev2_wd, "AFTER") == 0))
2361 COMPLETE_WITH_CONST("FROM");
2362 /* Complete DELETE FROM with a list of tables */
2363 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
2364 pg_strcasecmp(prev_wd, "FROM") == 0)
2365 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL);
2366 /* Complete DELETE FROM <table> */
2367 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
2368 pg_strcasecmp(prev2_wd, "FROM") == 0)
2370 static const char *const list_DELETE[] =
2371 {"USING", "WHERE", "SET", NULL};
2373 COMPLETE_WITH_LIST(list_DELETE);
2375 /* XXX: implement tab completion for DELETE ... USING */
2378 else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
2380 static const char *const list_DISCARD[] =
2381 {"ALL", "PLANS", "SEQUENCES", "TEMP", NULL};
2383 COMPLETE_WITH_LIST(list_DISCARD);
2389 * Complete DO with LANGUAGE.
2391 else if (pg_strcasecmp(prev_wd, "DO") == 0)
2393 static const char *const list_DO[] =
2396 COMPLETE_WITH_LIST(list_DO);
2399 /* DROP (when not the previous word) */
2400 /* DROP AGGREGATE */
2401 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2402 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
2403 COMPLETE_WITH_CONST("(");
2405 /* DROP object with CASCADE / RESTRICT */
2406 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2407 (pg_strcasecmp(prev2_wd, "COLLATION") == 0 ||
2408 pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
2409 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
2410 pg_strcasecmp(prev2_wd, "EXTENSION") == 0 ||
2411 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
2412 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2413 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
2414 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
2415 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
2416 pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
2417 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
2418 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
2419 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
2420 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2421 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
2422 prev_wd[strlen(prev_wd) - 1] == ')') ||
2423 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2424 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2425 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2426 pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
2427 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2428 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2429 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2430 (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
2431 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
2432 pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
2433 pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
2436 if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2437 pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
2439 COMPLETE_WITH_CONST("(");
2443 static const char *const list_DROPCR[] =
2444 {"CASCADE", "RESTRICT", NULL};
2446 COMPLETE_WITH_LIST(list_DROPCR);
2449 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2450 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2452 static const char *const drop_CREATE_FOREIGN[] =
2453 {"DATA WRAPPER", "TABLE", NULL};
2455 COMPLETE_WITH_LIST(drop_CREATE_FOREIGN);
2458 /* DROP MATERIALIZED VIEW */
2459 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2460 pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
2462 COMPLETE_WITH_CONST("VIEW");
2464 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2465 pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
2466 pg_strcasecmp(prev_wd, "VIEW") == 0)
2468 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
2471 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2472 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
2473 pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
2474 pg_strcasecmp(prev_wd, "(") == 0)
2475 COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
2477 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2478 pg_strcasecmp(prev_wd, "OWNED") == 0)
2479 COMPLETE_WITH_CONST("BY");
2480 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2481 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2482 pg_strcasecmp(prev_wd, "BY") == 0)
2483 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2484 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2485 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2486 pg_strcasecmp(prev_wd, "SEARCH") == 0)
2489 static const char *const list_ALTERTEXTSEARCH[] =
2490 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2492 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
2495 /* EXECUTE, but not EXECUTE embedded in other commands */
2496 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2497 prev2_wd[0] == '\0')
2498 COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
2503 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2505 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
2507 static const char *const list_EXPLAIN[] =
2508 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
2510 COMPLETE_WITH_LIST(list_EXPLAIN);
2512 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2513 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2515 static const char *const list_EXPLAIN[] =
2516 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
2518 COMPLETE_WITH_LIST(list_EXPLAIN);
2520 else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2521 pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
2522 (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
2523 pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
2524 pg_strcasecmp(prev_wd, "VERBOSE") == 0))
2526 static const char *const list_EXPLAIN[] =
2527 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
2529 COMPLETE_WITH_LIST(list_EXPLAIN);
2533 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
2534 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
2535 pg_strcasecmp(prev_wd, "MOVE") == 0)
2537 static const char *const list_FETCH1[] =
2538 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
2540 COMPLETE_WITH_LIST(list_FETCH1);
2542 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
2543 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
2544 pg_strcasecmp(prev2_wd, "MOVE") == 0)
2546 static const char *const list_FETCH2[] =
2547 {"ALL", "NEXT", "PRIOR", NULL};
2549 COMPLETE_WITH_LIST(list_FETCH2);
2553 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
2554 * but we may as well tab-complete both: perhaps some users prefer one
2555 * variant or the other.
2557 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
2558 pg_strcasecmp(prev3_wd, "MOVE") == 0)
2560 static const char *const list_FROMIN[] =
2561 {"FROM", "IN", NULL};
2563 COMPLETE_WITH_LIST(list_FROMIN);
2566 /* FOREIGN DATA WRAPPER */
2567 /* applies in ALTER/DROP FDW and in CREATE SERVER */
2568 else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
2569 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
2570 pg_strcasecmp(prev2_wd, "DATA") == 0 &&
2571 pg_strcasecmp(prev_wd, "WRAPPER") == 0)
2572 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2575 else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 &&
2576 pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
2577 pg_strcasecmp(prev_wd, "TABLE") == 0)
2578 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
2580 /* GRANT && REVOKE */
2581 /* Complete GRANT/REVOKE with a list of roles and privileges */
2582 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
2583 pg_strcasecmp(prev_wd, "REVOKE") == 0)
2585 COMPLETE_WITH_QUERY(Query_for_list_of_roles
2586 " UNION SELECT 'SELECT'"
2587 " UNION SELECT 'INSERT'"
2588 " UNION SELECT 'UPDATE'"
2589 " UNION SELECT 'DELETE'"
2590 " UNION SELECT 'TRUNCATE'"
2591 " UNION SELECT 'REFERENCES'"
2592 " UNION SELECT 'TRIGGER'"
2593 " UNION SELECT 'CREATE'"
2594 " UNION SELECT 'CONNECT'"
2595 " UNION SELECT 'TEMPORARY'"
2596 " UNION SELECT 'EXECUTE'"
2597 " UNION SELECT 'USAGE'"
2598 " UNION SELECT 'ALL'");
2602 * Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
2605 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2606 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
2608 if (pg_strcasecmp(prev_wd, "SELECT") == 0
2609 || pg_strcasecmp(prev_wd, "INSERT") == 0
2610 || pg_strcasecmp(prev_wd, "UPDATE") == 0
2611 || pg_strcasecmp(prev_wd, "DELETE") == 0
2612 || pg_strcasecmp(prev_wd, "TRUNCATE") == 0
2613 || pg_strcasecmp(prev_wd, "REFERENCES") == 0
2614 || pg_strcasecmp(prev_wd, "TRIGGER") == 0
2615 || pg_strcasecmp(prev_wd, "CREATE") == 0
2616 || pg_strcasecmp(prev_wd, "CONNECT") == 0
2617 || pg_strcasecmp(prev_wd, "TEMPORARY") == 0
2618 || pg_strcasecmp(prev_wd, "TEMP") == 0
2619 || pg_strcasecmp(prev_wd, "EXECUTE") == 0
2620 || pg_strcasecmp(prev_wd, "USAGE") == 0
2621 || pg_strcasecmp(prev_wd, "ALL") == 0)
2622 COMPLETE_WITH_CONST("ON");
2625 if (pg_strcasecmp(prev2_wd, "GRANT") == 0)
2626 COMPLETE_WITH_CONST("TO");
2628 COMPLETE_WITH_CONST("FROM");
2633 * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
2636 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
2637 * UNION; seems to work intuitively
2639 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
2640 * here will only work if the privilege list contains exactly one
2643 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
2644 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
2645 pg_strcasecmp(prev_wd, "ON") == 0)
2646 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
2647 " UNION SELECT 'DATABASE'"
2648 " UNION SELECT 'DOMAIN'"
2649 " UNION SELECT 'FOREIGN DATA WRAPPER'"
2650 " UNION SELECT 'FOREIGN SERVER'"
2651 " UNION SELECT 'FUNCTION'"
2652 " UNION SELECT 'LANGUAGE'"
2653 " UNION SELECT 'LARGE OBJECT'"
2654 " UNION SELECT 'SCHEMA'"
2655 " UNION SELECT 'TABLESPACE'"
2656 " UNION SELECT 'TYPE'");
2657 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2658 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2659 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2660 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2662 static const char *const list_privilege_foreign[] =
2663 {"DATA WRAPPER", "SERVER", NULL};
2665 COMPLETE_WITH_LIST(list_privilege_foreign);
2668 /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
2669 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2670 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2671 pg_strcasecmp(prev2_wd, "ON") == 0)
2673 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
2674 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2675 else if (pg_strcasecmp(prev_wd, "DOMAIN") == 0)
2676 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2677 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
2678 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2679 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
2680 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2681 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
2682 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2683 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
2684 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2685 else if (pg_strcasecmp(prev_wd, "TYPE") == 0)
2686 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2687 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
2688 COMPLETE_WITH_CONST("TO");
2690 COMPLETE_WITH_CONST("FROM");
2693 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
2694 else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
2695 pg_strcasecmp(prev3_wd, "ON") == 0)
2697 if (pg_strcasecmp(prev_wd, "TO") == 0)
2698 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2700 COMPLETE_WITH_CONST("TO");
2702 else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
2703 pg_strcasecmp(prev3_wd, "ON") == 0)
2705 if (pg_strcasecmp(prev_wd, "FROM") == 0)
2706 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2708 COMPLETE_WITH_CONST("FROM");
2711 /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */
2712 else if (pg_strcasecmp(prev3_wd, "GRANT") == 0 &&
2713 pg_strcasecmp(prev_wd, "TO") == 0)
2715 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2717 else if (pg_strcasecmp(prev3_wd, "REVOKE") == 0 &&
2718 pg_strcasecmp(prev_wd, "FROM") == 0)
2720 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2724 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2725 pg_strcasecmp(prev_wd, "GROUP") == 0)
2726 COMPLETE_WITH_CONST("BY");
2729 /* Complete INSERT with "INTO" */
2730 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
2731 COMPLETE_WITH_CONST("INTO");
2732 /* Complete INSERT INTO with table names */
2733 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
2734 pg_strcasecmp(prev_wd, "INTO") == 0)
2735 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL);
2736 /* Complete "INSERT INTO <table> (" with attribute names */
2737 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2738 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2739 pg_strcasecmp(prev_wd, "(") == 0)
2740 COMPLETE_WITH_ATTR(prev2_wd, "");
2743 * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
2744 * "TABLE" or "DEFAULT VALUES"
2746 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
2747 pg_strcasecmp(prev2_wd, "INTO") == 0)
2749 static const char *const list_INSERT[] =
2750 {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
2752 COMPLETE_WITH_LIST(list_INSERT);
2756 * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
2759 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2760 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2761 prev_wd[strlen(prev_wd) - 1] == ')')
2763 static const char *const list_INSERT[] =
2764 {"SELECT", "TABLE", "VALUES", NULL};
2766 COMPLETE_WITH_LIST(list_INSERT);
2769 /* Insert an open parenthesis after "VALUES" */
2770 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
2771 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
2772 COMPLETE_WITH_CONST("(");
2775 /* Complete LOCK [TABLE] with a list of tables */
2776 else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
2777 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2778 " UNION SELECT 'TABLE'");
2779 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2780 pg_strcasecmp(prev2_wd, "LOCK") == 0)
2781 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
2783 /* For the following, handle the case of a single table only for now */
2785 /* Complete LOCK [TABLE] <table> with "IN" */
2786 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
2787 pg_strcasecmp(prev_wd, "TABLE") != 0) ||
2788 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
2789 pg_strcasecmp(prev3_wd, "LOCK") == 0))
2790 COMPLETE_WITH_CONST("IN");
2792 /* Complete LOCK [TABLE] <table> IN with a lock mode */
2793 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
2794 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
2795 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
2796 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
2798 static const char *const lock_modes[] =
2799 {"ACCESS SHARE MODE",
2800 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
2801 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
2802 "SHARE ROW EXCLUSIVE MODE",
2803 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
2805 COMPLETE_WITH_LIST(lock_modes);
2809 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
2810 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'");
2813 else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
2814 COMPLETE_WITH_CONST("(");
2816 /* OWNER TO - complete with available roles */
2817 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
2818 pg_strcasecmp(prev_wd, "TO") == 0)
2819 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2822 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2823 pg_strcasecmp(prev_wd, "ORDER") == 0)
2824 COMPLETE_WITH_CONST("BY");
2825 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
2826 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
2827 pg_strcasecmp(prev_wd, "BY") == 0)
2828 COMPLETE_WITH_ATTR(prev3_wd, "");
2831 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
2832 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
2834 static const char *const list_PREPARE[] =
2835 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2837 COMPLETE_WITH_LIST(list_PREPARE);
2841 * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
2842 * managers, not for manual use in interactive sessions.
2845 /* REASSIGN OWNED BY xxx TO yyy */
2846 else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
2847 COMPLETE_WITH_CONST("OWNED");
2848 else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
2849 pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
2850 COMPLETE_WITH_CONST("BY");
2851 else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
2852 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2853 pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
2854 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2855 else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
2856 pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
2857 pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
2858 COMPLETE_WITH_CONST("TO");
2859 else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
2860 pg_strcasecmp(prev3_wd, "BY") == 0 &&
2861 pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
2862 pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
2863 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2865 /* REFRESH MATERIALIZED VIEW */
2866 else if (pg_strcasecmp(prev_wd, "REFRESH") == 0)
2867 COMPLETE_WITH_CONST("MATERIALIZED VIEW");
2868 else if (pg_strcasecmp(prev2_wd, "REFRESH") == 0 &&
2869 pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
2870 COMPLETE_WITH_CONST("VIEW");
2871 else if (pg_strcasecmp(prev3_wd, "REFRESH") == 0 &&
2872 pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
2873 pg_strcasecmp(prev_wd, "VIEW") == 0)
2874 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
2875 " UNION SELECT 'CONCURRENTLY'");
2876 else if (pg_strcasecmp(prev4_wd, "REFRESH") == 0 &&
2877 pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
2878 pg_strcasecmp(prev2_wd, "VIEW") == 0 &&
2879 pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
2880 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
2881 else if (pg_strcasecmp(prev4_wd, "REFRESH") == 0 &&
2882 pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
2883 pg_strcasecmp(prev2_wd, "VIEW") == 0)
2884 COMPLETE_WITH_CONST("WITH");
2885 else if (pg_strcasecmp(prev5_wd, "REFRESH") == 0 &&
2886 pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
2887 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2888 pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0)
2889 COMPLETE_WITH_CONST("WITH DATA");
2890 else if (pg_strcasecmp(prev5_wd, "REFRESH") == 0 &&
2891 pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
2892 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2893 pg_strcasecmp(prev_wd, "WITH") == 0)
2895 static const char *const list_WITH_DATA[] =
2896 {"NO DATA", "DATA", NULL};
2898 COMPLETE_WITH_LIST(list_WITH_DATA);
2900 else if (pg_strcasecmp(prev6_wd, "REFRESH") == 0 &&
2901 pg_strcasecmp(prev5_wd, "MATERIALIZED") == 0 &&
2902 pg_strcasecmp(prev4_wd, "VIEW") == 0 &&
2903 pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0 &&
2904 pg_strcasecmp(prev_wd, "WITH") == 0)
2905 COMPLETE_WITH_CONST("DATA");
2906 else if (pg_strcasecmp(prev6_wd, "REFRESH") == 0 &&
2907 pg_strcasecmp(prev5_wd, "MATERIALIZED") == 0 &&
2908 pg_strcasecmp(prev4_wd, "VIEW") == 0 &&
2909 pg_strcasecmp(prev2_wd, "WITH") == 0 &&
2910 pg_strcasecmp(prev_wd, "NO") == 0)
2911 COMPLETE_WITH_CONST("DATA");
2914 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
2916 static const char *const list_REINDEX[] =
2917 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
2919 COMPLETE_WITH_LIST(list_REINDEX);
2921 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
2923 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
2924 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
2925 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
2926 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2927 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
2928 pg_strcasecmp(prev_wd, "DATABASE") == 0)
2929 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2932 /* SECURITY LABEL */
2933 else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
2934 COMPLETE_WITH_CONST("LABEL");
2935 else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
2936 pg_strcasecmp(prev_wd, "LABEL") == 0)
2938 static const char *const list_SECURITY_LABEL_preposition[] =
2941 COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
2943 else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
2944 pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
2945 pg_strcasecmp(prev2_wd, "FOR") == 0)
2946 COMPLETE_WITH_CONST("ON");
2947 else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
2948 pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
2949 pg_strcasecmp(prev_wd, "ON") == 0) ||
2950 (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2951 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2952 pg_strcasecmp(prev3_wd, "FOR") == 0 &&
2953 pg_strcasecmp(prev_wd, "ON") == 0))
2955 static const char *const list_SECURITY_LABEL[] =
2956 {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW",
2957 "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "DOMAIN",
2958 "LARGE OBJECT", NULL};
2960 COMPLETE_WITH_LIST(list_SECURITY_LABEL);
2962 else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2963 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2964 pg_strcasecmp(prev3_wd, "ON") == 0)
2965 COMPLETE_WITH_CONST("IS");
2970 /* SET, RESET, SHOW */
2971 /* Complete with a variable name */
2972 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
2973 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
2974 pg_strcasecmp(prev_wd, "RESET") == 0)
2975 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
2976 else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
2977 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
2978 /* Complete "SET TRANSACTION" */
2979 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
2980 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2981 || (pg_strcasecmp(prev2_wd, "START") == 0
2982 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2983 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2984 && pg_strcasecmp(prev_wd, "WORK") == 0)
2985 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2986 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2987 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
2988 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
2989 && pg_strcasecmp(prev2_wd, "AS") == 0
2990 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
2992 static const char *const my_list[] =
2993 {"ISOLATION LEVEL", "READ", NULL};
2995 COMPLETE_WITH_LIST(my_list);
2997 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
2998 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
2999 || pg_strcasecmp(prev3_wd, "START") == 0
3000 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
3001 && pg_strcasecmp(prev3_wd, "AS") == 0))
3002 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
3003 || pg_strcasecmp(prev2_wd, "WORK") == 0)
3004 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
3005 COMPLETE_WITH_CONST("LEVEL");
3006 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
3007 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
3008 || pg_strcasecmp(prev4_wd, "START") == 0
3009 || pg_strcasecmp(prev4_wd, "AS") == 0)
3010 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
3011 || pg_strcasecmp(prev3_wd, "WORK") == 0)
3012 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
3013 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
3015 static const char *const my_list[] =
3016 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
3018 COMPLETE_WITH_LIST(my_list);
3020 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
3021 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
3022 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
3023 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
3024 pg_strcasecmp(prev_wd, "READ") == 0)
3026 static const char *const my_list[] =
3027 {"UNCOMMITTED", "COMMITTED", NULL};
3029 COMPLETE_WITH_LIST(my_list);
3031 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
3032 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
3033 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
3034 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
3035 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
3036 COMPLETE_WITH_CONST("READ");
3037 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
3038 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
3039 pg_strcasecmp(prev3_wd, "START") == 0 ||
3040 pg_strcasecmp(prev3_wd, "AS") == 0) &&
3041 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
3042 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
3043 pg_strcasecmp(prev_wd, "READ") == 0)
3045 static const char *const my_list[] =
3046 {"ONLY", "WRITE", NULL};
3048 COMPLETE_WITH_LIST(my_list);
3050 /* SET CONSTRAINTS */
3051 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3052 pg_strcasecmp(prev_wd, "CONSTRAINTS") == 0)
3054 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, "UNION SELECT 'ALL'");
3056 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
3057 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
3058 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
3060 static const char *const constraint_list[] =
3061 {"DEFERRED", "IMMEDIATE", NULL};
3063 COMPLETE_WITH_LIST(constraint_list);
3065 /* Complete SET ROLE */
3066 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3067 pg_strcasecmp(prev_wd, "ROLE") == 0)
3068 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3069 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
3070 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3071 pg_strcasecmp(prev_wd, "SESSION") == 0)
3073 static const char *const my_list[] =
3074 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
3076 COMPLETE_WITH_LIST(my_list);
3078 /* Complete SET SESSION AUTHORIZATION with username */
3079 else if (pg_strcasecmp(prev3_wd, "SET") == 0
3080 && pg_strcasecmp(prev2_wd, "SESSION") == 0
3081 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
3082 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
3083 /* Complete RESET SESSION with AUTHORIZATION */
3084 else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
3085 pg_strcasecmp(prev_wd, "SESSION") == 0)
3086 COMPLETE_WITH_CONST("AUTHORIZATION");
3087 /* Complete SET <var> with "TO" */
3088 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3089 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
3090 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
3091 pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
3092 prev_wd[strlen(prev_wd) - 1] != ')' &&
3093 prev_wd[strlen(prev_wd) - 1] != '=' &&
3094 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
3095 COMPLETE_WITH_CONST("TO");
3096 /* Suggest possible variable values */
3097 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
3098 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
3100 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
3102 static const char *const my_list[] =
3103 {"ISO", "SQL", "Postgres", "German",
3104 "YMD", "DMY", "MDY",
3105 "US", "European", "NonEuropean",
3108 COMPLETE_WITH_LIST(my_list);
3110 else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
3112 static const char *const my_list[] =
3113 {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
3115 COMPLETE_WITH_LIST(my_list);
3117 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
3119 static const char *const my_list[] =
3120 {"ON", "OFF", "DEFAULT", NULL};
3122 COMPLETE_WITH_LIST(my_list);
3126 static const char *const my_list[] =
3129 COMPLETE_WITH_LIST(my_list);
3133 /* START TRANSACTION */
3134 else if (pg_strcasecmp(prev_wd, "START") == 0)
3135 COMPLETE_WITH_CONST("TRANSACTION");
3137 /* TABLE, but not TABLE embedded in other commands */
3138 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
3139 prev2_wd[0] == '\0')
3140 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3143 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
3144 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3147 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
3148 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 '*'");
3151 /* If prev. word is UPDATE suggest a list of tables */
3152 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
3153 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
3154 /* Complete UPDATE <table> with "SET" */
3155 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
3156 COMPLETE_WITH_CONST("SET");
3159 * If the previous word is SET (and it wasn't caught above as the _first_
3160 * word) the word before it was (hopefully) a table name and we'll now
3161 * make a list of attributes.
3163 else if (pg_strcasecmp(prev_wd, "SET") == 0)
3164 COMPLETE_WITH_ATTR(prev2_wd, "");
3166 /* UPDATE xx SET yy = */
3167 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3168 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
3169 COMPLETE_WITH_CONST("=");
3172 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
3173 pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
3174 pg_strcasecmp(prev3_wd, "DROP") == 0) &&
3175 pg_strcasecmp(prev2_wd, "USER") == 0 &&
3176 pg_strcasecmp(prev_wd, "MAPPING") == 0)
3177 COMPLETE_WITH_CONST("FOR");
3178 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
3179 pg_strcasecmp(prev3_wd, "USER") == 0 &&
3180 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
3181 pg_strcasecmp(prev_wd, "FOR") == 0)
3182 COMPLETE_WITH_QUERY(Query_for_list_of_roles
3183 " UNION SELECT 'CURRENT_USER'"
3184 " UNION SELECT 'PUBLIC'"
3185 " UNION SELECT 'USER'");
3186 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
3187 pg_strcasecmp(prev4_wd, "DROP") == 0) &&
3188 pg_strcasecmp(prev3_wd, "USER") == 0 &&
3189 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
3190 pg_strcasecmp(prev_wd, "FOR") == 0)
3191 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3192 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
3193 pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
3194 pg_strcasecmp(prev5_wd, "DROP") == 0) &&
3195 pg_strcasecmp(prev4_wd, "USER") == 0 &&
3196 pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
3197 pg_strcasecmp(prev2_wd, "FOR") == 0)
3198 COMPLETE_WITH_CONST("SERVER");
3201 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
3202 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
3204 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
3205 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3206 " UNION SELECT 'FULL'"
3207 " UNION SELECT 'FREEZE'"
3208 " UNION SELECT 'ANALYZE'"
3209 " UNION SELECT 'VERBOSE'");
3210 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3211 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
3212 pg_strcasecmp(prev_wd, "FREEZE") == 0))
3213 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3214 " UNION SELECT 'ANALYZE'"
3215 " UNION SELECT 'VERBOSE'");
3216 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
3217 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
3218 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
3219 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
3220 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3221 " UNION SELECT 'VERBOSE'");
3222 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
3223 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
3224 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
3225 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
3226 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3227 " UNION SELECT 'ANALYZE'");
3228 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3229 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
3230 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3231 " UNION SELECT 'ANALYZE'");
3232 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3233 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
3234 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3235 " UNION SELECT 'VERBOSE'");
3236 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
3237 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
3238 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
3239 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
3240 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
3242 /* WITH [RECURSIVE] */
3245 * Only match when WITH is the first word, as WITH may appear in many
3248 else if (pg_strcasecmp(prev_wd, "WITH") == 0 &&
3249 prev2_wd[0] == '\0')
3250 COMPLETE_WITH_CONST("RECURSIVE");
3253 /* If the previous word is ANALYZE, produce list of tables */
3254 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
3255 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, NULL);
3258 /* Simple case of the word before the where being the table name */
3259 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
3260 COMPLETE_WITH_ATTR(prev2_wd, "");
3263 /* TODO: also include SRF ? */
3264 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
3265 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
3266 pg_strcasecmp(prev3_wd, "\\copy") != 0)
3267 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3270 else if (pg_strcasecmp(prev_wd, "JOIN") == 0)
3271 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3273 /* Backslash commands */
3274 /* TODO: \dc \dd \dl */
3275 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
3276 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3278 else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
3279 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
3280 else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
3281 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
3282 else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
3283 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
3284 else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
3285 COMPLETE_WITH_QUERY(Query_for_list_of_servers);
3286 else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
3287 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3288 else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
3289 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
3291 else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
3292 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3293 else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
3294 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
3295 else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
3296 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
3297 else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
3298 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
3299 /* must be at end of \dF */
3300 else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
3301 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
3303 else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
3304 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
3305 else if (strncmp(prev_wd, "\\dL", strlen("\\dL")) == 0)
3306 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
3307 else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
3308 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3309 else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0
3310 || strncmp(prev_wd, "\\z", strlen("\\z")) == 0)
3311 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3312 else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
3313 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
3314 else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
3315 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3316 else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
3317 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
3318 else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0
3319 || (strncmp(prev_wd, "\\dg", strlen("\\dg")) == 0))
3320 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3321 else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
3322 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
3323 else if (strncmp(prev_wd, "\\dx", strlen("\\dx")) == 0)
3324 COMPLETE_WITH_QUERY(Query_for_list_of_extensions);
3325 else if (strncmp(prev_wd, "\\dm", strlen("\\dm")) == 0)
3326 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
3328 /* must be at end of \d list */
3329 else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
3330 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3332 else if (strcmp(prev_wd, "\\ef") == 0)
3333 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3335 else if (strcmp(prev_wd, "\\encoding") == 0)
3336 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
3337 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
3338 COMPLETE_WITH_LIST(sql_commands);
3339 else if (strcmp(prev_wd, "\\password") == 0)
3340 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3341 else if (strcmp(prev_wd, "\\pset") == 0)
3343 static const char *const my_list[] =
3344 {"format", "border", "expanded",
3345 "null", "fieldsep", "tuples_only", "title", "tableattr",
3346 "linestyle", "pager", "recordsep", NULL};
3348 COMPLETE_WITH_LIST_CS(my_list);
3350 else if (strcmp(prev2_wd, "\\pset") == 0)
3352 if (strcmp(prev_wd, "format") == 0)
3354 static const char *const my_list[] =
3355 {"unaligned", "aligned", "wrapped", "html", "latex",
3358 COMPLETE_WITH_LIST_CS(my_list);
3360 else if (strcmp(prev_wd, "linestyle") == 0)
3362 static const char *const my_list[] =
3363 {"ascii", "old-ascii", "unicode", NULL};
3365 COMPLETE_WITH_LIST_CS(my_list);
3368 else if (strcmp(prev_wd, "\\set") == 0)
3370 matches = complete_from_variables(text, "", "");
3372 else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
3373 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3374 else if (strcmp(prev_wd, "\\cd") == 0 ||
3375 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
3376 strcmp(prev_wd, "\\g") == 0 ||
3377 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
3378 strcmp(prev_wd, "\\ir") == 0 || strcmp(prev_wd, "\\include_relative") == 0 ||
3379 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
3380 strcmp(prev_wd, "\\s") == 0 ||
3381 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0 ||
3382 strcmp(prev_wd, "\\lo_import") == 0
3385 completion_charp = "\\";
3386 matches = completion_matches(text, complete_from_files);
3390 * Finally, we look through the list of "things", such as TABLE, INDEX and
3391 * check if that was the previous word. If so, execute the query to get a
3398 for (i = 0; words_after_create[i].name; i++)
3400 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
3402 if (words_after_create[i].query)
3403 COMPLETE_WITH_QUERY(words_after_create[i].query);
3404 else if (words_after_create[i].squery)
3405 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
3413 * If we still don't have anything to match we have to fabricate some sort
3414 * of default list. If we were to just return NULL, readline automatically
3415 * attempts filename completion, and that's usually no good.
3417 if (matches == NULL)
3419 COMPLETE_WITH_CONST("");
3420 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
3421 rl_completion_append_character = '\0';
3429 for (i = 0; i < lengthof(previous_words); i++)
3430 free(previous_words[i]);
3433 /* Return our Grand List O' Matches */
3439 * GENERATOR FUNCTIONS
3441 * These functions do all the actual work of completing the input. They get
3442 * passed the text so far and the count how many times they have been called
3443 * so far with the same text.
3444 * If you read the above carefully, you'll see that these don't get called
3445 * directly but through the readline interface.
3446 * The return value is expected to be the full completion of the text, going
3447 * through a list each time, or NULL if there are no more matches. The string
3448 * will be free()'d by readline, so you must run it through strdup() or
3449 * something of that sort.
3453 * Common routine for create_command_generator and drop_command_generator.
3454 * Entries that have 'excluded' flags are not returned.
3457 create_or_drop_command_generator(const char *text, int state, bits32 excluded)
3459 static int list_index,
3463 /* If this is the first time for this completion, init some values */
3467 string_length = strlen(text);
3470 /* find something that matches */
3471 while ((name = words_after_create[list_index++].name))
3473 if ((pg_strncasecmp(name, text, string_length) == 0) &&
3474 !(words_after_create[list_index - 1].flags & excluded))
3475 return pg_strdup_keyword_case(name, text);
3477 /* if nothing matches, return NULL */
3482 * This one gives you one from a list of things you can put after CREATE
3486 create_command_generator(const char *text, int state)
3488 return create_or_drop_command_generator(text, state, THING_NO_CREATE);
3492 * This function gives you a list of things you can put after a DROP command.
3495 drop_command_generator(const char *text, int state)
3497 return create_or_drop_command_generator(text, state, THING_NO_DROP);
3500 /* The following two functions are wrappers for _complete_from_query */
3503 complete_from_query(const char *text, int state)
3505 return _complete_from_query(0, text, state);
3509 complete_from_schema_query(const char *text, int state)
3511 return _complete_from_query(1, text, state);
3516 * This creates a list of matching things, according to a query pointed to
3517 * by completion_charp.
3518 * The query can be one of two kinds:
3520 * 1. A simple query which must contain a %d and a %s, which will be replaced
3521 * by the string length of the text and the text itself. The query may also
3522 * have up to four more %s in it; the first two such will be replaced by the
3523 * value of completion_info_charp, the next two by the value of
3524 * completion_info_charp2.
3526 * 2. A schema query used for completion of both schema and relation names.
3527 * These are more complex and must contain in the following order:
3528 * %d %s %d %s %d %s %s %d %s
3529 * where %d is the string length of the text and %s the text itself.
3531 * It is assumed that strings should be escaped to become SQL literals
3532 * (that is, what is in the query is actually ... '%s' ...)
3534 * See top of file for examples of both kinds of query.
3537 _complete_from_query(int is_schema_query, const char *text, int state)
3539 static int list_index,
3541 static PGresult *result = NULL;
3544 * If this is the first time for this completion, we fetch a list of our
3545 * "things" from the backend.
3549 PQExpBufferData query_buffer;
3552 char *e_info_charp2;
3555 string_length = strlen(text);
3557 /* Free any prior result */
3561 /* Set up suitably-escaped copies of textual inputs */
3562 e_text = pg_malloc(string_length * 2 + 1);
3563 PQescapeString(e_text, text, string_length);
3565 if (completion_info_charp)
3569 charp_len = strlen(completion_info_charp);
3570 e_info_charp = pg_malloc(charp_len * 2 + 1);
3571 PQescapeString(e_info_charp, completion_info_charp,
3575 e_info_charp = NULL;
3577 if (completion_info_charp2)
3581 charp_len = strlen(completion_info_charp2);
3582 e_info_charp2 = pg_malloc(charp_len * 2 + 1);
3583 PQescapeString(e_info_charp2, completion_info_charp2,
3587 e_info_charp2 = NULL;
3589 initPQExpBuffer(&query_buffer);
3591 if (is_schema_query)
3593 /* completion_squery gives us the pieces to assemble */
3594 const char *qualresult = completion_squery->qualresult;
3596 if (qualresult == NULL)
3597 qualresult = completion_squery->result;
3599 /* Get unqualified names matching the input-so-far */
3600 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
3601 completion_squery->result,
3602 completion_squery->catname);
3603 if (completion_squery->selcondition)
3604 appendPQExpBuffer(&query_buffer, "%s AND ",
3605 completion_squery->selcondition);
3606 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
3607 completion_squery->result,
3608 string_length, e_text);
3609 appendPQExpBuffer(&query_buffer, " AND %s",
3610 completion_squery->viscondition);
3613 * When fetching relation names, suppress system catalogs unless
3614 * the input-so-far begins with "pg_". This is a compromise
3615 * between not offering system catalogs for completion at all, and
3616 * having them swamp the result when the input is just "p".
3618 if (strcmp(completion_squery->catname,
3619 "pg_catalog.pg_class c") == 0 &&
3620 strncmp(text, "pg_", 3) !=0)
3622 appendPQExpBuffer(&query_buffer,
3623 " AND c.relnamespace <> (SELECT oid FROM"
3624 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
3628 * Add in matching schema names, but only if there is more than
3629 * one potential match among schema names.
3631 appendPQExpBuffer(&query_buffer, "\nUNION\n"
3632 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
3633 "FROM pg_catalog.pg_namespace n "
3634 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
3635 string_length, e_text);
3636 appendPQExpBuffer(&query_buffer,
3637 " AND (SELECT pg_catalog.count(*)"
3638 " FROM pg_catalog.pg_namespace"
3639 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3640 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
3641 string_length, e_text);
3644 * Add in matching qualified names, but only if there is exactly
3645 * one schema matching the input-so-far.
3647 appendPQExpBuffer(&query_buffer, "\nUNION\n"
3648 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
3649 "FROM %s, pg_catalog.pg_namespace n "
3650 "WHERE %s = n.oid AND ",
3652 completion_squery->catname,
3653 completion_squery->namespace);
3654 if (completion_squery->selcondition)
3655 appendPQExpBuffer(&query_buffer, "%s AND ",
3656 completion_squery->selcondition);
3657 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
3659 string_length, e_text);
3662 * This condition exploits the single-matching-schema rule to
3663 * speed up the query
3665 appendPQExpBuffer(&query_buffer,
3666 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
3667 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
3668 string_length, e_text);
3669 appendPQExpBuffer(&query_buffer,
3670 " AND (SELECT pg_catalog.count(*)"
3671 " FROM pg_catalog.pg_namespace"
3672 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3673 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
3674 string_length, e_text);
3676 /* If an addon query was provided, use it */
3677 if (completion_charp)
3678 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
3682 /* completion_charp is an sprintf-style format string */
3683 appendPQExpBuffer(&query_buffer, completion_charp,
3684 string_length, e_text,
3685 e_info_charp, e_info_charp,
3686 e_info_charp2, e_info_charp2);
3689 /* Limit the number of records in the result */
3690 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
3691 completion_max_records);
3693 result = exec_query(query_buffer.data);
3695 termPQExpBuffer(&query_buffer);
3700 free(e_info_charp2);
3703 /* Find something that matches */
3704 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
3708 while (list_index < PQntuples(result) &&
3709 (item = PQgetvalue(result, list_index++, 0)))
3710 if (pg_strncasecmp(text, item, string_length) == 0)
3711 return pg_strdup(item);
3714 /* If nothing matches, free the db structure and return null */
3722 * This function returns in order one of a fixed, NULL pointer terminated list
3723 * of strings (if matching). This can be used if there are only a fixed number
3724 * SQL words that can appear at certain spot.
3727 complete_from_list(const char *text, int state)
3729 static int string_length,
3732 static bool casesensitive;
3735 /* need to have a list */
3736 Assert(completion_charpp != NULL);
3738 /* Initialization */
3742 string_length = strlen(text);
3743 casesensitive = completion_case_sensitive;
3747 while ((item = completion_charpp[list_index++]))
3749 /* First pass is case sensitive */
3750 if (casesensitive && strncmp(text, item, string_length) == 0)
3753 return pg_strdup(item);
3756 /* Second pass is case insensitive, don't bother counting matches */
3757 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
3759 if (completion_case_sensitive)
3760 return pg_strdup(item);
3764 * If case insensitive matching was requested initially,
3765 * adjust the case according to setting.
3767 return pg_strdup_keyword_case(item, text);
3772 * No matches found. If we're not case insensitive already, lets switch to
3773 * being case insensitive and try again
3775 if (casesensitive && matches == 0)
3777 casesensitive = false;
3780 return complete_from_list(text, state);
3783 /* If no more matches, return null. */
3789 * This function returns one fixed string the first time even if it doesn't
3790 * match what's there, and nothing the second time. This should be used if
3791 * there is only one possibility that can appear at a certain spot, so
3792 * misspellings will be overwritten. The string to be passed must be in
3796 complete_from_const(const char *text, int state)
3798 Assert(completion_charp != NULL);
3801 if (completion_case_sensitive)
3802 return pg_strdup(completion_charp);
3806 * If case insensitive matching was requested initially, adjust
3807 * the case according to setting.
3809 return pg_strdup_keyword_case(completion_charp, text);
3817 * This function supports completion with the name of a psql variable.
3818 * The variable names can be prefixed and suffixed with additional text
3819 * to support quoting usages.
3822 complete_from_variables(char *text, const char *prefix, const char *suffix)
3829 struct _variable *ptr;
3831 varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *));
3833 for (ptr = pset.vars->next; ptr; ptr = ptr->next)
3835 if (nvars >= maxvars)
3838 varnames = (char **) realloc(varnames,
3839 (maxvars + 1) * sizeof(char *));
3842 psql_error("out of memory\n");
3847 varnames[nvars++] = psprintf("%s%s%s", prefix, ptr->name, suffix);
3850 varnames[nvars] = NULL;
3851 COMPLETE_WITH_LIST_CS((const char *const *) varnames);
3853 for (i = 0; i < nvars; i++)
3862 * This function wraps rl_filename_completion_function() to strip quotes from
3863 * the input before searching for matches and to quote any matches for which
3864 * the consuming command will require it.
3867 complete_from_files(const char *text, int state)
3869 static const char *unquoted_text;
3870 char *unquoted_match;
3875 /* Initialization: stash the unquoted input. */
3876 unquoted_text = strtokx(text, "", NULL, "'", *completion_charp,
3877 false, true, pset.encoding);
3878 /* expect a NULL return for the empty string only */
3881 Assert(*text == '\0');
3882 unquoted_text = text;
3886 unquoted_match = filename_completion_function(unquoted_text, state);
3890 * Caller sets completion_charp to a zero- or one-character string
3891 * containing the escape character. This is necessary since \copy has
3892 * no escape character, but every other backslash command recognizes
3893 * "\" as an escape character. Since we have only two callers, don't
3894 * bother providing a macro to simplify this.
3896 ret = quote_if_needed(unquoted_match, " \t\r\n\"`",
3897 '\'', *completion_charp, pset.encoding);
3899 free(unquoted_match);
3901 ret = unquoted_match;
3908 /* HELPER FUNCTIONS */
3912 * Make a pg_strdup copy of s and convert the case according to
3913 * COMP_KEYWORD_CASE variable, using ref as the text that was already entered.
3916 pg_strdup_keyword_case(const char *s, const char *ref)
3920 unsigned char first = ref[0];
3924 varval = GetVariable(pset.vars, "COMP_KEYWORD_CASE");
3927 else if (strcmp(varval, "lower") == 0)
3929 else if (strcmp(varval, "preserve-lower") == 0)
3931 else if (strcmp(varval, "preserve-upper") == 0)
3933 else if (strcmp(varval, "upper") == 0)
3945 || ((tocase == -1 || tocase == +1) && islower(first))
3946 || (tocase == -1 && !isalpha(first))
3948 for (p = ret; *p; p++)
3949 *p = pg_tolower((unsigned char) *p);
3951 for (p = ret; *p; p++)
3952 *p = pg_toupper((unsigned char) *p);
3959 * Execute a query and report any errors. This should be the preferred way of
3960 * talking to the database in this file.
3963 exec_query(const char *query)
3967 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
3970 result = PQexec(pset.db, query);
3972 if (PQresultStatus(result) != PGRES_TUPLES_OK)
3975 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
3976 PQerrorMessage(pset.db), query);
3987 * Return the nwords word(s) before point. Words are returned right to left,
3988 * that is, previous_words[0] gets the last word before point.
3989 * If we run out of words, remaining array elements are set to empty strings.
3990 * Each array element is filled with a malloc'd string.
3993 get_previous_words(int point, char **previous_words, int nwords)
3995 const char *buf = rl_line_buffer; /* alias */
3998 /* first we look for a non-word char before the current point */
3999 for (i = point - 1; i >= 0; i--)
4000 if (strchr(WORD_BREAKS, buf[i]))
4004 while (nwords-- > 0)
4010 /* now find the first non-space which then constitutes the end */
4012 for (i = point; i >= 0; i--)
4014 if (!isspace((unsigned char) buf[i]))
4022 * If no end found we return an empty string, because there is no word
4033 * Otherwise we now look for the start. The start is either the
4034 * last character before any word-break character going backwards
4035 * from the end, or it's simply character 0. We also handle open
4036 * quotes and parentheses.
4038 bool inquotes = false;
4039 int parentheses = 0;
4041 for (start = end; start > 0; start--)
4043 if (buf[start] == '"')
4044 inquotes = !inquotes;
4047 if (buf[start] == ')')
4049 else if (buf[start] == '(')
4051 if (--parentheses <= 0)
4054 else if (parentheses == 0 &&
4055 strchr(WORD_BREAKS, buf[start - 1]))
4062 /* make a copy of chars from start to end inclusive */
4063 s = pg_malloc(end - start + 2);
4064 strlcpy(s, &buf[start], end - start + 2);
4067 *previous_words++ = s;
4074 * Surround a string with single quotes. This works for both SQL and
4075 * psql internal. Currently disabled because it is reported not to
4076 * cooperate with certain versions of readline.
4079 quote_file_name(char *text, int match_type, char *quote_pointer)
4084 (void) quote_pointer; /* not used */
4086 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
4087 s = pg_malloc(length);
4089 strcpy(s + 1, text);
4090 if (match_type == SINGLE_MATCH)
4091 s[length - 2] = '\'';
4092 s[length - 1] = '\0';
4097 dequote_file_name(char *text, char quote_char)
4103 return pg_strdup(text);
4105 length = strlen(text);
4106 s = pg_malloc(length - 2 + 1);
4107 strlcpy(s, text +1, length - 2 + 1);
4111 #endif /* NOT_USED */
4113 #endif /* USE_READLINE */