2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2008, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.171 2008/08/16 01:36:35 tgl Exp $
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
71 * This struct is used to define "schema queries", which are custom-built
72 * to obtain possibly-schema-qualified names of database objects. There is
73 * enough similarity in the structure that we don't want to repeat it each
74 * time. So we put the components of each query into this struct and
75 * assemble them with the common boilerplate in _complete_from_query().
77 typedef struct SchemaQuery
80 * Name of catalog or catalogs to be queried, with alias, eg.
81 * "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
86 * Selection condition --- only rows meeting this condition are candidates
87 * to display. If catname mentions multiple tables, include the necessary
88 * join condition here. For example, "c.relkind = 'r'". Write NULL (not
89 * an empty string) if not needed.
91 const char *selcondition;
94 * Visibility condition --- which rows are visible without schema
95 * qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
97 const char *viscondition;
100 * Namespace --- name of field to join to pg_namespace.oid. For example,
103 const char *namespace;
106 * Result --- the appropriately-quoted name to return, in the case of an
107 * unqualified name. For example, "pg_catalog.quote_ident(c.relname)".
112 * In some cases a different result must be used for qualified names.
113 * Enter that here, or write NULL if result can be used.
115 const char *qualresult;
119 /* Store maximum number of records we want from database queries
120 * (implemented via SELECT ... LIMIT xx).
122 static int completion_max_records;
125 * Communication variables set by COMPLETE_WITH_FOO macros and then used by
126 * the completion callback functions. Ugly but there is no better way.
128 static const char *completion_charp; /* to pass a string */
129 static const char *const * completion_charpp; /* to pass a list of strings */
130 static const char *completion_info_charp; /* to pass a second string */
131 static const char *completion_info_charp2; /* to pass a third string */
132 static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
135 * A few macros to ease typing. You can use these to complete the given
137 * 1) The results from a query you pass it. (Perhaps one of those below?)
138 * 2) The results from a schema query you pass it.
139 * 3) The items from a null-pointer-terminated list.
140 * 4) A string constant.
141 * 5) The list of attributes of the given table (possibly schema-qualified).
143 #define COMPLETE_WITH_QUERY(query) \
145 completion_charp = query; \
146 matches = completion_matches(text, complete_from_query); \
149 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
151 completion_squery = &(query); \
152 completion_charp = addon; \
153 matches = completion_matches(text, complete_from_schema_query); \
156 #define COMPLETE_WITH_LIST(list) \
158 completion_charpp = list; \
159 matches = completion_matches(text, complete_from_list); \
162 #define COMPLETE_WITH_CONST(string) \
164 completion_charp = string; \
165 matches = completion_matches(text, complete_from_const); \
168 #define COMPLETE_WITH_ATTR(relation, addon) \
170 char *_completion_schema; \
171 char *_completion_table; \
173 _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
174 false, false, pset.encoding); \
175 (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
176 false, false, pset.encoding); \
177 _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
178 false, false, pset.encoding); \
179 if (_completion_table == NULL) \
181 completion_charp = Query_for_list_of_attributes addon; \
182 completion_info_charp = relation; \
186 completion_charp = Query_for_list_of_attributes_with_schema addon; \
187 completion_info_charp = _completion_table; \
188 completion_info_charp2 = _completion_schema; \
190 matches = completion_matches(text, complete_from_query); \
194 * Assembly instructions for schema queries
197 static const SchemaQuery Query_for_list_of_aggregates = {
199 "pg_catalog.pg_proc p",
203 "pg_catalog.pg_function_is_visible(p.oid)",
207 "pg_catalog.quote_ident(p.proname)",
212 static const SchemaQuery Query_for_list_of_datatypes = {
214 "pg_catalog.pg_type t",
215 /* selcondition --- ignore table rowtypes and array types */
217 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
218 "AND t.typname !~ '^_'",
220 "pg_catalog.pg_type_is_visible(t.oid)",
224 "pg_catalog.format_type(t.oid, NULL)",
226 "pg_catalog.quote_ident(t.typname)"
229 static const SchemaQuery Query_for_list_of_domains = {
231 "pg_catalog.pg_type t",
235 "pg_catalog.pg_type_is_visible(t.oid)",
239 "pg_catalog.quote_ident(t.typname)",
244 static const SchemaQuery Query_for_list_of_functions = {
246 "pg_catalog.pg_proc p",
250 "pg_catalog.pg_function_is_visible(p.oid)",
254 "pg_catalog.quote_ident(p.proname)",
259 static const SchemaQuery Query_for_list_of_indexes = {
261 "pg_catalog.pg_class c",
263 "c.relkind IN ('i')",
265 "pg_catalog.pg_table_is_visible(c.oid)",
269 "pg_catalog.quote_ident(c.relname)",
274 static const SchemaQuery Query_for_list_of_sequences = {
276 "pg_catalog.pg_class c",
278 "c.relkind IN ('S')",
280 "pg_catalog.pg_table_is_visible(c.oid)",
284 "pg_catalog.quote_ident(c.relname)",
289 static const SchemaQuery Query_for_list_of_tables = {
291 "pg_catalog.pg_class c",
293 "c.relkind IN ('r')",
295 "pg_catalog.pg_table_is_visible(c.oid)",
299 "pg_catalog.quote_ident(c.relname)",
304 static const SchemaQuery Query_for_list_of_tisv = {
306 "pg_catalog.pg_class c",
308 "c.relkind IN ('r', 'i', 'S', 'v')",
310 "pg_catalog.pg_table_is_visible(c.oid)",
314 "pg_catalog.quote_ident(c.relname)",
319 static const SchemaQuery Query_for_list_of_tsv = {
321 "pg_catalog.pg_class c",
323 "c.relkind IN ('r', 'S', 'v')",
325 "pg_catalog.pg_table_is_visible(c.oid)",
329 "pg_catalog.quote_ident(c.relname)",
334 static const SchemaQuery Query_for_list_of_views = {
336 "pg_catalog.pg_class c",
338 "c.relkind IN ('v')",
340 "pg_catalog.pg_table_is_visible(c.oid)",
344 "pg_catalog.quote_ident(c.relname)",
351 * Queries to get lists of names of various kinds of things, possibly
352 * restricted to names matching a partially entered name. In these queries,
353 * the first %s will be replaced by the text entered so far (suitably escaped
354 * to become a SQL literal string). %d will be replaced by the length of the
355 * string (in unescaped form). A second and third %s, if present, will be
356 * replaced by a suitably-escaped version of the string provided in
357 * completion_info_charp. A fourth and fifth %s are similarly replaced by
358 * completion_info_charp2.
360 * Beware that the allowed sequences of %s and %d are determined by
361 * _complete_from_query().
364 #define Query_for_list_of_attributes \
365 "SELECT pg_catalog.quote_ident(attname) "\
366 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
367 " WHERE c.oid = a.attrelid "\
368 " AND a.attnum > 0 "\
369 " AND NOT a.attisdropped "\
370 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
371 " AND (pg_catalog.quote_ident(relname)='%s' "\
372 " OR '\"' || relname || '\"'='%s') "\
373 " AND pg_catalog.pg_table_is_visible(c.oid)"
375 #define Query_for_list_of_attributes_with_schema \
376 "SELECT pg_catalog.quote_ident(attname) "\
377 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
378 " WHERE c.oid = a.attrelid "\
379 " AND n.oid = c.relnamespace "\
380 " AND a.attnum > 0 "\
381 " AND NOT a.attisdropped "\
382 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
383 " AND (pg_catalog.quote_ident(relname)='%s' "\
384 " OR '\"' || relname || '\"' ='%s') "\
385 " AND (pg_catalog.quote_ident(nspname)='%s' "\
386 " OR '\"' || nspname || '\"' ='%s') "
388 #define Query_for_list_of_template_databases \
389 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
390 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' and datistemplate IS TRUE"
392 #define Query_for_list_of_databases \
393 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
394 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
396 #define Query_for_list_of_tablespaces \
397 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
398 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
400 #define Query_for_list_of_encodings \
401 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
402 " FROM pg_catalog.pg_conversion "\
403 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
405 #define Query_for_list_of_languages \
406 "SELECT pg_catalog.quote_ident(lanname) "\
407 " FROM pg_language "\
408 " WHERE lanname != 'internal' "\
409 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
411 #define Query_for_list_of_schemas \
412 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
413 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
415 #define Query_for_list_of_set_vars \
417 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
418 " WHERE context IN ('user', 'superuser') "\
419 " UNION ALL SELECT 'constraints' "\
420 " UNION ALL SELECT 'transaction' "\
421 " UNION ALL SELECT 'session' "\
422 " UNION ALL SELECT 'role' "\
423 " UNION ALL SELECT 'all') ss "\
424 " WHERE substring(name,1,%d)='%s'"
426 #define Query_for_list_of_show_vars \
428 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
429 " UNION ALL SELECT 'session authorization' "\
430 " UNION ALL SELECT 'all') ss "\
431 " WHERE substring(name,1,%d)='%s'"
434 * Note: As of Pg 8.2, we no longer use relkind 's', but we keep it here
435 * for compatibility with older servers
437 #define Query_for_list_of_system_relations \
438 "SELECT pg_catalog.quote_ident(relname) "\
439 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
440 " WHERE c.relkind IN ('r', 'v', 's', 'S') "\
441 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
442 " AND c.relnamespace = n.oid "\
443 " AND n.nspname = 'pg_catalog'"
445 #define Query_for_list_of_roles \
446 " SELECT pg_catalog.quote_ident(rolname) "\
447 " FROM pg_catalog.pg_roles "\
448 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
450 #define Query_for_list_of_grant_roles \
451 " SELECT pg_catalog.quote_ident(rolname) "\
452 " FROM pg_catalog.pg_roles "\
453 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
454 " UNION ALL SELECT 'PUBLIC'"
456 /* the silly-looking length condition is just to eat up the current word */
457 #define Query_for_table_owning_index \
458 "SELECT pg_catalog.quote_ident(c1.relname) "\
459 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
460 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
461 " and (%d = pg_catalog.length('%s'))"\
462 " and pg_catalog.quote_ident(c2.relname)='%s'"\
463 " and pg_catalog.pg_table_is_visible(c2.oid)"
465 /* the silly-looking length condition is just to eat up the current word */
466 #define Query_for_index_of_table \
467 "SELECT pg_catalog.quote_ident(c2.relname) "\
468 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
469 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
470 " and (%d = pg_catalog.length('%s'))"\
471 " and pg_catalog.quote_ident(c1.relname)='%s'"\
472 " and pg_catalog.pg_table_is_visible(c2.oid)"
474 /* the silly-looking length condition is just to eat up the current word */
475 #define Query_for_list_of_tables_for_trigger \
476 "SELECT pg_catalog.quote_ident(relname) "\
477 " FROM pg_catalog.pg_class"\
478 " WHERE (%d = pg_catalog.length('%s'))"\
480 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
481 " WHERE pg_catalog.quote_ident(tgname)='%s')"
483 #define Query_for_list_of_ts_configurations \
484 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
485 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
487 #define Query_for_list_of_ts_dictionaries \
488 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
489 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
491 #define Query_for_list_of_ts_parsers \
492 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
493 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
495 #define Query_for_list_of_ts_templates \
496 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
497 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
500 * This is a list of all "things" in Pgsql, which can show up after CREATE or
501 * DROP; and there is also a query to get a list of them.
507 const char *query; /* simple query, or NULL */
508 const SchemaQuery *squery; /* schema query, or NULL */
509 const bool noshow; /* NULL or true if this word should not show
510 * up after CREATE or DROP */
513 static const pgsql_thing_t words_after_create[] = {
514 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
515 {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
519 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
520 * to be used only by pg_dump.
522 {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, true},
523 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
524 {"DATABASE", Query_for_list_of_databases},
525 {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, true},
526 {"DOMAIN", NULL, &Query_for_list_of_domains},
527 {"FUNCTION", NULL, &Query_for_list_of_functions},
528 {"GROUP", Query_for_list_of_roles},
529 {"LANGUAGE", Query_for_list_of_languages},
530 {"INDEX", NULL, &Query_for_list_of_indexes},
531 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
533 {"PARSER", Query_for_list_of_ts_parsers, NULL, true},
534 {"ROLE", Query_for_list_of_roles},
535 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
536 {"SCHEMA", Query_for_list_of_schemas},
537 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
538 {"TABLE", NULL, &Query_for_list_of_tables},
539 {"TABLESPACE", Query_for_list_of_tablespaces},
540 {"TEMP", NULL, NULL}, /* for CREATE TEMP TABLE ... */
541 {"TEMPLATE", Query_for_list_of_ts_templates, NULL, true},
542 {"TEXT SEARCH", NULL, NULL},
543 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
544 {"TYPE", NULL, &Query_for_list_of_datatypes},
545 {"UNIQUE", NULL, NULL}, /* for CREATE UNIQUE INDEX ... */
546 {"USER", Query_for_list_of_roles},
547 {"VIEW", NULL, &Query_for_list_of_views},
548 {NULL, NULL, NULL, false} /* end of list */
552 /* Forward declaration of functions */
553 static char **psql_completion(char *text, int start, int end);
554 static char *create_command_generator(const char *text, int state);
555 static char *drop_command_generator(const char *text, int state);
556 static char *complete_from_query(const char *text, int state);
557 static char *complete_from_schema_query(const char *text, int state);
558 static char *_complete_from_query(int is_schema_query,
559 const char *text, int state);
560 static char *complete_from_const(const char *text, int state);
561 static char *complete_from_list(const char *text, int state);
563 static PGresult *exec_query(const char *query);
565 static char *previous_word(int point, int skip);
567 static int find_open_parenthesis(int end);
570 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
571 static char *dequote_file_name(char *text, char quote_char);
575 /* Initialize the readline library for our purposes. */
577 initialize_readline(void)
579 rl_readline_name = (char *) pset.progname;
580 rl_attempted_completion_function = (void *) psql_completion;
582 rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
584 completion_max_records = 1000;
587 * There is a variable rl_completion_query_items for this but apparently
588 * it's not defined everywhere.
593 /* The completion function. Acc. to readline spec this gets passed the text
594 entered to far and its start and end in the readline buffer. The return value
595 is some partially obscure list format that can be generated by the readline
596 libraries completion_matches() function, so we don't have to worry about it.
599 psql_completion(char *text, int start, int end)
601 /* This is the variable we'll return. */
602 char **matches = NULL;
604 /* These are going to contain some scannage of the input line. */
611 static const char *const sql_commands[] = {
612 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
613 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
614 "DELETE FROM", "DISCARD", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
615 "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
616 "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
617 "SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN",
618 "UPDATE", "VACUUM", "VALUES", NULL
621 static const char *const backslash_commands[] = {
622 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
623 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
624 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl",
625 "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
626 "\\e", "\\echo", "\\encoding",
627 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
628 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
629 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
630 "\\set", "\\t", "\\T",
631 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
634 (void) end; /* not used */
636 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
637 rl_completion_append_character = ' ';
640 /* Clear a few things. */
641 completion_charp = NULL;
642 completion_charpp = NULL;
643 completion_info_charp = NULL;
644 completion_info_charp2 = NULL;
647 * Scan the input line before our current position for the last five
648 * words. According to those we'll make some smart decisions on what the
649 * user is probably intending to type. TODO: Use strtokx() to do this.
651 prev_wd = previous_word(start, 0);
652 prev2_wd = previous_word(start, 1);
653 prev3_wd = previous_word(start, 2);
654 prev4_wd = previous_word(start, 3);
655 prev5_wd = previous_word(start, 4);
657 /* If a backslash command was started, continue */
659 COMPLETE_WITH_LIST(backslash_commands);
661 /* If no previous word, suggest one of the basic sql commands */
663 COMPLETE_WITH_LIST(sql_commands);
666 /* complete with something you can create */
667 else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
668 matches = completion_matches(text, create_command_generator);
670 /* DROP, except ALTER (TABLE|DOMAIN|GROUP) sth DROP */
671 /* complete with something you can drop */
672 else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
673 pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
674 pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
675 pg_strcasecmp(prev3_wd, "GROUP") != 0)
676 matches = completion_matches(text, drop_command_generator);
681 * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
682 * in ALTER TABLE sth ALTER
684 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
685 pg_strcasecmp(prev3_wd, "TABLE") != 0)
687 static const char *const list_ALTER[] =
688 {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
689 "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SEQUENCE", "TABLE",
690 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "VIEW", NULL};
692 COMPLETE_WITH_LIST(list_ALTER);
694 /* ALTER AGGREGATE,FUNCTION <name> */
695 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
696 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
697 pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
699 static const char *const list_ALTERAGG[] =
700 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
702 COMPLETE_WITH_LIST(list_ALTERAGG);
705 /* ALTER CONVERSION,SCHEMA <name> */
706 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
707 (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
708 pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
710 static const char *const list_ALTERGEN[] =
711 {"OWNER TO", "RENAME TO", NULL};
713 COMPLETE_WITH_LIST(list_ALTERGEN);
716 /* ALTER DATABASE <name> */
717 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
718 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
720 static const char *const list_ALTERDATABASE[] =
721 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
723 COMPLETE_WITH_LIST(list_ALTERDATABASE);
726 /* ALTER INDEX <name> */
727 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
728 pg_strcasecmp(prev2_wd, "INDEX") == 0)
730 static const char *const list_ALTERINDEX[] =
731 {"SET TABLESPACE", "OWNER TO", "RENAME TO", "SET", "RESET", NULL};
733 COMPLETE_WITH_LIST(list_ALTERINDEX);
736 /* ALTER LANGUAGE <name> */
737 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
738 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
740 static const char *const list_ALTERLANGUAGE[] =
741 {"OWNER TO", "RENAME TO", NULL};
743 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
746 /* ALTER USER,ROLE <name> */
747 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
748 (pg_strcasecmp(prev2_wd, "USER") == 0 ||
749 pg_strcasecmp(prev2_wd, "ROLE") == 0))
751 static const char *const list_ALTERUSER[] =
752 {"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
753 "NOCREATEUSER", "CREATEROLE", "NOCREATEROLE", "INHERIT", "NOINHERIT",
754 "LOGIN", "NOLOGIN", "CONNECTION LIMIT", "VALID UNTIL", "RENAME TO",
755 "SUPERUSER", "NOSUPERUSER", "SET", "RESET", NULL};
757 COMPLETE_WITH_LIST(list_ALTERUSER);
760 /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
761 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
762 (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
763 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
765 COMPLETE_WITH_CONST("PASSWORD");
767 /* ALTER DOMAIN <name> */
768 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
769 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
771 static const char *const list_ALTERDOMAIN[] =
772 {"ADD", "DROP", "OWNER TO", "SET", NULL};
774 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
776 /* ALTER DOMAIN <sth> DROP */
777 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
778 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
779 pg_strcasecmp(prev_wd, "DROP") == 0)
781 static const char *const list_ALTERDOMAIN2[] =
782 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
784 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
786 /* ALTER DOMAIN <sth> SET */
787 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
788 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
789 pg_strcasecmp(prev_wd, "SET") == 0)
791 static const char *const list_ALTERDOMAIN3[] =
792 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
794 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
796 /* ALTER SEQUENCE <name> */
797 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
798 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
800 static const char *const list_ALTERSEQUENCE[] =
801 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
802 "SET SCHEMA", "OWNED BY", "RENAME TO", NULL};
804 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
806 /* ALTER SEQUENCE <name> NO */
807 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
808 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
809 pg_strcasecmp(prev_wd, "NO") == 0)
811 static const char *const list_ALTERSEQUENCE2[] =
812 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
814 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
816 /* ALTER VIEW <name> */
817 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
818 pg_strcasecmp(prev2_wd, "VIEW") == 0)
820 static const char *const list_ALTERVIEW[] = {"RENAME TO", NULL};
822 COMPLETE_WITH_LIST(list_ALTERVIEW);
824 /* ALTER TRIGGER <name>, add ON */
825 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
826 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
827 COMPLETE_WITH_CONST("ON");
829 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
830 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
832 completion_info_charp = prev2_wd;
833 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
837 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
839 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
840 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
841 pg_strcasecmp(prev_wd, "ON") == 0)
842 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
844 /* ALTER TRIGGER <name> ON <name> */
845 else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
846 pg_strcasecmp(prev2_wd, "ON") == 0)
847 COMPLETE_WITH_CONST("RENAME TO");
850 * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
851 * RENAME, CLUSTER ON or OWNER
853 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
854 pg_strcasecmp(prev2_wd, "TABLE") == 0)
856 static const char *const list_ALTER2[] =
857 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
858 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET", NULL};
860 COMPLETE_WITH_LIST(list_ALTER2);
862 /* ALTER TABLE xxx ENABLE */
863 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
864 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
865 pg_strcasecmp(prev_wd, "ENABLE") == 0)
867 static const char *const list_ALTERENABLE[] =
868 {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
870 COMPLETE_WITH_LIST(list_ALTERENABLE);
872 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
873 pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
874 (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
875 pg_strcasecmp(prev_wd, "ALWAYS") == 0))
877 static const char *const list_ALTERENABLE2[] =
878 {"RULE", "TRIGGER", NULL};
880 COMPLETE_WITH_LIST(list_ALTERENABLE2);
882 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
883 pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
884 pg_strcasecmp(prev_wd, "DISABLE") == 0)
886 static const char *const list_ALTERDISABLE[] =
887 {"RULE", "TRIGGER", NULL};
889 COMPLETE_WITH_LIST(list_ALTERDISABLE);
892 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
893 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
894 (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
895 pg_strcasecmp(prev_wd, "RENAME") == 0))
896 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
899 * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
902 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
903 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
904 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
905 pg_strcasecmp(prev_wd, "COLUMN") == 0)
906 COMPLETE_WITH_ATTR(prev3_wd, "");
908 /* ALTER TABLE xxx RENAME yyy */
909 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
910 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
911 pg_strcasecmp(prev_wd, "TO") != 0)
912 COMPLETE_WITH_CONST("TO");
914 /* ALTER TABLE xxx RENAME COLUMN yyy */
915 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
916 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
917 pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
918 pg_strcasecmp(prev_wd, "TO") != 0)
919 COMPLETE_WITH_CONST("TO");
921 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
922 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
923 pg_strcasecmp(prev_wd, "DROP") == 0)
925 static const char *const list_TABLEDROP[] =
926 {"COLUMN", "CONSTRAINT", NULL};
928 COMPLETE_WITH_LIST(list_TABLEDROP);
930 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
931 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
932 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
933 pg_strcasecmp(prev_wd, "COLUMN") == 0)
934 COMPLETE_WITH_ATTR(prev3_wd, "");
935 /* ALTER TABLE ALTER [COLUMN] <foo> */
936 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
937 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
938 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
939 pg_strcasecmp(prev2_wd, "ALTER") == 0))
941 /* DROP ... does not work well yet */
942 static const char *const list_COLUMNALTER[] =
943 {"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
944 "DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
946 COMPLETE_WITH_LIST(list_COLUMNALTER);
948 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0)
949 COMPLETE_WITH_CONST("ON");
950 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
951 pg_strcasecmp(prev_wd, "ON") == 0)
953 completion_info_charp = prev3_wd;
954 COMPLETE_WITH_QUERY(Query_for_index_of_table);
956 /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
957 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
958 pg_strcasecmp(prev_wd, "SET") == 0)
960 static const char *const list_TABLESET[] =
961 {"WITHOUT", "TABLESPACE", "SCHEMA", NULL};
963 COMPLETE_WITH_LIST(list_TABLESET);
965 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
966 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
967 pg_strcasecmp(prev2_wd, "SET") == 0 &&
968 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
969 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
970 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
971 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
972 pg_strcasecmp(prev2_wd, "SET") == 0 &&
973 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
975 static const char *const list_TABLESET2[] =
976 {"CLUSTER", "OIDS", NULL};
978 COMPLETE_WITH_LIST(list_TABLESET2);
980 /* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */
981 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
982 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
984 static const char *const list_ALTERTSPC[] =
985 {"RENAME TO", "OWNER TO", NULL};
987 COMPLETE_WITH_LIST(list_ALTERTSPC);
989 /* ALTER TEXT SEARCH */
990 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
991 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
992 pg_strcasecmp(prev_wd, "SEARCH") == 0)
994 static const char *const list_ALTERTEXTSEARCH[] =
995 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
997 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
999 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1000 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1001 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1002 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1003 pg_strcasecmp(prev2_wd, "PARSER") == 0))
1004 COMPLETE_WITH_CONST("RENAME TO");
1006 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1007 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1008 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1009 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1011 static const char *const list_ALTERTEXTSEARCH2[] =
1012 {"OWNER TO", "RENAME TO", NULL};
1014 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1017 else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1018 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1019 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1020 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1022 static const char *const list_ALTERTEXTSEARCH3[] =
1023 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", NULL};
1025 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1028 /* complete ALTER TYPE <foo> with OWNER TO, SET SCHEMA */
1029 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1030 pg_strcasecmp(prev2_wd, "TYPE") == 0)
1032 static const char *const list_ALTERTYPE[] =
1033 {"OWNER TO", "SET SCHEMA", NULL};
1035 COMPLETE_WITH_LIST(list_ALTERTYPE);
1037 /* complete ALTER GROUP <foo> */
1038 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1039 pg_strcasecmp(prev2_wd, "GROUP") == 0)
1041 static const char *const list_ALTERGROUP[] =
1042 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1044 COMPLETE_WITH_LIST(list_ALTERGROUP);
1046 /* complete ALTER GROUP <foo> ADD|DROP with USER */
1047 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1048 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1049 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1050 pg_strcasecmp(prev_wd, "DROP") == 0))
1051 COMPLETE_WITH_CONST("USER");
1052 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1053 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1054 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1055 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1056 pg_strcasecmp(prev_wd, "USER") == 0)
1057 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1059 /* BEGIN, END, ABORT */
1060 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1061 pg_strcasecmp(prev_wd, "END") == 0 ||
1062 pg_strcasecmp(prev_wd, "ABORT") == 0)
1064 static const char *const list_TRANS[] =
1065 {"WORK", "TRANSACTION", NULL};
1067 COMPLETE_WITH_LIST(list_TRANS);
1070 else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1072 static const char *const list_COMMIT[] =
1073 {"WORK", "TRANSACTION", "PREPARED", NULL};
1075 COMPLETE_WITH_LIST(list_COMMIT);
1077 /* RELEASE SAVEPOINT */
1078 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1079 COMPLETE_WITH_CONST("SAVEPOINT");
1081 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1083 static const char *const list_TRANS[] =
1084 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1086 COMPLETE_WITH_LIST(list_TRANS);
1091 * If the previous word is CLUSTER and not without produce list of tables
1093 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1094 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1095 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1096 /* If we have CLUSTER <sth>, then add "USING" */
1097 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1098 pg_strcasecmp(prev_wd, "ON") != 0)
1100 COMPLETE_WITH_CONST("USING");
1104 * If we have CLUSTER <sth> USING, then add the index as well.
1106 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1107 pg_strcasecmp(prev_wd, "USING") == 0)
1109 completion_info_charp = prev2_wd;
1110 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1114 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1115 COMPLETE_WITH_CONST("ON");
1116 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1117 pg_strcasecmp(prev_wd, "ON") == 0)
1119 static const char *const list_COMMENT[] =
1120 {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
1121 "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1122 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1123 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1125 COMPLETE_WITH_LIST(list_COMMENT);
1127 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1128 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1129 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1130 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1132 static const char *const list_TRANS2[] =
1133 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1135 COMPLETE_WITH_LIST(list_TRANS2);
1137 else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1138 pg_strcasecmp(prev3_wd, "ON") == 0) ||
1139 (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1140 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1141 pg_strcasecmp(prev3_wd, "SEARCH") == 0))
1142 COMPLETE_WITH_CONST("IS");
1147 * If we have COPY [BINARY] (which you'd have to type yourself), offer
1148 * list of tables (Also cover the analogous backslash command)
1150 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1151 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1152 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1153 pg_strcasecmp(prev_wd, "BINARY") == 0))
1154 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1155 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1156 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1157 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1158 pg_strcasecmp(prev2_wd, "BINARY") == 0)
1160 static const char *const list_FROMTO[] =
1161 {"FROM", "TO", NULL};
1163 COMPLETE_WITH_LIST(list_FROMTO);
1165 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1166 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1167 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1168 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1169 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1170 pg_strcasecmp(prev_wd, "TO") == 0))
1171 matches = completion_matches(text, filename_completion_function);
1173 /* Handle COPY|BINARY <sth> FROM|TO filename */
1174 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1175 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1176 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1177 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1178 pg_strcasecmp(prev2_wd, "TO") == 0))
1180 static const char *const list_COPY[] =
1181 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", NULL};
1183 COMPLETE_WITH_LIST(list_COPY);
1186 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1187 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1188 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1189 pg_strcasecmp(prev3_wd, "TO") == 0))
1191 static const char *const list_CSV[] =
1192 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
1194 COMPLETE_WITH_LIST(list_CSV);
1197 /* CREATE DATABASE */
1198 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1199 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1201 static const char *const list_DATABASE[] =
1202 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1205 COMPLETE_WITH_LIST(list_DATABASE);
1208 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1209 pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1210 pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1211 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1214 /* First off we complete CREATE UNIQUE with "INDEX" */
1215 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1216 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1217 COMPLETE_WITH_CONST("INDEX");
1218 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
1219 else if (pg_strcasecmp(prev2_wd, "INDEX") == 0 &&
1220 (pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1221 pg_strcasecmp(prev3_wd, "UNIQUE") == 0))
1222 COMPLETE_WITH_CONST("ON");
1223 /* Complete ... INDEX <name> ON with a list of tables */
1224 else if (pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1225 pg_strcasecmp(prev_wd, "ON") == 0)
1226 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1229 * Complete INDEX <name> ON <table> with a list of table columns (which
1230 * should really be in parens)
1232 else if (pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1233 pg_strcasecmp(prev2_wd, "ON") == 0)
1235 if (find_open_parenthesis(end))
1236 COMPLETE_WITH_ATTR(prev_wd, "");
1238 COMPLETE_WITH_CONST("(");
1240 else if (pg_strcasecmp(prev5_wd, "INDEX") == 0 &&
1241 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1242 pg_strcasecmp(prev_wd, "(") == 0)
1243 COMPLETE_WITH_ATTR(prev2_wd, "");
1244 /* same if you put in USING */
1245 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1246 pg_strcasecmp(prev2_wd, "USING") == 0)
1247 COMPLETE_WITH_ATTR(prev3_wd, "");
1248 /* Complete USING with an index method */
1249 else if (pg_strcasecmp(prev_wd, "USING") == 0)
1251 static const char *const index_mth[] =
1252 {"BTREE", "HASH", "GIN", "GIST", NULL};
1254 COMPLETE_WITH_LIST(index_mth);
1258 /* Complete "CREATE RULE <sth>" with "AS" */
1259 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1260 pg_strcasecmp(prev2_wd, "RULE") == 0)
1261 COMPLETE_WITH_CONST("AS");
1262 /* Complete "CREATE RULE <sth> AS with "ON" */
1263 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1264 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1265 pg_strcasecmp(prev_wd, "AS") == 0)
1266 COMPLETE_WITH_CONST("ON");
1267 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1268 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1269 pg_strcasecmp(prev2_wd, "AS") == 0 &&
1270 pg_strcasecmp(prev_wd, "ON") == 0)
1272 static const char *const rule_events[] =
1273 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1275 COMPLETE_WITH_LIST(rule_events);
1277 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1278 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1279 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1280 (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1281 pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1282 COMPLETE_WITH_CONST("TO");
1283 /* Complete "AS ON <sth> TO" with a table name */
1284 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1285 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1286 pg_strcasecmp(prev_wd, "TO") == 0)
1287 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1290 /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
1291 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1292 (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
1293 pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
1295 static const char *const list_TEMP[] =
1296 {"SEQUENCE", "TABLE", "VIEW", NULL};
1298 COMPLETE_WITH_LIST(list_TEMP);
1301 /* CREATE TABLESPACE */
1302 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1303 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1305 static const char *const list_CREATETABLESPACE[] =
1306 {"OWNER", "LOCATION", NULL};
1308 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1310 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1311 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1312 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1313 pg_strcasecmp(prev2_wd, "OWNER") == 0)
1315 COMPLETE_WITH_CONST("LOCATION");
1318 /* CREATE TEXT SEARCH */
1319 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1320 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1321 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1323 static const char *const list_CREATETEXTSEARCH[] =
1324 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1326 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
1328 else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1329 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1330 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1331 COMPLETE_WITH_CONST("(");
1333 /* CREATE TRIGGER */
1334 /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1335 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1336 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1338 static const char *const list_CREATETRIGGER[] =
1339 {"BEFORE", "AFTER", NULL};
1341 COMPLETE_WITH_LIST(list_CREATETRIGGER);
1343 /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1344 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1345 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1346 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1347 pg_strcasecmp(prev2_wd, "AFTER") == 0))
1349 static const char *const list_CREATETRIGGER2[] =
1352 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1355 /* CREATE ROLE,USER,GROUP */
1356 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1357 (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1358 pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1360 static const char *const list_CREATEROLE[] =
1361 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1362 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOINHERIT", "NOLOGIN", "NOCREATEDB",
1363 "NOCREATEROLE", "NOCREATEUSER", "NOSUPERUSER", "ROLE", "SUPERUSER", "SYSID",
1364 "UNENCRYPTED", NULL};
1366 COMPLETE_WITH_LIST(list_CREATEROLE);
1370 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1373 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1374 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1375 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1376 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1378 COMPLETE_WITH_CONST("PASSWORD");
1380 /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1381 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1382 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1383 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1384 pg_strcasecmp(prev_wd, "IN") == 0)
1386 static const char *const list_CREATEROLE3[] =
1387 {"GROUP", "ROLE", NULL};
1389 COMPLETE_WITH_LIST(list_CREATEROLE3);
1393 /* Complete CREATE VIEW <name> with AS */
1394 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1395 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1396 COMPLETE_WITH_CONST("AS");
1397 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1398 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1399 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1400 pg_strcasecmp(prev_wd, "AS") == 0)
1401 COMPLETE_WITH_CONST("SELECT");
1404 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1406 static const char *const list_DECLARE[] =
1407 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1409 COMPLETE_WITH_LIST(list_DECLARE);
1412 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1414 static const char *const list_DECLARECURSOR[] =
1415 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1417 COMPLETE_WITH_LIST(list_DECLARECURSOR);
1424 * Complete DELETE with FROM (only if the word before that is not "ON"
1425 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1427 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1428 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1429 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1430 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1431 pg_strcasecmp(prev2_wd, "AFTER") == 0))
1432 COMPLETE_WITH_CONST("FROM");
1433 /* Complete DELETE FROM with a list of tables */
1434 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1435 pg_strcasecmp(prev_wd, "FROM") == 0)
1436 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1437 /* Complete DELETE FROM <table> */
1438 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1439 pg_strcasecmp(prev2_wd, "FROM") == 0)
1441 static const char *const list_DELETE[] =
1442 {"USING", "WHERE", "SET", NULL};
1444 COMPLETE_WITH_LIST(list_DELETE);
1446 /* XXX: implement tab completion for DELETE ... USING */
1449 else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
1451 static const char *const list_DISCARD[] =
1452 {"ALL", "PLANS", "TEMP", NULL};
1454 COMPLETE_WITH_LIST(list_DISCARD);
1457 /* DROP (when not the previous word) */
1458 /* DROP AGGREGATE */
1459 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1460 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1461 COMPLETE_WITH_CONST("(");
1463 /* DROP object with CASCADE / RESTRICT */
1464 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1465 (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1466 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1467 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1468 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1469 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1470 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1471 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1472 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1473 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1474 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1475 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1476 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1477 prev_wd[strlen(prev_wd) - 1] == ')') ||
1478 (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
1479 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1480 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1481 (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
1482 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
1483 pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
1484 pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
1487 if ((pg_strcasecmp(prev3_wd, "DROP") == 0) && (pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
1489 if (find_open_parenthesis(end))
1491 static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1492 char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev_wd));
1494 sprintf(tmp_buf, func_args_query, prev_wd);
1495 COMPLETE_WITH_QUERY(tmp_buf);
1500 COMPLETE_WITH_CONST("(");
1505 static const char *const list_DROPCR[] =
1506 {"CASCADE", "RESTRICT", NULL};
1508 COMPLETE_WITH_LIST(list_DROPCR);
1511 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1512 pg_strcasecmp(prev3_wd, "FUNCTION") == 0 &&
1513 pg_strcasecmp(prev_wd, "(") == 0)
1515 static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1516 char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev2_wd));
1518 sprintf(tmp_buf, func_args_query, prev2_wd);
1519 COMPLETE_WITH_QUERY(tmp_buf);
1523 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1524 pg_strcasecmp(prev_wd, "OWNED") == 0)
1525 COMPLETE_WITH_CONST("BY");
1526 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1527 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1528 pg_strcasecmp(prev_wd, "BY") == 0)
1529 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1530 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1531 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1532 pg_strcasecmp(prev_wd, "SEARCH") == 0)
1535 static const char *const list_ALTERTEXTSEARCH[] =
1536 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1538 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1544 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1546 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1548 static const char *const list_EXPLAIN[] =
1549 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
1551 COMPLETE_WITH_LIST(list_EXPLAIN);
1553 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1554 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1556 static const char *const list_EXPLAIN[] =
1557 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
1559 COMPLETE_WITH_LIST(list_EXPLAIN);
1561 else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1562 pg_strcasecmp(prev3_wd, "VACUUM") != 0 &&
1563 pg_strcasecmp(prev4_wd, "VACUUM") != 0 &&
1564 (pg_strcasecmp(prev2_wd, "ANALYZE") == 0 ||
1565 pg_strcasecmp(prev2_wd, "EXPLAIN") == 0))
1567 static const char *const list_EXPLAIN[] =
1568 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
1570 COMPLETE_WITH_LIST(list_EXPLAIN);
1574 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1575 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1576 pg_strcasecmp(prev_wd, "MOVE") == 0)
1578 static const char *const list_FETCH1[] =
1579 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1581 COMPLETE_WITH_LIST(list_FETCH1);
1583 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1584 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1585 pg_strcasecmp(prev2_wd, "MOVE") == 0)
1587 static const char *const list_FETCH2[] =
1588 {"ALL", "NEXT", "PRIOR", NULL};
1590 COMPLETE_WITH_LIST(list_FETCH2);
1594 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
1595 * but we may as well tab-complete both: perhaps some users prefer one
1596 * variant or the other.
1598 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
1599 pg_strcasecmp(prev3_wd, "MOVE") == 0)
1601 static const char *const list_FROMIN[] =
1602 {"FROM", "IN", NULL};
1604 COMPLETE_WITH_LIST(list_FROMIN);
1607 /* GRANT && REVOKE*/
1608 /* Complete GRANT/REVOKE with a list of privileges */
1609 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
1610 pg_strcasecmp(prev_wd, "REVOKE") == 0)
1612 static const char *const list_privileg[] =
1613 {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
1614 "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
1617 COMPLETE_WITH_LIST(list_privileg);
1619 /* Complete GRANT/REVOKE <sth> with "ON" */
1620 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1621 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
1622 COMPLETE_WITH_CONST("ON");
1625 * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
1628 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
1629 * UNION; seems to work intuitively
1631 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
1632 * here will only work if the privilege list contains exactly one
1635 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
1636 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
1637 pg_strcasecmp(prev_wd, "ON") == 0)
1638 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
1639 " UNION SELECT 'DATABASE'"
1640 " UNION SELECT 'FUNCTION'"
1641 " UNION SELECT 'LANGUAGE'"
1642 " UNION SELECT 'SCHEMA'"
1643 " UNION SELECT 'TABLESPACE'");
1645 /* Complete "GRANT/REVOKE * ON * " with "TO" */
1646 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1647 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1648 pg_strcasecmp(prev2_wd, "ON") == 0)
1650 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1651 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1652 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
1653 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1654 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
1655 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1656 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
1657 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1658 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1659 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1660 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
1661 COMPLETE_WITH_CONST("TO");
1663 COMPLETE_WITH_CONST("FROM");
1666 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1667 else if (pg_strcasecmp(prev3_wd, "ON") == 0 &&
1668 ((pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
1669 pg_strcasecmp(prev_wd, "TO") == 0) ||
1670 (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
1671 pg_strcasecmp(prev_wd, "FROM") == 0)))
1672 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1675 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1676 pg_strcasecmp(prev_wd, "GROUP") == 0)
1677 COMPLETE_WITH_CONST("BY");
1680 /* Complete INSERT with "INTO" */
1681 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
1682 COMPLETE_WITH_CONST("INTO");
1683 /* Complete INSERT INTO with table names */
1684 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
1685 pg_strcasecmp(prev_wd, "INTO") == 0)
1686 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1687 /* Complete "INSERT INTO <table> (" with attribute names */
1688 else if (rl_line_buffer[start - 1] == '(' &&
1689 pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1690 pg_strcasecmp(prev2_wd, "INTO") == 0)
1691 COMPLETE_WITH_ATTR(prev_wd, "");
1694 * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1697 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1698 pg_strcasecmp(prev2_wd, "INTO") == 0)
1700 static const char *const list_INSERT[] =
1701 {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1703 COMPLETE_WITH_LIST(list_INSERT);
1705 /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1706 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
1707 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
1708 prev_wd[strlen(prev_wd) - 1] == ')')
1710 static const char *const list_INSERT[] =
1711 {"SELECT", "VALUES", NULL};
1713 COMPLETE_WITH_LIST(list_INSERT);
1716 /* Insert an open parenthesis after "VALUES" */
1717 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
1718 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
1719 COMPLETE_WITH_CONST("(");
1722 /* Complete LOCK [TABLE] with a list of tables */
1723 else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
1724 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1725 " UNION SELECT 'TABLE'");
1726 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
1727 pg_strcasecmp(prev2_wd, "LOCK") == 0)
1728 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1730 /* For the following, handle the case of a single table only for now */
1732 /* Complete LOCK [TABLE] <table> with "IN" */
1733 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
1734 pg_strcasecmp(prev_wd, "TABLE")) ||
1735 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
1736 pg_strcasecmp(prev3_wd, "LOCK") == 0))
1737 COMPLETE_WITH_CONST("IN");
1739 /* Complete LOCK [TABLE] <table> IN with a lock mode */
1740 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
1741 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
1742 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1743 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
1745 static const char *const lock_modes[] =
1746 {"ACCESS SHARE MODE",
1747 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1748 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1749 "SHARE ROW EXCLUSIVE MODE",
1750 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1752 COMPLETE_WITH_LIST(lock_modes);
1756 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
1757 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1759 /* OWNER TO - complete with available roles */
1760 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
1761 pg_strcasecmp(prev_wd, "TO") == 0)
1762 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1765 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1766 pg_strcasecmp(prev_wd, "ORDER") == 0)
1767 COMPLETE_WITH_CONST("BY");
1768 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
1769 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
1770 pg_strcasecmp(prev_wd, "BY") == 0)
1771 COMPLETE_WITH_ATTR(prev3_wd, "");
1774 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
1775 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
1777 static const char *const list_PREPARE[] =
1778 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1780 COMPLETE_WITH_LIST(list_PREPARE);
1783 /* REASSIGN OWNED BY xxx TO yyy */
1784 else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
1785 COMPLETE_WITH_CONST("OWNED");
1786 else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
1787 pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
1788 COMPLETE_WITH_CONST("BY");
1789 else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
1790 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1791 pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
1792 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1793 else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
1794 pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
1795 pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
1796 COMPLETE_WITH_CONST("TO");
1797 else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
1798 pg_strcasecmp(prev3_wd, "BY") == 0 &&
1799 pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
1800 pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
1801 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1804 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
1806 static const char *const list_REINDEX[] =
1807 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
1809 COMPLETE_WITH_LIST(list_REINDEX);
1811 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
1813 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
1814 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1815 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
1816 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1817 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
1818 pg_strcasecmp(prev_wd, "DATABASE") == 0)
1819 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1825 /* SET, RESET, SHOW */
1826 /* Complete with a variable name */
1827 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
1828 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
1829 pg_strcasecmp(prev_wd, "RESET") == 0)
1830 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
1831 else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
1832 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
1833 /* Complete "SET TRANSACTION" */
1834 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
1835 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1836 || (pg_strcasecmp(prev2_wd, "START") == 0
1837 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1838 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1839 && pg_strcasecmp(prev_wd, "WORK") == 0)
1840 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1841 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1842 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
1843 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
1844 && pg_strcasecmp(prev2_wd, "AS") == 0
1845 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
1847 static const char *const my_list[] =
1848 {"ISOLATION LEVEL", "READ", NULL};
1850 COMPLETE_WITH_LIST(my_list);
1852 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
1853 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
1854 || pg_strcasecmp(prev3_wd, "START") == 0
1855 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
1856 && pg_strcasecmp(prev3_wd, "AS") == 0))
1857 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
1858 || pg_strcasecmp(prev2_wd, "WORK") == 0)
1859 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
1860 COMPLETE_WITH_CONST("LEVEL");
1861 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
1862 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
1863 || pg_strcasecmp(prev4_wd, "START") == 0
1864 || pg_strcasecmp(prev4_wd, "AS") == 0)
1865 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
1866 || pg_strcasecmp(prev3_wd, "WORK") == 0)
1867 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
1868 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
1870 static const char *const my_list[] =
1871 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
1873 COMPLETE_WITH_LIST(my_list);
1875 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1876 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1877 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1878 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1879 pg_strcasecmp(prev_wd, "READ") == 0)
1881 static const char *const my_list[] =
1882 {"UNCOMMITTED", "COMMITTED", NULL};
1884 COMPLETE_WITH_LIST(my_list);
1886 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1887 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1888 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1889 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1890 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
1891 COMPLETE_WITH_CONST("READ");
1892 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
1893 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
1894 pg_strcasecmp(prev3_wd, "START") == 0 ||
1895 pg_strcasecmp(prev3_wd, "AS") == 0) &&
1896 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
1897 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
1898 pg_strcasecmp(prev_wd, "READ") == 0)
1900 static const char *const my_list[] =
1901 {"ONLY", "WRITE", NULL};
1903 COMPLETE_WITH_LIST(my_list);
1905 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1906 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1907 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1909 static const char *const constraint_list[] =
1910 {"DEFERRED", "IMMEDIATE", NULL};
1912 COMPLETE_WITH_LIST(constraint_list);
1914 /* Complete SET ROLE */
1915 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1916 pg_strcasecmp(prev_wd, "ROLE") == 0)
1917 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1918 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1919 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1920 pg_strcasecmp(prev_wd, "SESSION") == 0)
1922 static const char *const my_list[] =
1923 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
1925 COMPLETE_WITH_LIST(my_list);
1927 /* Complete SET SESSION AUTHORIZATION with username */
1928 else if (pg_strcasecmp(prev3_wd, "SET") == 0
1929 && pg_strcasecmp(prev2_wd, "SESSION") == 0
1930 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1931 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
1932 /* Complete RESET SESSION with AUTHORIZATION */
1933 else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
1934 pg_strcasecmp(prev_wd, "SESSION") == 0)
1935 COMPLETE_WITH_CONST("AUTHORIZATION");
1936 /* Complete SET <var> with "TO" */
1937 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1938 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
1939 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
1940 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
1941 COMPLETE_WITH_CONST("TO");
1942 /* Suggest possible variable values */
1943 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1944 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1946 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
1948 static const char *const my_list[] =
1949 {"ISO", "SQL", "Postgres", "German",
1950 "YMD", "DMY", "MDY",
1951 "US", "European", "NonEuropean",
1954 COMPLETE_WITH_LIST(my_list);
1956 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
1958 static const char *const my_list[] =
1959 {"ON", "OFF", "DEFAULT", NULL};
1961 COMPLETE_WITH_LIST(my_list);
1965 static const char *const my_list[] =
1968 COMPLETE_WITH_LIST(my_list);
1972 /* START TRANSACTION */
1973 else if (pg_strcasecmp(prev_wd, "START") == 0)
1974 COMPLETE_WITH_CONST("TRANSACTION");
1977 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
1978 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1981 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
1982 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s' UNION SELECT '*'");
1985 /* If prev. word is UPDATE suggest a list of tables */
1986 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
1987 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1988 /* Complete UPDATE <table> with "SET" */
1989 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
1990 COMPLETE_WITH_CONST("SET");
1993 * If the previous word is SET (and it wasn't caught above as the _first_
1994 * word) the word before it was (hopefully) a table name and we'll now
1995 * make a list of attributes.
1997 else if (pg_strcasecmp(prev_wd, "SET") == 0)
1998 COMPLETE_WITH_ATTR(prev2_wd, "");
2000 /* UPDATE xx SET yy = */
2001 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2002 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
2003 COMPLETE_WITH_CONST("=");
2006 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
2007 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
2009 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
2010 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2011 " UNION SELECT 'FULL'"
2012 " UNION SELECT 'FREEZE'"
2013 " UNION SELECT 'ANALYZE'"
2014 " UNION SELECT 'VERBOSE'");
2015 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2016 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
2017 pg_strcasecmp(prev_wd, "FREEZE") == 0))
2018 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2019 " UNION SELECT 'ANALYZE'"
2020 " UNION SELECT 'VERBOSE'");
2021 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2022 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2023 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2024 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2025 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2026 " UNION SELECT 'VERBOSE'");
2027 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2028 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2029 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2030 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2031 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2032 " UNION SELECT 'ANALYZE'");
2033 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2034 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
2035 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2036 " UNION SELECT 'ANALYZE'");
2037 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2038 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2039 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2040 " UNION SELECT 'VERBOSE'");
2041 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2042 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
2043 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2044 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
2045 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2048 /* If the previous word is ANALYZE, produce list of tables */
2049 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2050 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2053 /* Simple case of the word before the where being the table name */
2054 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
2055 COMPLETE_WITH_ATTR(prev2_wd, "");
2058 /* TODO: also include SRF ? */
2059 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
2060 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
2061 pg_strcasecmp(prev3_wd, "\\copy") != 0)
2062 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
2065 /* Backslash commands */
2066 /* TODO: \dc \dd \dl */
2067 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
2068 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2069 else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
2070 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
2071 else if (strcmp(prev_wd, "\\da") == 0)
2072 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
2073 else if (strcmp(prev_wd, "\\db") == 0)
2074 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2075 else if (strcmp(prev_wd, "\\dD") == 0)
2076 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2077 else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
2078 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2079 else if (strcmp(prev_wd, "\\dF") == 0 || strcmp(prev_wd, "\\dF+") == 0)
2080 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
2081 else if (strcmp(prev_wd, "\\dFd") == 0 || strcmp(prev_wd, "\\dFd+") == 0)
2082 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
2083 else if (strcmp(prev_wd, "\\dFp") == 0 || strcmp(prev_wd, "\\dFp+") == 0)
2084 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
2085 else if (strcmp(prev_wd, "\\dFt") == 0 || strcmp(prev_wd, "\\dFt+") == 0)
2086 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
2087 else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
2088 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2089 else if (strcmp(prev_wd, "\\dn") == 0)
2090 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2091 else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
2092 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
2093 else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
2094 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
2095 else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
2096 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
2097 else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
2098 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2099 else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
2100 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2101 else if (strcmp(prev_wd, "\\du") == 0)
2102 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2103 else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
2104 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2105 else if (strcmp(prev_wd, "\\encoding") == 0)
2106 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
2107 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
2108 COMPLETE_WITH_LIST(sql_commands);
2109 else if (strcmp(prev_wd, "\\password") == 0)
2110 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2111 else if (strcmp(prev_wd, "\\pset") == 0)
2113 static const char *const my_list[] =
2114 {"format", "border", "expanded",
2115 "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
2118 COMPLETE_WITH_LIST(my_list);
2120 else if (strcmp(prev_wd, "\\cd") == 0 ||
2121 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
2122 strcmp(prev_wd, "\\g") == 0 ||
2123 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
2124 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
2125 strcmp(prev_wd, "\\s") == 0 ||
2126 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
2128 matches = completion_matches(text, filename_completion_function);
2132 * Finally, we look through the list of "things", such as TABLE, INDEX and
2133 * check if that was the previous word. If so, execute the query to get a
2140 for (i = 0; words_after_create[i].name; i++)
2142 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
2144 if (words_after_create[i].query)
2145 COMPLETE_WITH_QUERY(words_after_create[i].query);
2146 else if (words_after_create[i].squery)
2147 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
2155 * If we still don't have anything to match we have to fabricate some sort
2156 * of default list. If we were to just return NULL, readline automatically
2157 * attempts filename completion, and that's usually no good.
2159 if (matches == NULL)
2161 COMPLETE_WITH_CONST("");
2162 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
2163 rl_completion_append_character = '\0';
2174 /* Return our Grand List O' Matches */
2180 /* GENERATOR FUNCTIONS
2182 These functions do all the actual work of completing the input. They get
2183 passed the text so far and the count how many times they have been called so
2184 far with the same text.
2185 If you read the above carefully, you'll see that these don't get called
2186 directly but through the readline interface.
2187 The return value is expected to be the full completion of the text, going
2188 through a list each time, or NULL if there are no more matches. The string
2189 will be free()'d by readline, so you must run it through strdup() or
2190 something of that sort.
2193 /* This one gives you one from a list of things you can put after CREATE
2197 create_command_generator(const char *text, int state)
2199 static int list_index,
2203 /* If this is the first time for this completion, init some values */
2207 string_length = strlen(text);
2210 /* find something that matches */
2211 while ((name = words_after_create[list_index++].name))
2213 if ((pg_strncasecmp(name, text, string_length) == 0) && !words_after_create[list_index - 1].noshow)
2214 return pg_strdup(name);
2216 /* if nothing matches, return NULL */
2221 * This function gives you a list of things you can put after a DROP command.
2222 * Very similar to create_command_generator, but has an additional entry for
2223 * OWNED BY. (We do it this way in order not to duplicate the
2224 * words_after_create list.)
2227 drop_command_generator(const char *text, int state)
2229 static int list_index,
2235 /* If this is the first time for this completion, init some values */
2237 string_length = strlen(text);
2240 * DROP can be followed by "OWNED BY", which is not found in the list
2241 * for CREATE matches, so make it the first state. (We do not make it
2242 * the last state because it would be more difficult to detect when we
2243 * have to return NULL instead.)
2245 * Make sure we advance to the next state.
2248 if (pg_strncasecmp("OWNED", text, string_length) == 0)
2249 return pg_strdup("OWNED");
2253 * In subsequent attempts, try to complete with the same items we use for
2256 while ((name = words_after_create[list_index++ - 1].name))
2258 if ((pg_strncasecmp(name, text, string_length) == 0) && (!words_after_create[list_index - 2].noshow))
2259 return pg_strdup(name);
2262 /* if nothing matches, return NULL */
2266 /* The following two functions are wrappers for _complete_from_query */
2269 complete_from_query(const char *text, int state)
2271 return _complete_from_query(0, text, state);
2275 complete_from_schema_query(const char *text, int state)
2277 return _complete_from_query(1, text, state);
2281 /* This creates a list of matching things, according to a query pointed to
2282 by completion_charp.
2283 The query can be one of two kinds:
2284 - A simple query which must contain a %d and a %s, which will be replaced
2285 by the string length of the text and the text itself. The query may also
2286 have up to four more %s in it; the first two such will be replaced by the
2287 value of completion_info_charp, the next two by the value of
2288 completion_info_charp2.
2290 - A schema query used for completion of both schema and relation names;
2291 these are more complex and must contain in the following order:
2292 %d %s %d %s %d %s %s %d %s
2293 where %d is the string length of the text and %s the text itself.
2295 It is assumed that strings should be escaped to become SQL literals
2296 (that is, what is in the query is actually ... '%s' ...)
2298 See top of file for examples of both kinds of query.
2302 _complete_from_query(int is_schema_query, const char *text, int state)
2304 static int list_index,
2306 static PGresult *result = NULL;
2309 * If this is the first time for this completion, we fetch a list of our
2310 * "things" from the backend.
2314 PQExpBufferData query_buffer;
2317 char *e_info_charp2;
2320 string_length = strlen(text);
2322 /* Free any prior result */
2326 /* Set up suitably-escaped copies of textual inputs */
2327 e_text = pg_malloc(string_length * 2 + 1);
2328 PQescapeString(e_text, text, string_length);
2330 if (completion_info_charp)
2334 charp_len = strlen(completion_info_charp);
2335 e_info_charp = pg_malloc(charp_len * 2 + 1);
2336 PQescapeString(e_info_charp, completion_info_charp,
2340 e_info_charp = NULL;
2342 if (completion_info_charp2)
2346 charp_len = strlen(completion_info_charp2);
2347 e_info_charp2 = pg_malloc(charp_len * 2 + 1);
2348 PQescapeString(e_info_charp2, completion_info_charp2,
2352 e_info_charp2 = NULL;
2354 initPQExpBuffer(&query_buffer);
2356 if (is_schema_query)
2358 /* completion_squery gives us the pieces to assemble */
2359 const char *qualresult = completion_squery->qualresult;
2361 if (qualresult == NULL)
2362 qualresult = completion_squery->result;
2364 /* Get unqualified names matching the input-so-far */
2365 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
2366 completion_squery->result,
2367 completion_squery->catname);
2368 if (completion_squery->selcondition)
2369 appendPQExpBuffer(&query_buffer, "%s AND ",
2370 completion_squery->selcondition);
2371 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
2372 completion_squery->result,
2373 string_length, e_text);
2374 appendPQExpBuffer(&query_buffer, " AND %s",
2375 completion_squery->viscondition);
2378 * When fetching relation names, suppress system catalogs unless
2379 * the input-so-far begins with "pg_". This is a compromise
2380 * between not offering system catalogs for completion at all, and
2381 * having them swamp the result when the input is just "p".
2383 if (strcmp(completion_squery->catname,
2384 "pg_catalog.pg_class c") == 0 &&
2385 strncmp(text, "pg_", 3) !=0)
2387 appendPQExpBuffer(&query_buffer,
2388 " AND c.relnamespace <> (SELECT oid FROM"
2389 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
2393 * Add in matching schema names, but only if there is more than
2394 * one potential match among schema names.
2396 appendPQExpBuffer(&query_buffer, "\nUNION\n"
2397 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
2398 "FROM pg_catalog.pg_namespace n "
2399 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
2400 string_length, e_text);
2401 appendPQExpBuffer(&query_buffer,
2402 " AND (SELECT pg_catalog.count(*)"
2403 " FROM pg_catalog.pg_namespace"
2404 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2405 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
2406 string_length, e_text);
2409 * Add in matching qualified names, but only if there is exactly
2410 * one schema matching the input-so-far.
2412 appendPQExpBuffer(&query_buffer, "\nUNION\n"
2413 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
2414 "FROM %s, pg_catalog.pg_namespace n "
2415 "WHERE %s = n.oid AND ",
2417 completion_squery->catname,
2418 completion_squery->namespace);
2419 if (completion_squery->selcondition)
2420 appendPQExpBuffer(&query_buffer, "%s AND ",
2421 completion_squery->selcondition);
2422 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
2424 string_length, e_text);
2427 * This condition exploits the single-matching-schema rule to
2428 * speed up the query
2430 appendPQExpBuffer(&query_buffer,
2431 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
2432 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
2433 string_length, e_text);
2434 appendPQExpBuffer(&query_buffer,
2435 " AND (SELECT pg_catalog.count(*)"
2436 " FROM pg_catalog.pg_namespace"
2437 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2438 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
2439 string_length, e_text);
2441 /* If an addon query was provided, use it */
2442 if (completion_charp)
2443 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
2447 /* completion_charp is an sprintf-style format string */
2448 appendPQExpBuffer(&query_buffer, completion_charp,
2449 string_length, e_text,
2450 e_info_charp, e_info_charp,
2451 e_info_charp2, e_info_charp2);
2454 /* Limit the number of records in the result */
2455 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
2456 completion_max_records);
2458 result = exec_query(query_buffer.data);
2460 termPQExpBuffer(&query_buffer);
2465 free(e_info_charp2);
2468 /* Find something that matches */
2469 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
2473 while (list_index < PQntuples(result) &&
2474 (item = PQgetvalue(result, list_index++, 0)))
2475 if (pg_strncasecmp(text, item, string_length) == 0)
2476 return pg_strdup(item);
2479 /* If nothing matches, free the db structure and return null */
2486 /* This function returns in order one of a fixed, NULL pointer terminated list
2487 of strings (if matching). This can be used if there are only a fixed number
2488 SQL words that can appear at certain spot.
2491 complete_from_list(const char *text, int state)
2493 static int string_length,
2496 static bool casesensitive;
2499 /* need to have a list */
2500 psql_assert(completion_charpp);
2502 /* Initialization */
2506 string_length = strlen(text);
2507 casesensitive = true;
2511 while ((item = completion_charpp[list_index++]))
2513 /* First pass is case sensitive */
2514 if (casesensitive && strncmp(text, item, string_length) == 0)
2517 return pg_strdup(item);
2520 /* Second pass is case insensitive, don't bother counting matches */
2521 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
2522 return pg_strdup(item);
2526 * No matches found. If we're not case insensitive already, lets switch to
2527 * being case insensitive and try again
2529 if (casesensitive && matches == 0)
2531 casesensitive = false;
2534 return complete_from_list(text, state);
2537 /* If no more matches, return null. */
2542 /* This function returns one fixed string the first time even if it doesn't
2543 match what's there, and nothing the second time. This should be used if there
2544 is only one possibility that can appear at a certain spot, so misspellings
2545 will be overwritten.
2546 The string to be passed must be in completion_charp.
2549 complete_from_const(const char *text, int state)
2551 (void) text; /* We don't care about what was entered
2554 psql_assert(completion_charp);
2556 return pg_strdup(completion_charp);
2563 /* HELPER FUNCTIONS */
2567 * Execute a query and report any errors. This should be the preferred way of
2568 * talking to the database in this file.
2571 exec_query(const char *query)
2575 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
2578 result = PQexec(pset.db, query);
2580 if (PQresultStatus(result) != PGRES_TUPLES_OK)
2583 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
2584 PQerrorMessage(pset.db), query);
2596 * Return the word (space delimited) before point. Set skip > 0 to
2597 * skip that many words; e.g. skip=1 finds the word before the
2598 * previous one. Return value is NULL or a malloc'ed string.
2601 previous_word(int point, int skip)
2611 /* first we look for a space before the current word */
2612 for (i = point; i >= 0; i--)
2613 if (rl_line_buffer[i] == ' ')
2616 /* now find the first non-space which then constitutes the end */
2618 if (rl_line_buffer[i] != ' ')
2625 * If no end found we return null, because there is no word before the
2632 * Otherwise we now look for the start. The start is either the last
2633 * character before any space going backwards from the end, or it's
2634 * simply character 0
2636 for (start = end; start > 0; start--)
2638 if (rl_line_buffer[start] == '"')
2639 inquotes = !inquotes;
2640 if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
2648 s = pg_malloc(end - start + 2);
2649 strlcpy(s, &rl_line_buffer[start], end - start + 2);
2654 /* Find the parenthesis after the last word */
2658 find_open_parenthesis(int end)
2662 while ((rl_line_buffer[i] != ' ') && (i >= 0))
2664 if (rl_line_buffer[i] == '(')
2668 while ((rl_line_buffer[i] == ' ') && (i >= 0))
2672 if (rl_line_buffer[i] == '(')
2683 * Surround a string with single quotes. This works for both SQL and
2684 * psql internal. Currently disabled because it is reported not to
2685 * cooperate with certain versions of readline.
2688 quote_file_name(char *text, int match_type, char *quote_pointer)
2693 (void) quote_pointer; /* not used */
2695 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
2696 s = pg_malloc(length);
2698 strcpy(s + 1, text);
2699 if (match_type == SINGLE_MATCH)
2700 s[length - 2] = '\'';
2701 s[length - 1] = '\0';
2708 dequote_file_name(char *text, char quote_char)
2714 return pg_strdup(text);
2716 length = strlen(text);
2717 s = pg_malloc(length - 2 + 1);
2718 strlcpy(s, text +1, length - 2 + 1);
2724 #endif /* USE_READLINE */