2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2011, 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 */
137 * A few macros to ease typing. You can use these to complete the given
139 * 1) The results from a query you pass it. (Perhaps one of those below?)
140 * 2) The results from a schema query you pass it.
141 * 3) The items from a null-pointer-terminated list.
142 * 4) A string constant.
143 * 5) The list of attributes of the given table (possibly schema-qualified).
145 #define COMPLETE_WITH_QUERY(query) \
147 completion_charp = query; \
148 matches = completion_matches(text, complete_from_query); \
151 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
153 completion_squery = &(query); \
154 completion_charp = addon; \
155 matches = completion_matches(text, complete_from_schema_query); \
158 #define COMPLETE_WITH_LIST(list) \
160 completion_charpp = list; \
161 matches = completion_matches(text, complete_from_list); \
164 #define COMPLETE_WITH_CONST(string) \
166 completion_charp = string; \
167 matches = completion_matches(text, complete_from_const); \
170 #define COMPLETE_WITH_ATTR(relation, addon) \
172 char *_completion_schema; \
173 char *_completion_table; \
175 _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
176 false, false, pset.encoding); \
177 (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
178 false, false, pset.encoding); \
179 _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
180 false, false, pset.encoding); \
181 if (_completion_table == NULL) \
183 completion_charp = Query_for_list_of_attributes addon; \
184 completion_info_charp = relation; \
188 completion_charp = Query_for_list_of_attributes_with_schema addon; \
189 completion_info_charp = _completion_table; \
190 completion_info_charp2 = _completion_schema; \
192 matches = completion_matches(text, complete_from_query); \
196 * Assembly instructions for schema queries
199 static const SchemaQuery Query_for_list_of_aggregates = {
201 "pg_catalog.pg_proc p",
205 "pg_catalog.pg_function_is_visible(p.oid)",
209 "pg_catalog.quote_ident(p.proname)",
214 static const SchemaQuery Query_for_list_of_datatypes = {
216 "pg_catalog.pg_type t",
217 /* selcondition --- ignore table rowtypes and array types */
219 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
220 "AND t.typname !~ '^_'",
222 "pg_catalog.pg_type_is_visible(t.oid)",
226 "pg_catalog.format_type(t.oid, NULL)",
228 "pg_catalog.quote_ident(t.typname)"
231 static const SchemaQuery Query_for_list_of_domains = {
233 "pg_catalog.pg_type t",
237 "pg_catalog.pg_type_is_visible(t.oid)",
241 "pg_catalog.quote_ident(t.typname)",
246 static const SchemaQuery Query_for_list_of_functions = {
248 "pg_catalog.pg_proc p",
252 "pg_catalog.pg_function_is_visible(p.oid)",
256 "pg_catalog.quote_ident(p.proname)",
261 static const SchemaQuery Query_for_list_of_indexes = {
263 "pg_catalog.pg_class c",
265 "c.relkind IN ('i')",
267 "pg_catalog.pg_table_is_visible(c.oid)",
271 "pg_catalog.quote_ident(c.relname)",
276 static const SchemaQuery Query_for_list_of_sequences = {
278 "pg_catalog.pg_class c",
280 "c.relkind IN ('S')",
282 "pg_catalog.pg_table_is_visible(c.oid)",
286 "pg_catalog.quote_ident(c.relname)",
291 static const SchemaQuery Query_for_list_of_tables = {
293 "pg_catalog.pg_class c",
295 "c.relkind IN ('r')",
297 "pg_catalog.pg_table_is_visible(c.oid)",
301 "pg_catalog.quote_ident(c.relname)",
306 /* The bit masks for the following three functions come from
307 * src/include/catalog/pg_trigger.h.
309 static const SchemaQuery Query_for_list_of_insertables = {
311 "pg_catalog.pg_class c",
313 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
314 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))",
316 "pg_catalog.pg_table_is_visible(c.oid)",
320 "pg_catalog.quote_ident(c.relname)",
325 static const SchemaQuery Query_for_list_of_deletables = {
327 "pg_catalog.pg_class c",
329 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
330 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))",
332 "pg_catalog.pg_table_is_visible(c.oid)",
336 "pg_catalog.quote_ident(c.relname)",
341 static const SchemaQuery Query_for_list_of_updatables = {
343 "pg_catalog.pg_class c",
345 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
346 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))",
348 "pg_catalog.pg_table_is_visible(c.oid)",
352 "pg_catalog.quote_ident(c.relname)",
357 static const SchemaQuery Query_for_list_of_tisv = {
359 "pg_catalog.pg_class c",
361 "c.relkind IN ('r', 'i', 'S', 'v')",
363 "pg_catalog.pg_table_is_visible(c.oid)",
367 "pg_catalog.quote_ident(c.relname)",
372 static const SchemaQuery Query_for_list_of_tsv = {
374 "pg_catalog.pg_class c",
376 "c.relkind IN ('r', 'S', 'v')",
378 "pg_catalog.pg_table_is_visible(c.oid)",
382 "pg_catalog.quote_ident(c.relname)",
387 static const SchemaQuery Query_for_list_of_views = {
389 "pg_catalog.pg_class c",
391 "c.relkind IN ('v')",
393 "pg_catalog.pg_table_is_visible(c.oid)",
397 "pg_catalog.quote_ident(c.relname)",
404 * Queries to get lists of names of various kinds of things, possibly
405 * restricted to names matching a partially entered name. In these queries,
406 * the first %s will be replaced by the text entered so far (suitably escaped
407 * to become a SQL literal string). %d will be replaced by the length of the
408 * string (in unescaped form). A second and third %s, if present, will be
409 * replaced by a suitably-escaped version of the string provided in
410 * completion_info_charp. A fourth and fifth %s are similarly replaced by
411 * completion_info_charp2.
413 * Beware that the allowed sequences of %s and %d are determined by
414 * _complete_from_query().
417 #define Query_for_list_of_attributes \
418 "SELECT pg_catalog.quote_ident(attname) "\
419 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
420 " WHERE c.oid = a.attrelid "\
421 " AND a.attnum > 0 "\
422 " AND NOT a.attisdropped "\
423 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
424 " AND (pg_catalog.quote_ident(relname)='%s' "\
425 " OR '\"' || relname || '\"'='%s') "\
426 " AND pg_catalog.pg_table_is_visible(c.oid)"
428 #define Query_for_list_of_attributes_with_schema \
429 "SELECT pg_catalog.quote_ident(attname) "\
430 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
431 " WHERE c.oid = a.attrelid "\
432 " AND n.oid = c.relnamespace "\
433 " AND a.attnum > 0 "\
434 " AND NOT a.attisdropped "\
435 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
436 " AND (pg_catalog.quote_ident(relname)='%s' "\
437 " OR '\"' || relname || '\"' ='%s') "\
438 " AND (pg_catalog.quote_ident(nspname)='%s' "\
439 " OR '\"' || nspname || '\"' ='%s') "
441 #define Query_for_list_of_template_databases \
442 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
443 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
445 #define Query_for_list_of_databases \
446 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
447 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
449 #define Query_for_list_of_tablespaces \
450 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
451 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
453 #define Query_for_list_of_encodings \
454 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
455 " FROM pg_catalog.pg_conversion "\
456 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
458 #define Query_for_list_of_languages \
459 "SELECT pg_catalog.quote_ident(lanname) "\
460 " FROM pg_catalog.pg_language "\
461 " WHERE lanname != 'internal' "\
462 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
464 #define Query_for_list_of_schemas \
465 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
466 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
468 #define Query_for_list_of_set_vars \
470 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
471 " WHERE context IN ('user', 'superuser') "\
472 " UNION ALL SELECT 'constraints' "\
473 " UNION ALL SELECT 'transaction' "\
474 " UNION ALL SELECT 'session' "\
475 " UNION ALL SELECT 'role' "\
476 " UNION ALL SELECT 'tablespace' "\
477 " UNION ALL SELECT 'all') ss "\
478 " WHERE substring(name,1,%d)='%s'"
480 #define Query_for_list_of_show_vars \
482 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
483 " UNION ALL SELECT 'session authorization' "\
484 " UNION ALL SELECT 'all') ss "\
485 " WHERE substring(name,1,%d)='%s'"
487 #define Query_for_list_of_roles \
488 " SELECT pg_catalog.quote_ident(rolname) "\
489 " FROM pg_catalog.pg_roles "\
490 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
492 #define Query_for_list_of_grant_roles \
493 " SELECT pg_catalog.quote_ident(rolname) "\
494 " FROM pg_catalog.pg_roles "\
495 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
496 " UNION ALL SELECT 'PUBLIC'"
498 /* the silly-looking length condition is just to eat up the current word */
499 #define Query_for_table_owning_index \
500 "SELECT pg_catalog.quote_ident(c1.relname) "\
501 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
502 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
503 " and (%d = pg_catalog.length('%s'))"\
504 " and pg_catalog.quote_ident(c2.relname)='%s'"\
505 " and pg_catalog.pg_table_is_visible(c2.oid)"
507 /* the silly-looking length condition is just to eat up the current word */
508 #define Query_for_index_of_table \
509 "SELECT pg_catalog.quote_ident(c2.relname) "\
510 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
511 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
512 " and (%d = pg_catalog.length('%s'))"\
513 " and pg_catalog.quote_ident(c1.relname)='%s'"\
514 " and pg_catalog.pg_table_is_visible(c2.oid)"
516 /* the silly-looking length condition is just to eat up the current word */
517 #define Query_for_list_of_tables_for_trigger \
518 "SELECT pg_catalog.quote_ident(relname) "\
519 " FROM pg_catalog.pg_class"\
520 " WHERE (%d = pg_catalog.length('%s'))"\
522 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
523 " WHERE pg_catalog.quote_ident(tgname)='%s')"
525 #define Query_for_list_of_ts_configurations \
526 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
527 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
529 #define Query_for_list_of_ts_dictionaries \
530 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
531 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
533 #define Query_for_list_of_ts_parsers \
534 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
535 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
537 #define Query_for_list_of_ts_templates \
538 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
539 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
541 #define Query_for_list_of_fdws \
542 " SELECT pg_catalog.quote_ident(fdwname) "\
543 " FROM pg_catalog.pg_foreign_data_wrapper "\
544 " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
546 #define Query_for_list_of_servers \
547 " SELECT pg_catalog.quote_ident(srvname) "\
548 " FROM pg_catalog.pg_foreign_server "\
549 " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
551 #define Query_for_list_of_user_mappings \
552 " SELECT pg_catalog.quote_ident(usename) "\
553 " FROM pg_catalog.pg_user_mappings "\
554 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
556 #define Query_for_list_of_access_methods \
557 " SELECT pg_catalog.quote_ident(amname) "\
558 " FROM pg_catalog.pg_am "\
559 " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
561 #define Query_for_list_of_arguments \
562 " SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
563 " FROM pg_catalog.pg_proc "\
564 " WHERE proname='%s'"
567 * This is a list of all "things" in Pgsql, which can show up after CREATE or
568 * DROP; and there is also a query to get a list of them.
574 const char *query; /* simple query, or NULL */
575 const SchemaQuery *squery; /* schema query, or NULL */
576 const bool noshow; /* NULL or true if this word should not show
577 * up after CREATE or DROP */
580 static const pgsql_thing_t words_after_create[] = {
581 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
582 {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
586 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
587 * to be used only by pg_dump.
589 {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, true},
590 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
591 {"DATABASE", Query_for_list_of_databases},
592 {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, true},
593 {"DOMAIN", NULL, &Query_for_list_of_domains},
594 {"FOREIGN DATA WRAPPER", NULL, NULL},
595 {"FUNCTION", NULL, &Query_for_list_of_functions},
596 {"GROUP", Query_for_list_of_roles},
597 {"LANGUAGE", Query_for_list_of_languages},
598 {"INDEX", NULL, &Query_for_list_of_indexes},
599 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
601 {"PARSER", Query_for_list_of_ts_parsers, NULL, true},
602 {"ROLE", Query_for_list_of_roles},
603 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
604 {"SCHEMA", Query_for_list_of_schemas},
605 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
606 {"SERVER", Query_for_list_of_servers},
607 {"TABLE", NULL, &Query_for_list_of_tables},
608 {"TABLESPACE", Query_for_list_of_tablespaces},
609 {"TEMP", NULL, NULL}, /* for CREATE TEMP TABLE ... */
610 {"TEMPLATE", Query_for_list_of_ts_templates, NULL, true},
611 {"TEXT SEARCH", NULL, NULL},
612 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
613 {"TYPE", NULL, &Query_for_list_of_datatypes},
614 {"UNIQUE", NULL, NULL}, /* for CREATE UNIQUE INDEX ... */
615 {"USER", Query_for_list_of_roles},
616 {"USER MAPPING FOR", NULL, NULL},
617 {"VIEW", NULL, &Query_for_list_of_views},
618 {NULL, NULL, NULL, false} /* end of list */
622 /* Forward declaration of functions */
623 static char **psql_completion(char *text, int start, int end);
624 static char *create_command_generator(const char *text, int state);
625 static char *drop_command_generator(const char *text, int state);
626 static char *complete_from_query(const char *text, int state);
627 static char *complete_from_schema_query(const char *text, int state);
628 static char *_complete_from_query(int is_schema_query,
629 const char *text, int state);
630 static char *complete_from_list(const char *text, int state);
631 static char *complete_from_const(const char *text, int state);
632 static char **complete_from_variables(char *text,
633 const char *prefix, const char *suffix);
635 static PGresult *exec_query(const char *query);
637 static char *previous_word(int point, int skip);
640 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
641 static char *dequote_file_name(char *text, char quote_char);
646 * Initialize the readline library for our purposes.
649 initialize_readline(void)
651 rl_readline_name = (char *) pset.progname;
652 rl_attempted_completion_function = (void *) psql_completion;
654 rl_basic_word_break_characters = WORD_BREAKS;
656 completion_max_records = 1000;
659 * There is a variable rl_completion_query_items for this but apparently
660 * it's not defined everywhere.
666 * The completion function.
668 * According to readline spec this gets passed the text entered so far and its
669 * start and end positions in the readline buffer. The return value is some
670 * partially obscure list format that can be generated by readline's
671 * completion_matches() function, so we don't have to worry about it.
674 psql_completion(char *text, int start, int end)
676 /* This is the variable we'll return. */
677 char **matches = NULL;
679 /* These are going to contain some scannage of the input line. */
686 static const char *const sql_commands[] = {
687 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
688 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
689 "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
690 "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
691 "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
692 "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
693 "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
697 static const char *const backslash_commands[] = {
698 "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
699 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\deu", "\\dew", "\\df",
700 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl",
701 "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
702 "\\e", "\\echo", "\\ef", "\\encoding",
703 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
704 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
705 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
706 "\\set", "\\sf", "\\t", "\\T",
707 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
710 (void) end; /* not used */
712 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
713 rl_completion_append_character = ' ';
716 /* Clear a few things. */
717 completion_charp = NULL;
718 completion_charpp = NULL;
719 completion_info_charp = NULL;
720 completion_info_charp2 = NULL;
723 * Scan the input line before our current position for the last five
724 * words. According to those we'll make some smart decisions on what the
725 * user is probably intending to type. TODO: Use strtokx() to do this.
727 prev_wd = previous_word(start, 0);
728 prev2_wd = previous_word(start, 1);
729 prev3_wd = previous_word(start, 2);
730 prev4_wd = previous_word(start, 3);
731 prev5_wd = previous_word(start, 4);
733 /* If a backslash command was started, continue */
735 COMPLETE_WITH_LIST(backslash_commands);
737 /* If no previous word, suggest one of the basic sql commands */
739 COMPLETE_WITH_LIST(sql_commands);
742 /* complete with something you can create */
743 else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
744 matches = completion_matches(text, create_command_generator);
746 /* DROP, but watch out for DROP embedded in other commands */
747 /* complete with something you can drop */
748 else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
749 pg_strcasecmp(prev2_wd, "DROP") == 0)
750 matches = completion_matches(text, drop_command_generator);
755 * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
756 * in ALTER TABLE sth ALTER
758 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
759 pg_strcasecmp(prev3_wd, "TABLE") != 0)
761 static const char *const list_ALTER[] =
762 {"AGGREGATE", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", "FOREIGN DATA WRAPPER", "FUNCTION",
763 "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR", "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
764 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL};
766 COMPLETE_WITH_LIST(list_ALTER);
768 /* ALTER AGGREGATE,FUNCTION <name> */
769 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
770 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
771 pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
772 COMPLETE_WITH_CONST("(");
773 /* ALTER AGGREGATE,FUNCTION <name> (...) */
774 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
775 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
776 pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
778 if (prev_wd[strlen(prev_wd) - 1] == ')')
780 static const char *const list_ALTERAGG[] =
781 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
783 COMPLETE_WITH_LIST(list_ALTERAGG);
787 char *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
789 sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
790 COMPLETE_WITH_QUERY(tmp_buf);
795 /* ALTER SCHEMA <name> */
796 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
797 pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
799 static const char *const list_ALTERGEN[] =
800 {"OWNER TO", "RENAME TO", NULL};
802 COMPLETE_WITH_LIST(list_ALTERGEN);
805 /* ALTER CONVERSION <name> */
806 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
807 pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
809 static const char *const list_ALTERGEN[] =
810 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
812 COMPLETE_WITH_LIST(list_ALTERGEN);
815 /* ALTER DATABASE <name> */
816 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
817 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
819 static const char *const list_ALTERDATABASE[] =
820 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
822 COMPLETE_WITH_LIST(list_ALTERDATABASE);
825 /* ALTER FOREIGN DATA WRAPPER <name> */
826 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
827 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
828 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
829 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
831 static const char *const list_ALTER_FDW[] =
832 {"VALIDATOR", "OPTIONS", "OWNER TO", NULL};
834 COMPLETE_WITH_LIST(list_ALTER_FDW);
837 /* ALTER INDEX <name> */
838 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
839 pg_strcasecmp(prev2_wd, "INDEX") == 0)
841 static const char *const list_ALTERINDEX[] =
842 {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
844 COMPLETE_WITH_LIST(list_ALTERINDEX);
846 /* ALTER INDEX <name> SET */
847 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
848 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
849 pg_strcasecmp(prev_wd, "SET") == 0)
851 static const char *const list_ALTERINDEXSET[] =
852 {"(", "TABLESPACE", NULL};
854 COMPLETE_WITH_LIST(list_ALTERINDEXSET);
856 /* ALTER INDEX <name> RESET */
857 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
858 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
859 pg_strcasecmp(prev_wd, "RESET") == 0)
860 COMPLETE_WITH_CONST("(");
861 /* ALTER INDEX <foo> SET|RESET ( */
862 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
863 pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
864 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
865 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
866 pg_strcasecmp(prev_wd, "(") == 0)
868 static const char *const list_INDEXOPTIONS[] =
869 {"fillfactor", "fastupdate", NULL};
871 COMPLETE_WITH_LIST(list_INDEXOPTIONS);
874 /* ALTER LANGUAGE <name> */
875 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
876 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
878 static const char *const list_ALTERLANGUAGE[] =
879 {"OWNER TO", "RENAME TO", NULL};
881 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
884 /* ALTER LARGE OBJECT <oid> */
885 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
886 pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
887 pg_strcasecmp(prev2_wd, "OBJECT") == 0)
889 static const char *const list_ALTERLARGEOBJECT[] =
892 COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
895 /* ALTER USER,ROLE <name> */
896 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
897 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
898 (pg_strcasecmp(prev2_wd, "USER") == 0 ||
899 pg_strcasecmp(prev2_wd, "ROLE") == 0))
901 static const char *const list_ALTERUSER[] =
902 {"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
903 "NOCREATEUSER", "CREATEROLE", "NOCREATEROLE", "INHERIT", "NOINHERIT",
904 "LOGIN", "NOLOGIN", "CONNECTION LIMIT", "VALID UNTIL", "RENAME TO",
905 "SUPERUSER", "NOSUPERUSER", "SET", "RESET", NULL};
907 COMPLETE_WITH_LIST(list_ALTERUSER);
910 /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
911 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
912 (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
913 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
915 COMPLETE_WITH_CONST("PASSWORD");
917 /* ALTER DEFAULT PRIVILEGES */
918 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
919 pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
920 pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
922 static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
923 {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
925 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
927 /* ALTER DEFAULT PRIVILEGES FOR */
928 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
929 pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
930 pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
931 pg_strcasecmp(prev_wd, "FOR") == 0)
933 static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
934 {"ROLE", "USER", NULL};
936 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
938 /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
939 else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
940 pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
941 (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
942 pg_strcasecmp(prev3_wd, "IN") == 0))
944 static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
945 {"GRANT", "REVOKE", NULL};
947 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
949 /* ALTER DOMAIN <name> */
950 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
951 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
953 static const char *const list_ALTERDOMAIN[] =
954 {"ADD", "DROP", "OWNER TO", "SET", NULL};
956 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
958 /* ALTER DOMAIN <sth> DROP */
959 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
960 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
961 pg_strcasecmp(prev_wd, "DROP") == 0)
963 static const char *const list_ALTERDOMAIN2[] =
964 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
966 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
968 /* ALTER DOMAIN <sth> SET */
969 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
970 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
971 pg_strcasecmp(prev_wd, "SET") == 0)
973 static const char *const list_ALTERDOMAIN3[] =
974 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
976 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
978 /* ALTER SEQUENCE <name> */
979 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
980 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
982 static const char *const list_ALTERSEQUENCE[] =
983 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
984 "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
986 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
988 /* ALTER SEQUENCE <name> NO */
989 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
990 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
991 pg_strcasecmp(prev_wd, "NO") == 0)
993 static const char *const list_ALTERSEQUENCE2[] =
994 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
996 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
998 /* ALTER SERVER <name> */
999 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1000 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1002 static const char *const list_ALTER_SERVER[] =
1003 {"VERSION", "OPTIONS", "OWNER TO", NULL};
1005 COMPLETE_WITH_LIST(list_ALTER_SERVER);
1007 /* ALTER VIEW <name> */
1008 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1009 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1011 static const char *const list_ALTERVIEW[] =
1012 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1014 COMPLETE_WITH_LIST(list_ALTERVIEW);
1016 /* ALTER TRIGGER <name>, add ON */
1017 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1018 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1019 COMPLETE_WITH_CONST("ON");
1021 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1022 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
1024 completion_info_charp = prev2_wd;
1025 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1029 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1031 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1032 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1033 pg_strcasecmp(prev_wd, "ON") == 0)
1034 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1036 /* ALTER TRIGGER <name> ON <name> */
1037 else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1038 pg_strcasecmp(prev2_wd, "ON") == 0)
1039 COMPLETE_WITH_CONST("RENAME TO");
1042 * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
1043 * RENAME, CLUSTER ON or OWNER
1045 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1046 pg_strcasecmp(prev2_wd, "TABLE") == 0)
1048 static const char *const list_ALTER2[] =
1049 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1050 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET", NULL};
1052 COMPLETE_WITH_LIST(list_ALTER2);
1054 /* ALTER TABLE xxx ENABLE */
1055 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1056 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1057 pg_strcasecmp(prev_wd, "ENABLE") == 0)
1059 static const char *const list_ALTERENABLE[] =
1060 {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
1062 COMPLETE_WITH_LIST(list_ALTERENABLE);
1064 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1065 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1066 (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
1067 pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1069 static const char *const list_ALTERENABLE2[] =
1070 {"RULE", "TRIGGER", NULL};
1072 COMPLETE_WITH_LIST(list_ALTERENABLE2);
1074 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1075 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1076 pg_strcasecmp(prev_wd, "DISABLE") == 0)
1078 static const char *const list_ALTERDISABLE[] =
1079 {"RULE", "TRIGGER", NULL};
1081 COMPLETE_WITH_LIST(list_ALTERDISABLE);
1084 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
1085 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1086 (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
1087 pg_strcasecmp(prev_wd, "RENAME") == 0))
1088 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
1091 * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1094 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1095 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1096 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1097 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1098 COMPLETE_WITH_ATTR(prev3_wd, "");
1100 /* ALTER TABLE xxx RENAME yyy */
1101 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1102 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1103 pg_strcasecmp(prev_wd, "TO") != 0)
1104 COMPLETE_WITH_CONST("TO");
1106 /* ALTER TABLE xxx RENAME COLUMN yyy */
1107 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1108 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1109 pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
1110 pg_strcasecmp(prev_wd, "TO") != 0)
1111 COMPLETE_WITH_CONST("TO");
1113 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1114 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1115 pg_strcasecmp(prev_wd, "DROP") == 0)
1117 static const char *const list_TABLEDROP[] =
1118 {"COLUMN", "CONSTRAINT", NULL};
1120 COMPLETE_WITH_LIST(list_TABLEDROP);
1122 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
1123 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1124 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1125 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1126 COMPLETE_WITH_ATTR(prev3_wd, "");
1127 /* ALTER TABLE ALTER [COLUMN] <foo> */
1128 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1129 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1130 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1131 pg_strcasecmp(prev2_wd, "ALTER") == 0))
1133 static const char *const list_COLUMNALTER[] =
1134 {"TYPE", "SET", "RESET", "DROP", NULL};
1136 COMPLETE_WITH_LIST(list_COLUMNALTER);
1138 /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1139 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1140 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1141 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1142 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1143 pg_strcasecmp(prev_wd, "SET") == 0)
1145 static const char *const list_COLUMNSET[] =
1146 {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1148 COMPLETE_WITH_LIST(list_COLUMNSET);
1150 /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1151 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1152 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1153 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1154 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1155 pg_strcasecmp(prev_wd, "(") == 0)
1157 static const char *const list_COLUMNOPTIONS[] =
1158 {"n_distinct", "n_distinct_inherited", NULL};
1160 COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1162 /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1163 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1164 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1165 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1166 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1167 pg_strcasecmp(prev_wd, "STORAGE") == 0)
1169 static const char *const list_COLUMNSTORAGE[] =
1170 {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1172 COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1174 /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1175 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1176 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1177 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1178 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1179 pg_strcasecmp(prev_wd, "DROP") == 0)
1181 static const char *const list_COLUMNDROP[] =
1182 {"DEFAULT", "NOT NULL", NULL};
1184 COMPLETE_WITH_LIST(list_COLUMNDROP);
1186 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1187 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1188 COMPLETE_WITH_CONST("ON");
1189 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1190 pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1191 pg_strcasecmp(prev_wd, "ON") == 0)
1193 completion_info_charp = prev3_wd;
1194 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1196 /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
1197 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1198 pg_strcasecmp(prev_wd, "SET") == 0)
1200 static const char *const list_TABLESET[] =
1201 {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
1203 COMPLETE_WITH_LIST(list_TABLESET);
1205 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1206 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1207 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1208 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1209 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1210 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1211 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1212 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1213 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1215 static const char *const list_TABLESET2[] =
1216 {"CLUSTER", "OIDS", NULL};
1218 COMPLETE_WITH_LIST(list_TABLESET2);
1220 /* ALTER TABLE <foo> RESET */
1221 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1222 pg_strcasecmp(prev_wd, "RESET") == 0)
1223 COMPLETE_WITH_CONST("(");
1224 /* ALTER TABLE <foo> SET|RESET ( */
1225 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1226 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1227 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1228 pg_strcasecmp(prev_wd, "(") == 0)
1230 static const char *const list_TABLEOPTIONS[] =
1232 "autovacuum_analyze_scale_factor",
1233 "autovacuum_analyze_threshold",
1234 "autovacuum_enabled",
1235 "autovacuum_freeze_max_age",
1236 "autovacuum_freeze_min_age",
1237 "autovacuum_freeze_table_age",
1238 "autovacuum_vacuum_cost_delay",
1239 "autovacuum_vacuum_cost_limit",
1240 "autovacuum_vacuum_scale_factor",
1241 "autovacuum_vacuum_threshold",
1243 "toast.autovacuum_enabled",
1244 "toast.autovacuum_freeze_max_age",
1245 "toast.autovacuum_freeze_min_age",
1246 "toast.autovacuum_freeze_table_age",
1247 "toast.autovacuum_vacuum_cost_delay",
1248 "toast.autovacuum_vacuum_cost_limit",
1249 "toast.autovacuum_vacuum_scale_factor",
1250 "toast.autovacuum_vacuum_threshold",
1254 COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1257 /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1258 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1259 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1261 static const char *const list_ALTERTSPC[] =
1262 {"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1264 COMPLETE_WITH_LIST(list_ALTERTSPC);
1266 /* ALTER TABLESPACE <foo> SET|RESET */
1267 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1268 pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1269 (pg_strcasecmp(prev_wd, "SET") == 0 ||
1270 pg_strcasecmp(prev_wd, "RESET") == 0))
1271 COMPLETE_WITH_CONST("(");
1272 /* ALTER TABLESPACE <foo> SET|RESET ( */
1273 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1274 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1275 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1276 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1277 pg_strcasecmp(prev_wd, "(") == 0)
1279 static const char *const list_TABLESPACEOPTIONS[] =
1280 {"seq_page_cost", "random_page_cost", NULL};
1282 COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1285 /* ALTER TEXT SEARCH */
1286 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1287 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1288 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1290 static const char *const list_ALTERTEXTSEARCH[] =
1291 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1293 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1295 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1296 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1297 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1298 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1299 pg_strcasecmp(prev2_wd, "PARSER") == 0))
1301 static const char *const list_ALTERTEXTSEARCH2[] =
1302 {"RENAME TO", "SET SCHEMA", NULL};
1304 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1307 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1308 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1309 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1310 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1312 static const char *const list_ALTERTEXTSEARCH3[] =
1313 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1315 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1318 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1319 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1320 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1321 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1323 static const char *const list_ALTERTEXTSEARCH4[] =
1324 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1326 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
1329 /* complete ALTER TYPE <foo> with actions */
1330 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1331 pg_strcasecmp(prev2_wd, "TYPE") == 0)
1333 static const char *const list_ALTERTYPE[] =
1334 {"ADD ATTRIBUTE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
1335 "OWNER TO", "RENAME", "SET SCHEMA", NULL};
1337 COMPLETE_WITH_LIST(list_ALTERTYPE);
1339 /* ALTER TYPE <foo> RENAME */
1340 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1341 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1342 pg_strcasecmp(prev_wd, "RENAME") == 0)
1344 static const char *const list_ALTERTYPE[] =
1345 {"ATTRIBUTE", "TO", NULL};
1347 COMPLETE_WITH_LIST(list_ALTERTYPE);
1349 /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */
1350 else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 &&
1351 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1352 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)
1353 COMPLETE_WITH_CONST("TO");
1355 /* If we have TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list of attributes */
1356 else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 &&
1357 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1358 pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1359 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1360 pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0)
1361 COMPLETE_WITH_ATTR(prev3_wd, "");
1362 /* ALTER TYPE ALTER ATTRIBUTE <foo> */
1363 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1364 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0))
1366 COMPLETE_WITH_CONST("TYPE");
1368 /* complete ALTER GROUP <foo> */
1369 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1370 pg_strcasecmp(prev2_wd, "GROUP") == 0)
1372 static const char *const list_ALTERGROUP[] =
1373 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1375 COMPLETE_WITH_LIST(list_ALTERGROUP);
1377 /* complete ALTER GROUP <foo> ADD|DROP with USER */
1378 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1379 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1380 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1381 pg_strcasecmp(prev_wd, "DROP") == 0))
1382 COMPLETE_WITH_CONST("USER");
1383 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1384 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1385 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1386 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1387 pg_strcasecmp(prev_wd, "USER") == 0)
1388 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1390 /* BEGIN, END, ABORT */
1391 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1392 pg_strcasecmp(prev_wd, "END") == 0 ||
1393 pg_strcasecmp(prev_wd, "ABORT") == 0)
1395 static const char *const list_TRANS[] =
1396 {"WORK", "TRANSACTION", NULL};
1398 COMPLETE_WITH_LIST(list_TRANS);
1401 else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1403 static const char *const list_COMMIT[] =
1404 {"WORK", "TRANSACTION", "PREPARED", NULL};
1406 COMPLETE_WITH_LIST(list_COMMIT);
1408 /* RELEASE SAVEPOINT */
1409 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1410 COMPLETE_WITH_CONST("SAVEPOINT");
1412 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1414 static const char *const list_TRANS[] =
1415 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1417 COMPLETE_WITH_LIST(list_TRANS);
1422 * If the previous word is CLUSTER and not without produce list of tables
1424 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1425 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1426 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1427 /* If we have CLUSTER <sth>, then add "USING" */
1428 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1429 pg_strcasecmp(prev_wd, "ON") != 0)
1431 COMPLETE_WITH_CONST("USING");
1435 * If we have CLUSTER <sth> USING, then add the index as well.
1437 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1438 pg_strcasecmp(prev_wd, "USING") == 0)
1440 completion_info_charp = prev2_wd;
1441 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1445 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1446 COMPLETE_WITH_CONST("ON");
1447 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1448 pg_strcasecmp(prev_wd, "ON") == 0)
1450 static const char *const list_COMMENT[] =
1451 {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
1452 "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1453 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1454 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1456 COMPLETE_WITH_LIST(list_COMMENT);
1458 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1459 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1460 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1461 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1463 static const char *const list_TRANS2[] =
1464 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1466 COMPLETE_WITH_LIST(list_TRANS2);
1468 else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1469 pg_strcasecmp(prev3_wd, "ON") == 0) ||
1470 (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1471 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1472 pg_strcasecmp(prev3_wd, "SEARCH") == 0))
1473 COMPLETE_WITH_CONST("IS");
1478 * If we have COPY [BINARY] (which you'd have to type yourself), offer
1479 * list of tables (Also cover the analogous backslash command)
1481 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1482 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1483 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1484 pg_strcasecmp(prev_wd, "BINARY") == 0))
1485 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1486 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1487 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1488 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1489 pg_strcasecmp(prev2_wd, "BINARY") == 0)
1491 static const char *const list_FROMTO[] =
1492 {"FROM", "TO", NULL};
1494 COMPLETE_WITH_LIST(list_FROMTO);
1496 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1497 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1498 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1499 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1500 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1501 pg_strcasecmp(prev_wd, "TO") == 0))
1502 matches = completion_matches(text, filename_completion_function);
1504 /* Handle COPY|BINARY <sth> FROM|TO filename */
1505 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1506 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1507 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1508 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1509 pg_strcasecmp(prev2_wd, "TO") == 0))
1511 static const char *const list_COPY[] =
1512 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", NULL};
1514 COMPLETE_WITH_LIST(list_COPY);
1517 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1518 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1519 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1520 pg_strcasecmp(prev3_wd, "TO") == 0))
1522 static const char *const list_CSV[] =
1523 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
1525 COMPLETE_WITH_LIST(list_CSV);
1528 /* CREATE DATABASE */
1529 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1530 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1532 static const char *const list_DATABASE[] =
1533 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1536 COMPLETE_WITH_LIST(list_DATABASE);
1539 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1540 pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1541 pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1542 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1544 /* CREATE FOREIGN DATA WRAPPER */
1545 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1546 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1547 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1548 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1549 COMPLETE_WITH_CONST("VALIDATOR");
1552 /* First off we complete CREATE UNIQUE with "INDEX" */
1553 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1554 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1555 COMPLETE_WITH_CONST("INDEX");
1556 /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
1557 else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
1558 (pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
1559 pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
1560 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1561 " UNION SELECT 'ON'"
1562 " UNION SELECT 'CONCURRENTLY'");
1563 /* Complete ... INDEX [<name>] ON with a list of tables */
1564 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1565 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1566 pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
1567 pg_strcasecmp(prev_wd, "ON") == 0)
1568 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1569 /* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
1570 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1571 pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
1572 pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
1573 COMPLETE_WITH_CONST("ON");
1574 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
1575 else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1576 pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
1577 pg_strcasecmp(prev2_wd, "INDEX") == 0)
1579 static const char *const list_CREATE_INDEX[] =
1580 {"CONCURRENTLY", "ON", NULL};
1582 COMPLETE_WITH_LIST(list_CREATE_INDEX);
1586 * Complete INDEX <name> ON <table> with a list of table columns (which
1587 * should really be in parens)
1589 else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1590 pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1591 pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
1592 pg_strcasecmp(prev2_wd, "ON") == 0)
1594 static const char *const list_CREATE_INDEX2[] =
1595 {"(", "USING", NULL};
1597 COMPLETE_WITH_LIST(list_CREATE_INDEX2);
1599 else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
1600 pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1601 pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
1602 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1603 pg_strcasecmp(prev_wd, "(") == 0)
1604 COMPLETE_WITH_ATTR(prev2_wd, "");
1605 /* same if you put in USING */
1606 else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1607 pg_strcasecmp(prev3_wd, "USING") == 0 &&
1608 pg_strcasecmp(prev_wd, "(") == 0)
1609 COMPLETE_WITH_ATTR(prev4_wd, "");
1610 /* Complete USING with an index method */
1611 else if (pg_strcasecmp(prev_wd, "USING") == 0)
1612 COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
1613 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1614 pg_strcasecmp(prev2_wd, "USING") == 0)
1615 COMPLETE_WITH_CONST("(");
1618 /* Complete "CREATE RULE <sth>" with "AS" */
1619 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1620 pg_strcasecmp(prev2_wd, "RULE") == 0)
1621 COMPLETE_WITH_CONST("AS");
1622 /* Complete "CREATE RULE <sth> AS with "ON" */
1623 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1624 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1625 pg_strcasecmp(prev_wd, "AS") == 0)
1626 COMPLETE_WITH_CONST("ON");
1627 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1628 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1629 pg_strcasecmp(prev2_wd, "AS") == 0 &&
1630 pg_strcasecmp(prev_wd, "ON") == 0)
1632 static const char *const rule_events[] =
1633 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1635 COMPLETE_WITH_LIST(rule_events);
1637 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1638 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1639 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1640 (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1641 pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1642 COMPLETE_WITH_CONST("TO");
1643 /* Complete "AS ON <sth> TO" with a table name */
1644 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1645 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1646 pg_strcasecmp(prev_wd, "TO") == 0)
1647 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1649 /* CREATE SERVER <name> */
1650 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1651 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1653 static const char *const list_CREATE_SERVER[] =
1654 {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
1656 COMPLETE_WITH_LIST(list_CREATE_SERVER);
1660 /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
1661 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1662 (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
1663 pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
1665 static const char *const list_TEMP[] =
1666 {"SEQUENCE", "TABLE", "VIEW", NULL};
1668 COMPLETE_WITH_LIST(list_TEMP);
1671 /* CREATE TABLESPACE */
1672 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1673 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1675 static const char *const list_CREATETABLESPACE[] =
1676 {"OWNER", "LOCATION", NULL};
1678 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1680 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1681 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1682 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1683 pg_strcasecmp(prev2_wd, "OWNER") == 0)
1685 COMPLETE_WITH_CONST("LOCATION");
1688 /* CREATE TEXT SEARCH */
1689 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1690 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1691 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1693 static const char *const list_CREATETEXTSEARCH[] =
1694 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1696 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
1698 else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1699 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1700 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1701 COMPLETE_WITH_CONST("(");
1703 /* CREATE TRIGGER */
1704 /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1705 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1706 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1708 static const char *const list_CREATETRIGGER[] =
1709 {"BEFORE", "AFTER", "INSTEAD OF", NULL};
1711 COMPLETE_WITH_LIST(list_CREATETRIGGER);
1713 /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
1714 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1715 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1716 (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
1717 pg_strcasecmp(prev_wd, "AFTER") == 0))
1719 static const char *const list_CREATETRIGGER_EVENTS[] =
1720 {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
1722 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
1724 /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1725 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1726 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1727 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1728 pg_strcasecmp(prev2_wd, "AFTER") == 0))
1730 static const char *const list_CREATETRIGGER2[] =
1733 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1737 * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
1740 else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
1741 (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
1742 pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
1743 pg_strcasecmp(prev_wd, "ON") == 0)
1744 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1745 /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
1746 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0)
1747 COMPLETE_WITH_CONST("PROCEDURE");
1749 /* CREATE ROLE,USER,GROUP */
1750 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1751 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1752 (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1753 pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1755 static const char *const list_CREATEROLE[] =
1756 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1757 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOINHERIT", "NOLOGIN", "NOCREATEDB",
1758 "NOCREATEROLE", "NOCREATEUSER", "NOSUPERUSER", "ROLE", "SUPERUSER", "SYSID",
1759 "UNENCRYPTED", NULL};
1761 COMPLETE_WITH_LIST(list_CREATEROLE);
1765 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1768 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1769 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1770 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1771 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1773 COMPLETE_WITH_CONST("PASSWORD");
1775 /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1776 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1777 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1778 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1779 pg_strcasecmp(prev_wd, "IN") == 0)
1781 static const char *const list_CREATEROLE3[] =
1782 {"GROUP", "ROLE", NULL};
1784 COMPLETE_WITH_LIST(list_CREATEROLE3);
1788 /* Complete CREATE VIEW <name> with AS */
1789 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1790 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1791 COMPLETE_WITH_CONST("AS");
1792 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1793 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1794 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1795 pg_strcasecmp(prev_wd, "AS") == 0)
1796 COMPLETE_WITH_CONST("SELECT");
1799 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1801 static const char *const list_DECLARE[] =
1802 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1804 COMPLETE_WITH_LIST(list_DECLARE);
1808 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1810 static const char *const list_DECLARECURSOR[] =
1811 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1813 COMPLETE_WITH_LIST(list_DECLARECURSOR);
1820 * Complete DELETE with FROM (only if the word before that is not "ON"
1821 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1823 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1824 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1825 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1826 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1827 pg_strcasecmp(prev2_wd, "AFTER") == 0))
1828 COMPLETE_WITH_CONST("FROM");
1829 /* Complete DELETE FROM with a list of tables */
1830 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1831 pg_strcasecmp(prev_wd, "FROM") == 0)
1832 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL);
1833 /* Complete DELETE FROM <table> */
1834 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1835 pg_strcasecmp(prev2_wd, "FROM") == 0)
1837 static const char *const list_DELETE[] =
1838 {"USING", "WHERE", "SET", NULL};
1840 COMPLETE_WITH_LIST(list_DELETE);
1842 /* XXX: implement tab completion for DELETE ... USING */
1845 else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
1847 static const char *const list_DISCARD[] =
1848 {"ALL", "PLANS", "TEMP", NULL};
1850 COMPLETE_WITH_LIST(list_DISCARD);
1856 * Complete DO with LANGUAGE.
1858 else if (pg_strcasecmp(prev_wd, "DO") == 0)
1860 static const char *const list_DO[] =
1863 COMPLETE_WITH_LIST(list_DO);
1866 /* DROP (when not the previous word) */
1867 /* DROP AGGREGATE */
1868 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1869 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1870 COMPLETE_WITH_CONST("(");
1872 /* DROP object with CASCADE / RESTRICT */
1873 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1874 (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1875 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1876 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1877 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1878 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1879 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1880 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1881 pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
1882 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1883 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1884 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1885 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1886 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1887 prev_wd[strlen(prev_wd) - 1] == ')') ||
1888 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
1889 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1890 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1891 pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
1892 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
1893 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1894 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1895 (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
1896 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
1897 pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
1898 pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
1901 if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1902 pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
1904 COMPLETE_WITH_CONST("(");
1908 static const char *const list_DROPCR[] =
1909 {"CASCADE", "RESTRICT", NULL};
1911 COMPLETE_WITH_LIST(list_DROPCR);
1914 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1915 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
1916 pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
1917 pg_strcasecmp(prev_wd, "(") == 0)
1919 char *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
1921 sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
1922 COMPLETE_WITH_QUERY(tmp_buf);
1926 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1927 pg_strcasecmp(prev_wd, "OWNED") == 0)
1928 COMPLETE_WITH_CONST("BY");
1929 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1930 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1931 pg_strcasecmp(prev_wd, "BY") == 0)
1932 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1933 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1934 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1935 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1938 static const char *const list_ALTERTEXTSEARCH[] =
1939 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1941 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1947 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1949 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1951 static const char *const list_EXPLAIN[] =
1952 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
1954 COMPLETE_WITH_LIST(list_EXPLAIN);
1956 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1957 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1959 static const char *const list_EXPLAIN[] =
1960 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
1962 COMPLETE_WITH_LIST(list_EXPLAIN);
1964 else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1965 pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
1966 (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
1967 pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
1968 pg_strcasecmp(prev_wd, "VERBOSE") == 0))
1970 static const char *const list_EXPLAIN[] =
1971 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
1973 COMPLETE_WITH_LIST(list_EXPLAIN);
1977 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1978 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1979 pg_strcasecmp(prev_wd, "MOVE") == 0)
1981 static const char *const list_FETCH1[] =
1982 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1984 COMPLETE_WITH_LIST(list_FETCH1);
1986 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1987 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1988 pg_strcasecmp(prev2_wd, "MOVE") == 0)
1990 static const char *const list_FETCH2[] =
1991 {"ALL", "NEXT", "PRIOR", NULL};
1993 COMPLETE_WITH_LIST(list_FETCH2);
1997 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
1998 * but we may as well tab-complete both: perhaps some users prefer one
1999 * variant or the other.
2001 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
2002 pg_strcasecmp(prev3_wd, "MOVE") == 0)
2004 static const char *const list_FROMIN[] =
2005 {"FROM", "IN", NULL};
2007 COMPLETE_WITH_LIST(list_FROMIN);
2010 /* FOREIGN DATA WRAPPER */
2011 /* applies in ALTER/DROP FDW and in CREATE SERVER */
2012 else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
2013 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
2014 pg_strcasecmp(prev2_wd, "DATA") == 0 &&
2015 pg_strcasecmp(prev_wd, "WRAPPER") == 0)
2016 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2018 /* GRANT && REVOKE */
2019 /* Complete GRANT/REVOKE with a list of privileges */
2020 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
2021 pg_strcasecmp(prev_wd, "REVOKE") == 0)
2023 static const char *const list_privilege[] =
2024 {"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
2025 "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
2028 COMPLETE_WITH_LIST(list_privilege);
2030 /* Complete GRANT/REVOKE <sth> with "ON" */
2031 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2032 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
2033 COMPLETE_WITH_CONST("ON");
2036 * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
2039 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
2040 * UNION; seems to work intuitively
2042 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
2043 * here will only work if the privilege list contains exactly one
2046 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
2047 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
2048 pg_strcasecmp(prev_wd, "ON") == 0)
2049 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
2050 " UNION SELECT 'DATABASE'"
2051 " UNION SELECT 'FOREIGN DATA WRAPPER'"
2052 " UNION SELECT 'FOREIGN SERVER'"
2053 " UNION SELECT 'FUNCTION'"
2054 " UNION SELECT 'LANGUAGE'"
2055 " UNION SELECT 'LARGE OBJECT'"
2056 " UNION SELECT 'SCHEMA'"
2057 " UNION SELECT 'TABLESPACE'");
2058 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2059 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2060 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2061 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2063 static const char *const list_privilege_foreign[] =
2064 {"DATA WRAPPER", "SERVER", NULL};
2066 COMPLETE_WITH_LIST(list_privilege_foreign);
2069 /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
2070 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2071 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2072 pg_strcasecmp(prev2_wd, "ON") == 0)
2074 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
2075 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2076 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
2077 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2078 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
2079 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2080 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
2081 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2082 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
2083 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2084 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
2085 COMPLETE_WITH_CONST("TO");
2087 COMPLETE_WITH_CONST("FROM");
2090 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
2091 else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
2092 pg_strcasecmp(prev3_wd, "ON") == 0)
2094 if (pg_strcasecmp(prev_wd, "TO") == 0)
2095 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2097 COMPLETE_WITH_CONST("TO");
2099 else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
2100 pg_strcasecmp(prev3_wd, "ON") == 0)
2102 if (pg_strcasecmp(prev_wd, "FROM") == 0)
2103 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2105 COMPLETE_WITH_CONST("FROM");
2109 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2110 pg_strcasecmp(prev_wd, "GROUP") == 0)
2111 COMPLETE_WITH_CONST("BY");
2114 /* Complete INSERT with "INTO" */
2115 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
2116 COMPLETE_WITH_CONST("INTO");
2117 /* Complete INSERT INTO with table names */
2118 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
2119 pg_strcasecmp(prev_wd, "INTO") == 0)
2120 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL);
2121 /* Complete "INSERT INTO <table> (" with attribute names */
2122 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2123 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2124 pg_strcasecmp(prev_wd, "(") == 0)
2125 COMPLETE_WITH_ATTR(prev2_wd, "");
2128 * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
2129 * "TABLE" or "DEFAULT VALUES"
2131 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
2132 pg_strcasecmp(prev2_wd, "INTO") == 0)
2134 static const char *const list_INSERT[] =
2135 {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
2137 COMPLETE_WITH_LIST(list_INSERT);
2141 * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
2144 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2145 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2146 prev_wd[strlen(prev_wd) - 1] == ')')
2148 static const char *const list_INSERT[] =
2149 {"SELECT", "TABLE", "VALUES", NULL};
2151 COMPLETE_WITH_LIST(list_INSERT);
2154 /* Insert an open parenthesis after "VALUES" */
2155 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
2156 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
2157 COMPLETE_WITH_CONST("(");
2160 /* Complete LOCK [TABLE] with a list of tables */
2161 else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
2162 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2163 " UNION SELECT 'TABLE'");
2164 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2165 pg_strcasecmp(prev2_wd, "LOCK") == 0)
2166 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
2168 /* For the following, handle the case of a single table only for now */
2170 /* Complete LOCK [TABLE] <table> with "IN" */
2171 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
2172 pg_strcasecmp(prev_wd, "TABLE")) ||
2173 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
2174 pg_strcasecmp(prev3_wd, "LOCK") == 0))
2175 COMPLETE_WITH_CONST("IN");
2177 /* Complete LOCK [TABLE] <table> IN with a lock mode */
2178 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
2179 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
2180 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
2181 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
2183 static const char *const lock_modes[] =
2184 {"ACCESS SHARE MODE",
2185 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
2186 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
2187 "SHARE ROW EXCLUSIVE MODE",
2188 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
2190 COMPLETE_WITH_LIST(lock_modes);
2194 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
2195 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'");
2198 else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
2199 COMPLETE_WITH_CONST("(");
2201 /* OWNER TO - complete with available roles */
2202 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
2203 pg_strcasecmp(prev_wd, "TO") == 0)
2204 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2207 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2208 pg_strcasecmp(prev_wd, "ORDER") == 0)
2209 COMPLETE_WITH_CONST("BY");
2210 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
2211 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
2212 pg_strcasecmp(prev_wd, "BY") == 0)
2213 COMPLETE_WITH_ATTR(prev3_wd, "");
2216 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
2217 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
2219 static const char *const list_PREPARE[] =
2220 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2222 COMPLETE_WITH_LIST(list_PREPARE);
2226 * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
2227 * managers, not for manual use in interactive sessions.
2230 /* REASSIGN OWNED BY xxx TO yyy */
2231 else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
2232 COMPLETE_WITH_CONST("OWNED");
2233 else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
2234 pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
2235 COMPLETE_WITH_CONST("BY");
2236 else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
2237 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2238 pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
2239 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2240 else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
2241 pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
2242 pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
2243 COMPLETE_WITH_CONST("TO");
2244 else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
2245 pg_strcasecmp(prev3_wd, "BY") == 0 &&
2246 pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
2247 pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
2248 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2251 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
2253 static const char *const list_REINDEX[] =
2254 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
2256 COMPLETE_WITH_LIST(list_REINDEX);
2258 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
2260 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
2261 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2262 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
2263 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2264 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
2265 pg_strcasecmp(prev_wd, "DATABASE") == 0)
2266 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2269 /* SECURITY LABEL */
2270 else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
2271 COMPLETE_WITH_CONST("LABEL");
2272 else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
2273 pg_strcasecmp(prev_wd, "LABEL") == 0)
2275 static const char *const list_SECURITY_LABEL_preposition[] =
2277 COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
2279 else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
2280 pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
2281 pg_strcasecmp(prev2_wd, "FOR") == 0)
2282 COMPLETE_WITH_CONST("ON");
2283 else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
2284 pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
2285 pg_strcasecmp(prev_wd, "ON") == 0) ||
2286 (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2287 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2288 pg_strcasecmp(prev3_wd, "FOR") == 0 &&
2289 pg_strcasecmp(prev_wd, "ON") == 0))
2291 static const char *const list_SECURITY_LABEL[] =
2292 {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN",
2293 "AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT",
2296 COMPLETE_WITH_LIST(list_SECURITY_LABEL);
2298 else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2299 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2300 pg_strcasecmp(prev3_wd, "ON") == 0)
2301 COMPLETE_WITH_CONST("IS");
2306 /* SET, RESET, SHOW */
2307 /* Complete with a variable name */
2308 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
2309 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
2310 pg_strcasecmp(prev_wd, "RESET") == 0)
2311 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
2312 else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
2313 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
2314 /* Complete "SET TRANSACTION" */
2315 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
2316 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2317 || (pg_strcasecmp(prev2_wd, "START") == 0
2318 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2319 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2320 && pg_strcasecmp(prev_wd, "WORK") == 0)
2321 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2322 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2323 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
2324 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
2325 && pg_strcasecmp(prev2_wd, "AS") == 0
2326 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
2328 static const char *const my_list[] =
2329 {"ISOLATION LEVEL", "READ", NULL};
2331 COMPLETE_WITH_LIST(my_list);
2333 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
2334 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
2335 || pg_strcasecmp(prev3_wd, "START") == 0
2336 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
2337 && pg_strcasecmp(prev3_wd, "AS") == 0))
2338 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
2339 || pg_strcasecmp(prev2_wd, "WORK") == 0)
2340 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
2341 COMPLETE_WITH_CONST("LEVEL");
2342 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
2343 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
2344 || pg_strcasecmp(prev4_wd, "START") == 0
2345 || pg_strcasecmp(prev4_wd, "AS") == 0)
2346 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
2347 || pg_strcasecmp(prev3_wd, "WORK") == 0)
2348 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
2349 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
2351 static const char *const my_list[] =
2352 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
2354 COMPLETE_WITH_LIST(my_list);
2356 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2357 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2358 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2359 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2360 pg_strcasecmp(prev_wd, "READ") == 0)
2362 static const char *const my_list[] =
2363 {"UNCOMMITTED", "COMMITTED", NULL};
2365 COMPLETE_WITH_LIST(my_list);
2367 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2368 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2369 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2370 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2371 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
2372 COMPLETE_WITH_CONST("READ");
2373 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
2374 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
2375 pg_strcasecmp(prev3_wd, "START") == 0 ||
2376 pg_strcasecmp(prev3_wd, "AS") == 0) &&
2377 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
2378 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
2379 pg_strcasecmp(prev_wd, "READ") == 0)
2381 static const char *const my_list[] =
2382 {"ONLY", "WRITE", NULL};
2384 COMPLETE_WITH_LIST(my_list);
2386 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
2387 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2388 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
2390 static const char *const constraint_list[] =
2391 {"DEFERRED", "IMMEDIATE", NULL};
2393 COMPLETE_WITH_LIST(constraint_list);
2395 /* Complete SET ROLE */
2396 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2397 pg_strcasecmp(prev_wd, "ROLE") == 0)
2398 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2399 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
2400 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2401 pg_strcasecmp(prev_wd, "SESSION") == 0)
2403 static const char *const my_list[] =
2404 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
2406 COMPLETE_WITH_LIST(my_list);
2408 /* Complete SET SESSION AUTHORIZATION with username */
2409 else if (pg_strcasecmp(prev3_wd, "SET") == 0
2410 && pg_strcasecmp(prev2_wd, "SESSION") == 0
2411 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
2412 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
2413 /* Complete RESET SESSION with AUTHORIZATION */
2414 else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
2415 pg_strcasecmp(prev_wd, "SESSION") == 0)
2416 COMPLETE_WITH_CONST("AUTHORIZATION");
2417 /* Complete SET <var> with "TO" */
2418 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2419 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
2420 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
2421 pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
2422 prev_wd[strlen(prev_wd) - 1] != ')' &&
2423 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
2424 COMPLETE_WITH_CONST("TO");
2425 /* Suggest possible variable values */
2426 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2427 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
2429 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
2431 static const char *const my_list[] =
2432 {"ISO", "SQL", "Postgres", "German",
2433 "YMD", "DMY", "MDY",
2434 "US", "European", "NonEuropean",
2437 COMPLETE_WITH_LIST(my_list);
2439 else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
2441 static const char *const my_list[] =
2442 {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
2444 COMPLETE_WITH_LIST(my_list);
2446 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
2448 static const char *const my_list[] =
2449 {"ON", "OFF", "DEFAULT", NULL};
2451 COMPLETE_WITH_LIST(my_list);
2455 static const char *const my_list[] =
2458 COMPLETE_WITH_LIST(my_list);
2462 /* START TRANSACTION */
2463 else if (pg_strcasecmp(prev_wd, "START") == 0)
2464 COMPLETE_WITH_CONST("TRANSACTION");
2467 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
2468 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2471 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
2472 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 '*'");
2475 /* If prev. word is UPDATE suggest a list of tables */
2476 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
2477 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
2478 /* Complete UPDATE <table> with "SET" */
2479 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
2480 COMPLETE_WITH_CONST("SET");
2483 * If the previous word is SET (and it wasn't caught above as the _first_
2484 * word) the word before it was (hopefully) a table name and we'll now
2485 * make a list of attributes.
2487 else if (pg_strcasecmp(prev_wd, "SET") == 0)
2488 COMPLETE_WITH_ATTR(prev2_wd, "");
2490 /* UPDATE xx SET yy = */
2491 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2492 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
2493 COMPLETE_WITH_CONST("=");
2496 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
2497 pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2498 pg_strcasecmp(prev3_wd, "DROP") == 0) &&
2499 pg_strcasecmp(prev2_wd, "USER") == 0 &&
2500 pg_strcasecmp(prev_wd, "MAPPING") == 0)
2501 COMPLETE_WITH_CONST("FOR");
2502 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2503 pg_strcasecmp(prev3_wd, "USER") == 0 &&
2504 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2505 pg_strcasecmp(prev_wd, "FOR") == 0)
2506 COMPLETE_WITH_QUERY(Query_for_list_of_roles
2507 " UNION SELECT 'CURRENT_USER'"
2508 " UNION SELECT 'PUBLIC'"
2509 " UNION SELECT 'USER'");
2510 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
2511 pg_strcasecmp(prev4_wd, "DROP") == 0) &&
2512 pg_strcasecmp(prev3_wd, "USER") == 0 &&
2513 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2514 pg_strcasecmp(prev_wd, "FOR") == 0)
2515 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2516 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
2517 pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
2518 pg_strcasecmp(prev5_wd, "DROP") == 0) &&
2519 pg_strcasecmp(prev4_wd, "USER") == 0 &&
2520 pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
2521 pg_strcasecmp(prev2_wd, "FOR") == 0)
2522 COMPLETE_WITH_CONST("SERVER");
2525 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
2526 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
2528 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
2529 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2530 " UNION SELECT 'FULL'"
2531 " UNION SELECT 'FREEZE'"
2532 " UNION SELECT 'ANALYZE'"
2533 " UNION SELECT 'VERBOSE'");
2534 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2535 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
2536 pg_strcasecmp(prev_wd, "FREEZE") == 0))
2537 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2538 " UNION SELECT 'ANALYZE'"
2539 " UNION SELECT 'VERBOSE'");
2540 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2541 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2542 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2543 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2544 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2545 " UNION SELECT 'VERBOSE'");
2546 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2547 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2548 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2549 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2550 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2551 " UNION SELECT 'ANALYZE'");
2552 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2553 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
2554 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2555 " UNION SELECT 'ANALYZE'");
2556 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2557 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2558 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2559 " UNION SELECT 'VERBOSE'");
2560 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2561 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
2562 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2563 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
2564 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2566 /* WITH [RECURSIVE] */
2567 else if (pg_strcasecmp(prev_wd, "WITH") == 0)
2568 COMPLETE_WITH_CONST("RECURSIVE");
2571 /* If the previous word is ANALYZE, produce list of tables */
2572 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2573 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2576 /* Simple case of the word before the where being the table name */
2577 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
2578 COMPLETE_WITH_ATTR(prev2_wd, "");
2581 /* TODO: also include SRF ? */
2582 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
2583 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
2584 pg_strcasecmp(prev3_wd, "\\copy") != 0)
2585 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
2587 /* Backslash commands */
2588 /* TODO: \dc \dd \dl */
2589 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
2590 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2592 else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
2593 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
2594 else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
2595 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2596 else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
2597 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2598 else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
2599 COMPLETE_WITH_QUERY(Query_for_list_of_servers);
2600 else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
2601 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2602 else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
2603 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2605 else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
2606 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2607 else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
2608 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
2609 else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
2610 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
2611 else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
2612 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
2613 /* must be at end of \dF */
2614 else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
2615 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
2617 else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
2618 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2619 else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
2620 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2621 else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0
2622 || strncmp(prev_wd, "\\z", strlen("\\z")) == 0)
2623 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
2624 else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
2625 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
2626 else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
2627 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2628 else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
2629 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2630 else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0
2631 || (strncmp(prev_wd, "\\dg", strlen("\\dg")) == 0))
2632 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2633 else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
2634 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2636 /* must be at end of \d list */
2637 else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
2638 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
2640 else if (strcmp(prev_wd, "\\ef") == 0)
2641 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2643 else if (strcmp(prev_wd, "\\encoding") == 0)
2644 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
2645 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
2646 COMPLETE_WITH_LIST(sql_commands);
2647 else if (strcmp(prev_wd, "\\password") == 0)
2648 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2649 else if (strcmp(prev_wd, "\\pset") == 0)
2651 static const char *const my_list[] =
2652 {"format", "border", "expanded",
2653 "null", "fieldsep", "tuples_only", "title", "tableattr",
2654 "linestyle", "pager", "recordsep", NULL};
2656 COMPLETE_WITH_LIST(my_list);
2658 else if (strcmp(prev_wd, "\\set") == 0)
2660 matches = complete_from_variables(text, "", "");
2662 else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
2663 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2664 else if (strcmp(prev_wd, "\\cd") == 0 ||
2665 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
2666 strcmp(prev_wd, "\\g") == 0 ||
2667 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
2668 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
2669 strcmp(prev_wd, "\\s") == 0 ||
2670 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
2672 matches = completion_matches(text, filename_completion_function);
2674 /* Variable interpolation */
2675 else if (text[0] == ':' && text[1] != ':')
2677 if (text[1] == '\'')
2678 matches = complete_from_variables(text, ":'", "'");
2679 else if (text[1] == '"')
2680 matches = complete_from_variables(text, ":\"", "\"");
2682 matches = complete_from_variables(text, ":", "");
2686 * Finally, we look through the list of "things", such as TABLE, INDEX and
2687 * check if that was the previous word. If so, execute the query to get a
2694 for (i = 0; words_after_create[i].name; i++)
2696 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
2698 if (words_after_create[i].query)
2699 COMPLETE_WITH_QUERY(words_after_create[i].query);
2700 else if (words_after_create[i].squery)
2701 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
2709 * If we still don't have anything to match we have to fabricate some sort
2710 * of default list. If we were to just return NULL, readline automatically
2711 * attempts filename completion, and that's usually no good.
2713 if (matches == NULL)
2715 COMPLETE_WITH_CONST("");
2716 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
2717 rl_completion_append_character = '\0';
2728 /* Return our Grand List O' Matches */
2734 * GENERATOR FUNCTIONS
2736 * These functions do all the actual work of completing the input. They get
2737 * passed the text so far and the count how many times they have been called
2738 * so far with the same text.
2739 * If you read the above carefully, you'll see that these don't get called
2740 * directly but through the readline interface.
2741 * The return value is expected to be the full completion of the text, going
2742 * through a list each time, or NULL if there are no more matches. The string
2743 * will be free()'d by readline, so you must run it through strdup() or
2744 * something of that sort.
2748 * This one gives you one from a list of things you can put after CREATE
2752 create_command_generator(const char *text, int state)
2754 static int list_index,
2758 /* If this is the first time for this completion, init some values */
2762 string_length = strlen(text);
2765 /* find something that matches */
2766 while ((name = words_after_create[list_index++].name))
2768 if ((pg_strncasecmp(name, text, string_length) == 0) &&
2769 !words_after_create[list_index - 1].noshow)
2770 return pg_strdup(name);
2772 /* if nothing matches, return NULL */
2777 * This function gives you a list of things you can put after a DROP command.
2778 * Very similar to create_command_generator, but has an additional entry for
2779 * OWNED BY. (We do it this way in order not to duplicate the
2780 * words_after_create list.)
2783 drop_command_generator(const char *text, int state)
2785 static int list_index,
2791 /* If this is the first time for this completion, init some values */
2793 string_length = strlen(text);
2796 * DROP can be followed by "OWNED BY", which is not found in the list
2797 * for CREATE matches, so make it the first state. (We do not make it
2798 * the last state because it would be more difficult to detect when we
2799 * have to return NULL instead.)
2801 * Make sure we advance to the next state.
2804 if (pg_strncasecmp("OWNED", text, string_length) == 0)
2805 return pg_strdup("OWNED");
2809 * In subsequent attempts, try to complete with the same items we use for
2812 while ((name = words_after_create[list_index++ - 1].name))
2814 if ((pg_strncasecmp(name, text, string_length) == 0) && (!words_after_create[list_index - 2].noshow))
2815 return pg_strdup(name);
2818 /* if nothing matches, return NULL */
2822 /* The following two functions are wrappers for _complete_from_query */
2825 complete_from_query(const char *text, int state)
2827 return _complete_from_query(0, text, state);
2831 complete_from_schema_query(const char *text, int state)
2833 return _complete_from_query(1, text, state);
2838 * This creates a list of matching things, according to a query pointed to
2839 * by completion_charp.
2840 * The query can be one of two kinds:
2842 * 1. A simple query which must contain a %d and a %s, which will be replaced
2843 * by the string length of the text and the text itself. The query may also
2844 * have up to four more %s in it; the first two such will be replaced by the
2845 * value of completion_info_charp, the next two by the value of
2846 * completion_info_charp2.
2848 * 2. A schema query used for completion of both schema and relation names.
2849 * These are more complex and must contain in the following order:
2850 * %d %s %d %s %d %s %s %d %s
2851 * where %d is the string length of the text and %s the text itself.
2853 * It is assumed that strings should be escaped to become SQL literals
2854 * (that is, what is in the query is actually ... '%s' ...)
2856 * See top of file for examples of both kinds of query.
2859 _complete_from_query(int is_schema_query, const char *text, int state)
2861 static int list_index,
2863 static PGresult *result = NULL;
2866 * If this is the first time for this completion, we fetch a list of our
2867 * "things" from the backend.
2871 PQExpBufferData query_buffer;
2874 char *e_info_charp2;
2877 string_length = strlen(text);
2879 /* Free any prior result */
2883 /* Set up suitably-escaped copies of textual inputs */
2884 e_text = pg_malloc(string_length * 2 + 1);
2885 PQescapeString(e_text, text, string_length);
2887 if (completion_info_charp)
2891 charp_len = strlen(completion_info_charp);
2892 e_info_charp = pg_malloc(charp_len * 2 + 1);
2893 PQescapeString(e_info_charp, completion_info_charp,
2897 e_info_charp = NULL;
2899 if (completion_info_charp2)
2903 charp_len = strlen(completion_info_charp2);
2904 e_info_charp2 = pg_malloc(charp_len * 2 + 1);
2905 PQescapeString(e_info_charp2, completion_info_charp2,
2909 e_info_charp2 = NULL;
2911 initPQExpBuffer(&query_buffer);
2913 if (is_schema_query)
2915 /* completion_squery gives us the pieces to assemble */
2916 const char *qualresult = completion_squery->qualresult;
2918 if (qualresult == NULL)
2919 qualresult = completion_squery->result;
2921 /* Get unqualified names matching the input-so-far */
2922 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
2923 completion_squery->result,
2924 completion_squery->catname);
2925 if (completion_squery->selcondition)
2926 appendPQExpBuffer(&query_buffer, "%s AND ",
2927 completion_squery->selcondition);
2928 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
2929 completion_squery->result,
2930 string_length, e_text);
2931 appendPQExpBuffer(&query_buffer, " AND %s",
2932 completion_squery->viscondition);
2935 * When fetching relation names, suppress system catalogs unless
2936 * the input-so-far begins with "pg_". This is a compromise
2937 * between not offering system catalogs for completion at all, and
2938 * having them swamp the result when the input is just "p".
2940 if (strcmp(completion_squery->catname,
2941 "pg_catalog.pg_class c") == 0 &&
2942 strncmp(text, "pg_", 3) !=0)
2944 appendPQExpBuffer(&query_buffer,
2945 " AND c.relnamespace <> (SELECT oid FROM"
2946 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
2950 * Add in matching schema names, but only if there is more than
2951 * one potential match among schema names.
2953 appendPQExpBuffer(&query_buffer, "\nUNION\n"
2954 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
2955 "FROM pg_catalog.pg_namespace n "
2956 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
2957 string_length, e_text);
2958 appendPQExpBuffer(&query_buffer,
2959 " AND (SELECT pg_catalog.count(*)"
2960 " FROM pg_catalog.pg_namespace"
2961 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2962 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
2963 string_length, e_text);
2966 * Add in matching qualified names, but only if there is exactly
2967 * one schema matching the input-so-far.
2969 appendPQExpBuffer(&query_buffer, "\nUNION\n"
2970 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
2971 "FROM %s, pg_catalog.pg_namespace n "
2972 "WHERE %s = n.oid AND ",
2974 completion_squery->catname,
2975 completion_squery->namespace);
2976 if (completion_squery->selcondition)
2977 appendPQExpBuffer(&query_buffer, "%s AND ",
2978 completion_squery->selcondition);
2979 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
2981 string_length, e_text);
2984 * This condition exploits the single-matching-schema rule to
2985 * speed up the query
2987 appendPQExpBuffer(&query_buffer,
2988 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
2989 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
2990 string_length, e_text);
2991 appendPQExpBuffer(&query_buffer,
2992 " AND (SELECT pg_catalog.count(*)"
2993 " FROM pg_catalog.pg_namespace"
2994 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2995 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
2996 string_length, e_text);
2998 /* If an addon query was provided, use it */
2999 if (completion_charp)
3000 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
3004 /* completion_charp is an sprintf-style format string */
3005 appendPQExpBuffer(&query_buffer, completion_charp,
3006 string_length, e_text,
3007 e_info_charp, e_info_charp,
3008 e_info_charp2, e_info_charp2);
3011 /* Limit the number of records in the result */
3012 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
3013 completion_max_records);
3015 result = exec_query(query_buffer.data);
3017 termPQExpBuffer(&query_buffer);
3022 free(e_info_charp2);
3025 /* Find something that matches */
3026 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
3030 while (list_index < PQntuples(result) &&
3031 (item = PQgetvalue(result, list_index++, 0)))
3032 if (pg_strncasecmp(text, item, string_length) == 0)
3033 return pg_strdup(item);
3036 /* If nothing matches, free the db structure and return null */
3044 * This function returns in order one of a fixed, NULL pointer terminated list
3045 * of strings (if matching). This can be used if there are only a fixed number
3046 * SQL words that can appear at certain spot.
3049 complete_from_list(const char *text, int state)
3051 static int string_length,
3054 static bool casesensitive;
3057 /* need to have a list */
3058 psql_assert(completion_charpp);
3060 /* Initialization */
3064 string_length = strlen(text);
3065 casesensitive = true;
3069 while ((item = completion_charpp[list_index++]))
3071 /* First pass is case sensitive */
3072 if (casesensitive && strncmp(text, item, string_length) == 0)
3075 return pg_strdup(item);
3078 /* Second pass is case insensitive, don't bother counting matches */
3079 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
3080 return pg_strdup(item);
3084 * No matches found. If we're not case insensitive already, lets switch to
3085 * being case insensitive and try again
3087 if (casesensitive && matches == 0)
3089 casesensitive = false;
3092 return complete_from_list(text, state);
3095 /* If no more matches, return null. */
3101 * This function returns one fixed string the first time even if it doesn't
3102 * match what's there, and nothing the second time. This should be used if
3103 * there is only one possibility that can appear at a certain spot, so
3104 * misspellings will be overwritten. The string to be passed must be in
3108 complete_from_const(const char *text, int state)
3110 (void) text; /* We don't care about what was entered
3113 psql_assert(completion_charp);
3115 return pg_strdup(completion_charp);
3122 * This function supports completion with the name of a psql variable.
3123 * The variable names can be prefixed and suffixed with additional text
3124 * to support quoting usages.
3127 complete_from_variables(char *text, const char *prefix, const char *suffix)
3130 int overhead = strlen(prefix) + strlen(suffix) + 1;
3131 const char **varnames;
3135 struct _variable *ptr;
3137 varnames = (const char **) pg_malloc((maxvars + 1) * sizeof(char *));
3139 for (ptr = pset.vars->next; ptr; ptr = ptr->next)
3143 if (nvars >= maxvars)
3146 varnames = (const char **) realloc(varnames,
3147 (maxvars + 1) * sizeof(char *));
3150 psql_error("out of memory\n");
3155 buffer = (char *) pg_malloc(strlen(ptr->name) + overhead);
3156 sprintf(buffer, "%s%s%s", prefix, ptr->name, suffix);
3157 varnames[nvars++] = buffer;
3160 varnames[nvars] = NULL;
3161 COMPLETE_WITH_LIST(varnames);
3163 for (i = 0; i < nvars; i++)
3164 free((void *) varnames[i]);
3171 /* HELPER FUNCTIONS */
3175 * Execute a query and report any errors. This should be the preferred way of
3176 * talking to the database in this file.
3179 exec_query(const char *query)
3183 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
3186 result = PQexec(pset.db, query);
3188 if (PQresultStatus(result) != PGRES_TUPLES_OK)
3191 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
3192 PQerrorMessage(pset.db), query);
3203 * Return the word (space delimited) before point. Set skip > 0 to
3204 * skip that many words; e.g. skip=1 finds the word before the
3205 * previous one. Return value is NULL or a malloc'ed string.
3208 previous_word(int point, int skip)
3215 const char *buf = rl_line_buffer; /* alias */
3217 /* first we look for a space or a parenthesis before the current word */
3218 for (i = point - 1; i >= 0; i--)
3219 if (strchr(WORD_BREAKS, buf[i]))
3225 int parentheses = 0;
3227 /* now find the first non-space which then constitutes the end */
3228 for (i = point; i >= 0; i--)
3236 * If no end found we return null, because there is no word before the
3243 * Otherwise we now look for the start. The start is either the last
3244 * character before any space going backwards from the end, or it's
3245 * simply character 0. We also handle open quotes and parentheses.
3247 for (start = end; start > 0; start--)
3249 if (buf[start] == '"')
3250 inquotes = !inquotes;
3253 if (buf[start] == ')')
3255 else if (buf[start] == '(')
3257 if (--parentheses <= 0)
3260 else if (parentheses == 0 &&
3261 strchr(WORD_BREAKS, buf[start - 1]))
3270 s = pg_malloc(end - start + 2);
3271 strlcpy(s, &buf[start], end - start + 2);
3279 * Surround a string with single quotes. This works for both SQL and
3280 * psql internal. Currently disabled because it is reported not to
3281 * cooperate with certain versions of readline.
3284 quote_file_name(char *text, int match_type, char *quote_pointer)
3289 (void) quote_pointer; /* not used */
3291 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
3292 s = pg_malloc(length);
3294 strcpy(s + 1, text);
3295 if (match_type == SINGLE_MATCH)
3296 s[length - 2] = '\'';
3297 s[length - 1] = '\0';
3302 dequote_file_name(char *text, char quote_char)
3308 return pg_strdup(text);
3310 length = strlen(text);
3311 s = pg_malloc(length - 2 + 1);
3312 strlcpy(s, text +1, length - 2 + 1);
3316 #endif /* NOT_USED */
3318 #endif /* USE_READLINE */