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_foreign_tables = {
293 "pg_catalog.pg_class c",
295 "c.relkind IN ('f')",
297 "pg_catalog.pg_table_is_visible(c.oid)",
301 "pg_catalog.quote_ident(c.relname)",
306 static const SchemaQuery Query_for_list_of_tables = {
308 "pg_catalog.pg_class c",
310 "c.relkind IN ('r')",
312 "pg_catalog.pg_table_is_visible(c.oid)",
316 "pg_catalog.quote_ident(c.relname)",
321 /* The bit masks for the following three functions come from
322 * src/include/catalog/pg_trigger.h.
324 static const SchemaQuery Query_for_list_of_insertables = {
326 "pg_catalog.pg_class c",
328 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
329 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))",
331 "pg_catalog.pg_table_is_visible(c.oid)",
335 "pg_catalog.quote_ident(c.relname)",
340 static const SchemaQuery Query_for_list_of_deletables = {
342 "pg_catalog.pg_class c",
344 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
345 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))",
347 "pg_catalog.pg_table_is_visible(c.oid)",
351 "pg_catalog.quote_ident(c.relname)",
356 static const SchemaQuery Query_for_list_of_updatables = {
358 "pg_catalog.pg_class c",
360 "(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
361 "(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))",
363 "pg_catalog.pg_table_is_visible(c.oid)",
367 "pg_catalog.quote_ident(c.relname)",
372 static const SchemaQuery Query_for_list_of_tisvf = {
374 "pg_catalog.pg_class c",
376 "c.relkind IN ('r', 'i', 'S', 'v', 'f')",
378 "pg_catalog.pg_table_is_visible(c.oid)",
382 "pg_catalog.quote_ident(c.relname)",
387 static const SchemaQuery Query_for_list_of_tsvf = {
389 "pg_catalog.pg_class c",
391 "c.relkind IN ('r', 'S', 'v', 'f')",
393 "pg_catalog.pg_table_is_visible(c.oid)",
397 "pg_catalog.quote_ident(c.relname)",
402 static const SchemaQuery Query_for_list_of_views = {
404 "pg_catalog.pg_class c",
406 "c.relkind IN ('v')",
408 "pg_catalog.pg_table_is_visible(c.oid)",
412 "pg_catalog.quote_ident(c.relname)",
419 * Queries to get lists of names of various kinds of things, possibly
420 * restricted to names matching a partially entered name. In these queries,
421 * the first %s will be replaced by the text entered so far (suitably escaped
422 * to become a SQL literal string). %d will be replaced by the length of the
423 * string (in unescaped form). A second and third %s, if present, will be
424 * replaced by a suitably-escaped version of the string provided in
425 * completion_info_charp. A fourth and fifth %s are similarly replaced by
426 * completion_info_charp2.
428 * Beware that the allowed sequences of %s and %d are determined by
429 * _complete_from_query().
432 #define Query_for_list_of_attributes \
433 "SELECT pg_catalog.quote_ident(attname) "\
434 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
435 " WHERE c.oid = a.attrelid "\
436 " AND a.attnum > 0 "\
437 " AND NOT a.attisdropped "\
438 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
439 " AND (pg_catalog.quote_ident(relname)='%s' "\
440 " OR '\"' || relname || '\"'='%s') "\
441 " AND pg_catalog.pg_table_is_visible(c.oid)"
443 #define Query_for_list_of_attributes_with_schema \
444 "SELECT pg_catalog.quote_ident(attname) "\
445 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
446 " WHERE c.oid = a.attrelid "\
447 " AND n.oid = c.relnamespace "\
448 " AND a.attnum > 0 "\
449 " AND NOT a.attisdropped "\
450 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
451 " AND (pg_catalog.quote_ident(relname)='%s' "\
452 " OR '\"' || relname || '\"' ='%s') "\
453 " AND (pg_catalog.quote_ident(nspname)='%s' "\
454 " OR '\"' || nspname || '\"' ='%s') "
456 #define Query_for_list_of_template_databases \
457 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
458 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
460 #define Query_for_list_of_databases \
461 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
462 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
464 #define Query_for_list_of_tablespaces \
465 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
466 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
468 #define Query_for_list_of_encodings \
469 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
470 " FROM pg_catalog.pg_conversion "\
471 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
473 #define Query_for_list_of_languages \
474 "SELECT pg_catalog.quote_ident(lanname) "\
475 " FROM pg_catalog.pg_language "\
476 " WHERE lanname != 'internal' "\
477 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
479 #define Query_for_list_of_schemas \
480 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
481 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
483 #define Query_for_list_of_set_vars \
485 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
486 " WHERE context IN ('user', 'superuser') "\
487 " UNION ALL SELECT 'constraints' "\
488 " UNION ALL SELECT 'transaction' "\
489 " UNION ALL SELECT 'session' "\
490 " UNION ALL SELECT 'role' "\
491 " UNION ALL SELECT 'tablespace' "\
492 " UNION ALL SELECT 'all') ss "\
493 " WHERE substring(name,1,%d)='%s'"
495 #define Query_for_list_of_show_vars \
497 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
498 " UNION ALL SELECT 'session authorization' "\
499 " UNION ALL SELECT 'all') ss "\
500 " WHERE substring(name,1,%d)='%s'"
502 #define Query_for_list_of_roles \
503 " SELECT pg_catalog.quote_ident(rolname) "\
504 " FROM pg_catalog.pg_roles "\
505 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
507 #define Query_for_list_of_grant_roles \
508 " SELECT pg_catalog.quote_ident(rolname) "\
509 " FROM pg_catalog.pg_roles "\
510 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
511 " UNION ALL SELECT 'PUBLIC'"
513 /* the silly-looking length condition is just to eat up the current word */
514 #define Query_for_table_owning_index \
515 "SELECT pg_catalog.quote_ident(c1.relname) "\
516 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
517 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
518 " and (%d = pg_catalog.length('%s'))"\
519 " and pg_catalog.quote_ident(c2.relname)='%s'"\
520 " and pg_catalog.pg_table_is_visible(c2.oid)"
522 /* the silly-looking length condition is just to eat up the current word */
523 #define Query_for_index_of_table \
524 "SELECT pg_catalog.quote_ident(c2.relname) "\
525 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
526 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
527 " and (%d = pg_catalog.length('%s'))"\
528 " and pg_catalog.quote_ident(c1.relname)='%s'"\
529 " and pg_catalog.pg_table_is_visible(c2.oid)"
531 /* the silly-looking length condition is just to eat up the current word */
532 #define Query_for_list_of_tables_for_trigger \
533 "SELECT pg_catalog.quote_ident(relname) "\
534 " FROM pg_catalog.pg_class"\
535 " WHERE (%d = pg_catalog.length('%s'))"\
537 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
538 " WHERE pg_catalog.quote_ident(tgname)='%s')"
540 #define Query_for_list_of_ts_configurations \
541 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
542 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
544 #define Query_for_list_of_ts_dictionaries \
545 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
546 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
548 #define Query_for_list_of_ts_parsers \
549 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
550 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
552 #define Query_for_list_of_ts_templates \
553 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
554 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
556 #define Query_for_list_of_fdws \
557 " SELECT pg_catalog.quote_ident(fdwname) "\
558 " FROM pg_catalog.pg_foreign_data_wrapper "\
559 " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
561 #define Query_for_list_of_servers \
562 " SELECT pg_catalog.quote_ident(srvname) "\
563 " FROM pg_catalog.pg_foreign_server "\
564 " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
566 #define Query_for_list_of_user_mappings \
567 " SELECT pg_catalog.quote_ident(usename) "\
568 " FROM pg_catalog.pg_user_mappings "\
569 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
571 #define Query_for_list_of_access_methods \
572 " SELECT pg_catalog.quote_ident(amname) "\
573 " FROM pg_catalog.pg_am "\
574 " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
576 #define Query_for_list_of_arguments \
577 " SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
578 " FROM pg_catalog.pg_proc "\
579 " WHERE proname='%s'"
581 #define Query_for_list_of_extensions \
582 " SELECT pg_catalog.quote_ident(extname) "\
583 " FROM pg_catalog.pg_extension "\
584 " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
586 #define Query_for_list_of_available_extensions \
587 " SELECT pg_catalog.quote_ident(name) "\
588 " FROM pg_catalog.pg_available_extensions "\
589 " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
592 * This is a list of all "things" in Pgsql, which can show up after CREATE or
593 * DROP; and there is also a query to get a list of them.
599 const char *query; /* simple query, or NULL */
600 const SchemaQuery *squery; /* schema query, or NULL */
601 const bits32 flags; /* visibility flags, see below */
604 #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
605 #define THING_NO_DROP (1 << 1) /* should not show up after DROP */
606 #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
608 static const pgsql_thing_t words_after_create[] = {
609 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
610 {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
612 {"COLLATION", "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding = pg_char_to_encoding(getdatabaseencoding()) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s'"},
615 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
616 * to be used only by pg_dump.
618 {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
619 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
620 {"DATABASE", Query_for_list_of_databases},
621 {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
622 {"DOMAIN", NULL, &Query_for_list_of_domains},
623 {"EXTENSION", Query_for_list_of_extensions},
624 {"FOREIGN DATA WRAPPER", NULL, NULL},
625 {"FOREIGN TABLE", NULL, NULL},
626 {"FUNCTION", NULL, &Query_for_list_of_functions},
627 {"GROUP", Query_for_list_of_roles},
628 {"LANGUAGE", Query_for_list_of_languages},
629 {"INDEX", NULL, &Query_for_list_of_indexes},
630 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
632 {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */
633 {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
634 {"ROLE", Query_for_list_of_roles},
635 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
636 {"SCHEMA", Query_for_list_of_schemas},
637 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
638 {"SERVER", Query_for_list_of_servers},
639 {"TABLE", NULL, &Query_for_list_of_tables},
640 {"TABLESPACE", Query_for_list_of_tablespaces},
641 {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
642 {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
643 {"TEXT SEARCH", NULL, NULL},
644 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
645 {"TYPE", NULL, &Query_for_list_of_datatypes},
646 {"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
647 {"UNLOGGED", NULL, NULL, THING_NO_DROP},/* for CREATE UNLOGGED TABLE ... */
648 {"USER", Query_for_list_of_roles},
649 {"USER MAPPING FOR", NULL, NULL},
650 {"VIEW", NULL, &Query_for_list_of_views},
651 {NULL} /* end of list */
655 /* Forward declaration of functions */
656 static char **psql_completion(char *text, int start, int end);
657 static char *create_command_generator(const char *text, int state);
658 static char *drop_command_generator(const char *text, int state);
659 static char *complete_from_query(const char *text, int state);
660 static char *complete_from_schema_query(const char *text, int state);
661 static char *_complete_from_query(int is_schema_query,
662 const char *text, int state);
663 static char *complete_from_list(const char *text, int state);
664 static char *complete_from_const(const char *text, int state);
665 static char **complete_from_variables(char *text,
666 const char *prefix, const char *suffix);
668 static PGresult *exec_query(const char *query);
670 static char *previous_word(int point, int skip);
673 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
674 static char *dequote_file_name(char *text, char quote_char);
679 * Initialize the readline library for our purposes.
682 initialize_readline(void)
684 rl_readline_name = (char *) pset.progname;
685 rl_attempted_completion_function = (void *) psql_completion;
687 rl_basic_word_break_characters = WORD_BREAKS;
689 completion_max_records = 1000;
692 * There is a variable rl_completion_query_items for this but apparently
693 * it's not defined everywhere.
699 * The completion function.
701 * According to readline spec this gets passed the text entered so far and its
702 * start and end positions in the readline buffer. The return value is some
703 * partially obscure list format that can be generated by readline's
704 * completion_matches() function, so we don't have to worry about it.
707 psql_completion(char *text, int start, int end)
709 /* This is the variable we'll return. */
710 char **matches = NULL;
712 /* These are going to contain some scannage of the input line. */
719 static const char *const sql_commands[] = {
720 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
721 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
722 "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
723 "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
724 "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
725 "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
726 "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
730 static const char *const backslash_commands[] = {
731 "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
732 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df",
733 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
734 "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
735 "\\e", "\\echo", "\\ef", "\\encoding",
736 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
737 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
738 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
739 "\\set", "\\sf", "\\t", "\\T",
740 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
743 (void) end; /* not used */
745 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
746 rl_completion_append_character = ' ';
749 /* Clear a few things. */
750 completion_charp = NULL;
751 completion_charpp = NULL;
752 completion_info_charp = NULL;
753 completion_info_charp2 = NULL;
756 * Scan the input line before our current position for the last five
757 * words. According to those we'll make some smart decisions on what the
758 * user is probably intending to type. TODO: Use strtokx() to do this.
760 prev_wd = previous_word(start, 0);
761 prev2_wd = previous_word(start, 1);
762 prev3_wd = previous_word(start, 2);
763 prev4_wd = previous_word(start, 3);
764 prev5_wd = previous_word(start, 4);
766 /* If a backslash command was started, continue */
768 COMPLETE_WITH_LIST(backslash_commands);
770 /* Variable interpolation */
771 else if (text[0] == ':' && text[1] != ':')
774 matches = complete_from_variables(text, ":'", "'");
775 else if (text[1] == '"')
776 matches = complete_from_variables(text, ":\"", "\"");
778 matches = complete_from_variables(text, ":", "");
781 /* If no previous word, suggest one of the basic sql commands */
783 COMPLETE_WITH_LIST(sql_commands);
786 /* complete with something you can create */
787 else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
788 matches = completion_matches(text, create_command_generator);
790 /* DROP, but watch out for DROP embedded in other commands */
791 /* complete with something you can drop */
792 else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
793 pg_strcasecmp(prev2_wd, "DROP") == 0)
794 matches = completion_matches(text, drop_command_generator);
799 * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
800 * in ALTER TABLE sth ALTER
802 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
803 pg_strcasecmp(prev3_wd, "TABLE") != 0)
805 static const char *const list_ALTER[] =
806 {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
807 "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
808 "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR",
809 "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
810 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
811 "USER", "USER MAPPING FOR", "VIEW", NULL};
813 COMPLETE_WITH_LIST(list_ALTER);
815 /* ALTER AGGREGATE,FUNCTION <name> */
816 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
817 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
818 pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
819 COMPLETE_WITH_CONST("(");
820 /* ALTER AGGREGATE,FUNCTION <name> (...) */
821 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
822 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
823 pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
825 if (prev_wd[strlen(prev_wd) - 1] == ')')
827 static const char *const list_ALTERAGG[] =
828 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
830 COMPLETE_WITH_LIST(list_ALTERAGG);
834 char *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
836 sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
837 COMPLETE_WITH_QUERY(tmp_buf);
842 /* ALTER SCHEMA <name> */
843 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
844 pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
846 static const char *const list_ALTERGEN[] =
847 {"OWNER TO", "RENAME TO", NULL};
849 COMPLETE_WITH_LIST(list_ALTERGEN);
852 /* ALTER COLLATION <name> */
853 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
854 pg_strcasecmp(prev2_wd, "COLLATION") == 0)
856 static const char *const list_ALTERGEN[] =
857 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
859 COMPLETE_WITH_LIST(list_ALTERGEN);
862 /* ALTER CONVERSION <name> */
863 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
864 pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
866 static const char *const list_ALTERGEN[] =
867 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
869 COMPLETE_WITH_LIST(list_ALTERGEN);
872 /* ALTER DATABASE <name> */
873 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
874 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
876 static const char *const list_ALTERDATABASE[] =
877 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
879 COMPLETE_WITH_LIST(list_ALTERDATABASE);
882 /* ALTER EXTENSION <name> */
883 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
884 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
886 static const char *const list_ALTEREXTENSION[] =
887 {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
889 COMPLETE_WITH_LIST(list_ALTEREXTENSION);
893 else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
894 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
896 static const char *const list_ALTER_FOREIGN[] =
897 {"DATA WRAPPER", "TABLE", NULL};
899 COMPLETE_WITH_LIST(list_ALTER_FOREIGN);
902 /* ALTER FOREIGN DATA WRAPPER <name> */
903 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
904 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
905 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
906 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
908 static const char *const list_ALTER_FDW[] =
909 {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
911 COMPLETE_WITH_LIST(list_ALTER_FDW);
914 /* ALTER FOREIGN TABLE <name> */
915 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
916 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
917 pg_strcasecmp(prev2_wd, "TABLE") == 0)
919 static const char *const list_ALTER_FOREIGN_TABLE[] =
920 {"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL};
922 COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
925 /* ALTER INDEX <name> */
926 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
927 pg_strcasecmp(prev2_wd, "INDEX") == 0)
929 static const char *const list_ALTERINDEX[] =
930 {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
932 COMPLETE_WITH_LIST(list_ALTERINDEX);
934 /* ALTER INDEX <name> SET */
935 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
936 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
937 pg_strcasecmp(prev_wd, "SET") == 0)
939 static const char *const list_ALTERINDEXSET[] =
940 {"(", "TABLESPACE", NULL};
942 COMPLETE_WITH_LIST(list_ALTERINDEXSET);
944 /* ALTER INDEX <name> RESET */
945 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
946 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
947 pg_strcasecmp(prev_wd, "RESET") == 0)
948 COMPLETE_WITH_CONST("(");
949 /* ALTER INDEX <foo> SET|RESET ( */
950 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
951 pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
952 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
953 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
954 pg_strcasecmp(prev_wd, "(") == 0)
956 static const char *const list_INDEXOPTIONS[] =
957 {"fillfactor", "fastupdate", NULL};
959 COMPLETE_WITH_LIST(list_INDEXOPTIONS);
962 /* ALTER LANGUAGE <name> */
963 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
964 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
966 static const char *const list_ALTERLANGUAGE[] =
967 {"OWNER TO", "RENAME TO", NULL};
969 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
972 /* ALTER LARGE OBJECT <oid> */
973 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
974 pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
975 pg_strcasecmp(prev2_wd, "OBJECT") == 0)
977 static const char *const list_ALTERLARGEOBJECT[] =
980 COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
983 /* ALTER USER,ROLE <name> */
984 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
985 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
986 (pg_strcasecmp(prev2_wd, "USER") == 0 ||
987 pg_strcasecmp(prev2_wd, "ROLE") == 0))
989 static const char *const list_ALTERUSER[] =
990 {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
991 "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
992 "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
993 "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
994 "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", NULL};
996 COMPLETE_WITH_LIST(list_ALTERUSER);
999 /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
1000 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1001 (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1002 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1004 COMPLETE_WITH_CONST("PASSWORD");
1006 /* ALTER DEFAULT PRIVILEGES */
1007 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1008 pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
1009 pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
1011 static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
1012 {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
1014 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
1016 /* ALTER DEFAULT PRIVILEGES FOR */
1017 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1018 pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
1019 pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
1020 pg_strcasecmp(prev_wd, "FOR") == 0)
1022 static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
1023 {"ROLE", "USER", NULL};
1025 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
1027 /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
1028 else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
1029 pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
1030 (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
1031 pg_strcasecmp(prev3_wd, "IN") == 0))
1033 static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
1034 {"GRANT", "REVOKE", NULL};
1036 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
1038 /* ALTER DOMAIN <name> */
1039 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1040 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
1042 static const char *const list_ALTERDOMAIN[] =
1043 {"ADD", "DROP", "OWNER TO", "SET", NULL};
1045 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1047 /* ALTER DOMAIN <sth> DROP */
1048 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1049 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1050 pg_strcasecmp(prev_wd, "DROP") == 0)
1052 static const char *const list_ALTERDOMAIN2[] =
1053 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
1055 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
1057 /* ALTER DOMAIN <sth> SET */
1058 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1059 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1060 pg_strcasecmp(prev_wd, "SET") == 0)
1062 static const char *const list_ALTERDOMAIN3[] =
1063 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
1065 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
1067 /* ALTER SEQUENCE <name> */
1068 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1069 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
1071 static const char *const list_ALTERSEQUENCE[] =
1072 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
1073 "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
1075 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
1077 /* ALTER SEQUENCE <name> NO */
1078 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1079 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
1080 pg_strcasecmp(prev_wd, "NO") == 0)
1082 static const char *const list_ALTERSEQUENCE2[] =
1083 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
1085 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
1087 /* ALTER SERVER <name> */
1088 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1089 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1091 static const char *const list_ALTER_SERVER[] =
1092 {"VERSION", "OPTIONS", "OWNER TO", NULL};
1094 COMPLETE_WITH_LIST(list_ALTER_SERVER);
1096 /* ALTER VIEW <name> */
1097 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1098 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1100 static const char *const list_ALTERVIEW[] =
1101 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1103 COMPLETE_WITH_LIST(list_ALTERVIEW);
1105 /* ALTER TRIGGER <name>, add ON */
1106 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1107 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1108 COMPLETE_WITH_CONST("ON");
1110 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1111 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
1113 completion_info_charp = prev2_wd;
1114 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1118 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1120 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1121 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1122 pg_strcasecmp(prev_wd, "ON") == 0)
1123 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1125 /* ALTER TRIGGER <name> ON <name> */
1126 else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1127 pg_strcasecmp(prev2_wd, "ON") == 0)
1128 COMPLETE_WITH_CONST("RENAME TO");
1131 * If we detect ALTER TABLE <name>, suggest sub commands
1133 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1134 pg_strcasecmp(prev2_wd, "TABLE") == 0)
1136 static const char *const list_ALTER2[] =
1137 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1138 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
1139 "VALIDATE CONSTRAINT", NULL};
1141 COMPLETE_WITH_LIST(list_ALTER2);
1143 /* ALTER TABLE xxx ENABLE */
1144 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1145 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1146 pg_strcasecmp(prev_wd, "ENABLE") == 0)
1148 static const char *const list_ALTERENABLE[] =
1149 {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
1151 COMPLETE_WITH_LIST(list_ALTERENABLE);
1153 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1154 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1155 (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
1156 pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1158 static const char *const list_ALTERENABLE2[] =
1159 {"RULE", "TRIGGER", NULL};
1161 COMPLETE_WITH_LIST(list_ALTERENABLE2);
1163 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1164 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1165 pg_strcasecmp(prev_wd, "DISABLE") == 0)
1167 static const char *const list_ALTERDISABLE[] =
1168 {"RULE", "TRIGGER", NULL};
1170 COMPLETE_WITH_LIST(list_ALTERDISABLE);
1173 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
1174 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1175 (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
1176 pg_strcasecmp(prev_wd, "RENAME") == 0))
1177 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
1180 * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1183 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1184 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1185 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1186 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1187 COMPLETE_WITH_ATTR(prev3_wd, "");
1189 /* ALTER TABLE xxx RENAME yyy */
1190 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1191 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1192 pg_strcasecmp(prev_wd, "TO") != 0)
1193 COMPLETE_WITH_CONST("TO");
1195 /* ALTER TABLE xxx RENAME COLUMN yyy */
1196 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1197 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1198 pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
1199 pg_strcasecmp(prev_wd, "TO") != 0)
1200 COMPLETE_WITH_CONST("TO");
1202 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1203 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1204 pg_strcasecmp(prev_wd, "DROP") == 0)
1206 static const char *const list_TABLEDROP[] =
1207 {"COLUMN", "CONSTRAINT", NULL};
1209 COMPLETE_WITH_LIST(list_TABLEDROP);
1211 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
1212 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1213 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1214 pg_strcasecmp(prev_wd, "COLUMN") == 0)
1215 COMPLETE_WITH_ATTR(prev3_wd, "");
1216 /* ALTER TABLE ALTER [COLUMN] <foo> */
1217 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1218 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1219 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1220 pg_strcasecmp(prev2_wd, "ALTER") == 0))
1222 static const char *const list_COLUMNALTER[] =
1223 {"TYPE", "SET", "RESET", "DROP", NULL};
1225 COMPLETE_WITH_LIST(list_COLUMNALTER);
1227 /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1228 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1229 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1230 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1231 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1232 pg_strcasecmp(prev_wd, "SET") == 0)
1234 static const char *const list_COLUMNSET[] =
1235 {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1237 COMPLETE_WITH_LIST(list_COLUMNSET);
1239 /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1240 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1241 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1242 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1243 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1244 pg_strcasecmp(prev_wd, "(") == 0)
1246 static const char *const list_COLUMNOPTIONS[] =
1247 {"n_distinct", "n_distinct_inherited", NULL};
1249 COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1251 /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1252 else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1253 pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1254 pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1255 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1256 pg_strcasecmp(prev_wd, "STORAGE") == 0)
1258 static const char *const list_COLUMNSTORAGE[] =
1259 {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1261 COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1263 /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1264 else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1265 pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1266 (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1267 pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1268 pg_strcasecmp(prev_wd, "DROP") == 0)
1270 static const char *const list_COLUMNDROP[] =
1271 {"DEFAULT", "NOT NULL", NULL};
1273 COMPLETE_WITH_LIST(list_COLUMNDROP);
1275 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1276 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1277 COMPLETE_WITH_CONST("ON");
1278 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1279 pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1280 pg_strcasecmp(prev_wd, "ON") == 0)
1282 completion_info_charp = prev3_wd;
1283 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1285 /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
1286 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1287 pg_strcasecmp(prev_wd, "SET") == 0)
1289 static const char *const list_TABLESET[] =
1290 {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
1292 COMPLETE_WITH_LIST(list_TABLESET);
1294 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1295 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1296 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1297 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1298 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1299 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1300 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1301 pg_strcasecmp(prev2_wd, "SET") == 0 &&
1302 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1304 static const char *const list_TABLESET2[] =
1305 {"CLUSTER", "OIDS", NULL};
1307 COMPLETE_WITH_LIST(list_TABLESET2);
1309 /* ALTER TABLE <foo> RESET */
1310 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1311 pg_strcasecmp(prev_wd, "RESET") == 0)
1312 COMPLETE_WITH_CONST("(");
1313 /* ALTER TABLE <foo> SET|RESET ( */
1314 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1315 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1316 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1317 pg_strcasecmp(prev_wd, "(") == 0)
1319 static const char *const list_TABLEOPTIONS[] =
1321 "autovacuum_analyze_scale_factor",
1322 "autovacuum_analyze_threshold",
1323 "autovacuum_enabled",
1324 "autovacuum_freeze_max_age",
1325 "autovacuum_freeze_min_age",
1326 "autovacuum_freeze_table_age",
1327 "autovacuum_vacuum_cost_delay",
1328 "autovacuum_vacuum_cost_limit",
1329 "autovacuum_vacuum_scale_factor",
1330 "autovacuum_vacuum_threshold",
1332 "toast.autovacuum_enabled",
1333 "toast.autovacuum_freeze_max_age",
1334 "toast.autovacuum_freeze_min_age",
1335 "toast.autovacuum_freeze_table_age",
1336 "toast.autovacuum_vacuum_cost_delay",
1337 "toast.autovacuum_vacuum_cost_limit",
1338 "toast.autovacuum_vacuum_scale_factor",
1339 "toast.autovacuum_vacuum_threshold",
1343 COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1346 /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1347 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1348 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1350 static const char *const list_ALTERTSPC[] =
1351 {"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1353 COMPLETE_WITH_LIST(list_ALTERTSPC);
1355 /* ALTER TABLESPACE <foo> SET|RESET */
1356 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1357 pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1358 (pg_strcasecmp(prev_wd, "SET") == 0 ||
1359 pg_strcasecmp(prev_wd, "RESET") == 0))
1360 COMPLETE_WITH_CONST("(");
1361 /* ALTER TABLESPACE <foo> SET|RESET ( */
1362 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1363 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1364 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1365 pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1366 pg_strcasecmp(prev_wd, "(") == 0)
1368 static const char *const list_TABLESPACEOPTIONS[] =
1369 {"seq_page_cost", "random_page_cost", NULL};
1371 COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1374 /* ALTER TEXT SEARCH */
1375 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1376 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1377 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1379 static const char *const list_ALTERTEXTSEARCH[] =
1380 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1382 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1384 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1385 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1386 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1387 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1388 pg_strcasecmp(prev2_wd, "PARSER") == 0))
1390 static const char *const list_ALTERTEXTSEARCH2[] =
1391 {"RENAME TO", "SET SCHEMA", NULL};
1393 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1396 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1397 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1398 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1399 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1401 static const char *const list_ALTERTEXTSEARCH3[] =
1402 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1404 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1407 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1408 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1409 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1410 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1412 static const char *const list_ALTERTEXTSEARCH4[] =
1413 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1415 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
1418 /* complete ALTER TYPE <foo> with actions */
1419 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1420 pg_strcasecmp(prev2_wd, "TYPE") == 0)
1422 static const char *const list_ALTERTYPE[] =
1423 {"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
1424 "OWNER TO", "RENAME", "SET SCHEMA", NULL};
1426 COMPLETE_WITH_LIST(list_ALTERTYPE);
1428 /* complete ALTER TYPE <foo> ADD with actions */
1429 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1430 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1431 pg_strcasecmp(prev_wd, "ADD") == 0)
1433 static const char *const list_ALTERTYPE[] =
1434 {"ATTRIBUTE", "VALUE", NULL};
1436 COMPLETE_WITH_LIST(list_ALTERTYPE);
1438 /* ALTER TYPE <foo> RENAME */
1439 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1440 pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1441 pg_strcasecmp(prev_wd, "RENAME") == 0)
1443 static const char *const list_ALTERTYPE[] =
1444 {"ATTRIBUTE", "TO", NULL};
1446 COMPLETE_WITH_LIST(list_ALTERTYPE);
1448 /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */
1449 else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 &&
1450 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1451 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)
1452 COMPLETE_WITH_CONST("TO");
1454 /* If we have TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list of attributes */
1455 else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 &&
1456 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1457 pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1458 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1459 pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0)
1460 COMPLETE_WITH_ATTR(prev3_wd, "");
1461 /* ALTER TYPE ALTER ATTRIBUTE <foo> */
1462 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1463 pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0))
1465 COMPLETE_WITH_CONST("TYPE");
1467 /* complete ALTER GROUP <foo> */
1468 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1469 pg_strcasecmp(prev2_wd, "GROUP") == 0)
1471 static const char *const list_ALTERGROUP[] =
1472 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1474 COMPLETE_WITH_LIST(list_ALTERGROUP);
1476 /* complete ALTER GROUP <foo> ADD|DROP with USER */
1477 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1478 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1479 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1480 pg_strcasecmp(prev_wd, "DROP") == 0))
1481 COMPLETE_WITH_CONST("USER");
1482 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1483 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1484 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1485 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1486 pg_strcasecmp(prev_wd, "USER") == 0)
1487 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1489 /* BEGIN, END, ABORT */
1490 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1491 pg_strcasecmp(prev_wd, "END") == 0 ||
1492 pg_strcasecmp(prev_wd, "ABORT") == 0)
1494 static const char *const list_TRANS[] =
1495 {"WORK", "TRANSACTION", NULL};
1497 COMPLETE_WITH_LIST(list_TRANS);
1500 else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1502 static const char *const list_COMMIT[] =
1503 {"WORK", "TRANSACTION", "PREPARED", NULL};
1505 COMPLETE_WITH_LIST(list_COMMIT);
1507 /* RELEASE SAVEPOINT */
1508 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1509 COMPLETE_WITH_CONST("SAVEPOINT");
1511 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1513 static const char *const list_TRANS[] =
1514 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1516 COMPLETE_WITH_LIST(list_TRANS);
1521 * If the previous word is CLUSTER and not without produce list of tables
1523 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1524 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1525 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1526 /* If we have CLUSTER <sth>, then add "USING" */
1527 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1528 pg_strcasecmp(prev_wd, "ON") != 0)
1530 COMPLETE_WITH_CONST("USING");
1534 * If we have CLUSTER <sth> USING, then add the index as well.
1536 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1537 pg_strcasecmp(prev_wd, "USING") == 0)
1539 completion_info_charp = prev2_wd;
1540 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1544 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1545 COMPLETE_WITH_CONST("ON");
1546 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1547 pg_strcasecmp(prev_wd, "ON") == 0)
1549 static const char *const list_COMMENT[] =
1550 {"CAST", "COLLATION", "CONVERSION", "DATABASE", "FOREIGN TABLE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
1551 "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1552 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1553 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1555 COMPLETE_WITH_LIST(list_COMMENT);
1557 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1558 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1559 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1560 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1562 static const char *const list_TRANS2[] =
1563 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1565 COMPLETE_WITH_LIST(list_TRANS2);
1567 else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1568 pg_strcasecmp(prev3_wd, "ON") == 0) ||
1569 (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1570 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1571 pg_strcasecmp(prev3_wd, "SEARCH") == 0))
1572 COMPLETE_WITH_CONST("IS");
1577 * If we have COPY [BINARY] (which you'd have to type yourself), offer
1578 * list of tables (Also cover the analogous backslash command)
1580 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1581 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1582 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1583 pg_strcasecmp(prev_wd, "BINARY") == 0))
1584 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1585 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1586 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1587 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1588 pg_strcasecmp(prev2_wd, "BINARY") == 0)
1590 static const char *const list_FROMTO[] =
1591 {"FROM", "TO", NULL};
1593 COMPLETE_WITH_LIST(list_FROMTO);
1595 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1596 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1597 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1598 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1599 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1600 pg_strcasecmp(prev_wd, "TO") == 0))
1601 matches = completion_matches(text, filename_completion_function);
1603 /* Handle COPY|BINARY <sth> FROM|TO filename */
1604 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1605 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1606 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1607 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1608 pg_strcasecmp(prev2_wd, "TO") == 0))
1610 static const char *const list_COPY[] =
1611 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL};
1613 COMPLETE_WITH_LIST(list_COPY);
1616 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1617 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1618 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1619 pg_strcasecmp(prev3_wd, "TO") == 0))
1621 static const char *const list_CSV[] =
1622 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL};
1624 COMPLETE_WITH_LIST(list_CSV);
1627 /* CREATE DATABASE */
1628 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1629 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1631 static const char *const list_DATABASE[] =
1632 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1635 COMPLETE_WITH_LIST(list_DATABASE);
1638 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1639 pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1640 pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1641 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1643 /* CREATE EXTENSION */
1644 /* Complete with available extensions rather than installed ones. */
1645 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1646 pg_strcasecmp(prev_wd, "EXTENSION") == 0)
1647 COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
1648 /* CREATE EXTENSION <name> */
1649 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1650 pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
1651 COMPLETE_WITH_CONST("WITH SCHEMA");
1653 /* CREATE FOREIGN */
1654 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1655 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1657 static const char *const list_CREATE_FOREIGN[] =
1658 {"DATA WRAPPER", "TABLE", NULL};
1660 COMPLETE_WITH_LIST(list_CREATE_FOREIGN);
1663 /* CREATE FOREIGN DATA WRAPPER */
1664 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1665 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1666 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1667 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1669 static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] =
1670 {"HANDLER", "VALIDATOR", NULL};
1672 COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER);
1676 /* First off we complete CREATE UNIQUE with "INDEX" */
1677 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1678 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1679 COMPLETE_WITH_CONST("INDEX");
1680 /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
1681 else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
1682 (pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
1683 pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
1684 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1685 " UNION SELECT 'ON'"
1686 " UNION SELECT 'CONCURRENTLY'");
1687 /* Complete ... INDEX [<name>] ON with a list of tables */
1688 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1689 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1690 pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
1691 pg_strcasecmp(prev_wd, "ON") == 0)
1692 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1693 /* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
1694 else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1695 pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
1696 pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
1697 COMPLETE_WITH_CONST("ON");
1698 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
1699 else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1700 pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
1701 pg_strcasecmp(prev2_wd, "INDEX") == 0)
1703 static const char *const list_CREATE_INDEX[] =
1704 {"CONCURRENTLY", "ON", NULL};
1706 COMPLETE_WITH_LIST(list_CREATE_INDEX);
1710 * Complete INDEX <name> ON <table> with a list of table columns (which
1711 * should really be in parens)
1713 else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1714 pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1715 pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
1716 pg_strcasecmp(prev2_wd, "ON") == 0)
1718 static const char *const list_CREATE_INDEX2[] =
1719 {"(", "USING", NULL};
1721 COMPLETE_WITH_LIST(list_CREATE_INDEX2);
1723 else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
1724 pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1725 pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
1726 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1727 pg_strcasecmp(prev_wd, "(") == 0)
1728 COMPLETE_WITH_ATTR(prev2_wd, "");
1729 /* same if you put in USING */
1730 else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1731 pg_strcasecmp(prev3_wd, "USING") == 0 &&
1732 pg_strcasecmp(prev_wd, "(") == 0)
1733 COMPLETE_WITH_ATTR(prev4_wd, "");
1734 /* Complete USING with an index method */
1735 else if (pg_strcasecmp(prev_wd, "USING") == 0)
1736 COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
1737 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1738 pg_strcasecmp(prev2_wd, "USING") == 0)
1739 COMPLETE_WITH_CONST("(");
1742 /* Complete "CREATE RULE <sth>" with "AS" */
1743 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1744 pg_strcasecmp(prev2_wd, "RULE") == 0)
1745 COMPLETE_WITH_CONST("AS");
1746 /* Complete "CREATE RULE <sth> AS with "ON" */
1747 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1748 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1749 pg_strcasecmp(prev_wd, "AS") == 0)
1750 COMPLETE_WITH_CONST("ON");
1751 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1752 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1753 pg_strcasecmp(prev2_wd, "AS") == 0 &&
1754 pg_strcasecmp(prev_wd, "ON") == 0)
1756 static const char *const rule_events[] =
1757 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1759 COMPLETE_WITH_LIST(rule_events);
1761 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1762 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1763 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1764 (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1765 pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1766 COMPLETE_WITH_CONST("TO");
1767 /* Complete "AS ON <sth> TO" with a table name */
1768 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1769 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1770 pg_strcasecmp(prev_wd, "TO") == 0)
1771 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1773 /* CREATE SERVER <name> */
1774 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1775 pg_strcasecmp(prev2_wd, "SERVER") == 0)
1777 static const char *const list_CREATE_SERVER[] =
1778 {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
1780 COMPLETE_WITH_LIST(list_CREATE_SERVER);
1784 /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
1785 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1786 (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
1787 pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
1789 static const char *const list_TEMP[] =
1790 {"SEQUENCE", "TABLE", "VIEW", NULL};
1792 COMPLETE_WITH_LIST(list_TEMP);
1794 /* Complete "CREATE UNLOGGED" with TABLE */
1795 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1796 pg_strcasecmp(prev_wd, "UNLOGGED") == 0)
1798 COMPLETE_WITH_CONST("TABLE");
1801 /* CREATE TABLESPACE */
1802 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1803 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1805 static const char *const list_CREATETABLESPACE[] =
1806 {"OWNER", "LOCATION", NULL};
1808 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1810 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1811 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1812 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1813 pg_strcasecmp(prev2_wd, "OWNER") == 0)
1815 COMPLETE_WITH_CONST("LOCATION");
1818 /* CREATE TEXT SEARCH */
1819 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1820 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1821 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1823 static const char *const list_CREATETEXTSEARCH[] =
1824 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1826 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
1828 else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1829 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1830 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1831 COMPLETE_WITH_CONST("(");
1833 /* CREATE TRIGGER */
1834 /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1835 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1836 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1838 static const char *const list_CREATETRIGGER[] =
1839 {"BEFORE", "AFTER", "INSTEAD OF", NULL};
1841 COMPLETE_WITH_LIST(list_CREATETRIGGER);
1843 /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
1844 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1845 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1846 (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
1847 pg_strcasecmp(prev_wd, "AFTER") == 0))
1849 static const char *const list_CREATETRIGGER_EVENTS[] =
1850 {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
1852 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
1854 /* complete CREATE TRIGGER <name> INSTEAD OF with an event */
1855 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1856 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1857 pg_strcasecmp(prev2_wd, "INSTEAD") == 0 &&
1858 pg_strcasecmp(prev_wd, "OF") == 0)
1860 static const char *const list_CREATETRIGGER_EVENTS[] =
1861 {"INSERT", "DELETE", "UPDATE", NULL};
1863 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
1865 /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1866 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1867 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1868 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1869 pg_strcasecmp(prev2_wd, "AFTER") == 0)) ||
1870 (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
1871 pg_strcasecmp(prev3_wd, "INSTEAD") == 0 &&
1872 pg_strcasecmp(prev2_wd, "OF") == 0))
1874 static const char *const list_CREATETRIGGER2[] =
1877 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1881 * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
1884 else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
1885 (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
1886 pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
1887 pg_strcasecmp(prev_wd, "ON") == 0)
1888 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1889 /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
1890 else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 &&
1891 pg_strcasecmp(prev3_wd, "OF") == 0 &&
1892 pg_strcasecmp(prev_wd, "ON") == 0)
1893 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
1894 /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
1895 else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0)
1896 COMPLETE_WITH_CONST("PROCEDURE");
1898 /* CREATE ROLE,USER,GROUP */
1899 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1900 !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1901 (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1902 pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1904 static const char *const list_CREATEROLE[] =
1905 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1906 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB",
1907 "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN",
1908 "NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE",
1909 "SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", NULL};
1911 COMPLETE_WITH_LIST(list_CREATEROLE);
1915 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1918 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1919 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1920 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1921 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1923 COMPLETE_WITH_CONST("PASSWORD");
1925 /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1926 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1927 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1928 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1929 pg_strcasecmp(prev_wd, "IN") == 0)
1931 static const char *const list_CREATEROLE3[] =
1932 {"GROUP", "ROLE", NULL};
1934 COMPLETE_WITH_LIST(list_CREATEROLE3);
1938 /* Complete CREATE VIEW <name> with AS */
1939 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1940 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1941 COMPLETE_WITH_CONST("AS");
1942 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1943 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1944 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1945 pg_strcasecmp(prev_wd, "AS") == 0)
1946 COMPLETE_WITH_CONST("SELECT");
1949 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1951 static const char *const list_DECLARE[] =
1952 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1954 COMPLETE_WITH_LIST(list_DECLARE);
1958 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1960 static const char *const list_DECLARECURSOR[] =
1961 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1963 COMPLETE_WITH_LIST(list_DECLARECURSOR);
1970 * Complete DELETE with FROM (only if the word before that is not "ON"
1971 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1973 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1974 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1975 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1976 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1977 pg_strcasecmp(prev2_wd, "AFTER") == 0))
1978 COMPLETE_WITH_CONST("FROM");
1979 /* Complete DELETE FROM with a list of tables */
1980 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1981 pg_strcasecmp(prev_wd, "FROM") == 0)
1982 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL);
1983 /* Complete DELETE FROM <table> */
1984 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1985 pg_strcasecmp(prev2_wd, "FROM") == 0)
1987 static const char *const list_DELETE[] =
1988 {"USING", "WHERE", "SET", NULL};
1990 COMPLETE_WITH_LIST(list_DELETE);
1992 /* XXX: implement tab completion for DELETE ... USING */
1995 else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
1997 static const char *const list_DISCARD[] =
1998 {"ALL", "PLANS", "TEMP", NULL};
2000 COMPLETE_WITH_LIST(list_DISCARD);
2006 * Complete DO with LANGUAGE.
2008 else if (pg_strcasecmp(prev_wd, "DO") == 0)
2010 static const char *const list_DO[] =
2013 COMPLETE_WITH_LIST(list_DO);
2016 /* DROP (when not the previous word) */
2017 /* DROP AGGREGATE */
2018 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2019 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
2020 COMPLETE_WITH_CONST("(");
2022 /* DROP object with CASCADE / RESTRICT */
2023 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2024 (pg_strcasecmp(prev2_wd, "COLLATION") == 0 ||
2025 pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
2026 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
2027 pg_strcasecmp(prev2_wd, "EXTENSION") == 0 ||
2028 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
2029 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2030 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
2031 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
2032 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
2033 pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
2034 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
2035 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
2036 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
2037 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2038 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
2039 prev_wd[strlen(prev_wd) - 1] == ')') ||
2040 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2041 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2042 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2043 pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
2044 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2045 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2046 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2047 (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
2048 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
2049 pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
2050 pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
2053 if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2054 pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
2056 COMPLETE_WITH_CONST("(");
2060 static const char *const list_DROPCR[] =
2061 {"CASCADE", "RESTRICT", NULL};
2063 COMPLETE_WITH_LIST(list_DROPCR);
2066 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2067 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2069 static const char *const drop_CREATE_FOREIGN[] =
2070 {"DATA WRAPPER", "TABLE", NULL};
2072 COMPLETE_WITH_LIST(drop_CREATE_FOREIGN);
2074 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2075 (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
2076 pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
2077 pg_strcasecmp(prev_wd, "(") == 0)
2079 char *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
2081 sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
2082 COMPLETE_WITH_QUERY(tmp_buf);
2086 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2087 pg_strcasecmp(prev_wd, "OWNED") == 0)
2088 COMPLETE_WITH_CONST("BY");
2089 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2090 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2091 pg_strcasecmp(prev_wd, "BY") == 0)
2092 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2093 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2094 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2095 pg_strcasecmp(prev_wd, "SEARCH") == 0)
2098 static const char *const list_ALTERTEXTSEARCH[] =
2099 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2101 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
2107 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2109 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
2111 static const char *const list_EXPLAIN[] =
2112 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
2114 COMPLETE_WITH_LIST(list_EXPLAIN);
2116 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2117 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2119 static const char *const list_EXPLAIN[] =
2120 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
2122 COMPLETE_WITH_LIST(list_EXPLAIN);
2124 else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2125 pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
2126 (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
2127 pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
2128 pg_strcasecmp(prev_wd, "VERBOSE") == 0))
2130 static const char *const list_EXPLAIN[] =
2131 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
2133 COMPLETE_WITH_LIST(list_EXPLAIN);
2137 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
2138 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
2139 pg_strcasecmp(prev_wd, "MOVE") == 0)
2141 static const char *const list_FETCH1[] =
2142 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
2144 COMPLETE_WITH_LIST(list_FETCH1);
2146 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
2147 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
2148 pg_strcasecmp(prev2_wd, "MOVE") == 0)
2150 static const char *const list_FETCH2[] =
2151 {"ALL", "NEXT", "PRIOR", NULL};
2153 COMPLETE_WITH_LIST(list_FETCH2);
2157 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
2158 * but we may as well tab-complete both: perhaps some users prefer one
2159 * variant or the other.
2161 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
2162 pg_strcasecmp(prev3_wd, "MOVE") == 0)
2164 static const char *const list_FROMIN[] =
2165 {"FROM", "IN", NULL};
2167 COMPLETE_WITH_LIST(list_FROMIN);
2170 /* FOREIGN DATA WRAPPER */
2171 /* applies in ALTER/DROP FDW and in CREATE SERVER */
2172 else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
2173 pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
2174 pg_strcasecmp(prev2_wd, "DATA") == 0 &&
2175 pg_strcasecmp(prev_wd, "WRAPPER") == 0)
2176 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2179 else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 &&
2180 pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
2181 pg_strcasecmp(prev_wd, "TABLE") == 0)
2182 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
2184 /* GRANT && REVOKE */
2185 /* Complete GRANT/REVOKE with a list of privileges */
2186 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
2187 pg_strcasecmp(prev_wd, "REVOKE") == 0)
2189 static const char *const list_privilege[] =
2190 {"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
2191 "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
2194 COMPLETE_WITH_LIST(list_privilege);
2196 /* Complete GRANT/REVOKE <sth> with "ON" */
2197 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2198 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
2199 COMPLETE_WITH_CONST("ON");
2202 * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
2205 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
2206 * UNION; seems to work intuitively
2208 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
2209 * here will only work if the privilege list contains exactly one
2212 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
2213 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
2214 pg_strcasecmp(prev_wd, "ON") == 0)
2215 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf,
2216 " UNION SELECT 'DATABASE'"
2217 " UNION SELECT 'FOREIGN DATA WRAPPER'"
2218 " UNION SELECT 'FOREIGN SERVER'"
2219 " UNION SELECT 'FOREIGN TABLE'"
2220 " UNION SELECT 'FUNCTION'"
2221 " UNION SELECT 'LANGUAGE'"
2222 " UNION SELECT 'LARGE OBJECT'"
2223 " UNION SELECT 'SCHEMA'"
2224 " UNION SELECT 'TABLESPACE'");
2225 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2226 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2227 pg_strcasecmp(prev2_wd, "ON") == 0 &&
2228 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2230 static const char *const list_privilege_foreign[] =
2231 {"DATA WRAPPER", "SERVER", "TABLE", NULL};
2233 COMPLETE_WITH_LIST(list_privilege_foreign);
2236 /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
2237 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2238 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2239 pg_strcasecmp(prev2_wd, "ON") == 0)
2241 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
2242 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2243 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
2244 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2245 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
2246 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2247 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
2248 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2249 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
2250 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2251 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
2252 COMPLETE_WITH_CONST("TO");
2254 COMPLETE_WITH_CONST("FROM");
2257 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
2258 else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
2259 pg_strcasecmp(prev3_wd, "ON") == 0)
2261 if (pg_strcasecmp(prev_wd, "TO") == 0)
2262 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2264 COMPLETE_WITH_CONST("TO");
2266 else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
2267 pg_strcasecmp(prev3_wd, "ON") == 0)
2269 if (pg_strcasecmp(prev_wd, "FROM") == 0)
2270 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2272 COMPLETE_WITH_CONST("FROM");
2276 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2277 pg_strcasecmp(prev_wd, "GROUP") == 0)
2278 COMPLETE_WITH_CONST("BY");
2281 /* Complete INSERT with "INTO" */
2282 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
2283 COMPLETE_WITH_CONST("INTO");
2284 /* Complete INSERT INTO with table names */
2285 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
2286 pg_strcasecmp(prev_wd, "INTO") == 0)
2287 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL);
2288 /* Complete "INSERT INTO <table> (" with attribute names */
2289 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2290 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2291 pg_strcasecmp(prev_wd, "(") == 0)
2292 COMPLETE_WITH_ATTR(prev2_wd, "");
2295 * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
2296 * "TABLE" or "DEFAULT VALUES"
2298 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
2299 pg_strcasecmp(prev2_wd, "INTO") == 0)
2301 static const char *const list_INSERT[] =
2302 {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
2304 COMPLETE_WITH_LIST(list_INSERT);
2308 * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
2311 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2312 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2313 prev_wd[strlen(prev_wd) - 1] == ')')
2315 static const char *const list_INSERT[] =
2316 {"SELECT", "TABLE", "VALUES", NULL};
2318 COMPLETE_WITH_LIST(list_INSERT);
2321 /* Insert an open parenthesis after "VALUES" */
2322 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
2323 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
2324 COMPLETE_WITH_CONST("(");
2327 /* Complete LOCK [TABLE] with a list of tables */
2328 else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
2329 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2330 " UNION SELECT 'TABLE'");
2331 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2332 pg_strcasecmp(prev2_wd, "LOCK") == 0)
2333 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
2335 /* For the following, handle the case of a single table only for now */
2337 /* Complete LOCK [TABLE] <table> with "IN" */
2338 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
2339 pg_strcasecmp(prev_wd, "TABLE")) ||
2340 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
2341 pg_strcasecmp(prev3_wd, "LOCK") == 0))
2342 COMPLETE_WITH_CONST("IN");
2344 /* Complete LOCK [TABLE] <table> IN with a lock mode */
2345 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
2346 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
2347 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
2348 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
2350 static const char *const lock_modes[] =
2351 {"ACCESS SHARE MODE",
2352 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
2353 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
2354 "SHARE ROW EXCLUSIVE MODE",
2355 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
2357 COMPLETE_WITH_LIST(lock_modes);
2361 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
2362 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'");
2365 else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
2366 COMPLETE_WITH_CONST("(");
2368 /* OWNER TO - complete with available roles */
2369 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
2370 pg_strcasecmp(prev_wd, "TO") == 0)
2371 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2374 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2375 pg_strcasecmp(prev_wd, "ORDER") == 0)
2376 COMPLETE_WITH_CONST("BY");
2377 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
2378 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
2379 pg_strcasecmp(prev_wd, "BY") == 0)
2380 COMPLETE_WITH_ATTR(prev3_wd, "");
2383 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
2384 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
2386 static const char *const list_PREPARE[] =
2387 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2389 COMPLETE_WITH_LIST(list_PREPARE);
2393 * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
2394 * managers, not for manual use in interactive sessions.
2397 /* REASSIGN OWNED BY xxx TO yyy */
2398 else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
2399 COMPLETE_WITH_CONST("OWNED");
2400 else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
2401 pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
2402 COMPLETE_WITH_CONST("BY");
2403 else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
2404 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2405 pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
2406 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2407 else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
2408 pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
2409 pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
2410 COMPLETE_WITH_CONST("TO");
2411 else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
2412 pg_strcasecmp(prev3_wd, "BY") == 0 &&
2413 pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
2414 pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
2415 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2418 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
2420 static const char *const list_REINDEX[] =
2421 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
2423 COMPLETE_WITH_LIST(list_REINDEX);
2425 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
2427 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
2428 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2429 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
2430 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2431 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
2432 pg_strcasecmp(prev_wd, "DATABASE") == 0)
2433 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2436 /* SECURITY LABEL */
2437 else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
2438 COMPLETE_WITH_CONST("LABEL");
2439 else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
2440 pg_strcasecmp(prev_wd, "LABEL") == 0)
2442 static const char *const list_SECURITY_LABEL_preposition[] =
2444 COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
2446 else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
2447 pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
2448 pg_strcasecmp(prev2_wd, "FOR") == 0)
2449 COMPLETE_WITH_CONST("ON");
2450 else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
2451 pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
2452 pg_strcasecmp(prev_wd, "ON") == 0) ||
2453 (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2454 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2455 pg_strcasecmp(prev3_wd, "FOR") == 0 &&
2456 pg_strcasecmp(prev_wd, "ON") == 0))
2458 static const char *const list_SECURITY_LABEL[] =
2459 {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN",
2460 "AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT",
2463 COMPLETE_WITH_LIST(list_SECURITY_LABEL);
2465 else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2466 pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2467 pg_strcasecmp(prev3_wd, "ON") == 0)
2468 COMPLETE_WITH_CONST("IS");
2473 /* SET, RESET, SHOW */
2474 /* Complete with a variable name */
2475 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
2476 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
2477 pg_strcasecmp(prev_wd, "RESET") == 0)
2478 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
2479 else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
2480 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
2481 /* Complete "SET TRANSACTION" */
2482 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
2483 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2484 || (pg_strcasecmp(prev2_wd, "START") == 0
2485 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2486 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2487 && pg_strcasecmp(prev_wd, "WORK") == 0)
2488 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2489 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2490 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
2491 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
2492 && pg_strcasecmp(prev2_wd, "AS") == 0
2493 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
2495 static const char *const my_list[] =
2496 {"ISOLATION LEVEL", "READ", NULL};
2498 COMPLETE_WITH_LIST(my_list);
2500 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
2501 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
2502 || pg_strcasecmp(prev3_wd, "START") == 0
2503 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
2504 && pg_strcasecmp(prev3_wd, "AS") == 0))
2505 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
2506 || pg_strcasecmp(prev2_wd, "WORK") == 0)
2507 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
2508 COMPLETE_WITH_CONST("LEVEL");
2509 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
2510 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
2511 || pg_strcasecmp(prev4_wd, "START") == 0
2512 || pg_strcasecmp(prev4_wd, "AS") == 0)
2513 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
2514 || pg_strcasecmp(prev3_wd, "WORK") == 0)
2515 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
2516 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
2518 static const char *const my_list[] =
2519 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
2521 COMPLETE_WITH_LIST(my_list);
2523 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2524 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2525 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2526 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2527 pg_strcasecmp(prev_wd, "READ") == 0)
2529 static const char *const my_list[] =
2530 {"UNCOMMITTED", "COMMITTED", NULL};
2532 COMPLETE_WITH_LIST(my_list);
2534 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2535 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2536 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2537 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2538 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
2539 COMPLETE_WITH_CONST("READ");
2540 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
2541 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
2542 pg_strcasecmp(prev3_wd, "START") == 0 ||
2543 pg_strcasecmp(prev3_wd, "AS") == 0) &&
2544 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
2545 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
2546 pg_strcasecmp(prev_wd, "READ") == 0)
2548 static const char *const my_list[] =
2549 {"ONLY", "WRITE", NULL};
2551 COMPLETE_WITH_LIST(my_list);
2553 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
2554 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2555 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
2557 static const char *const constraint_list[] =
2558 {"DEFERRED", "IMMEDIATE", NULL};
2560 COMPLETE_WITH_LIST(constraint_list);
2562 /* Complete SET ROLE */
2563 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2564 pg_strcasecmp(prev_wd, "ROLE") == 0)
2565 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2566 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
2567 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2568 pg_strcasecmp(prev_wd, "SESSION") == 0)
2570 static const char *const my_list[] =
2571 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
2573 COMPLETE_WITH_LIST(my_list);
2575 /* Complete SET SESSION AUTHORIZATION with username */
2576 else if (pg_strcasecmp(prev3_wd, "SET") == 0
2577 && pg_strcasecmp(prev2_wd, "SESSION") == 0
2578 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
2579 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
2580 /* Complete RESET SESSION with AUTHORIZATION */
2581 else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
2582 pg_strcasecmp(prev_wd, "SESSION") == 0)
2583 COMPLETE_WITH_CONST("AUTHORIZATION");
2584 /* Complete SET <var> with "TO" */
2585 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2586 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
2587 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
2588 pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
2589 prev_wd[strlen(prev_wd) - 1] != ')' &&
2590 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
2591 COMPLETE_WITH_CONST("TO");
2592 /* Suggest possible variable values */
2593 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2594 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
2596 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
2598 static const char *const my_list[] =
2599 {"ISO", "SQL", "Postgres", "German",
2600 "YMD", "DMY", "MDY",
2601 "US", "European", "NonEuropean",
2604 COMPLETE_WITH_LIST(my_list);
2606 else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
2608 static const char *const my_list[] =
2609 {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
2611 COMPLETE_WITH_LIST(my_list);
2613 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
2615 static const char *const my_list[] =
2616 {"ON", "OFF", "DEFAULT", NULL};
2618 COMPLETE_WITH_LIST(my_list);
2622 static const char *const my_list[] =
2625 COMPLETE_WITH_LIST(my_list);
2629 /* START TRANSACTION */
2630 else if (pg_strcasecmp(prev_wd, "START") == 0)
2631 COMPLETE_WITH_CONST("TRANSACTION");
2634 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
2635 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2638 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
2639 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 '*'");
2642 /* If prev. word is UPDATE suggest a list of tables */
2643 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
2644 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
2645 /* Complete UPDATE <table> with "SET" */
2646 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
2647 COMPLETE_WITH_CONST("SET");
2650 * If the previous word is SET (and it wasn't caught above as the _first_
2651 * word) the word before it was (hopefully) a table name and we'll now
2652 * make a list of attributes.
2654 else if (pg_strcasecmp(prev_wd, "SET") == 0)
2655 COMPLETE_WITH_ATTR(prev2_wd, "");
2657 /* UPDATE xx SET yy = */
2658 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2659 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
2660 COMPLETE_WITH_CONST("=");
2663 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
2664 pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2665 pg_strcasecmp(prev3_wd, "DROP") == 0) &&
2666 pg_strcasecmp(prev2_wd, "USER") == 0 &&
2667 pg_strcasecmp(prev_wd, "MAPPING") == 0)
2668 COMPLETE_WITH_CONST("FOR");
2669 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2670 pg_strcasecmp(prev3_wd, "USER") == 0 &&
2671 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2672 pg_strcasecmp(prev_wd, "FOR") == 0)
2673 COMPLETE_WITH_QUERY(Query_for_list_of_roles
2674 " UNION SELECT 'CURRENT_USER'"
2675 " UNION SELECT 'PUBLIC'"
2676 " UNION SELECT 'USER'");
2677 else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
2678 pg_strcasecmp(prev4_wd, "DROP") == 0) &&
2679 pg_strcasecmp(prev3_wd, "USER") == 0 &&
2680 pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2681 pg_strcasecmp(prev_wd, "FOR") == 0)
2682 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2683 else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
2684 pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
2685 pg_strcasecmp(prev5_wd, "DROP") == 0) &&
2686 pg_strcasecmp(prev4_wd, "USER") == 0 &&
2687 pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
2688 pg_strcasecmp(prev2_wd, "FOR") == 0)
2689 COMPLETE_WITH_CONST("SERVER");
2692 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
2693 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
2695 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
2696 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2697 " UNION SELECT 'FULL'"
2698 " UNION SELECT 'FREEZE'"
2699 " UNION SELECT 'ANALYZE'"
2700 " UNION SELECT 'VERBOSE'");
2701 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2702 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
2703 pg_strcasecmp(prev_wd, "FREEZE") == 0))
2704 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2705 " UNION SELECT 'ANALYZE'"
2706 " UNION SELECT 'VERBOSE'");
2707 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2708 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2709 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2710 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2711 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2712 " UNION SELECT 'VERBOSE'");
2713 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2714 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2715 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2716 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2717 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2718 " UNION SELECT 'ANALYZE'");
2719 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2720 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
2721 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2722 " UNION SELECT 'ANALYZE'");
2723 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2724 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2725 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2726 " UNION SELECT 'VERBOSE'");
2727 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2728 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
2729 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2730 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
2731 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2733 /* WITH [RECURSIVE] */
2734 else if (pg_strcasecmp(prev_wd, "WITH") == 0)
2735 COMPLETE_WITH_CONST("RECURSIVE");
2738 /* If the previous word is ANALYZE, produce list of tables */
2739 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2740 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2743 /* Simple case of the word before the where being the table name */
2744 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
2745 COMPLETE_WITH_ATTR(prev2_wd, "");
2748 /* TODO: also include SRF ? */
2749 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
2750 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
2751 pg_strcasecmp(prev3_wd, "\\copy") != 0)
2752 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2754 /* Backslash commands */
2755 /* TODO: \dc \dd \dl */
2756 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
2757 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2759 else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
2760 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
2761 else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
2762 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2763 else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
2764 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2765 else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
2766 COMPLETE_WITH_QUERY(Query_for_list_of_servers);
2767 else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
2768 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2769 else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
2770 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2772 else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
2773 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2774 else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
2775 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
2776 else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
2777 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
2778 else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
2779 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
2780 /* must be at end of \dF */
2781 else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
2782 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
2784 else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
2785 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2786 else if (strncmp(prev_wd, "\\dL", strlen("\\dL")) == 0)
2787 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2788 else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
2789 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2790 else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0
2791 || strncmp(prev_wd, "\\z", strlen("\\z")) == 0)
2792 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2793 else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
2794 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
2795 else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
2796 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2797 else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
2798 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2799 else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0
2800 || (strncmp(prev_wd, "\\dg", strlen("\\dg")) == 0))
2801 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2802 else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
2803 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2805 /* must be at end of \d list */
2806 else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
2807 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisvf, NULL);
2809 else if (strcmp(prev_wd, "\\ef") == 0)
2810 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2812 else if (strcmp(prev_wd, "\\encoding") == 0)
2813 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
2814 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
2815 COMPLETE_WITH_LIST(sql_commands);
2816 else if (strcmp(prev_wd, "\\password") == 0)
2817 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2818 else if (strcmp(prev_wd, "\\pset") == 0)
2820 static const char *const my_list[] =
2821 {"format", "border", "expanded",
2822 "null", "fieldsep", "tuples_only", "title", "tableattr",
2823 "linestyle", "pager", "recordsep", NULL};
2825 COMPLETE_WITH_LIST(my_list);
2827 else if (strcmp(prev_wd, "\\set") == 0)
2829 matches = complete_from_variables(text, "", "");
2831 else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
2832 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2833 else if (strcmp(prev_wd, "\\cd") == 0 ||
2834 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
2835 strcmp(prev_wd, "\\g") == 0 ||
2836 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
2837 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
2838 strcmp(prev_wd, "\\s") == 0 ||
2839 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
2841 matches = completion_matches(text, filename_completion_function);
2844 * Finally, we look through the list of "things", such as TABLE, INDEX and
2845 * check if that was the previous word. If so, execute the query to get a
2852 for (i = 0; words_after_create[i].name; i++)
2854 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
2856 if (words_after_create[i].query)
2857 COMPLETE_WITH_QUERY(words_after_create[i].query);
2858 else if (words_after_create[i].squery)
2859 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
2867 * If we still don't have anything to match we have to fabricate some sort
2868 * of default list. If we were to just return NULL, readline automatically
2869 * attempts filename completion, and that's usually no good.
2871 if (matches == NULL)
2873 COMPLETE_WITH_CONST("");
2874 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
2875 rl_completion_append_character = '\0';
2886 /* Return our Grand List O' Matches */
2892 * GENERATOR FUNCTIONS
2894 * These functions do all the actual work of completing the input. They get
2895 * passed the text so far and the count how many times they have been called
2896 * so far with the same text.
2897 * If you read the above carefully, you'll see that these don't get called
2898 * directly but through the readline interface.
2899 * The return value is expected to be the full completion of the text, going
2900 * through a list each time, or NULL if there are no more matches. The string
2901 * will be free()'d by readline, so you must run it through strdup() or
2902 * something of that sort.
2906 * Common routine for create_command_generator and drop_command_generator.
2907 * Entries that have 'excluded' flags are not returned.
2910 create_or_drop_command_generator(const char *text, int state, bits32 excluded)
2912 static int list_index,
2916 /* If this is the first time for this completion, init some values */
2920 string_length = strlen(text);
2923 /* find something that matches */
2924 while ((name = words_after_create[list_index++].name))
2926 if ((pg_strncasecmp(name, text, string_length) == 0) &&
2927 !(words_after_create[list_index - 1].flags & excluded))
2928 return pg_strdup(name);
2930 /* if nothing matches, return NULL */
2935 * This one gives you one from a list of things you can put after CREATE
2939 create_command_generator(const char *text, int state)
2941 return create_or_drop_command_generator(text, state, THING_NO_CREATE);
2945 * This function gives you a list of things you can put after a DROP command.
2948 drop_command_generator(const char *text, int state)
2950 return create_or_drop_command_generator(text, state, THING_NO_DROP);
2953 /* The following two functions are wrappers for _complete_from_query */
2956 complete_from_query(const char *text, int state)
2958 return _complete_from_query(0, text, state);
2962 complete_from_schema_query(const char *text, int state)
2964 return _complete_from_query(1, text, state);
2969 * This creates a list of matching things, according to a query pointed to
2970 * by completion_charp.
2971 * The query can be one of two kinds:
2973 * 1. A simple query which must contain a %d and a %s, which will be replaced
2974 * by the string length of the text and the text itself. The query may also
2975 * have up to four more %s in it; the first two such will be replaced by the
2976 * value of completion_info_charp, the next two by the value of
2977 * completion_info_charp2.
2979 * 2. A schema query used for completion of both schema and relation names.
2980 * These are more complex and must contain in the following order:
2981 * %d %s %d %s %d %s %s %d %s
2982 * where %d is the string length of the text and %s the text itself.
2984 * It is assumed that strings should be escaped to become SQL literals
2985 * (that is, what is in the query is actually ... '%s' ...)
2987 * See top of file for examples of both kinds of query.
2990 _complete_from_query(int is_schema_query, const char *text, int state)
2992 static int list_index,
2994 static PGresult *result = NULL;
2997 * If this is the first time for this completion, we fetch a list of our
2998 * "things" from the backend.
3002 PQExpBufferData query_buffer;
3005 char *e_info_charp2;
3008 string_length = strlen(text);
3010 /* Free any prior result */
3014 /* Set up suitably-escaped copies of textual inputs */
3015 e_text = pg_malloc(string_length * 2 + 1);
3016 PQescapeString(e_text, text, string_length);
3018 if (completion_info_charp)
3022 charp_len = strlen(completion_info_charp);
3023 e_info_charp = pg_malloc(charp_len * 2 + 1);
3024 PQescapeString(e_info_charp, completion_info_charp,
3028 e_info_charp = NULL;
3030 if (completion_info_charp2)
3034 charp_len = strlen(completion_info_charp2);
3035 e_info_charp2 = pg_malloc(charp_len * 2 + 1);
3036 PQescapeString(e_info_charp2, completion_info_charp2,
3040 e_info_charp2 = NULL;
3042 initPQExpBuffer(&query_buffer);
3044 if (is_schema_query)
3046 /* completion_squery gives us the pieces to assemble */
3047 const char *qualresult = completion_squery->qualresult;
3049 if (qualresult == NULL)
3050 qualresult = completion_squery->result;
3052 /* Get unqualified names matching the input-so-far */
3053 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
3054 completion_squery->result,
3055 completion_squery->catname);
3056 if (completion_squery->selcondition)
3057 appendPQExpBuffer(&query_buffer, "%s AND ",
3058 completion_squery->selcondition);
3059 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
3060 completion_squery->result,
3061 string_length, e_text);
3062 appendPQExpBuffer(&query_buffer, " AND %s",
3063 completion_squery->viscondition);
3066 * When fetching relation names, suppress system catalogs unless
3067 * the input-so-far begins with "pg_". This is a compromise
3068 * between not offering system catalogs for completion at all, and
3069 * having them swamp the result when the input is just "p".
3071 if (strcmp(completion_squery->catname,
3072 "pg_catalog.pg_class c") == 0 &&
3073 strncmp(text, "pg_", 3) !=0)
3075 appendPQExpBuffer(&query_buffer,
3076 " AND c.relnamespace <> (SELECT oid FROM"
3077 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
3081 * Add in matching schema names, but only if there is more than
3082 * one potential match among schema names.
3084 appendPQExpBuffer(&query_buffer, "\nUNION\n"
3085 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
3086 "FROM pg_catalog.pg_namespace n "
3087 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
3088 string_length, e_text);
3089 appendPQExpBuffer(&query_buffer,
3090 " AND (SELECT pg_catalog.count(*)"
3091 " FROM pg_catalog.pg_namespace"
3092 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3093 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
3094 string_length, e_text);
3097 * Add in matching qualified names, but only if there is exactly
3098 * one schema matching the input-so-far.
3100 appendPQExpBuffer(&query_buffer, "\nUNION\n"
3101 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
3102 "FROM %s, pg_catalog.pg_namespace n "
3103 "WHERE %s = n.oid AND ",
3105 completion_squery->catname,
3106 completion_squery->namespace);
3107 if (completion_squery->selcondition)
3108 appendPQExpBuffer(&query_buffer, "%s AND ",
3109 completion_squery->selcondition);
3110 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
3112 string_length, e_text);
3115 * This condition exploits the single-matching-schema rule to
3116 * speed up the query
3118 appendPQExpBuffer(&query_buffer,
3119 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
3120 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
3121 string_length, e_text);
3122 appendPQExpBuffer(&query_buffer,
3123 " AND (SELECT pg_catalog.count(*)"
3124 " FROM pg_catalog.pg_namespace"
3125 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3126 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
3127 string_length, e_text);
3129 /* If an addon query was provided, use it */
3130 if (completion_charp)
3131 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
3135 /* completion_charp is an sprintf-style format string */
3136 appendPQExpBuffer(&query_buffer, completion_charp,
3137 string_length, e_text,
3138 e_info_charp, e_info_charp,
3139 e_info_charp2, e_info_charp2);
3142 /* Limit the number of records in the result */
3143 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
3144 completion_max_records);
3146 result = exec_query(query_buffer.data);
3148 termPQExpBuffer(&query_buffer);
3153 free(e_info_charp2);
3156 /* Find something that matches */
3157 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
3161 while (list_index < PQntuples(result) &&
3162 (item = PQgetvalue(result, list_index++, 0)))
3163 if (pg_strncasecmp(text, item, string_length) == 0)
3164 return pg_strdup(item);
3167 /* If nothing matches, free the db structure and return null */
3175 * This function returns in order one of a fixed, NULL pointer terminated list
3176 * of strings (if matching). This can be used if there are only a fixed number
3177 * SQL words that can appear at certain spot.
3180 complete_from_list(const char *text, int state)
3182 static int string_length,
3185 static bool casesensitive;
3188 /* need to have a list */
3189 psql_assert(completion_charpp);
3191 /* Initialization */
3195 string_length = strlen(text);
3196 casesensitive = true;
3200 while ((item = completion_charpp[list_index++]))
3202 /* First pass is case sensitive */
3203 if (casesensitive && strncmp(text, item, string_length) == 0)
3206 return pg_strdup(item);
3209 /* Second pass is case insensitive, don't bother counting matches */
3210 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
3211 return pg_strdup(item);
3215 * No matches found. If we're not case insensitive already, lets switch to
3216 * being case insensitive and try again
3218 if (casesensitive && matches == 0)
3220 casesensitive = false;
3223 return complete_from_list(text, state);
3226 /* If no more matches, return null. */
3232 * This function returns one fixed string the first time even if it doesn't
3233 * match what's there, and nothing the second time. This should be used if
3234 * there is only one possibility that can appear at a certain spot, so
3235 * misspellings will be overwritten. The string to be passed must be in
3239 complete_from_const(const char *text, int state)
3241 (void) text; /* We don't care about what was entered
3244 psql_assert(completion_charp);
3246 return pg_strdup(completion_charp);
3253 * This function supports completion with the name of a psql variable.
3254 * The variable names can be prefixed and suffixed with additional text
3255 * to support quoting usages.
3258 complete_from_variables(char *text, const char *prefix, const char *suffix)
3261 int overhead = strlen(prefix) + strlen(suffix) + 1;
3262 const char **varnames;
3266 struct _variable *ptr;
3268 varnames = (const char **) pg_malloc((maxvars + 1) * sizeof(char *));
3270 for (ptr = pset.vars->next; ptr; ptr = ptr->next)
3274 if (nvars >= maxvars)
3277 varnames = (const char **) realloc(varnames,
3278 (maxvars + 1) * sizeof(char *));
3281 psql_error("out of memory\n");
3286 buffer = (char *) pg_malloc(strlen(ptr->name) + overhead);
3287 sprintf(buffer, "%s%s%s", prefix, ptr->name, suffix);
3288 varnames[nvars++] = buffer;
3291 varnames[nvars] = NULL;
3292 COMPLETE_WITH_LIST(varnames);
3294 for (i = 0; i < nvars; i++)
3295 free((void *) varnames[i]);
3302 /* HELPER FUNCTIONS */
3306 * Execute a query and report any errors. This should be the preferred way of
3307 * talking to the database in this file.
3310 exec_query(const char *query)
3314 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
3317 result = PQexec(pset.db, query);
3319 if (PQresultStatus(result) != PGRES_TUPLES_OK)
3322 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
3323 PQerrorMessage(pset.db), query);
3334 * Return the word (space delimited) before point. Set skip > 0 to
3335 * skip that many words; e.g. skip=1 finds the word before the
3336 * previous one. Return value is NULL or a malloc'ed string.
3339 previous_word(int point, int skip)
3346 const char *buf = rl_line_buffer; /* alias */
3348 /* first we look for a space or a parenthesis before the current word */
3349 for (i = point - 1; i >= 0; i--)
3350 if (strchr(WORD_BREAKS, buf[i]))
3356 int parentheses = 0;
3358 /* now find the first non-space which then constitutes the end */
3359 for (i = point; i >= 0; i--)
3367 * If no end found we return null, because there is no word before the
3374 * Otherwise we now look for the start. The start is either the last
3375 * character before any space going backwards from the end, or it's
3376 * simply character 0. We also handle open quotes and parentheses.
3378 for (start = end; start > 0; start--)
3380 if (buf[start] == '"')
3381 inquotes = !inquotes;
3384 if (buf[start] == ')')
3386 else if (buf[start] == '(')
3388 if (--parentheses <= 0)
3391 else if (parentheses == 0 &&
3392 strchr(WORD_BREAKS, buf[start - 1]))
3401 s = pg_malloc(end - start + 2);
3402 strlcpy(s, &buf[start], end - start + 2);
3410 * Surround a string with single quotes. This works for both SQL and
3411 * psql internal. Currently disabled because it is reported not to
3412 * cooperate with certain versions of readline.
3415 quote_file_name(char *text, int match_type, char *quote_pointer)
3420 (void) quote_pointer; /* not used */
3422 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
3423 s = pg_malloc(length);
3425 strcpy(s + 1, text);
3426 if (match_type == SINGLE_MATCH)
3427 s[length - 2] = '\'';
3428 s[length - 1] = '\0';
3433 dequote_file_name(char *text, char quote_char)
3439 return pg_strdup(text);
3441 length = strlen(text);
3442 s = pg_malloc(length - 2 + 1);
3443 strlcpy(s, text +1, length - 2 + 1);
3447 #endif /* NOT_USED */
3449 #endif /* USE_READLINE */