2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2012, PostgreSQL Global Development Group
6 * src/bin/psql/tab-complete.c
9 /*----------------------------------------------------------------------
10 * This file implements a somewhat more sophisticated readline "TAB
11 * completion" in psql. It is not intended to be AI, to replace
12 * learning SQL, or to relieve you from thinking about what you're
13 * doing. Also it does not always give you all the syntactically legal
14 * completions, only those that are the most common or the ones that
15 * the programmer felt most like implementing.
17 * CAVEAT: Tab completion causes queries to be sent to the backend.
18 * The number of tuples returned gets limited, in most default
19 * installations to 1000, but if you still don't like this prospect,
20 * you can turn off tab completion in your ~/.inputrc (or else
21 * ${INPUTRC}) file so:
24 * set disable-completion on
27 * See `man 3 readline' or `info readline' for the full details. Also,
32 * - If you split your queries across lines, this whole thing gets
33 * confused. (To fix this, one would have to read psql's query
34 * buffer rather than readline's line buffer, which would require
35 * some major revisions of things.)
37 * - Table or attribute names with spaces in it may confuse it.
39 * - Quotes, parenthesis, and other funny characters are not handled
40 * all that gracefully.
41 *----------------------------------------------------------------------
44 #include "postgres_fe.h"
45 #include "tab-complete.h"
48 /* If we don't have this, we might as well forget about the whole thing: */
53 #include "pqexpbuffer.h"
56 #include "stringutils.h"
58 #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
59 #define filename_completion_function rl_filename_completion_function
61 /* missing in some header files */
62 extern char *filename_completion_function();
65 #ifdef HAVE_RL_COMPLETION_MATCHES
66 #define completion_matches rl_completion_matches
69 /* word break characters */
70 #define WORD_BREAKS "\t\n@$><=;|&{() "
73 * This struct is used to define "schema queries", which are custom-built
74 * to obtain possibly-schema-qualified names of database objects. There is
75 * enough similarity in the structure that we don't want to repeat it each
76 * time. So we put the components of each query into this struct and
77 * assemble them with the common boilerplate in _complete_from_query().
79 typedef struct SchemaQuery
82 * Name of catalog or catalogs to be queried, with alias, eg.
83 * "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
88 * Selection condition --- only rows meeting this condition are candidates
89 * to display. If catname mentions multiple tables, include the necessary
90 * join condition here. For example, "c.relkind = 'r'". Write NULL (not
91 * an empty string) if not needed.
93 const char *selcondition;
96 * Visibility condition --- which rows are visible without schema
97 * qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
99 const char *viscondition;
102 * Namespace --- name of field to join to pg_namespace.oid. For example,
105 const char *namespace;
108 * Result --- the appropriately-quoted name to return, in the case of an
109 * unqualified name. For example, "pg_catalog.quote_ident(c.relname)".
114 * In some cases a different result must be used for qualified names.
115 * Enter that here, or write NULL if result can be used.
117 const char *qualresult;
121 /* Store maximum number of records we want from database queries
122 * (implemented via SELECT ... LIMIT xx).
124 static int completion_max_records;
127 * Communication variables set by COMPLETE_WITH_FOO macros and then used by
128 * the completion callback functions. Ugly but there is no better way.
130 static const char *completion_charp; /* to pass a string */
131 static const char *const * completion_charpp; /* to pass a list of strings */
132 static const char *completion_info_charp; /* to pass a second string */
133 static const char *completion_info_charp2; /* to pass a third string */
134 static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
135 static bool completion_case_sensitive; /* completion is case sensitive */
138 * A few macros to ease typing. You can use these to complete the given
140 * 1) The results from a query you pass it. (Perhaps one of those below?)
141 * 2) The results from a schema query you pass it.
142 * 3) The items from a null-pointer-terminated list.
143 * 4) A string constant.
144 * 5) The list of attributes of the given table (possibly schema-qualified).
146 #define COMPLETE_WITH_QUERY(query) \
148 completion_charp = query; \
149 matches = completion_matches(text, complete_from_query); \
152 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
154 completion_squery = &(query); \
155 completion_charp = addon; \
156 matches = completion_matches(text, complete_from_schema_query); \
159 #define COMPLETE_WITH_LIST_CS(list) \
161 completion_charpp = list; \
162 completion_case_sensitive = true; \
163 matches = completion_matches(text, complete_from_list); \
166 #define COMPLETE_WITH_LIST(list) \
168 completion_charpp = list; \
169 completion_case_sensitive = false; \
170 matches = completion_matches(text, complete_from_list); \
173 #define COMPLETE_WITH_CONST(string) \
175 completion_charp = string; \
176 completion_case_sensitive = false; \
177 matches = completion_matches(text, complete_from_const); \
180 #define COMPLETE_WITH_ATTR(relation, addon) \
182 char *_completion_schema; \
183 char *_completion_table; \
185 _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
186 false, false, pset.encoding); \
187 (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
188 false, false, pset.encoding); \
189 _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
190 false, false, pset.encoding); \
191 if (_completion_table == NULL) \
193 completion_charp = Query_for_list_of_attributes addon; \
194 completion_info_charp = relation; \
198 completion_charp = Query_for_list_of_attributes_with_schema addon; \
199 completion_info_charp = _completion_table; \
200 completion_info_charp2 = _completion_schema; \
202 matches = completion_matches(text, complete_from_query); \
206 * Assembly instructions for schema queries
209 static const SchemaQuery Query_for_list_of_aggregates = {
211 "pg_catalog.pg_proc p",
215 "pg_catalog.pg_function_is_visible(p.oid)",
219 "pg_catalog.quote_ident(p.proname)",
224 static const SchemaQuery Query_for_list_of_datatypes = {
226 "pg_catalog.pg_type t",
227 /* selcondition --- ignore table rowtypes and array types */
229 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
230 "AND t.typname !~ '^_'",
232 "pg_catalog.pg_type_is_visible(t.oid)",
236 "pg_catalog.format_type(t.oid, NULL)",
238 "pg_catalog.quote_ident(t.typname)"
241 static const SchemaQuery Query_for_list_of_domains = {
243 "pg_catalog.pg_type t",
247 "pg_catalog.pg_type_is_visible(t.oid)",
251 "pg_catalog.quote_ident(t.typname)",
256 static const SchemaQuery Query_for_list_of_functions = {
258 "pg_catalog.pg_proc p",
262 "pg_catalog.pg_function_is_visible(p.oid)",
266 "pg_catalog.quote_ident(p.proname)",
271 static const SchemaQuery Query_for_list_of_indexes = {
273 "pg_catalog.pg_class c",
275 "c.relkind IN ('i')",
277 "pg_catalog.pg_table_is_visible(c.oid)",
281 "pg_catalog.quote_ident(c.relname)",
286 static const SchemaQuery Query_for_list_of_sequences = {
288 "pg_catalog.pg_class c",
290 "c.relkind IN ('S')",
292 "pg_catalog.pg_table_is_visible(c.oid)",
296 "pg_catalog.quote_ident(c.relname)",
301 static const SchemaQuery Query_for_list_of_foreign_tables = {
303 "pg_catalog.pg_class c",
305 "c.relkind IN ('f')",
307 "pg_catalog.pg_table_is_visible(c.oid)",
311 "pg_catalog.quote_ident(c.relname)",
316 static const SchemaQuery Query_for_list_of_tables = {
318 "pg_catalog.pg_class c",
320 "c.relkind IN ('r')",
322 "pg_catalog.pg_table_is_visible(c.oid)",
326 "pg_catalog.quote_ident(c.relname)",
331 /* The bit masks for the following three functions come from
332 * src/include/catalog/pg_trigger.h.
334 static const SchemaQuery Query_for_list_of_insertables = {
336 "pg_catalog.pg_class c",
338 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
339 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))",
341 "pg_catalog.pg_table_is_visible(c.oid)",
345 "pg_catalog.quote_ident(c.relname)",
350 static const SchemaQuery Query_for_list_of_deletables = {
352 "pg_catalog.pg_class c",
354 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
355 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))",
357 "pg_catalog.pg_table_is_visible(c.oid)",
361 "pg_catalog.quote_ident(c.relname)",
366 static const SchemaQuery Query_for_list_of_updatables = {
368 "pg_catalog.pg_class c",
370 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
371 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))",
373 "pg_catalog.pg_table_is_visible(c.oid)",
377 "pg_catalog.quote_ident(c.relname)",
382 static const SchemaQuery Query_for_list_of_relations = {
384 "pg_catalog.pg_class c",
388 "pg_catalog.pg_table_is_visible(c.oid)",
392 "pg_catalog.quote_ident(c.relname)",
397 static const SchemaQuery Query_for_list_of_tsvf = {
399 "pg_catalog.pg_class c",
401 "c.relkind IN ('r', 'S', 'v', 'f')",
403 "pg_catalog.pg_table_is_visible(c.oid)",
407 "pg_catalog.quote_ident(c.relname)",
412 static const SchemaQuery Query_for_list_of_views = {
414 "pg_catalog.pg_class c",
416 "c.relkind IN ('v')",
418 "pg_catalog.pg_table_is_visible(c.oid)",
422 "pg_catalog.quote_ident(c.relname)",
429 * Queries to get lists of names of various kinds of things, possibly
430 * restricted to names matching a partially entered name. In these queries,
431 * the first %s will be replaced by the text entered so far (suitably escaped
432 * to become a SQL literal string). %d will be replaced by the length of the
433 * string (in unescaped form). A second and third %s, if present, will be
434 * replaced by a suitably-escaped version of the string provided in
435 * completion_info_charp. A fourth and fifth %s are similarly replaced by
436 * completion_info_charp2.
438 * Beware that the allowed sequences of %s and %d are determined by
439 * _complete_from_query().
442 #define Query_for_list_of_attributes \
443 "SELECT pg_catalog.quote_ident(attname) "\
444 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
445 " WHERE c.oid = a.attrelid "\
446 " AND a.attnum > 0 "\
447 " AND NOT a.attisdropped "\
448 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
449 " AND (pg_catalog.quote_ident(relname)='%s' "\
450 " OR '\"' || relname || '\"'='%s') "\
451 " AND pg_catalog.pg_table_is_visible(c.oid)"
453 #define Query_for_list_of_attributes_with_schema \
454 "SELECT pg_catalog.quote_ident(attname) "\
455 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
456 " WHERE c.oid = a.attrelid "\
457 " AND n.oid = c.relnamespace "\
458 " AND a.attnum > 0 "\
459 " AND NOT a.attisdropped "\
460 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
461 " AND (pg_catalog.quote_ident(relname)='%s' "\
462 " OR '\"' || relname || '\"' ='%s') "\
463 " AND (pg_catalog.quote_ident(nspname)='%s' "\
464 " OR '\"' || nspname || '\"' ='%s') "
466 #define Query_for_list_of_template_databases \
467 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
468 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
470 #define Query_for_list_of_databases \
471 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
472 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
474 #define Query_for_list_of_tablespaces \
475 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
476 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
478 #define Query_for_list_of_encodings \
479 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
480 " FROM pg_catalog.pg_conversion "\
481 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
483 #define Query_for_list_of_languages \
484 "SELECT pg_catalog.quote_ident(lanname) "\
485 " FROM pg_catalog.pg_language "\
486 " WHERE lanname != 'internal' "\
487 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
489 #define Query_for_list_of_schemas \
490 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
491 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
493 #define Query_for_list_of_set_vars \
495 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
496 " WHERE context IN ('user', 'superuser') "\
497 " UNION ALL SELECT 'constraints' "\
498 " UNION ALL SELECT 'transaction' "\
499 " UNION ALL SELECT 'session' "\
500 " UNION ALL SELECT 'role' "\
501 " UNION ALL SELECT 'tablespace' "\
502 " UNION ALL SELECT 'all') ss "\
503 " WHERE substring(name,1,%d)='%s'"
505 #define Query_for_list_of_show_vars \
507 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
508 " UNION ALL SELECT 'session authorization' "\
509 " UNION ALL SELECT 'all') ss "\
510 " WHERE substring(name,1,%d)='%s'"
512 #define Query_for_list_of_roles \
513 " SELECT pg_catalog.quote_ident(rolname) "\
514 " FROM pg_catalog.pg_roles "\
515 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
517 #define Query_for_list_of_grant_roles \
518 " SELECT pg_catalog.quote_ident(rolname) "\
519 " FROM pg_catalog.pg_roles "\
520 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
521 " UNION ALL SELECT 'PUBLIC'"
523 /* the silly-looking length condition is just to eat up the current word */
524 #define Query_for_table_owning_index \
525 "SELECT pg_catalog.quote_ident(c1.relname) "\
526 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
527 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
528 " and (%d = pg_catalog.length('%s'))"\
529 " and pg_catalog.quote_ident(c2.relname)='%s'"\
530 " and pg_catalog.pg_table_is_visible(c2.oid)"
532 /* the silly-looking length condition is just to eat up the current word */
533 #define Query_for_index_of_table \
534 "SELECT pg_catalog.quote_ident(c2.relname) "\
535 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
536 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
537 " and (%d = pg_catalog.length('%s'))"\
538 " and pg_catalog.quote_ident(c1.relname)='%s'"\
539 " and pg_catalog.pg_table_is_visible(c2.oid)"
541 /* the silly-looking length condition is just to eat up the current word */
542 #define Query_for_list_of_tables_for_trigger \
543 "SELECT pg_catalog.quote_ident(relname) "\
544 " FROM pg_catalog.pg_class"\
545 " WHERE (%d = pg_catalog.length('%s'))"\
547 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
548 " WHERE pg_catalog.quote_ident(tgname)='%s')"
550 #define Query_for_list_of_ts_configurations \
551 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
552 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
554 #define Query_for_list_of_ts_dictionaries \
555 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
556 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
558 #define Query_for_list_of_ts_parsers \
559 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
560 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
562 #define Query_for_list_of_ts_templates \
563 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
564 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
566 #define Query_for_list_of_fdws \
567 " SELECT pg_catalog.quote_ident(fdwname) "\
568 " FROM pg_catalog.pg_foreign_data_wrapper "\
569 " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
571 #define Query_for_list_of_servers \
572 " SELECT pg_catalog.quote_ident(srvname) "\
573 " FROM pg_catalog.pg_foreign_server "\
574 " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
576 #define Query_for_list_of_user_mappings \
577 " SELECT pg_catalog.quote_ident(usename) "\
578 " FROM pg_catalog.pg_user_mappings "\
579 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
581 #define Query_for_list_of_access_methods \
582 " SELECT pg_catalog.quote_ident(amname) "\
583 " FROM pg_catalog.pg_am "\
584 " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
586 #define Query_for_list_of_arguments \
587 " SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
588 " FROM pg_catalog.pg_proc "\
589 " WHERE proname='%s'"
591 #define Query_for_list_of_extensions \
592 " SELECT pg_catalog.quote_ident(extname) "\
593 " FROM pg_catalog.pg_extension "\
594 " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
596 #define Query_for_list_of_available_extensions \
597 " SELECT pg_catalog.quote_ident(name) "\
598 " FROM pg_catalog.pg_available_extensions "\
599 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
601 #define Query_for_list_of_prepared_statements \
602 " SELECT pg_catalog.quote_ident(name) "\
603 " FROM pg_catalog.pg_prepared_statements "\
604 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'"
607 * This is a list of all "things" in Pgsql, which can show up after CREATE or
608 * DROP; and there is also a query to get a list of them.
614 const char *query; /* simple query, or NULL */
615 const SchemaQuery *squery; /* schema query, or NULL */
616 const bits32 flags; /* visibility flags, see below */
619 #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
620 #define THING_NO_DROP (1 << 1) /* should not show up after DROP */
621 #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
623 static const pgsql_thing_t words_after_create[] = {
624 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
625 {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
627 {"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'"},
630 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
631 * to be used only by pg_dump.
633 {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
634 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
635 {"DATABASE", Query_for_list_of_databases},
636 {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
637 {"DOMAIN", NULL, &Query_for_list_of_domains},
638 {"EXTENSION", Query_for_list_of_extensions},
639 {"FOREIGN DATA WRAPPER", NULL, NULL},
640 {"FOREIGN TABLE", NULL, NULL},
641 {"FUNCTION", NULL, &Query_for_list_of_functions},
642 {"GROUP", Query_for_list_of_roles},
643 {"LANGUAGE", Query_for_list_of_languages},
644 {"INDEX", NULL, &Query_for_list_of_indexes},
645 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
647 {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */
648 {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
649 {"ROLE", Query_for_list_of_roles},
650 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
651 {"SCHEMA", Query_for_list_of_schemas},
652 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
653 {"SERVER", Query_for_list_of_servers},
654 {"TABLE", NULL, &Query_for_list_of_tables},
655 {"TABLESPACE", Query_for_list_of_tablespaces},
656 {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
657 {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
658 {"TEXT SEARCH", NULL, NULL},
659 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
660 {"TYPE", NULL, &Query_for_list_of_datatypes},
661 {"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
662 {"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE
664 {"USER", Query_for_list_of_roles},
665 {"USER MAPPING FOR", NULL, NULL},
666 {"VIEW", NULL, &Query_for_list_of_views},
667 {NULL} /* end of list */
671 /* Forward declaration of functions */
672 static char **psql_completion(char *text, int start, int end);
673 static char *create_command_generator(const char *text, int state);
674 static char *drop_command_generator(const char *text, int state);
675 static char *complete_from_query(const char *text, int state);
676 static char *complete_from_schema_query(const char *text, int state);
677 static char *_complete_from_query(int is_schema_query,
678 const char *text, int state);
679 static char *complete_from_list(const char *text, int state);
680 static char *complete_from_const(const char *text, int state);
681 static char **complete_from_variables(char *text,
682 const char *prefix, const char *suffix);
683 static char *complete_from_files(const char *text, int state);
685 static char *pg_strdup_same_case(const char *s, const char *ref);
686 static PGresult *exec_query(const char *query);
688 static void get_previous_words(int point, char **previous_words, int nwords);
691 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
692 static char *dequote_file_name(char *text, char quote_char);
697 * Initialize the readline library for our purposes.
700 initialize_readline(void)
702 rl_readline_name = (char *) pset.progname;
703 rl_attempted_completion_function = (void *) psql_completion;
705 rl_basic_word_break_characters = WORD_BREAKS;
707 completion_max_records = 1000;
710 * There is a variable rl_completion_query_items for this but apparently
711 * it's not defined everywhere.
717 * The completion function.
719 * According to readline spec this gets passed the text entered so far and its
720 * start and end positions in the readline buffer. The return value is some
721 * partially obscure list format that can be generated by readline's
722 * completion_matches() function, so we don't have to worry about it.
725 psql_completion(char *text, int start, int end)
727 /* This is the variable we'll return. */
728 char **matches = NULL;
730 /* This array will contain some scannage of the input line. */
731 char *previous_words[6];
733 /* For compactness, we use these macros to reference previous_words[]. */
734 #define prev_wd (previous_words[0])
735 #define prev2_wd (previous_words[1])
736 #define prev3_wd (previous_words[2])
737 #define prev4_wd (previous_words[3])
738 #define prev5_wd (previous_words[4])
739 #define prev6_wd (previous_words[5])
741 static const char *const sql_commands[] = {
742 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
743 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
744 "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
745 "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
746 "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
747 "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
748 "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
752 static const char *const backslash_commands[] = {
753 "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
754 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df",
755 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
756 "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
757 "\\e", "\\echo", "\\ef", "\\encoding",
758 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
759 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
760 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
761 "\\set", "\\sf", "\\t", "\\T",
762 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
765 (void) end; /* not used */
767 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
768 rl_completion_append_character = ' ';
771 /* Clear a few things. */
772 completion_charp = NULL;
773 completion_charpp = NULL;
774 completion_info_charp = NULL;
775 completion_info_charp2 = NULL;
778 * Scan the input line before our current position for the last few
779 * words. According to those we'll make some smart decisions on what the
780 * user is probably intending to type.
782 get_previous_words(start, previous_words, lengthof(previous_words));
784 /* If a backslash command was started, continue */
786 COMPLETE_WITH_LIST_CS(backslash_commands);
788 /* Variable interpolation */
789 else if (text[0] == ':' && text[1] != ':')
792 matches = complete_from_variables(text, ":'", "'");
793 else if (text[1] == '"')
794 matches = complete_from_variables(text, ":\"", "\"");
796 matches = complete_from_variables(text, ":", "");
799 /* If no previous word, suggest one of the basic sql commands */
800 else if (prev_wd[0] == '\0')
801 COMPLETE_WITH_LIST(sql_commands);
804 /* complete with something you can create */
805 else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
806 matches = completion_matches(text, create_command_generator);
808 /* DROP, but not DROP embedded in other commands */
809 /* complete with something you can drop */
810 else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
812 matches = completion_matches(text, drop_command_generator);
817 * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
818 * in ALTER TABLE sth ALTER
820 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
821 pg_strcasecmp(prev3_wd, "TABLE") != 0)
823 static const char *const list_ALTER[] =
824 {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
825 "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
826 "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR",
827 "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
828 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
829 "USER", "USER MAPPING FOR", "VIEW", NULL};
831 COMPLETE_WITH_LIST(list_ALTER);
833 /* ALTER AGGREGATE,FUNCTION <name> */
834 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
835 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
836 pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
837 COMPLETE_WITH_CONST("(");
838 /* ALTER AGGREGATE,FUNCTION <name> (...) */
839 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
840 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
841 pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
843 if (prev_wd[strlen(prev_wd) - 1] == ')')
845 static const char *const list_ALTERAGG[] =
846 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
848 COMPLETE_WITH_LIST(list_ALTERAGG);
852 char *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
854 sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
855 COMPLETE_WITH_QUERY(tmp_buf);
860 /* ALTER SCHEMA <name> */
861 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
862 pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
864 static const char *const list_ALTERGEN[] =
865 {"OWNER TO", "RENAME TO", NULL};
867 COMPLETE_WITH_LIST(list_ALTERGEN);
870 /* ALTER COLLATION <name> */
871 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
872 pg_strcasecmp(prev2_wd, "COLLATION") == 0)
874 static const char *const list_ALTERGEN[] =
875 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
877 COMPLETE_WITH_LIST(list_ALTERGEN);
880 /* ALTER CONVERSION <name> */
881 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
882 pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
884 static const char *const list_ALTERGEN[] =
885 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
887 COMPLETE_WITH_LIST(list_ALTERGEN);
890 /* ALTER DATABASE <name> */
891 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
892 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
894 static const char *const list_ALTERDATABASE[] =
895 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
897 COMPLETE_WITH_LIST(list_ALTERDATABASE);
900 /* ALTER EXTENSION <name> */
901 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
902 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
904 static const char *const list_ALTEREXTENSION[] =
905 {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
907 COMPLETE_WITH_LIST(list_ALTEREXTENSION);
911 else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
912 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
914 static const char *const list_ALTER_FOREIGN[] =
915 {"DATA WRAPPER", "TABLE", NULL};
917 COMPLETE_WITH_LIST(list_ALTER_FOREIGN);
920 /* ALTER FOREIGN DATA WRAPPER <name> */
921 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
922 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
923 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
924 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
926 static const char *const list_ALTER_FDW[] =
927 {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
929 COMPLETE_WITH_LIST(list_ALTER_FDW);
932 /* ALTER FOREIGN TABLE <name> */
933 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
934 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
935 pg_strcasecmp(prev2_wd, "TABLE") == 0)
937 static const char *const list_ALTER_FOREIGN_TABLE[] =
938 {"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL};
940 COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
943 /* ALTER INDEX <name> */
944 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
945 pg_strcasecmp(prev2_wd, "INDEX") == 0)
947 static const char *const list_ALTERINDEX[] =
948 {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
950 COMPLETE_WITH_LIST(list_ALTERINDEX);
952 /* ALTER INDEX <name> SET */
953 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
954 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
955 pg_strcasecmp(prev_wd, "SET") == 0)
957 static const char *const list_ALTERINDEXSET[] =
958 {"(", "TABLESPACE", NULL};
960 COMPLETE_WITH_LIST(list_ALTERINDEXSET);
962 /* ALTER INDEX <name> RESET */
963 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
964 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
965 pg_strcasecmp(prev_wd, "RESET") == 0)
966 COMPLETE_WITH_CONST("(");
967 /* ALTER INDEX <foo> SET|RESET ( */
968 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
969 pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
970 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
971 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
972 pg_strcasecmp(prev_wd, "(") == 0)
974 static const char *const list_INDEXOPTIONS[] =
975 {"fillfactor", "fastupdate", NULL};
977 COMPLETE_WITH_LIST(list_INDEXOPTIONS);
980 /* ALTER LANGUAGE <name> */
981 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
982 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
984 static const char *const list_ALTERLANGUAGE[] =
985 {"OWNER TO", "RENAME TO", NULL};
987 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
990 /* ALTER LARGE OBJECT <oid> */
991 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
992 pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
993 pg_strcasecmp(prev2_wd, "OBJECT") == 0)
995 static const char *const list_ALTERLARGEOBJECT[] =
998 COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
1001 /* ALTER USER,ROLE <name> */
1002 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1003 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1004 (pg_strcasecmp(prev2_wd, "USER") == 0 ||
1005 pg_strcasecmp(prev2_wd, "ROLE") == 0))
1007 static const char *const list_ALTERUSER[] =
1008 {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1009 "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
1010 "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
1011 "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
1012 "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", NULL};
1014 COMPLETE_WITH_LIST(list_ALTERUSER);
1017 /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
1018 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1019 (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1020 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1022 COMPLETE_WITH_CONST("PASSWORD");
1024 /* ALTER DEFAULT PRIVILEGES */
1025 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1026 pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
1027 pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
1029 static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
1030 {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
1032 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
1034 /* ALTER DEFAULT PRIVILEGES FOR */
1035 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1036 pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
1037 pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
1038 pg_strcasecmp(prev_wd, "FOR") == 0)
1040 static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
1041 {"ROLE", "USER", NULL};
1043 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
1045 /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
1046 else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
1047 pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
1048 (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
1049 pg_strcasecmp(prev3_wd, "IN") == 0))
1051 static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
1052 {"GRANT", "REVOKE", NULL};
1054 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
1056 /* ALTER DOMAIN <name> */
1057 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1058 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
1060 static const char *const list_ALTERDOMAIN[] =
1061 {"ADD", "DROP", "OWNER TO", "SET", NULL};
1063 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1065 /* ALTER DOMAIN <sth> DROP */
1066 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1067 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1068 pg_strcasecmp(prev_wd, "DROP") == 0)
1070 static const char *const list_ALTERDOMAIN2[] =
1071 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
1073 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
1075 /* ALTER DOMAIN <sth> SET */
1076 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1077 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1078 pg_strcasecmp(prev_wd, "SET") == 0)
1080 static const char *const list_ALTERDOMAIN3[] =
1081 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
1083 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
1085 /* ALTER SEQUENCE <name> */
1086 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1087 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
1089 static const char *const list_ALTERSEQUENCE[] =
1090 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
1091 "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
1093 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
1095 /* ALTER SEQUENCE <name> NO */
1096 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1097 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
1098 pg_strcasecmp(prev_wd, "NO") == 0)
1100 static const char *const list_ALTERSEQUENCE2[] =
1101 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
1103 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
1105 /* ALTER SERVER <name> */
1106 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1107 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1109 static const char *const list_ALTER_SERVER[] =
1110 {"VERSION", "OPTIONS", "OWNER TO", NULL};
1112 COMPLETE_WITH_LIST(list_ALTER_SERVER);
1114 /* ALTER VIEW <name> */
1115 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1116 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1118 static const char *const list_ALTERVIEW[] =
1119 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1121 COMPLETE_WITH_LIST(list_ALTERVIEW);
1123 /* ALTER TRIGGER <name>, add ON */
1124 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1125 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1126 COMPLETE_WITH_CONST("ON");
1128 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1129 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
1131 completion_info_charp = prev2_wd;
1132 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1136 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1138 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1139 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1140 pg_strcasecmp(prev_wd, "ON") == 0)
1141 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1143 /* ALTER TRIGGER <name> ON <name> */
1144 else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1145 pg_strcasecmp(prev2_wd, "ON") == 0)
1146 COMPLETE_WITH_CONST("RENAME TO");
1149 * If we detect ALTER TABLE <name>, suggest sub commands
1151 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1152 pg_strcasecmp(prev2_wd, "TABLE") == 0)
1154 static const char *const list_ALTER2[] =
1155 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1156 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
1157 "VALIDATE CONSTRAINT", NULL};
1159 COMPLETE_WITH_LIST(list_ALTER2);
1161 /* ALTER TABLE xxx ENABLE */
1162 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1163 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1164 pg_strcasecmp(prev_wd, "ENABLE") == 0)
1166 static const char *const list_ALTERENABLE[] =
1167 {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
1169 COMPLETE_WITH_LIST(list_ALTERENABLE);
1171 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1172 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1173 (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
1174 pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1176 static const char *const list_ALTERENABLE2[] =
1177 {"RULE", "TRIGGER", NULL};
1179 COMPLETE_WITH_LIST(list_ALTERENABLE2);
1181 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1182 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1183 pg_strcasecmp(prev_wd, "DISABLE") == 0)
1185 static const char *const list_ALTERDISABLE[] =
1186 {"RULE", "TRIGGER", NULL};
1188 COMPLETE_WITH_LIST(list_ALTERDISABLE);
1191 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
1192 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1193 (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
1194 pg_strcasecmp(prev_wd, "RENAME") == 0))
1195 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
1198 * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1201 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1202 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1203 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1204 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1205 COMPLETE_WITH_ATTR(prev3_wd, "");
1207 /* ALTER TABLE xxx RENAME yyy */
1208 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1209 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1210 pg_strcasecmp(prev_wd, "TO") != 0)
1211 COMPLETE_WITH_CONST("TO");
1213 /* ALTER TABLE xxx RENAME COLUMN yyy */
1214 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1215 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1216 pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
1217 pg_strcasecmp(prev_wd, "TO") != 0)
1218 COMPLETE_WITH_CONST("TO");
1220 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1221 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1222 pg_strcasecmp(prev_wd, "DROP") == 0)
1224 static const char *const list_TABLEDROP[] =
1225 {"COLUMN", "CONSTRAINT", NULL};
1227 COMPLETE_WITH_LIST(list_TABLEDROP);
1229 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
1230 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1231 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1232 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1233 COMPLETE_WITH_ATTR(prev3_wd, "");
1234 /* ALTER TABLE ALTER [COLUMN] <foo> */
1235 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1236 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1237 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1238 pg_strcasecmp(prev2_wd, "ALTER") == 0))
1240 static const char *const list_COLUMNALTER[] =
1241 {"TYPE", "SET", "RESET", "DROP", NULL};
1243 COMPLETE_WITH_LIST(list_COLUMNALTER);
1245 /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1246 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1247 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1248 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1249 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1250 pg_strcasecmp(prev_wd, "SET") == 0)
1252 static const char *const list_COLUMNSET[] =
1253 {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1255 COMPLETE_WITH_LIST(list_COLUMNSET);
1257 /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1258 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1259 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1260 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1261 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1262 pg_strcasecmp(prev_wd, "(") == 0)
1264 static const char *const list_COLUMNOPTIONS[] =
1265 {"n_distinct", "n_distinct_inherited", NULL};
1267 COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1269 /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1270 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1271 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1272 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1273 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1274 pg_strcasecmp(prev_wd, "STORAGE") == 0)
1276 static const char *const list_COLUMNSTORAGE[] =
1277 {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1279 COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1281 /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1282 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1283 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1284 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1285 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1286 pg_strcasecmp(prev_wd, "DROP") == 0)
1288 static const char *const list_COLUMNDROP[] =
1289 {"DEFAULT", "NOT NULL", NULL};
1291 COMPLETE_WITH_LIST(list_COLUMNDROP);
1293 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1294 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1295 COMPLETE_WITH_CONST("ON");
1296 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1297 pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1298 pg_strcasecmp(prev_wd, "ON") == 0)
1300 completion_info_charp = prev3_wd;
1301 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1303 /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
1304 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1305 pg_strcasecmp(prev_wd, "SET") == 0)
1307 static const char *const list_TABLESET[] =
1308 {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
1310 COMPLETE_WITH_LIST(list_TABLESET);
1312 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1313 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1314 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1315 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1316 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1317 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1318 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1319 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1320 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1322 static const char *const list_TABLESET2[] =
1323 {"CLUSTER", "OIDS", NULL};
1325 COMPLETE_WITH_LIST(list_TABLESET2);
1327 /* ALTER TABLE <foo> RESET */
1328 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1329 pg_strcasecmp(prev_wd, "RESET") == 0)
1330 COMPLETE_WITH_CONST("(");
1331 /* ALTER TABLE <foo> SET|RESET ( */
1332 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1333 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1334 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1335 pg_strcasecmp(prev_wd, "(") == 0)
1337 static const char *const list_TABLEOPTIONS[] =
1339 "autovacuum_analyze_scale_factor",
1340 "autovacuum_analyze_threshold",
1341 "autovacuum_enabled",
1342 "autovacuum_freeze_max_age",
1343 "autovacuum_freeze_min_age",
1344 "autovacuum_freeze_table_age",
1345 "autovacuum_vacuum_cost_delay",
1346 "autovacuum_vacuum_cost_limit",
1347 "autovacuum_vacuum_scale_factor",
1348 "autovacuum_vacuum_threshold",
1350 "toast.autovacuum_enabled",
1351 "toast.autovacuum_freeze_max_age",
1352 "toast.autovacuum_freeze_min_age",
1353 "toast.autovacuum_freeze_table_age",
1354 "toast.autovacuum_vacuum_cost_delay",
1355 "toast.autovacuum_vacuum_cost_limit",
1356 "toast.autovacuum_vacuum_scale_factor",
1357 "toast.autovacuum_vacuum_threshold",
1361 COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1364 /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1365 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1366 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1368 static const char *const list_ALTERTSPC[] =
1369 {"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1371 COMPLETE_WITH_LIST(list_ALTERTSPC);
1373 /* ALTER TABLESPACE <foo> SET|RESET */
1374 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1375 pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1376 (pg_strcasecmp(prev_wd, "SET") == 0 ||
1377 pg_strcasecmp(prev_wd, "RESET") == 0))
1378 COMPLETE_WITH_CONST("(");
1379 /* ALTER TABLESPACE <foo> SET|RESET ( */
1380 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1381 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1382 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1383 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1384 pg_strcasecmp(prev_wd, "(") == 0)
1386 static const char *const list_TABLESPACEOPTIONS[] =
1387 {"seq_page_cost", "random_page_cost", NULL};
1389 COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1392 /* ALTER TEXT SEARCH */
1393 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1394 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1395 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1397 static const char *const list_ALTERTEXTSEARCH[] =
1398 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1400 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1402 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1403 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1404 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1405 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1406 pg_strcasecmp(prev2_wd, "PARSER") == 0))
1408 static const char *const list_ALTERTEXTSEARCH2[] =
1409 {"RENAME TO", "SET SCHEMA", NULL};
1411 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1414 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1415 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1416 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1417 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1419 static const char *const list_ALTERTEXTSEARCH3[] =
1420 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1422 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1425 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1426 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1427 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1428 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1430 static const char *const list_ALTERTEXTSEARCH4[] =
1431 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1433 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
1436 /* complete ALTER TYPE <foo> with actions */
1437 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1438 pg_strcasecmp(prev2_wd, "TYPE") == 0)
1440 static const char *const list_ALTERTYPE[] =
1441 {"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
1442 "OWNER TO", "RENAME", "SET SCHEMA", NULL};
1444 COMPLETE_WITH_LIST(list_ALTERTYPE);
1446 /* complete ALTER TYPE <foo> ADD with actions */
1447 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1448 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1449 pg_strcasecmp(prev_wd, "ADD") == 0)
1451 static const char *const list_ALTERTYPE[] =
1452 {"ATTRIBUTE", "VALUE", NULL};
1454 COMPLETE_WITH_LIST(list_ALTERTYPE);
1456 /* ALTER TYPE <foo> RENAME */
1457 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1458 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1459 pg_strcasecmp(prev_wd, "RENAME") == 0)
1461 static const char *const list_ALTERTYPE[] =
1462 {"ATTRIBUTE", "TO", NULL};
1464 COMPLETE_WITH_LIST(list_ALTERTYPE);
1466 /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */
1467 else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 &&
1468 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1469 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)
1470 COMPLETE_WITH_CONST("TO");
1473 * If we have TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list of
1476 else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 &&
1477 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1478 pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1479 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1480 pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0)
1481 COMPLETE_WITH_ATTR(prev3_wd, "");
1482 /* ALTER TYPE ALTER ATTRIBUTE <foo> */
1483 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1484 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0))
1486 COMPLETE_WITH_CONST("TYPE");
1488 /* complete ALTER GROUP <foo> */
1489 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1490 pg_strcasecmp(prev2_wd, "GROUP") == 0)
1492 static const char *const list_ALTERGROUP[] =
1493 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1495 COMPLETE_WITH_LIST(list_ALTERGROUP);
1497 /* complete ALTER GROUP <foo> ADD|DROP with USER */
1498 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1499 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1500 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1501 pg_strcasecmp(prev_wd, "DROP") == 0))
1502 COMPLETE_WITH_CONST("USER");
1503 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1504 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1505 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1506 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1507 pg_strcasecmp(prev_wd, "USER") == 0)
1508 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1510 /* BEGIN, END, ABORT */
1511 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1512 pg_strcasecmp(prev_wd, "END") == 0 ||
1513 pg_strcasecmp(prev_wd, "ABORT") == 0)
1515 static const char *const list_TRANS[] =
1516 {"WORK", "TRANSACTION", NULL};
1518 COMPLETE_WITH_LIST(list_TRANS);
1521 else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1523 static const char *const list_COMMIT[] =
1524 {"WORK", "TRANSACTION", "PREPARED", NULL};
1526 COMPLETE_WITH_LIST(list_COMMIT);
1528 /* RELEASE SAVEPOINT */
1529 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1530 COMPLETE_WITH_CONST("SAVEPOINT");
1532 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1534 static const char *const list_TRANS[] =
1535 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1537 COMPLETE_WITH_LIST(list_TRANS);
1542 * If the previous word is CLUSTER and not without produce list of tables
1544 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1545 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1546 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1547 /* If we have CLUSTER <sth>, then add "USING" */
1548 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1549 pg_strcasecmp(prev_wd, "ON") != 0)
1551 COMPLETE_WITH_CONST("USING");
1555 * If we have CLUSTER <sth> USING, then add the index as well.
1557 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1558 pg_strcasecmp(prev_wd, "USING") == 0)
1560 completion_info_charp = prev2_wd;
1561 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1565 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1566 COMPLETE_WITH_CONST("ON");
1567 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1568 pg_strcasecmp(prev_wd, "ON") == 0)
1570 static const char *const list_COMMENT[] =
1571 {"CAST", "COLLATION", "CONVERSION", "DATABASE", "EXTENSION",
1572 "FOREIGN DATA WRAPPER", "FOREIGN TABLE",
1573 "SERVER", "INDEX", "LANGUAGE", "RULE", "SCHEMA", "SEQUENCE",
1574 "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1575 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1576 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1578 COMPLETE_WITH_LIST(list_COMMENT);
1580 else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
1581 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1582 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1584 static const char *const list_TRANS2[] =
1585 {"DATA WRAPPER", "TABLE", NULL};
1587 COMPLETE_WITH_LIST(list_TRANS2);
1589 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1590 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1591 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1592 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1594 static const char *const list_TRANS2[] =
1595 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1597 COMPLETE_WITH_LIST(list_TRANS2);
1599 else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1600 pg_strcasecmp(prev3_wd, "ON") == 0) ||
1601 (pg_strcasecmp(prev5_wd, "COMMENT") == 0 &&
1602 pg_strcasecmp(prev4_wd, "ON") == 0) ||
1603 (pg_strcasecmp(prev6_wd, "COMMENT") == 0 &&
1604 pg_strcasecmp(prev5_wd, "ON") == 0))
1605 COMPLETE_WITH_CONST("IS");
1610 * If we have COPY [BINARY] (which you'd have to type yourself), offer
1611 * list of tables (Also cover the analogous backslash command)
1613 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1614 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1615 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1616 pg_strcasecmp(prev_wd, "BINARY") == 0))
1617 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1618 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1619 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1620 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1621 pg_strcasecmp(prev2_wd, "BINARY") == 0)
1623 static const char *const list_FROMTO[] =
1624 {"FROM", "TO", NULL};
1626 COMPLETE_WITH_LIST(list_FROMTO);
1628 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1629 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1630 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1631 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1632 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1633 pg_strcasecmp(prev_wd, "TO") == 0))
1635 completion_charp = "";
1636 matches = completion_matches(text, complete_from_files);
1639 /* Handle COPY|BINARY <sth> FROM|TO filename */
1640 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1641 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1642 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1643 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1644 pg_strcasecmp(prev2_wd, "TO") == 0))
1646 static const char *const list_COPY[] =
1647 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL};
1649 COMPLETE_WITH_LIST(list_COPY);
1652 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1653 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1654 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1655 pg_strcasecmp(prev3_wd, "TO") == 0))
1657 static const char *const list_CSV[] =
1658 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL};
1660 COMPLETE_WITH_LIST(list_CSV);
1663 /* CREATE DATABASE */
1664 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1665 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1667 static const char *const list_DATABASE[] =
1668 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1671 COMPLETE_WITH_LIST(list_DATABASE);
1674 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1675 pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1676 pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1677 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1679 /* CREATE EXTENSION */
1680 /* Complete with available extensions rather than installed ones. */
1681 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1682 pg_strcasecmp(prev_wd, "EXTENSION") == 0)
1683 COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
1684 /* CREATE EXTENSION <name> */
1685 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1686 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
1687 COMPLETE_WITH_CONST("WITH SCHEMA");
1689 /* CREATE FOREIGN */
1690 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1691 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1693 static const char *const list_CREATE_FOREIGN[] =
1694 {"DATA WRAPPER", "TABLE", NULL};
1696 COMPLETE_WITH_LIST(list_CREATE_FOREIGN);
1699 /* CREATE FOREIGN DATA WRAPPER */
1700 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1701 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1702 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1703 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1705 static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] =
1706 {"HANDLER", "VALIDATOR", NULL};
1708 COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER);
1712 /* First off we complete CREATE UNIQUE with "INDEX" */
1713 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1714 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1715 COMPLETE_WITH_CONST("INDEX");
1716 /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
1717 else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
1718 (pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
1719 pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
1720 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1721 " UNION SELECT 'ON'"
1722 " UNION SELECT 'CONCURRENTLY'");
1723 /* Complete ... INDEX [<name>] ON with a list of tables */
1724 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1725 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1726 pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
1727 pg_strcasecmp(prev_wd, "ON") == 0)
1728 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1729 /* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
1730 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1731 pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
1732 pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
1733 COMPLETE_WITH_CONST("ON");
1734 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
1735 else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1736 pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
1737 pg_strcasecmp(prev2_wd, "INDEX") == 0)
1739 static const char *const list_CREATE_INDEX[] =
1740 {"CONCURRENTLY", "ON", NULL};
1742 COMPLETE_WITH_LIST(list_CREATE_INDEX);
1746 * Complete INDEX <name> ON <table> with a list of table columns (which
1747 * should really be in parens)
1749 else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1750 pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1751 pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
1752 pg_strcasecmp(prev2_wd, "ON") == 0)
1754 static const char *const list_CREATE_INDEX2[] =
1755 {"(", "USING", NULL};
1757 COMPLETE_WITH_LIST(list_CREATE_INDEX2);
1759 else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
1760 pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1761 pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
1762 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1763 pg_strcasecmp(prev_wd, "(") == 0)
1764 COMPLETE_WITH_ATTR(prev2_wd, "");
1765 /* same if you put in USING */
1766 else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1767 pg_strcasecmp(prev3_wd, "USING") == 0 &&
1768 pg_strcasecmp(prev_wd, "(") == 0)
1769 COMPLETE_WITH_ATTR(prev4_wd, "");
1770 /* Complete USING with an index method */
1771 else if (pg_strcasecmp(prev_wd, "USING") == 0)
1772 COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
1773 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1774 pg_strcasecmp(prev2_wd, "USING") == 0)
1775 COMPLETE_WITH_CONST("(");
1778 /* Complete "CREATE RULE <sth>" with "AS" */
1779 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1780 pg_strcasecmp(prev2_wd, "RULE") == 0)
1781 COMPLETE_WITH_CONST("AS");
1782 /* Complete "CREATE RULE <sth> AS with "ON" */
1783 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1784 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1785 pg_strcasecmp(prev_wd, "AS") == 0)
1786 COMPLETE_WITH_CONST("ON");
1787 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1788 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1789 pg_strcasecmp(prev2_wd, "AS") == 0 &&
1790 pg_strcasecmp(prev_wd, "ON") == 0)
1792 static const char *const rule_events[] =
1793 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1795 COMPLETE_WITH_LIST(rule_events);
1797 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1798 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1799 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1800 (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1801 pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1802 COMPLETE_WITH_CONST("TO");
1803 /* Complete "AS ON <sth> TO" with a table name */
1804 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1805 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1806 pg_strcasecmp(prev_wd, "TO") == 0)
1807 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1809 /* CREATE SERVER <name> */
1810 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1811 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1813 static const char *const list_CREATE_SERVER[] =
1814 {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
1816 COMPLETE_WITH_LIST(list_CREATE_SERVER);
1820 /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
1821 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1822 (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
1823 pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
1825 static const char *const list_TEMP[] =
1826 {"SEQUENCE", "TABLE", "VIEW", NULL};
1828 COMPLETE_WITH_LIST(list_TEMP);
1830 /* Complete "CREATE UNLOGGED" with TABLE */
1831 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1832 pg_strcasecmp(prev_wd, "UNLOGGED") == 0)
1834 COMPLETE_WITH_CONST("TABLE");
1837 /* CREATE TABLESPACE */
1838 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1839 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1841 static const char *const list_CREATETABLESPACE[] =
1842 {"OWNER", "LOCATION", NULL};
1844 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1846 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1847 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1848 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1849 pg_strcasecmp(prev2_wd, "OWNER") == 0)
1851 COMPLETE_WITH_CONST("LOCATION");
1854 /* CREATE TEXT SEARCH */
1855 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1856 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1857 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1859 static const char *const list_CREATETEXTSEARCH[] =
1860 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1862 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
1864 else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1865 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1866 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1867 COMPLETE_WITH_CONST("(");
1869 /* CREATE TRIGGER */
1870 /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1871 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1872 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1874 static const char *const list_CREATETRIGGER[] =
1875 {"BEFORE", "AFTER", "INSTEAD OF", NULL};
1877 COMPLETE_WITH_LIST(list_CREATETRIGGER);
1879 /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
1880 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1881 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1882 (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
1883 pg_strcasecmp(prev_wd, "AFTER") == 0))
1885 static const char *const list_CREATETRIGGER_EVENTS[] =
1886 {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
1888 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
1890 /* complete CREATE TRIGGER <name> INSTEAD OF with an event */
1891 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1892 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1893 pg_strcasecmp(prev2_wd, "INSTEAD") == 0 &&
1894 pg_strcasecmp(prev_wd, "OF") == 0)
1896 static const char *const list_CREATETRIGGER_EVENTS[] =
1897 {"INSERT", "DELETE", "UPDATE", NULL};
1899 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
1901 /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1902 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1903 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1904 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1905 pg_strcasecmp(prev2_wd, "AFTER") == 0)) ||
1906 (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
1907 pg_strcasecmp(prev3_wd, "INSTEAD") == 0 &&
1908 pg_strcasecmp(prev2_wd, "OF") == 0))
1910 static const char *const list_CREATETRIGGER2[] =
1913 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1917 * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
1920 else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
1921 (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
1922 pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
1923 pg_strcasecmp(prev_wd, "ON") == 0)
1924 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1925 /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
1926 else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 &&
1927 pg_strcasecmp(prev3_wd, "OF") == 0 &&
1928 pg_strcasecmp(prev_wd, "ON") == 0)
1929 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
1930 /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
1931 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
1932 prev2_wd[0] != '\0')
1933 COMPLETE_WITH_CONST("PROCEDURE");
1935 /* CREATE ROLE,USER,GROUP */
1936 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1937 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1938 (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1939 pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1941 static const char *const list_CREATEROLE[] =
1942 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1943 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB",
1944 "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN",
1945 "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE",
1946 "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", NULL};
1948 COMPLETE_WITH_LIST(list_CREATEROLE);
1952 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1955 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1956 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1957 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1958 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1960 COMPLETE_WITH_CONST("PASSWORD");
1962 /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1963 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1964 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1965 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1966 pg_strcasecmp(prev_wd, "IN") == 0)
1968 static const char *const list_CREATEROLE3[] =
1969 {"GROUP", "ROLE", NULL};
1971 COMPLETE_WITH_LIST(list_CREATEROLE3);
1975 /* Complete CREATE VIEW <name> with AS */
1976 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1977 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1978 COMPLETE_WITH_CONST("AS");
1979 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1980 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1981 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1982 pg_strcasecmp(prev_wd, "AS") == 0)
1983 COMPLETE_WITH_CONST("SELECT");
1986 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1988 static const char *const list_DECLARE[] =
1989 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1991 COMPLETE_WITH_LIST(list_DECLARE);
1995 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1997 static const char *const list_DECLARECURSOR[] =
1998 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
2000 COMPLETE_WITH_LIST(list_DECLARECURSOR);
2007 * Complete DELETE with FROM (only if the word before that is not "ON"
2008 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
2010 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
2011 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
2012 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2013 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2014 pg_strcasecmp(prev2_wd, "AFTER") == 0))
2015 COMPLETE_WITH_CONST("FROM");
2016 /* Complete DELETE FROM with a list of tables */
2017 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
2018 pg_strcasecmp(prev_wd, "FROM") == 0)
2019 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL);
2020 /* Complete DELETE FROM <table> */
2021 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
2022 pg_strcasecmp(prev2_wd, "FROM") == 0)
2024 static const char *const list_DELETE[] =
2025 {"USING", "WHERE", "SET", NULL};
2027 COMPLETE_WITH_LIST(list_DELETE);
2029 /* XXX: implement tab completion for DELETE ... USING */
2032 else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
2034 static const char *const list_DISCARD[] =
2035 {"ALL", "PLANS", "TEMP", NULL};
2037 COMPLETE_WITH_LIST(list_DISCARD);
2043 * Complete DO with LANGUAGE.
2045 else if (pg_strcasecmp(prev_wd, "DO") == 0)
2047 static const char *const list_DO[] =
2050 COMPLETE_WITH_LIST(list_DO);
2053 /* DROP (when not the previous word) */
2054 /* DROP AGGREGATE */
2055 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2056 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
2057 COMPLETE_WITH_CONST("(");
2059 /* DROP object with CASCADE / RESTRICT */
2060 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2061 (pg_strcasecmp(prev2_wd, "COLLATION") == 0 ||
2062 pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
2063 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
2064 pg_strcasecmp(prev2_wd, "EXTENSION") == 0 ||
2065 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
2066 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2067 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
2068 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
2069 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
2070 pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
2071 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
2072 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
2073 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
2074 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2075 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
2076 prev_wd[strlen(prev_wd) - 1] == ')') ||
2077 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2078 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2079 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2080 pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
2081 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2082 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2083 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2084 (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
2085 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
2086 pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
2087 pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
2090 if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2091 pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
2093 COMPLETE_WITH_CONST("(");
2097 static const char *const list_DROPCR[] =
2098 {"CASCADE", "RESTRICT", NULL};
2100 COMPLETE_WITH_LIST(list_DROPCR);
2103 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2104 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2106 static const char *const drop_CREATE_FOREIGN[] =
2107 {"DATA WRAPPER", "TABLE", NULL};
2109 COMPLETE_WITH_LIST(drop_CREATE_FOREIGN);
2111 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2112 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
2113 pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
2114 pg_strcasecmp(prev_wd, "(") == 0)
2116 char *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
2118 sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
2119 COMPLETE_WITH_QUERY(tmp_buf);
2123 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2124 pg_strcasecmp(prev_wd, "OWNED") == 0)
2125 COMPLETE_WITH_CONST("BY");
2126 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2127 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2128 pg_strcasecmp(prev_wd, "BY") == 0)
2129 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2130 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2131 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2132 pg_strcasecmp(prev_wd, "SEARCH") == 0)
2135 static const char *const list_ALTERTEXTSEARCH[] =
2136 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2138 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
2141 /* EXECUTE, but not EXECUTE embedded in other commands */
2142 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2143 prev2_wd[0] == '\0')
2144 COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
2149 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2151 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
2153 static const char *const list_EXPLAIN[] =
2154 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
2156 COMPLETE_WITH_LIST(list_EXPLAIN);
2158 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2159 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2161 static const char *const list_EXPLAIN[] =
2162 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
2164 COMPLETE_WITH_LIST(list_EXPLAIN);
2166 else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2167 pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
2168 (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
2169 pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
2170 pg_strcasecmp(prev_wd, "VERBOSE") == 0))
2172 static const char *const list_EXPLAIN[] =
2173 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
2175 COMPLETE_WITH_LIST(list_EXPLAIN);
2179 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
2180 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
2181 pg_strcasecmp(prev_wd, "MOVE") == 0)
2183 static const char *const list_FETCH1[] =
2184 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
2186 COMPLETE_WITH_LIST(list_FETCH1);
2188 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
2189 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
2190 pg_strcasecmp(prev2_wd, "MOVE") == 0)
2192 static const char *const list_FETCH2[] =
2193 {"ALL", "NEXT", "PRIOR", NULL};
2195 COMPLETE_WITH_LIST(list_FETCH2);
2199 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
2200 * but we may as well tab-complete both: perhaps some users prefer one
2201 * variant or the other.
2203 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
2204 pg_strcasecmp(prev3_wd, "MOVE") == 0)
2206 static const char *const list_FROMIN[] =
2207 {"FROM", "IN", NULL};
2209 COMPLETE_WITH_LIST(list_FROMIN);
2212 /* FOREIGN DATA WRAPPER */
2213 /* applies in ALTER/DROP FDW and in CREATE SERVER */
2214 else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
2215 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
2216 pg_strcasecmp(prev2_wd, "DATA") == 0 &&
2217 pg_strcasecmp(prev_wd, "WRAPPER") == 0)
2218 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2221 else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 &&
2222 pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
2223 pg_strcasecmp(prev_wd, "TABLE") == 0)
2224 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
2226 /* GRANT && REVOKE */
2227 /* Complete GRANT/REVOKE with a list of roles and privileges */
2228 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
2229 pg_strcasecmp(prev_wd, "REVOKE") == 0)
2231 COMPLETE_WITH_QUERY(Query_for_list_of_roles
2232 " UNION SELECT 'SELECT'"
2233 " UNION SELECT 'INSERT'"
2234 " UNION SELECT 'UPDATE'"
2235 " UNION SELECT 'DELETE'"
2236 " UNION SELECT 'TRUNCATE'"
2237 " UNION SELECT 'REFERENCES'"
2238 " UNION SELECT 'TRIGGER'"
2239 " UNION SELECT 'CREATE'"
2240 " UNION SELECT 'CONNECT'"
2241 " UNION SELECT 'TEMPORARY'"
2242 " UNION SELECT 'EXECUTE'"
2243 " UNION SELECT 'USAGE'"
2244 " UNION SELECT 'ALL'");
2246 /* Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with TO/FROM */
2247 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2248 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
2250 if (pg_strcasecmp(prev_wd, "SELECT") == 0
2251 || pg_strcasecmp(prev_wd, "INSERT") == 0
2252 || pg_strcasecmp(prev_wd, "UPDATE") == 0
2253 || pg_strcasecmp(prev_wd, "DELETE") == 0
2254 || pg_strcasecmp(prev_wd, "TRUNCATE") == 0
2255 || pg_strcasecmp(prev_wd, "REFERENCES") == 0
2256 || pg_strcasecmp(prev_wd, "TRIGGER") == 0
2257 || pg_strcasecmp(prev_wd, "CREATE") == 0
2258 || pg_strcasecmp(prev_wd, "CONNECT") == 0
2259 || pg_strcasecmp(prev_wd, "TEMPORARY") == 0
2260 || pg_strcasecmp(prev_wd, "TEMP") == 0
2261 || pg_strcasecmp(prev_wd, "EXECUTE") == 0
2262 || pg_strcasecmp(prev_wd, "USAGE") == 0
2263 || pg_strcasecmp(prev_wd, "ALL") == 0)
2264 COMPLETE_WITH_CONST("ON");
2267 if (pg_strcasecmp(prev2_wd, "GRANT") == 0)
2268 COMPLETE_WITH_CONST("TO");
2270 COMPLETE_WITH_CONST("FROM");
2275 * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
2278 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
2279 * UNION; seems to work intuitively
2281 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
2282 * here will only work if the privilege list contains exactly one
2285 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
2286 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
2287 pg_strcasecmp(prev_wd, "ON") == 0)
2288 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf,
2289 " UNION SELECT 'DATABASE'"
2290 " UNION SELECT 'DOMAIN'"
2291 " UNION SELECT 'FOREIGN DATA WRAPPER'"
2292 " UNION SELECT 'FOREIGN SERVER'"
2293 " UNION SELECT 'FUNCTION'"
2294 " UNION SELECT 'LANGUAGE'"
2295 " UNION SELECT 'LARGE OBJECT'"
2296 " UNION SELECT 'SCHEMA'"
2297 " UNION SELECT 'TABLESPACE'"
2298 " UNION SELECT 'TYPE'");
2299 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2300 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2301 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2302 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2304 static const char *const list_privilege_foreign[] =
2305 {"DATA WRAPPER", "SERVER", NULL};
2307 COMPLETE_WITH_LIST(list_privilege_foreign);
2310 /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
2311 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2312 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2313 pg_strcasecmp(prev2_wd, "ON") == 0)
2315 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
2316 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2317 else if (pg_strcasecmp(prev_wd, "DOMAIN") == 0)
2318 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2319 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
2320 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2321 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
2322 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2323 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
2324 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2325 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
2326 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2327 else if (pg_strcasecmp(prev_wd, "TYPE") == 0)
2328 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2329 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
2330 COMPLETE_WITH_CONST("TO");
2332 COMPLETE_WITH_CONST("FROM");
2335 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
2336 else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
2337 pg_strcasecmp(prev3_wd, "ON") == 0)
2339 if (pg_strcasecmp(prev_wd, "TO") == 0)
2340 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2342 COMPLETE_WITH_CONST("TO");
2344 else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
2345 pg_strcasecmp(prev3_wd, "ON") == 0)
2347 if (pg_strcasecmp(prev_wd, "FROM") == 0)
2348 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2350 COMPLETE_WITH_CONST("FROM");
2353 /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */
2354 else if (pg_strcasecmp(prev3_wd, "GRANT") == 0 &&
2355 pg_strcasecmp(prev_wd, "TO") == 0)
2357 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2359 else if (pg_strcasecmp(prev3_wd, "REVOKE") == 0 &&
2360 pg_strcasecmp(prev_wd, "FROM") == 0)
2362 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2366 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2367 pg_strcasecmp(prev_wd, "GROUP") == 0)
2368 COMPLETE_WITH_CONST("BY");
2371 /* Complete INSERT with "INTO" */
2372 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
2373 COMPLETE_WITH_CONST("INTO");
2374 /* Complete INSERT INTO with table names */
2375 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
2376 pg_strcasecmp(prev_wd, "INTO") == 0)
2377 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL);
2378 /* Complete "INSERT INTO <table> (" with attribute names */
2379 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2380 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2381 pg_strcasecmp(prev_wd, "(") == 0)
2382 COMPLETE_WITH_ATTR(prev2_wd, "");
2385 * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
2386 * "TABLE" or "DEFAULT VALUES"
2388 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
2389 pg_strcasecmp(prev2_wd, "INTO") == 0)
2391 static const char *const list_INSERT[] =
2392 {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
2394 COMPLETE_WITH_LIST(list_INSERT);
2398 * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
2401 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2402 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2403 prev_wd[strlen(prev_wd) - 1] == ')')
2405 static const char *const list_INSERT[] =
2406 {"SELECT", "TABLE", "VALUES", NULL};
2408 COMPLETE_WITH_LIST(list_INSERT);
2411 /* Insert an open parenthesis after "VALUES" */
2412 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
2413 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
2414 COMPLETE_WITH_CONST("(");
2417 /* Complete LOCK [TABLE] with a list of tables */
2418 else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
2419 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2420 " UNION SELECT 'TABLE'");
2421 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2422 pg_strcasecmp(prev2_wd, "LOCK") == 0)
2423 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
2425 /* For the following, handle the case of a single table only for now */
2427 /* Complete LOCK [TABLE] <table> with "IN" */
2428 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
2429 pg_strcasecmp(prev_wd, "TABLE") != 0) ||
2430 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
2431 pg_strcasecmp(prev3_wd, "LOCK") == 0))
2432 COMPLETE_WITH_CONST("IN");
2434 /* Complete LOCK [TABLE] <table> IN with a lock mode */
2435 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
2436 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
2437 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
2438 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
2440 static const char *const lock_modes[] =
2441 {"ACCESS SHARE MODE",
2442 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
2443 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
2444 "SHARE ROW EXCLUSIVE MODE",
2445 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
2447 COMPLETE_WITH_LIST(lock_modes);
2451 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
2452 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'");
2455 else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
2456 COMPLETE_WITH_CONST("(");
2458 /* OWNER TO - complete with available roles */
2459 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
2460 pg_strcasecmp(prev_wd, "TO") == 0)
2461 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2464 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2465 pg_strcasecmp(prev_wd, "ORDER") == 0)
2466 COMPLETE_WITH_CONST("BY");
2467 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
2468 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
2469 pg_strcasecmp(prev_wd, "BY") == 0)
2470 COMPLETE_WITH_ATTR(prev3_wd, "");
2473 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
2474 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
2476 static const char *const list_PREPARE[] =
2477 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2479 COMPLETE_WITH_LIST(list_PREPARE);
2483 * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
2484 * managers, not for manual use in interactive sessions.
2487 /* REASSIGN OWNED BY xxx TO yyy */
2488 else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
2489 COMPLETE_WITH_CONST("OWNED");
2490 else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
2491 pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
2492 COMPLETE_WITH_CONST("BY");
2493 else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
2494 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2495 pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
2496 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2497 else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
2498 pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
2499 pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
2500 COMPLETE_WITH_CONST("TO");
2501 else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
2502 pg_strcasecmp(prev3_wd, "BY") == 0 &&
2503 pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
2504 pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
2505 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2508 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
2510 static const char *const list_REINDEX[] =
2511 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
2513 COMPLETE_WITH_LIST(list_REINDEX);
2515 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
2517 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
2518 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2519 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
2520 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2521 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
2522 pg_strcasecmp(prev_wd, "DATABASE") == 0)
2523 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2526 /* SECURITY LABEL */
2527 else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
2528 COMPLETE_WITH_CONST("LABEL");
2529 else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
2530 pg_strcasecmp(prev_wd, "LABEL") == 0)
2532 static const char *const list_SECURITY_LABEL_preposition[] =
2535 COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
2537 else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
2538 pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
2539 pg_strcasecmp(prev2_wd, "FOR") == 0)
2540 COMPLETE_WITH_CONST("ON");
2541 else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
2542 pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
2543 pg_strcasecmp(prev_wd, "ON") == 0) ||
2544 (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2545 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2546 pg_strcasecmp(prev3_wd, "FOR") == 0 &&
2547 pg_strcasecmp(prev_wd, "ON") == 0))
2549 static const char *const list_SECURITY_LABEL[] =
2550 {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN",
2551 "AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT",
2554 COMPLETE_WITH_LIST(list_SECURITY_LABEL);
2556 else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2557 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2558 pg_strcasecmp(prev3_wd, "ON") == 0)
2559 COMPLETE_WITH_CONST("IS");
2564 /* SET, RESET, SHOW */
2565 /* Complete with a variable name */
2566 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
2567 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
2568 pg_strcasecmp(prev_wd, "RESET") == 0)
2569 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
2570 else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
2571 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
2572 /* Complete "SET TRANSACTION" */
2573 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
2574 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2575 || (pg_strcasecmp(prev2_wd, "START") == 0
2576 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2577 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2578 && pg_strcasecmp(prev_wd, "WORK") == 0)
2579 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2580 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2581 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
2582 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
2583 && pg_strcasecmp(prev2_wd, "AS") == 0
2584 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
2586 static const char *const my_list[] =
2587 {"ISOLATION LEVEL", "READ", NULL};
2589 COMPLETE_WITH_LIST(my_list);
2591 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
2592 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
2593 || pg_strcasecmp(prev3_wd, "START") == 0
2594 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
2595 && pg_strcasecmp(prev3_wd, "AS") == 0))
2596 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
2597 || pg_strcasecmp(prev2_wd, "WORK") == 0)
2598 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
2599 COMPLETE_WITH_CONST("LEVEL");
2600 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
2601 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
2602 || pg_strcasecmp(prev4_wd, "START") == 0
2603 || pg_strcasecmp(prev4_wd, "AS") == 0)
2604 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
2605 || pg_strcasecmp(prev3_wd, "WORK") == 0)
2606 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
2607 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
2609 static const char *const my_list[] =
2610 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
2612 COMPLETE_WITH_LIST(my_list);
2614 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2615 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2616 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2617 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2618 pg_strcasecmp(prev_wd, "READ") == 0)
2620 static const char *const my_list[] =
2621 {"UNCOMMITTED", "COMMITTED", NULL};
2623 COMPLETE_WITH_LIST(my_list);
2625 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2626 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2627 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2628 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2629 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
2630 COMPLETE_WITH_CONST("READ");
2631 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
2632 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
2633 pg_strcasecmp(prev3_wd, "START") == 0 ||
2634 pg_strcasecmp(prev3_wd, "AS") == 0) &&
2635 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
2636 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
2637 pg_strcasecmp(prev_wd, "READ") == 0)
2639 static const char *const my_list[] =
2640 {"ONLY", "WRITE", NULL};
2642 COMPLETE_WITH_LIST(my_list);
2644 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
2645 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2646 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
2648 static const char *const constraint_list[] =
2649 {"DEFERRED", "IMMEDIATE", NULL};
2651 COMPLETE_WITH_LIST(constraint_list);
2653 /* Complete SET ROLE */
2654 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2655 pg_strcasecmp(prev_wd, "ROLE") == 0)
2656 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2657 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
2658 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2659 pg_strcasecmp(prev_wd, "SESSION") == 0)
2661 static const char *const my_list[] =
2662 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
2664 COMPLETE_WITH_LIST(my_list);
2666 /* Complete SET SESSION AUTHORIZATION with username */
2667 else if (pg_strcasecmp(prev3_wd, "SET") == 0
2668 && pg_strcasecmp(prev2_wd, "SESSION") == 0
2669 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
2670 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
2671 /* Complete RESET SESSION with AUTHORIZATION */
2672 else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
2673 pg_strcasecmp(prev_wd, "SESSION") == 0)
2674 COMPLETE_WITH_CONST("AUTHORIZATION");
2675 /* Complete SET <var> with "TO" */
2676 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2677 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
2678 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
2679 pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
2680 prev_wd[strlen(prev_wd) - 1] != ')' &&
2681 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
2682 COMPLETE_WITH_CONST("TO");
2683 /* Suggest possible variable values */
2684 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2685 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
2687 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
2689 static const char *const my_list[] =
2690 {"ISO", "SQL", "Postgres", "German",
2691 "YMD", "DMY", "MDY",
2692 "US", "European", "NonEuropean",
2695 COMPLETE_WITH_LIST(my_list);
2697 else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
2699 static const char *const my_list[] =
2700 {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
2702 COMPLETE_WITH_LIST(my_list);
2704 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
2706 static const char *const my_list[] =
2707 {"ON", "OFF", "DEFAULT", NULL};
2709 COMPLETE_WITH_LIST(my_list);
2713 static const char *const my_list[] =
2716 COMPLETE_WITH_LIST(my_list);
2720 /* START TRANSACTION */
2721 else if (pg_strcasecmp(prev_wd, "START") == 0)
2722 COMPLETE_WITH_CONST("TRANSACTION");
2724 /* TABLE, but not TABLE embedded in other commands */
2725 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2726 prev2_wd[0] == '\0')
2727 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
2730 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
2731 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2734 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
2735 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 '*'");
2738 /* If prev. word is UPDATE suggest a list of tables */
2739 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
2740 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
2741 /* Complete UPDATE <table> with "SET" */
2742 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
2743 COMPLETE_WITH_CONST("SET");
2746 * If the previous word is SET (and it wasn't caught above as the _first_
2747 * word) the word before it was (hopefully) a table name and we'll now
2748 * make a list of attributes.
2750 else if (pg_strcasecmp(prev_wd, "SET") == 0)
2751 COMPLETE_WITH_ATTR(prev2_wd, "");
2753 /* UPDATE xx SET yy = */
2754 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2755 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
2756 COMPLETE_WITH_CONST("=");
2759 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
2760 pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2761 pg_strcasecmp(prev3_wd, "DROP") == 0) &&
2762 pg_strcasecmp(prev2_wd, "USER") == 0 &&
2763 pg_strcasecmp(prev_wd, "MAPPING") == 0)
2764 COMPLETE_WITH_CONST("FOR");
2765 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2766 pg_strcasecmp(prev3_wd, "USER") == 0 &&
2767 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2768 pg_strcasecmp(prev_wd, "FOR") == 0)
2769 COMPLETE_WITH_QUERY(Query_for_list_of_roles
2770 " UNION SELECT 'CURRENT_USER'"
2771 " UNION SELECT 'PUBLIC'"
2772 " UNION SELECT 'USER'");
2773 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
2774 pg_strcasecmp(prev4_wd, "DROP") == 0) &&
2775 pg_strcasecmp(prev3_wd, "USER") == 0 &&
2776 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2777 pg_strcasecmp(prev_wd, "FOR") == 0)
2778 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2779 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
2780 pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
2781 pg_strcasecmp(prev5_wd, "DROP") == 0) &&
2782 pg_strcasecmp(prev4_wd, "USER") == 0 &&
2783 pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
2784 pg_strcasecmp(prev2_wd, "FOR") == 0)
2785 COMPLETE_WITH_CONST("SERVER");
2788 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
2789 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
2791 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
2792 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2793 " UNION SELECT 'FULL'"
2794 " UNION SELECT 'FREEZE'"
2795 " UNION SELECT 'ANALYZE'"
2796 " UNION SELECT 'VERBOSE'");
2797 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2798 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
2799 pg_strcasecmp(prev_wd, "FREEZE") == 0))
2800 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2801 " UNION SELECT 'ANALYZE'"
2802 " UNION SELECT 'VERBOSE'");
2803 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2804 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2805 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2806 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2807 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2808 " UNION SELECT 'VERBOSE'");
2809 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2810 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2811 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2812 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2813 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2814 " UNION SELECT 'ANALYZE'");
2815 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2816 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
2817 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2818 " UNION SELECT 'ANALYZE'");
2819 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2820 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2821 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2822 " UNION SELECT 'VERBOSE'");
2823 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2824 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
2825 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2826 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
2827 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2829 /* WITH [RECURSIVE] */
2830 else if (pg_strcasecmp(prev_wd, "WITH") == 0)
2831 COMPLETE_WITH_CONST("RECURSIVE");
2834 /* If the previous word is ANALYZE, produce list of tables */
2835 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2836 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2839 /* Simple case of the word before the where being the table name */
2840 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
2841 COMPLETE_WITH_ATTR(prev2_wd, "");
2844 /* TODO: also include SRF ? */
2845 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
2846 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
2847 pg_strcasecmp(prev3_wd, "\\copy") != 0)
2848 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2851 else if (pg_strcasecmp(prev_wd, "JOIN") == 0)
2852 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2854 /* Backslash commands */
2855 /* TODO: \dc \dd \dl */
2856 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
2857 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2859 else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
2860 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
2861 else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
2862 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2863 else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
2864 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2865 else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
2866 COMPLETE_WITH_QUERY(Query_for_list_of_servers);
2867 else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
2868 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2869 else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
2870 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2872 else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
2873 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2874 else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
2875 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
2876 else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
2877 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
2878 else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
2879 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
2880 /* must be at end of \dF */
2881 else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
2882 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
2884 else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
2885 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2886 else if (strncmp(prev_wd, "\\dL", strlen("\\dL")) == 0)
2887 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2888 else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
2889 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2890 else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0
2891 || strncmp(prev_wd, "\\z", strlen("\\z")) == 0)
2892 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2893 else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
2894 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
2895 else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
2896 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2897 else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
2898 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2899 else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0
2900 || (strncmp(prev_wd, "\\dg", strlen("\\dg")) == 0))
2901 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2902 else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
2903 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2905 /* must be at end of \d list */
2906 else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
2907 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
2909 else if (strcmp(prev_wd, "\\ef") == 0)
2910 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2912 else if (strcmp(prev_wd, "\\encoding") == 0)
2913 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
2914 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
2915 COMPLETE_WITH_LIST(sql_commands);
2916 else if (strcmp(prev_wd, "\\password") == 0)
2917 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2918 else if (strcmp(prev_wd, "\\pset") == 0)
2920 static const char *const my_list[] =
2921 {"format", "border", "expanded",
2922 "null", "fieldsep", "tuples_only", "title", "tableattr",
2923 "linestyle", "pager", "recordsep", NULL};
2925 COMPLETE_WITH_LIST_CS(my_list);
2927 else if (strcmp(prev2_wd, "\\pset") == 0)
2929 if (strcmp(prev_wd, "format") == 0)
2931 static const char *const my_list[] =
2932 {"unaligned", "aligned", "wrapped", "html", "latex",
2935 COMPLETE_WITH_LIST_CS(my_list);
2937 else if (strcmp(prev_wd, "linestyle") == 0)
2939 static const char *const my_list[] =
2940 {"ascii", "old-ascii", "unicode", NULL};
2942 COMPLETE_WITH_LIST_CS(my_list);
2945 else if (strcmp(prev_wd, "\\set") == 0)
2947 matches = complete_from_variables(text, "", "");
2949 else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
2950 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2951 else if (strcmp(prev_wd, "\\cd") == 0 ||
2952 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
2953 strcmp(prev_wd, "\\g") == 0 ||
2954 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
2955 strcmp(prev_wd, "\\ir") == 0 || strcmp(prev_wd, "\\include_relative") == 0 ||
2956 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
2957 strcmp(prev_wd, "\\s") == 0 ||
2958 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
2961 completion_charp = "\\";
2962 matches = completion_matches(text, complete_from_files);
2966 * Finally, we look through the list of "things", such as TABLE, INDEX and
2967 * check if that was the previous word. If so, execute the query to get a
2974 for (i = 0; words_after_create[i].name; i++)
2976 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
2978 if (words_after_create[i].query)
2979 COMPLETE_WITH_QUERY(words_after_create[i].query);
2980 else if (words_after_create[i].squery)
2981 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
2989 * If we still don't have anything to match we have to fabricate some sort
2990 * of default list. If we were to just return NULL, readline automatically
2991 * attempts filename completion, and that's usually no good.
2993 if (matches == NULL)
2995 COMPLETE_WITH_CONST("");
2996 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
2997 rl_completion_append_character = '\0';
3005 for (i = 0; i < lengthof(previous_words); i++)
3006 free(previous_words[i]);
3009 /* Return our Grand List O' Matches */
3015 * GENERATOR FUNCTIONS
3017 * These functions do all the actual work of completing the input. They get
3018 * passed the text so far and the count how many times they have been called
3019 * so far with the same text.
3020 * If you read the above carefully, you'll see that these don't get called
3021 * directly but through the readline interface.
3022 * The return value is expected to be the full completion of the text, going
3023 * through a list each time, or NULL if there are no more matches. The string
3024 * will be free()'d by readline, so you must run it through strdup() or
3025 * something of that sort.
3029 * Common routine for create_command_generator and drop_command_generator.
3030 * Entries that have 'excluded' flags are not returned.
3033 create_or_drop_command_generator(const char *text, int state, bits32 excluded)
3035 static int list_index,
3039 /* If this is the first time for this completion, init some values */
3043 string_length = strlen(text);
3046 /* find something that matches */
3047 while ((name = words_after_create[list_index++].name))
3049 if ((pg_strncasecmp(name, text, string_length) == 0) &&
3050 !(words_after_create[list_index - 1].flags & excluded))
3051 return pg_strdup_same_case(name, text);
3053 /* if nothing matches, return NULL */
3058 * This one gives you one from a list of things you can put after CREATE
3062 create_command_generator(const char *text, int state)
3064 return create_or_drop_command_generator(text, state, THING_NO_CREATE);
3068 * This function gives you a list of things you can put after a DROP command.
3071 drop_command_generator(const char *text, int state)
3073 return create_or_drop_command_generator(text, state, THING_NO_DROP);
3076 /* The following two functions are wrappers for _complete_from_query */
3079 complete_from_query(const char *text, int state)
3081 return _complete_from_query(0, text, state);
3085 complete_from_schema_query(const char *text, int state)
3087 return _complete_from_query(1, text, state);
3092 * This creates a list of matching things, according to a query pointed to
3093 * by completion_charp.
3094 * The query can be one of two kinds:
3096 * 1. A simple query which must contain a %d and a %s, which will be replaced
3097 * by the string length of the text and the text itself. The query may also
3098 * have up to four more %s in it; the first two such will be replaced by the
3099 * value of completion_info_charp, the next two by the value of
3100 * completion_info_charp2.
3102 * 2. A schema query used for completion of both schema and relation names.
3103 * These are more complex and must contain in the following order:
3104 * %d %s %d %s %d %s %s %d %s
3105 * where %d is the string length of the text and %s the text itself.
3107 * It is assumed that strings should be escaped to become SQL literals
3108 * (that is, what is in the query is actually ... '%s' ...)
3110 * See top of file for examples of both kinds of query.
3113 _complete_from_query(int is_schema_query, const char *text, int state)
3115 static int list_index,
3117 static PGresult *result = NULL;
3120 * If this is the first time for this completion, we fetch a list of our
3121 * "things" from the backend.
3125 PQExpBufferData query_buffer;
3128 char *e_info_charp2;
3131 string_length = strlen(text);
3133 /* Free any prior result */
3137 /* Set up suitably-escaped copies of textual inputs */
3138 e_text = pg_malloc(string_length * 2 + 1);
3139 PQescapeString(e_text, text, string_length);
3141 if (completion_info_charp)
3145 charp_len = strlen(completion_info_charp);
3146 e_info_charp = pg_malloc(charp_len * 2 + 1);
3147 PQescapeString(e_info_charp, completion_info_charp,
3151 e_info_charp = NULL;
3153 if (completion_info_charp2)
3157 charp_len = strlen(completion_info_charp2);
3158 e_info_charp2 = pg_malloc(charp_len * 2 + 1);
3159 PQescapeString(e_info_charp2, completion_info_charp2,
3163 e_info_charp2 = NULL;
3165 initPQExpBuffer(&query_buffer);
3167 if (is_schema_query)
3169 /* completion_squery gives us the pieces to assemble */
3170 const char *qualresult = completion_squery->qualresult;
3172 if (qualresult == NULL)
3173 qualresult = completion_squery->result;
3175 /* Get unqualified names matching the input-so-far */
3176 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
3177 completion_squery->result,
3178 completion_squery->catname);
3179 if (completion_squery->selcondition)
3180 appendPQExpBuffer(&query_buffer, "%s AND ",
3181 completion_squery->selcondition);
3182 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
3183 completion_squery->result,
3184 string_length, e_text);
3185 appendPQExpBuffer(&query_buffer, " AND %s",
3186 completion_squery->viscondition);
3189 * When fetching relation names, suppress system catalogs unless
3190 * the input-so-far begins with "pg_". This is a compromise
3191 * between not offering system catalogs for completion at all, and
3192 * having them swamp the result when the input is just "p".
3194 if (strcmp(completion_squery->catname,
3195 "pg_catalog.pg_class c") == 0 &&
3196 strncmp(text, "pg_", 3) !=0)
3198 appendPQExpBuffer(&query_buffer,
3199 " AND c.relnamespace <> (SELECT oid FROM"
3200 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
3204 * Add in matching schema names, but only if there is more than
3205 * one potential match among schema names.
3207 appendPQExpBuffer(&query_buffer, "\nUNION\n"
3208 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
3209 "FROM pg_catalog.pg_namespace n "
3210 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
3211 string_length, e_text);
3212 appendPQExpBuffer(&query_buffer,
3213 " AND (SELECT pg_catalog.count(*)"
3214 " FROM pg_catalog.pg_namespace"
3215 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3216 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
3217 string_length, e_text);
3220 * Add in matching qualified names, but only if there is exactly
3221 * one schema matching the input-so-far.
3223 appendPQExpBuffer(&query_buffer, "\nUNION\n"
3224 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
3225 "FROM %s, pg_catalog.pg_namespace n "
3226 "WHERE %s = n.oid AND ",
3228 completion_squery->catname,
3229 completion_squery->namespace);
3230 if (completion_squery->selcondition)
3231 appendPQExpBuffer(&query_buffer, "%s AND ",
3232 completion_squery->selcondition);
3233 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
3235 string_length, e_text);
3238 * This condition exploits the single-matching-schema rule to
3239 * speed up the query
3241 appendPQExpBuffer(&query_buffer,
3242 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
3243 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
3244 string_length, e_text);
3245 appendPQExpBuffer(&query_buffer,
3246 " AND (SELECT pg_catalog.count(*)"
3247 " FROM pg_catalog.pg_namespace"
3248 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3249 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
3250 string_length, e_text);
3252 /* If an addon query was provided, use it */
3253 if (completion_charp)
3254 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
3258 /* completion_charp is an sprintf-style format string */
3259 appendPQExpBuffer(&query_buffer, completion_charp,
3260 string_length, e_text,
3261 e_info_charp, e_info_charp,
3262 e_info_charp2, e_info_charp2);
3265 /* Limit the number of records in the result */
3266 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
3267 completion_max_records);
3269 result = exec_query(query_buffer.data);
3271 termPQExpBuffer(&query_buffer);
3276 free(e_info_charp2);
3279 /* Find something that matches */
3280 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
3284 while (list_index < PQntuples(result) &&
3285 (item = PQgetvalue(result, list_index++, 0)))
3286 if (pg_strncasecmp(text, item, string_length) == 0)
3287 return pg_strdup(item);
3290 /* If nothing matches, free the db structure and return null */
3298 * This function returns in order one of a fixed, NULL pointer terminated list
3299 * of strings (if matching). This can be used if there are only a fixed number
3300 * SQL words that can appear at certain spot.
3303 complete_from_list(const char *text, int state)
3305 static int string_length,
3308 static bool casesensitive;
3311 /* need to have a list */
3312 psql_assert(completion_charpp);
3314 /* Initialization */
3318 string_length = strlen(text);
3319 casesensitive = completion_case_sensitive;
3323 while ((item = completion_charpp[list_index++]))
3325 /* First pass is case sensitive */
3326 if (casesensitive && strncmp(text, item, string_length) == 0)
3329 return pg_strdup(item);
3332 /* Second pass is case insensitive, don't bother counting matches */
3333 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
3335 if (completion_case_sensitive)
3336 return pg_strdup(item);
3338 /* If case insensitive matching was requested initially, return
3339 * it in the case of what was already entered. */
3340 return pg_strdup_same_case(item, text);
3345 * No matches found. If we're not case insensitive already, lets switch to
3346 * being case insensitive and try again
3348 if (casesensitive && matches == 0)
3350 casesensitive = false;
3353 return complete_from_list(text, state);
3356 /* If no more matches, return null. */
3362 * This function returns one fixed string the first time even if it doesn't
3363 * match what's there, and nothing the second time. This should be used if
3364 * there is only one possibility that can appear at a certain spot, so
3365 * misspellings will be overwritten. The string to be passed must be in
3369 complete_from_const(const char *text, int state)
3371 psql_assert(completion_charp);
3374 if (completion_case_sensitive)
3375 return pg_strdup(completion_charp);
3377 /* If case insensitive matching was requested initially, return it
3378 * in the case of what was already entered. */
3379 return pg_strdup_same_case(completion_charp, text);
3387 * This function supports completion with the name of a psql variable.
3388 * The variable names can be prefixed and suffixed with additional text
3389 * to support quoting usages.
3392 complete_from_variables(char *text, const char *prefix, const char *suffix)
3395 int overhead = strlen(prefix) + strlen(suffix) + 1;
3400 struct _variable *ptr;
3402 varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *));
3404 for (ptr = pset.vars->next; ptr; ptr = ptr->next)
3408 if (nvars >= maxvars)
3411 varnames = (char **) realloc(varnames,
3412 (maxvars + 1) * sizeof(char *));
3415 psql_error("out of memory\n");
3420 buffer = (char *) pg_malloc(strlen(ptr->name) + overhead);
3421 sprintf(buffer, "%s%s%s", prefix, ptr->name, suffix);
3422 varnames[nvars++] = buffer;
3425 varnames[nvars] = NULL;
3426 COMPLETE_WITH_LIST_CS((const char * const *) varnames);
3428 for (i = 0; i < nvars; i++)
3437 * This function wraps rl_filename_completion_function() to strip quotes from
3438 * the input before searching for matches and to quote any matches for which
3439 * the consuming command will require it.
3442 complete_from_files(const char *text, int state)
3444 static const char *unquoted_text;
3445 char *unquoted_match;
3450 /* Initialization: stash the unquoted input. */
3451 unquoted_text = strtokx(text, "", NULL, "'", *completion_charp,
3452 false, true, pset.encoding);
3453 /* expect a NULL return for the empty string only */
3456 psql_assert(!*text);
3457 unquoted_text = text;
3461 unquoted_match = filename_completion_function(unquoted_text, state);
3465 * Caller sets completion_charp to a zero- or one-character string
3466 * containing the escape character. This is necessary since \copy has
3467 * no escape character, but every other backslash command recognizes
3468 * "\" as an escape character. Since we have only two callers, don't
3469 * bother providing a macro to simplify this.
3471 ret = quote_if_needed(unquoted_match, " \t\r\n\"`",
3472 '\'', *completion_charp, pset.encoding);
3474 free(unquoted_match);
3476 ret = unquoted_match;
3483 /* HELPER FUNCTIONS */
3487 * Make a pg_strdup copy of s and convert it to the same case as ref.
3490 pg_strdup_same_case(const char *s, const char *ref)
3493 unsigned char first = ref[0];
3499 for (p = ret; *p; p++)
3500 *p = pg_tolower((unsigned char) *p);
3502 for (p = ret; *p; p++)
3503 *p = pg_toupper((unsigned char) *p);
3507 return pg_strdup(s);
3512 * Execute a query and report any errors. This should be the preferred way of
3513 * talking to the database in this file.
3516 exec_query(const char *query)
3520 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
3523 result = PQexec(pset.db, query);
3525 if (PQresultStatus(result) != PGRES_TUPLES_OK)
3528 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
3529 PQerrorMessage(pset.db), query);
3540 * Return the nwords word(s) before point. Words are returned right to left,
3541 * that is, previous_words[0] gets the last word before point.
3542 * If we run out of words, remaining array elements are set to empty strings.
3543 * Each array element is filled with a malloc'd string.
3546 get_previous_words(int point, char **previous_words, int nwords)
3548 const char *buf = rl_line_buffer; /* alias */
3551 /* first we look for a non-word char before the current point */
3552 for (i = point - 1; i >= 0; i--)
3553 if (strchr(WORD_BREAKS, buf[i]))
3557 while (nwords-- > 0)
3563 /* now find the first non-space which then constitutes the end */
3565 for (i = point; i >= 0; i--)
3567 if (!isspace((unsigned char) buf[i]))
3575 * If no end found we return an empty string, because there is no word
3586 * Otherwise we now look for the start. The start is either the
3587 * last character before any word-break character going backwards
3588 * from the end, or it's simply character 0. We also handle open
3589 * quotes and parentheses.
3591 bool inquotes = false;
3592 int parentheses = 0;
3594 for (start = end; start > 0; start--)
3596 if (buf[start] == '"')
3597 inquotes = !inquotes;
3600 if (buf[start] == ')')
3602 else if (buf[start] == '(')
3604 if (--parentheses <= 0)
3607 else if (parentheses == 0 &&
3608 strchr(WORD_BREAKS, buf[start - 1]))
3615 /* make a copy of chars from start to end inclusive */
3616 s = pg_malloc(end - start + 2);
3617 strlcpy(s, &buf[start], end - start + 2);
3620 *previous_words++ = s;
3627 * Surround a string with single quotes. This works for both SQL and
3628 * psql internal. Currently disabled because it is reported not to
3629 * cooperate with certain versions of readline.
3632 quote_file_name(char *text, int match_type, char *quote_pointer)
3637 (void) quote_pointer; /* not used */
3639 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
3640 s = pg_malloc(length);
3642 strcpy(s + 1, text);
3643 if (match_type == SINGLE_MATCH)
3644 s[length - 2] = '\'';
3645 s[length - 1] = '\0';
3650 dequote_file_name(char *text, char quote_char)
3656 return pg_strdup(text);
3658 length = strlen(text);
3659 s = pg_malloc(length - 2 + 1);
3660 strlcpy(s, text +1, length - 2 + 1);
3664 #endif /* NOT_USED */
3666 #endif /* USE_READLINE */