2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2005, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.132 2005/06/21 00:48:33 neilc 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"
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
87 * candidates to display. If catname mentions multiple tables,
88 * include the necessary join condition here. For example, "c.relkind
89 * = 'r'". Write NULL (not an empty string) if not needed.
91 const char *selcondition;
94 * Visibility condition --- which rows are visible without schema
95 * qualification? For example,
96 * "pg_catalog.pg_table_is_visible(c.oid)".
98 const char *viscondition;
101 * Namespace --- name of field to join to pg_namespace.oid. For
102 * example, "c.relnamespace".
104 const char *namespace;
107 * Result --- the appropriately-quoted name to return, in the case of
108 * an unqualified name. For example,
109 * "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
133 static const char *completion_info_charp; /* to pass a second string */
134 static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
136 /* A couple of macros to ease typing. You can use these to complete the given
138 1) The results from a query you pass it. (Perhaps one of those below?)
139 2) The results from a schema query you pass it.
140 3) The items from a null-pointer-terminated list.
142 5) The list of attributes to the given table.
144 #define COMPLETE_WITH_QUERY(query) \
145 do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
146 #define COMPLETE_WITH_SCHEMA_QUERY(query,addon) \
147 do { completion_squery = &(query); completion_charp = addon; matches = completion_matches(text, complete_from_schema_query); } while(0)
148 #define COMPLETE_WITH_LIST(list) \
149 do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
150 #define COMPLETE_WITH_CONST(string) \
151 do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
152 #define COMPLETE_WITH_ATTR(table) \
153 do {completion_charp = Query_for_list_of_attributes; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0)
156 * Assembly instructions for schema queries
159 static const SchemaQuery Query_for_list_of_aggregates = {
161 "pg_catalog.pg_proc p",
165 "pg_catalog.pg_function_is_visible(p.oid)",
169 "pg_catalog.quote_ident(p.proname)",
174 static const SchemaQuery Query_for_list_of_datatypes = {
176 "pg_catalog.pg_type t",
177 /* selcondition --- ignore table rowtypes and array types */
179 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
180 "AND t.typname !~ '^_'",
182 "pg_catalog.pg_type_is_visible(t.oid)",
186 "pg_catalog.format_type(t.oid, NULL)",
188 "pg_catalog.quote_ident(t.typname)"
191 static const SchemaQuery Query_for_list_of_domains = {
193 "pg_catalog.pg_type t",
197 "pg_catalog.pg_type_is_visible(t.oid)",
201 "pg_catalog.quote_ident(t.typname)",
206 static const SchemaQuery Query_for_list_of_functions = {
208 "pg_catalog.pg_proc p",
212 "pg_catalog.pg_function_is_visible(p.oid)",
216 "pg_catalog.quote_ident(p.proname)",
221 static const SchemaQuery Query_for_list_of_indexes = {
223 "pg_catalog.pg_class c",
225 "c.relkind IN ('i')",
227 "pg_catalog.pg_table_is_visible(c.oid)",
231 "pg_catalog.quote_ident(c.relname)",
236 static const SchemaQuery Query_for_list_of_sequences = {
238 "pg_catalog.pg_class c",
240 "c.relkind IN ('S')",
242 "pg_catalog.pg_table_is_visible(c.oid)",
246 "pg_catalog.quote_ident(c.relname)",
251 static const SchemaQuery Query_for_list_of_tables = {
253 "pg_catalog.pg_class c",
255 "c.relkind IN ('r')",
257 "pg_catalog.pg_table_is_visible(c.oid)",
261 "pg_catalog.quote_ident(c.relname)",
266 static const SchemaQuery Query_for_list_of_tisv = {
268 "pg_catalog.pg_class c",
270 "c.relkind IN ('r', 'i', 'S', 'v')",
272 "pg_catalog.pg_table_is_visible(c.oid)",
276 "pg_catalog.quote_ident(c.relname)",
281 static const SchemaQuery Query_for_list_of_tsv = {
283 "pg_catalog.pg_class c",
285 "c.relkind IN ('r', 'S', 'v')",
287 "pg_catalog.pg_table_is_visible(c.oid)",
291 "pg_catalog.quote_ident(c.relname)",
296 static const SchemaQuery Query_for_list_of_views = {
298 "pg_catalog.pg_class c",
300 "c.relkind IN ('v')",
302 "pg_catalog.pg_table_is_visible(c.oid)",
306 "pg_catalog.quote_ident(c.relname)",
313 * Queries to get lists of names of various kinds of things, possibly
314 * restricted to names matching a partially entered name. In these queries,
315 * %s will be replaced by the text entered so far (suitably escaped to
316 * become a SQL literal string). %d will be replaced by the length of the
317 * string (in unescaped form). A second %s, if present, will be replaced
318 * by a suitably-escaped version of the string provided in
319 * completion_info_charp.
321 * Beware that the allowed sequences of %s and %d are determined by
322 * _complete_from_query().
325 #define Query_for_list_of_attributes \
326 "SELECT pg_catalog.quote_ident(attname) "\
327 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
328 " WHERE c.oid = a.attrelid "\
329 " AND a.attnum > 0 "\
330 " AND NOT a.attisdropped "\
331 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
332 " AND pg_catalog.quote_ident(relname)='%s' "\
333 " AND pg_catalog.pg_table_is_visible(c.oid)"
335 #define Query_for_list_of_databases \
336 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
337 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
339 #define Query_for_list_of_tablespaces \
340 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
341 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
343 #define Query_for_list_of_encodings \
344 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
345 " FROM pg_catalog.pg_conversion "\
346 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
348 #define Query_for_list_of_languages \
349 "SELECT pg_catalog.quote_ident(lanname) "\
350 " FROM pg_language "\
351 " WHERE lanname != 'internal' "\
352 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
354 #define Query_for_list_of_schemas \
355 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
356 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
358 #define Query_for_list_of_system_relations \
359 "SELECT pg_catalog.quote_ident(relname) "\
360 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
361 " WHERE c.relkind IN ('r', 'v', 's', 'S') "\
362 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
363 " AND c.relnamespace = n.oid "\
364 " AND n.nspname = 'pg_catalog'"
366 #define Query_for_list_of_users \
367 " SELECT pg_catalog.quote_ident(usename) "\
368 " FROM pg_catalog.pg_user "\
369 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
371 #define Query_for_list_of_grant_users \
372 " SELECT pg_catalog.quote_ident(usename) "\
373 " FROM pg_catalog.pg_user "\
374 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"\
375 " UNION SELECT 'PUBLIC' UNION SELECT 'GROUP'"
377 /* the silly-looking length condition is just to eat up the current word */
378 #define Query_for_table_owning_index \
379 "SELECT pg_catalog.quote_ident(c1.relname) "\
380 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
381 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
382 " and (%d = length('%s'))"\
383 " and pg_catalog.quote_ident(c2.relname)='%s'"\
384 " and pg_catalog.pg_table_is_visible(c2.oid)"
386 /* the silly-looking length condition is just to eat up the current word */
387 #define Query_for_index_of_table \
388 "SELECT pg_catalog.quote_ident(c2.relname) "\
389 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
390 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
391 " and (%d = length('%s'))"\
392 " and pg_catalog.quote_ident(c1.relname)='%s'"\
393 " and pg_catalog.pg_table_is_visible(c2.oid)"
395 /* the silly-looking length condition is just to eat up the current word */
396 #define Query_for_list_of_tables_for_trigger \
397 "SELECT pg_catalog.quote_ident(relname) "\
398 " FROM pg_catalog.pg_class"\
399 " WHERE (%d = length('%s'))"\
401 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
402 " WHERE pg_catalog.quote_ident(tgname)='%s')"
405 * This is a list of all "things" in Pgsql, which can show up after CREATE or
406 * DROP; and there is also a query to get a list of them.
412 const char *query; /* simple query, or NULL */
413 const SchemaQuery *squery; /* schema query, or NULL */
416 static const pgsql_thing_t words_after_create[] = {
417 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
418 {"CAST", NULL, NULL}, /* Casts have complex structures for
419 * names, so skip it */
420 /* CREATE CONSTRAINT TRIGGER is not supported here because it is designed to be used only by pg_dump. */
421 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
422 {"DATABASE", Query_for_list_of_databases},
423 {"DOMAIN", NULL, &Query_for_list_of_domains},
424 {"FUNCTION", NULL, &Query_for_list_of_functions},
425 {"GROUP", "SELECT pg_catalog.quote_ident(groname) FROM pg_catalog.pg_group WHERE substring(pg_catalog.quote_ident(groname),1,%d)='%s'"},
426 {"LANGUAGE", Query_for_list_of_languages},
427 {"INDEX", NULL, &Query_for_list_of_indexes},
428 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such
430 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
431 {"SCHEMA", Query_for_list_of_schemas},
432 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
433 {"TABLE", NULL, &Query_for_list_of_tables},
434 {"TABLESPACE", Query_for_list_of_tablespaces},
435 {"TEMP", NULL, NULL}, /* for CREATE TEMP TABLE ... */
436 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
437 {"TYPE", NULL, &Query_for_list_of_datatypes},
438 {"UNIQUE", NULL, NULL}, /* for CREATE UNIQUE INDEX ... */
439 {"USER", Query_for_list_of_users},
440 {"VIEW", NULL, &Query_for_list_of_views},
441 {NULL, NULL, NULL} /* end of list */
445 /* Forward declaration of functions */
446 static char **psql_completion(char *text, int start, int end);
447 static char *create_command_generator(const char *text, int state);
448 static char *complete_from_query(const char *text, int state);
449 static char *complete_from_schema_query(const char *text, int state);
450 static char *_complete_from_query(int is_schema_query,
451 const char *text, int state);
452 static char *complete_from_const(const char *text, int state);
453 static char *complete_from_list(const char *text, int state);
455 static PGresult *exec_query(const char *query);
457 static char *previous_word(int point, int skip);
460 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
461 static char *dequote_file_name(char *text, char quote_char);
465 /* Initialize the readline library for our purposes. */
467 initialize_readline(void)
469 rl_readline_name = (char *) pset.progname;
470 rl_attempted_completion_function = (void *) psql_completion;
472 rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
474 completion_max_records = 1000;
477 * There is a variable rl_completion_query_items for this but
478 * apparently it's not defined everywhere.
483 /* The completion function. Acc. to readline spec this gets passed the text
484 entered to far and its start and end in the readline buffer. The return value
485 is some partially obscure list format that can be generated by the readline
486 libraries completion_matches() function, so we don't have to worry about it.
489 psql_completion(char *text, int start, int end)
491 /* This is the variable we'll return. */
492 char **matches = NULL;
494 /* These are going to contain some scannage of the input line. */
501 static const char *const sql_commands[] = {
502 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
503 "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE FROM", "DROP", "END", "EXECUTE",
504 "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
505 "PREPARE", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", "SAVEPOINT",
506 "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
509 static const char *const pgsql_variables[] = {
510 /* these SET arguments are known in gram.y */
517 * the rest should match USERSET and possibly SUSET entries in
518 * backend/utils/misc/guc.c.
521 "australian_timezones",
523 "client_min_messages",
526 "cpu_index_tuple_cost",
531 "debug_pretty_print",
534 "debug_print_rewritten",
535 "default_statistics_target",
536 "default_tablespace",
537 "default_transaction_isolation",
538 "default_transaction_read_only",
540 "dynamic_library_path",
541 "effective_cache_size",
551 "explain_pretty_print",
552 "extra_float_digits",
553 "from_collapse_limit",
559 "geqo_selection_bias",
561 "join_collapse_limit",
568 "log_error_verbosity",
569 "log_executor_stats",
570 "log_min_duration_statement",
571 "log_min_error_statement",
576 "log_statement_stats",
577 "maintenance_work_mem",
579 "max_files_per_process",
582 "max_locks_per_transaction",
584 "password_encryption",
596 "stats_command_string",
597 "stats_reset_on_server_start",
599 "stats_start_collector",
600 "superuser_reserved_connections",
606 "transform_null_equals",
607 "unix_socket_directory",
609 "unix_socket_permissions",
617 static const char *const backslash_commands[] = {
618 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
619 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
620 "\\dg", "\\di", "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS",
621 "\\dt", "\\dT", "\\dv", "\\du",
622 "\\e", "\\echo", "\\encoding",
623 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
624 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
625 "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
626 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
629 (void) end; /* not used */
631 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
632 rl_completion_append_character = ' ';
635 /* Clear a few things. */
636 completion_charp = NULL;
637 completion_charpp = NULL;
638 completion_info_charp = NULL;
641 * Scan the input line before our current position for the last four
642 * words. According to those we'll make some smart decisions on what
643 * the user is probably intending to type. TODO: Use strtokx() to do
646 prev_wd = previous_word(start, 0);
647 prev2_wd = previous_word(start, 1);
648 prev3_wd = previous_word(start, 2);
649 prev4_wd = previous_word(start, 3);
650 prev5_wd = previous_word(start, 4);
652 /* If a backslash command was started, continue */
654 COMPLETE_WITH_LIST(backslash_commands);
656 /* If no previous word, suggest one of the basic sql commands */
658 COMPLETE_WITH_LIST(sql_commands);
660 /* CREATE or DROP but not ALTER (TABLE|DOMAIN|GROUP) sth DROP */
661 /* complete with something you can create or drop */
662 else if (pg_strcasecmp(prev_wd, "CREATE") == 0 ||
663 (pg_strcasecmp(prev_wd, "DROP") == 0 &&
664 pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
665 pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
666 pg_strcasecmp(prev3_wd, "GROUP") != 0))
667 matches = completion_matches(text, create_command_generator);
672 * complete with what you can alter (TABLE, GROUP, USER, ...) unless
673 * we're in ALTER TABLE sth ALTER
675 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
676 pg_strcasecmp(prev3_wd, "TABLE") != 0)
678 static const char *const list_ALTER[] =
679 {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
680 "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "SCHEMA", "SEQUENCE", "TABLE",
681 "TABLESPACE", "TRIGGER", "TYPE", "USER", NULL};
683 COMPLETE_WITH_LIST(list_ALTER);
686 /* ALTER AGGREGATE,CONVERSION,FUNCTION,SCHEMA <name> */
687 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
688 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
689 pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
690 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
691 pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
693 static const char *const list_ALTERGEN[] =
694 {"OWNER TO", "RENAME TO", NULL};
696 COMPLETE_WITH_LIST(list_ALTERGEN);
699 /* ALTER DATABASE <name> */
700 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
701 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
703 static const char *const list_ALTERDATABASE[] =
704 {"RESET", "SET", "OWNER TO", "RENAME TO", NULL};
706 COMPLETE_WITH_LIST(list_ALTERDATABASE);
709 /* ALTER INDEX <name> */
710 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
711 pg_strcasecmp(prev2_wd, "INDEX") == 0)
713 static const char *const list_ALTERINDEX[] =
714 {"SET TABLESPACE", "OWNER TO", "RENAME TO", NULL};
716 COMPLETE_WITH_LIST(list_ALTERINDEX);
719 /* ALTER LANGUAGE <name> */
720 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
721 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
722 COMPLETE_WITH_CONST("RENAME TO");
724 /* ALTER USER <name> */
725 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
726 pg_strcasecmp(prev2_wd, "USER") == 0)
728 static const char *const list_ALTERUSER[] =
729 {"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
730 "NOCREATEUSER", "VALID UNTIL", "RENAME TO", "SET", "RESET", NULL};
732 COMPLETE_WITH_LIST(list_ALTERUSER);
735 /* ALTER DOMAIN <name> */
736 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
737 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
739 static const char *const list_ALTERDOMAIN[] =
740 {"ADD", "DROP", "OWNER TO", "SET", NULL};
742 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
744 /* ALTER DOMAIN <sth> DROP */
745 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
746 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
747 pg_strcasecmp(prev_wd, "DROP") == 0)
749 static const char *const list_ALTERDOMAIN2[] =
750 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
752 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
754 /* ALTER DOMAIN <sth> SET */
755 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
756 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
757 pg_strcasecmp(prev_wd, "SET") == 0)
759 static const char *const list_ALTERDOMAIN3[] =
760 {"DEFAULT", "NOT NULL", NULL};
762 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
764 /* ALTER SEQUENCE <name> */
765 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
766 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
768 static const char *const list_ALTERSCHEMA[] =
769 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE", NULL};
771 COMPLETE_WITH_LIST(list_ALTERSCHEMA);
773 /* ALTER SEQUENCE <name> NO */
774 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
775 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
776 pg_strcasecmp(prev_wd, "NO") == 0)
778 static const char *const list_ALTERSCHEMA2[] =
779 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
781 COMPLETE_WITH_LIST(list_ALTERSCHEMA2);
783 /* ALTER TRIGGER <name>, add ON */
784 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
785 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
786 COMPLETE_WITH_CONST("ON");
788 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
789 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
791 completion_info_charp = prev2_wd;
792 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
796 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
798 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
799 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
800 pg_strcasecmp(prev_wd, "ON") == 0)
801 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
803 /* ALTER TRIGGER <name> ON <name> */
804 else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
805 pg_strcasecmp(prev2_wd, "ON") == 0)
806 COMPLETE_WITH_CONST("RENAME TO");
809 * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
810 * RENAME, CLUSTER ON or OWNER
812 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
813 pg_strcasecmp(prev2_wd, "TABLE") == 0)
815 static const char *const list_ALTER2[] =
816 {"ADD", "ALTER", "CLUSTER ON", "DROP", "RENAME", "OWNER TO",
819 COMPLETE_WITH_LIST(list_ALTER2);
821 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
822 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
823 (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
824 pg_strcasecmp(prev_wd, "RENAME") == 0))
825 COMPLETE_WITH_ATTR(prev2_wd);
827 /* ALTER TABLE xxx RENAME yyy */
828 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
829 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
830 pg_strcasecmp(prev_wd, "TO") != 0)
831 COMPLETE_WITH_CONST("TO");
833 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
834 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
835 pg_strcasecmp(prev_wd, "DROP") == 0)
837 static const char *const list_TABLEDROP[] =
838 {"COLUMN", "CONSTRAINT", NULL};
840 COMPLETE_WITH_LIST(list_TABLEDROP);
842 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
843 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
844 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
845 pg_strcasecmp(prev_wd, "COLUMN") == 0)
846 COMPLETE_WITH_ATTR(prev3_wd);
847 /* ALTER TABLE ALTER [COLUMN] <foo> */
848 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
849 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
850 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
851 pg_strcasecmp(prev2_wd, "ALTER") == 0))
853 /* DROP ... does not work well yet */
854 static const char *const list_COLUMNALTER[] =
855 {"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
856 "DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
858 COMPLETE_WITH_LIST(list_COLUMNALTER);
860 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
861 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
862 COMPLETE_WITH_CONST("ON");
863 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
864 pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
865 pg_strcasecmp(prev_wd, "ON") == 0)
867 completion_info_charp = prev3_wd;
868 COMPLETE_WITH_QUERY(Query_for_index_of_table);
870 /* If we have TABLE <sth> SET, provide WITHOUT or TABLESPACE */
871 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
872 pg_strcasecmp(prev_wd, "SET") == 0)
874 static const char *const list_TABLESET[] =
875 {"WITHOUT", "TABLESPACE", NULL};
877 COMPLETE_WITH_LIST(list_TABLESET);
879 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
880 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
881 pg_strcasecmp(prev2_wd, "SET") == 0 &&
882 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
883 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
884 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
885 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
886 pg_strcasecmp(prev2_wd, "SET") == 0 &&
887 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
889 static const char *const list_TABLESET2[] =
890 {"CLUSTER", "OIDS", NULL};
892 COMPLETE_WITH_LIST(list_TABLESET2);
894 /* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */
895 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
896 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
898 static const char *const list_ALTERTSPC[] =
899 {"RENAME TO", "OWNER TO", NULL};
901 COMPLETE_WITH_LIST(list_ALTERTSPC);
903 /* complete ALTER TYPE <foo> with OWNER TO */
904 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
905 pg_strcasecmp(prev2_wd, "TYPE") == 0)
906 COMPLETE_WITH_CONST("OWNER TO");
907 /* complete ALTER GROUP <foo> */
908 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
909 pg_strcasecmp(prev2_wd, "GROUP") == 0)
911 static const char *const list_ALTERGROUP[] =
912 {"ADD USER", "DROP USER", "RENAME TO", NULL};
914 COMPLETE_WITH_LIST(list_ALTERGROUP);
916 /* complete ALTER GROUP <foo> ADD|DROP with USER */
917 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
918 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
919 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
920 pg_strcasecmp(prev_wd, "DROP") == 0))
921 COMPLETE_WITH_CONST("USER");
922 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
923 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
924 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
925 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
926 pg_strcasecmp(prev_wd, "USER") == 0)
927 COMPLETE_WITH_QUERY(Query_for_list_of_users);
929 /* BEGIN, END, COMMIT, ABORT */
930 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
931 pg_strcasecmp(prev_wd, "END") == 0 ||
932 pg_strcasecmp(prev_wd, "COMMIT") == 0 ||
933 pg_strcasecmp(prev_wd, "ABORT") == 0)
935 static const char *const list_TRANS[] =
936 {"WORK", "TRANSACTION", NULL};
938 COMPLETE_WITH_LIST(list_TRANS);
940 /* RELEASE SAVEPOINT */
941 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
942 COMPLETE_WITH_CONST("SAVEPOINT");
944 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
946 static const char *const list_TRANS[] =
947 {"WORK", "TRANSACTION", "TO SAVEPOINT", NULL};
949 COMPLETE_WITH_LIST(list_TRANS);
954 * If the previous word is CLUSTER and not without produce list of
957 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
958 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
959 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
960 /* If we have CLUSTER <sth>, then add "ON" */
961 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
962 pg_strcasecmp(prev_wd, "ON") != 0)
963 COMPLETE_WITH_CONST("ON");
966 * If we have CLUSTER <sth> ON, then add the correct tablename as
969 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
970 pg_strcasecmp(prev_wd, "ON") == 0)
972 completion_info_charp = prev2_wd;
973 COMPLETE_WITH_QUERY(Query_for_table_owning_index);
977 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
978 COMPLETE_WITH_CONST("ON");
979 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
980 pg_strcasecmp(prev_wd, "ON") == 0)
982 static const char *const list_COMMENT[] =
983 {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
984 "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
985 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
987 COMPLETE_WITH_LIST(list_COMMENT);
989 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
990 pg_strcasecmp(prev3_wd, "ON") == 0)
991 COMPLETE_WITH_CONST("IS");
996 * If we have COPY [BINARY] (which you'd have to type yourself), offer
997 * list of tables (Also cover the analogous backslash command)
999 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1000 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1001 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1002 pg_strcasecmp(prev_wd, "BINARY") == 0))
1003 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1004 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1005 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1006 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1007 pg_strcasecmp(prev2_wd, "BINARY") == 0)
1009 static const char *const list_FROMTO[] =
1010 {"FROM", "TO", NULL};
1012 COMPLETE_WITH_LIST(list_FROMTO);
1014 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1015 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1016 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1017 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1018 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1019 pg_strcasecmp(prev_wd, "TO") == 0))
1020 matches = completion_matches(text, filename_completion_function);
1022 /* Handle COPY|BINARY <sth> FROM|TO filename */
1023 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1024 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1025 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1026 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1027 pg_strcasecmp(prev2_wd, "TO") == 0))
1029 static const char *const list_COPY[] =
1030 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", NULL};
1032 COMPLETE_WITH_LIST(list_COPY);
1035 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1036 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1037 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1038 pg_strcasecmp(prev3_wd, "TO") == 0))
1040 static const char *const list_CSV[] =
1041 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
1043 COMPLETE_WITH_LIST(list_CSV);
1047 /* First off we complete CREATE UNIQUE with "INDEX" */
1048 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1049 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1050 COMPLETE_WITH_CONST("INDEX");
1051 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
1052 else if (pg_strcasecmp(prev2_wd, "INDEX") == 0 &&
1053 (pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1054 pg_strcasecmp(prev3_wd, "UNIQUE") == 0))
1055 COMPLETE_WITH_CONST("ON");
1056 /* Complete ... INDEX <name> ON with a list of tables */
1057 else if (pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1058 pg_strcasecmp(prev_wd, "ON") == 0)
1059 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1062 * Complete INDEX <name> ON <table> with a list of table columns
1063 * (which should really be in parens)
1065 else if (pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1066 pg_strcasecmp(prev2_wd, "ON") == 0)
1067 COMPLETE_WITH_ATTR(prev_wd);
1068 /* same if you put in USING */
1069 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1070 pg_strcasecmp(prev2_wd, "USING") == 0)
1071 COMPLETE_WITH_ATTR(prev3_wd);
1072 /* Complete USING with an index method */
1073 else if (pg_strcasecmp(prev_wd, "USING") == 0)
1075 static const char *const index_mth[] =
1076 {"BTREE", "RTREE", "HASH", "GIST", NULL};
1078 COMPLETE_WITH_LIST(index_mth);
1082 /* Complete "CREATE RULE <sth>" with "AS" */
1083 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1084 pg_strcasecmp(prev2_wd, "RULE") == 0)
1085 COMPLETE_WITH_CONST("AS");
1086 /* Complete "CREATE RULE <sth> AS with "ON" */
1087 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1088 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1089 pg_strcasecmp(prev_wd, "AS") == 0)
1090 COMPLETE_WITH_CONST("ON");
1091 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1092 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1093 pg_strcasecmp(prev2_wd, "AS") == 0 &&
1094 pg_strcasecmp(prev_wd, "ON") == 0)
1096 static const char *const rule_events[] =
1097 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1099 COMPLETE_WITH_LIST(rule_events);
1101 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1102 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1103 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1104 (toupper((unsigned char) prev_wd[4]) == 'T' ||
1105 toupper((unsigned char) prev_wd[5]) == 'T'))
1106 COMPLETE_WITH_CONST("TO");
1107 /* Complete "AS ON <sth> TO" with a table name */
1108 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1109 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1110 pg_strcasecmp(prev_wd, "TO") == 0)
1111 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1114 /* Complete CREATE TEMP with "TABLE" */
1115 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1116 pg_strcasecmp(prev_wd, "TEMP") == 0)
1117 COMPLETE_WITH_CONST("TABLE");
1119 /* CREATE TABLESPACE */
1120 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1121 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1123 static const char *const list_CREATETABLESPACE[] =
1124 {"OWNER", "LOCATION", NULL};
1126 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1128 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1129 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1130 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1131 pg_strcasecmp(prev2_wd, "OWNER") == 0)
1133 COMPLETE_WITH_CONST("LOCATION");
1136 /* CREATE TRIGGER */
1137 /* is on the agenda . . . */
1140 /* Complete "CREATE VIEW <name>" with "AS" */
1141 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1142 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1143 COMPLETE_WITH_CONST("AS");
1144 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1145 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1146 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1147 pg_strcasecmp(prev_wd, "AS") == 0)
1148 COMPLETE_WITH_CONST("SELECT");
1151 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1153 static const char *const list_DECLARE[] =
1154 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1155 COMPLETE_WITH_LIST(list_DECLARE);
1158 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1160 static const char *const list_DECLARECURSOR[] =
1161 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1162 COMPLETE_WITH_LIST(list_DECLARECURSOR);
1168 * Complete DELETE with FROM (only if the word before that is not "ON"
1169 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1171 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1172 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1173 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1174 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1175 pg_strcasecmp(prev2_wd, "AFTER") == 0))
1176 COMPLETE_WITH_CONST("FROM");
1177 /* Complete DELETE FROM with a list of tables */
1178 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1179 pg_strcasecmp(prev_wd, "FROM") == 0)
1180 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1181 /* Complete DELETE FROM <table> */
1182 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1183 pg_strcasecmp(prev2_wd, "FROM") == 0)
1185 static const char *const list_DELETE[] =
1186 {"USING", "WHERE", "SET", NULL};
1188 COMPLETE_WITH_LIST(list_DELETE);
1190 /* XXX: implement tab completion for DELETE ... USING */
1192 /* DROP (when not the previous word) */
1193 /* DROP AGGREGATE */
1194 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1195 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1196 COMPLETE_WITH_CONST("(");
1198 /* DROP object with CASCADE / RESTRICT */
1199 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1200 (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1201 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1202 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1203 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1204 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1205 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1206 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1207 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1208 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1209 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1210 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1211 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1212 prev_wd[strlen(prev_wd) - 1] == ')'))
1214 static const char *const list_DROPCR[] =
1215 {"CASCADE", "RESTRICT", NULL};
1216 COMPLETE_WITH_LIST(list_DROPCR);
1221 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1223 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1225 static const char *const list_EXPLAIN[] =
1226 {"SELECT","INSERT","DELETE","UPDATE","DECLARE","ANALYZE","VERBOSE",NULL};
1227 COMPLETE_WITH_LIST(list_EXPLAIN);
1229 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1230 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1232 static const char *const list_EXPLAIN[] =
1233 {"SELECT","INSERT","DELETE","UPDATE","DECLARE","VERBOSE",NULL};
1234 COMPLETE_WITH_LIST(list_EXPLAIN);
1236 else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1237 pg_strcasecmp(prev3_wd, "VACUUM") != 0 &&
1238 pg_strcasecmp(prev4_wd, "VACUUM") != 0 &&
1239 (pg_strcasecmp(prev2_wd, "ANALYZE") == 0 ||
1240 pg_strcasecmp(prev2_wd, "EXPLAIN") == 0))
1242 static const char *const list_EXPLAIN[] =
1243 {"SELECT","INSERT","DELETE","UPDATE","DECLARE",NULL};
1244 COMPLETE_WITH_LIST(list_EXPLAIN);
1248 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1249 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1250 pg_strcasecmp(prev_wd, "MOVE") == 0)
1252 static const char *const list_FETCH1[] =
1253 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1255 COMPLETE_WITH_LIST(list_FETCH1);
1257 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1258 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1259 pg_strcasecmp(prev2_wd, "MOVE") == 0)
1261 static const char *const list_FETCH2[] =
1262 {"ALL", "NEXT", "PRIOR", NULL};
1264 COMPLETE_WITH_LIST(list_FETCH2);
1268 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are
1269 * equivalent, but we may as well tab-complete both: perhaps some
1270 * users prefer one variant or the other.
1272 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
1273 pg_strcasecmp(prev3_wd, "MOVE") == 0)
1275 static const char *const list_FROMIN[] =
1276 {"FROM", "IN", NULL};
1278 COMPLETE_WITH_LIST(list_FROMIN);
1281 /* GRANT && REVOKE*/
1282 /* Complete GRANT/REVOKE with a list of privileges */
1283 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
1284 pg_strcasecmp(prev_wd, "REVOKE") == 0)
1286 static const char *const list_privileg[] =
1287 {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
1288 "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
1290 COMPLETE_WITH_LIST(list_privileg);
1292 /* Complete GRANT/REVOKE <sth> with "ON" */
1293 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1294 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
1295 COMPLETE_WITH_CONST("ON");
1298 * Complete GRANT/REVOKE <sth> ON with a list of tables, views,
1299 * sequences, and indexes
1301 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result
1302 * via UNION; seems to work intuitively
1304 * Note: GRANT/REVOKE can get quite complex; tab-completion as
1305 * implemented here will only work if the privilege list contains
1306 * exactly one privilege
1308 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
1309 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
1310 pg_strcasecmp(prev_wd, "ON") == 0)
1311 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
1312 " UNION SELECT 'DATABASE'"
1313 " UNION SELECT 'FUNCTION'"
1314 " UNION SELECT 'LANGUAGE'"
1315 " UNION SELECT 'SCHEMA'"
1316 " UNION SELECT 'TABLESPACE'");
1318 /* Complete "GRANT/REVOKE * ON * " with "TO" */
1319 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1320 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1321 pg_strcasecmp(prev2_wd, "ON") == 0)
1323 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1324 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1325 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
1326 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1327 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
1328 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1329 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
1330 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1331 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1332 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1333 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
1334 COMPLETE_WITH_CONST("TO");
1336 COMPLETE_WITH_CONST("FROM");
1339 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1340 else if (pg_strcasecmp(prev3_wd, "ON") == 0 &&
1341 ((pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
1342 pg_strcasecmp(prev_wd, "TO") == 0) ||
1343 (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
1344 pg_strcasecmp(prev_wd, "FROM") == 0)))
1345 COMPLETE_WITH_QUERY(Query_for_list_of_grant_users);
1348 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1349 pg_strcasecmp(prev_wd, "GROUP") == 0)
1350 COMPLETE_WITH_CONST("BY");
1353 /* Complete INSERT with "INTO" */
1354 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
1355 COMPLETE_WITH_CONST("INTO");
1356 /* Complete INSERT INTO with table names */
1357 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
1358 pg_strcasecmp(prev_wd, "INTO") == 0)
1359 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1360 /* Complete "INSERT INTO <table> (" with attribute names */
1361 else if (rl_line_buffer[start - 1] == '(' &&
1362 pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1363 pg_strcasecmp(prev2_wd, "INTO") == 0)
1364 COMPLETE_WITH_ATTR(prev_wd);
1367 * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1370 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1371 pg_strcasecmp(prev2_wd, "INTO") == 0)
1373 static const char *const list_INSERT[] =
1374 {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1376 COMPLETE_WITH_LIST(list_INSERT);
1378 /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1379 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
1380 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
1381 prev_wd[strlen(prev_wd) - 1] == ')')
1383 static const char *const list_INSERT[] =
1384 {"SELECT", "VALUES", NULL};
1386 COMPLETE_WITH_LIST(list_INSERT);
1389 /* Insert an open parenthesis after "VALUES" */
1390 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
1391 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
1392 COMPLETE_WITH_CONST("(");
1395 /* Complete LOCK [TABLE] with a list of tables */
1396 else if (pg_strcasecmp(prev_wd, "LOCK") == 0 ||
1397 (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
1398 pg_strcasecmp(prev2_wd, "LOCK") == 0))
1399 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1401 /* For the following, handle the case of a single table only for now */
1403 /* Complete LOCK [TABLE] <table> with "IN" */
1404 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
1405 pg_strcasecmp(prev_wd, "TABLE")) ||
1406 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
1407 pg_strcasecmp(prev3_wd, "LOCK") == 0))
1408 COMPLETE_WITH_CONST("IN");
1410 /* Complete LOCK [TABLE] <table> IN with a lock mode */
1411 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
1412 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
1413 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1414 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
1416 static const char *const lock_modes[] =
1417 {"ACCESS SHARE MODE",
1418 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1419 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1420 "SHARE ROW EXCLUSIVE MODE",
1421 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1423 COMPLETE_WITH_LIST(lock_modes);
1427 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
1428 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1430 /* OWNER TO - complete with available users*/
1431 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
1432 pg_strcasecmp(prev_wd, "TO") == 0)
1433 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1436 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1437 pg_strcasecmp(prev_wd, "ORDER") == 0)
1438 COMPLETE_WITH_CONST("BY");
1439 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
1440 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
1441 pg_strcasecmp(prev_wd, "BY") == 0)
1442 COMPLETE_WITH_ATTR(prev3_wd);
1445 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
1446 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
1448 static const char *const list_PREPARE[] =
1449 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1451 COMPLETE_WITH_LIST(list_PREPARE);
1456 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
1458 static const char *const list_REINDEX[] =
1459 {"TABLE", "DATABASE", "INDEX", NULL};
1461 COMPLETE_WITH_LIST(list_REINDEX);
1463 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
1465 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
1466 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1467 else if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1468 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1469 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
1470 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1476 /* SET, RESET, SHOW */
1477 /* Complete with a variable name */
1478 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
1479 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
1480 pg_strcasecmp(prev_wd, "RESET") == 0 ||
1481 pg_strcasecmp(prev_wd, "SHOW") == 0)
1482 COMPLETE_WITH_LIST(pgsql_variables);
1483 /* Complete "SET TRANSACTION" */
1484 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
1485 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1486 || (pg_strcasecmp(prev2_wd, "START") == 0
1487 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1488 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1489 && pg_strcasecmp(prev_wd, "WORK") == 0)
1490 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1491 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1492 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
1493 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
1494 && pg_strcasecmp(prev2_wd, "AS") == 0
1495 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
1497 static const char *const my_list[] =
1498 {"ISOLATION LEVEL", "READ", NULL};
1500 COMPLETE_WITH_LIST(my_list);
1502 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
1503 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
1504 || pg_strcasecmp(prev3_wd, "START") == 0
1505 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
1506 && pg_strcasecmp(prev3_wd, "AS") == 0))
1507 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
1508 || pg_strcasecmp(prev2_wd, "WORK") == 0)
1509 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
1510 COMPLETE_WITH_CONST("LEVEL");
1511 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
1512 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
1513 || pg_strcasecmp(prev4_wd, "START") == 0
1514 || pg_strcasecmp(prev4_wd, "AS") == 0)
1515 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
1516 || pg_strcasecmp(prev3_wd, "WORK") == 0)
1517 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
1518 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
1520 static const char *const my_list[] =
1521 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
1523 COMPLETE_WITH_LIST(my_list);
1525 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1526 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1527 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1528 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1529 pg_strcasecmp(prev_wd, "READ") == 0)
1531 static const char *const my_list[] =
1532 {"UNCOMMITTED", "COMMITTED", NULL};
1534 COMPLETE_WITH_LIST(my_list);
1536 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1537 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1538 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1539 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1540 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
1541 COMPLETE_WITH_CONST("READ");
1542 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
1543 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
1544 pg_strcasecmp(prev3_wd, "START") == 0 ||
1545 pg_strcasecmp(prev3_wd, "AS") == 0) &&
1546 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
1547 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
1548 pg_strcasecmp(prev_wd, "READ") == 0)
1550 static const char *const my_list[] =
1551 {"ONLY", "WRITE", NULL};
1553 COMPLETE_WITH_LIST(my_list);
1555 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1556 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1557 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1559 static const char *const constraint_list[] =
1560 {"DEFERRED", "IMMEDIATE", NULL};
1562 COMPLETE_WITH_LIST(constraint_list);
1564 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1565 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1566 pg_strcasecmp(prev_wd, "SESSION") == 0)
1568 static const char *const my_list[] =
1569 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
1571 COMPLETE_WITH_LIST(my_list);
1573 /* Complete SET SESSION AUTHORIZATION with username */
1574 else if (pg_strcasecmp(prev3_wd, "SET") == 0
1575 && pg_strcasecmp(prev2_wd, "SESSION") == 0
1576 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1577 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1578 /* Complete SET <var> with "TO" */
1579 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1580 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
1581 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
1582 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
1583 COMPLETE_WITH_CONST("TO");
1584 /* Suggest possible variable values */
1585 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1586 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1588 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
1590 static const char *const my_list[] =
1591 {"ISO", "SQL", "Postgres", "German",
1592 "YMD", "DMY", "MDY",
1593 "US", "European", "NonEuropean",
1596 COMPLETE_WITH_LIST(my_list);
1598 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
1600 static const char *const my_list[] =
1601 {"ON", "OFF", "DEFAULT", NULL};
1603 COMPLETE_WITH_LIST(my_list);
1607 static const char *const my_list[] =
1610 COMPLETE_WITH_LIST(my_list);
1614 /* START TRANSACTION */
1615 else if (pg_strcasecmp(prev_wd, "START") == 0)
1616 COMPLETE_WITH_CONST("TRANSACTION");
1619 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
1620 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1623 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
1624 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 '*'");
1627 /* If prev. word is UPDATE suggest a list of tables */
1628 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
1629 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1630 /* Complete UPDATE <table> with "SET" */
1631 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
1632 COMPLETE_WITH_CONST("SET");
1635 * If the previous word is SET (and it wasn't caught above as the
1636 * _first_ word) the word before it was (hopefully) a table name and
1637 * we'll now make a list of attributes.
1639 else if (pg_strcasecmp(prev_wd, "SET") == 0)
1640 COMPLETE_WITH_ATTR(prev2_wd);
1642 /* UPDATE xx SET yy = */
1643 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1644 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
1645 COMPLETE_WITH_CONST("=");
1648 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
1649 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
1651 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
1652 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1653 " UNION SELECT 'FULL'"
1654 " UNION SELECT 'FREEZE'"
1655 " UNION SELECT 'ANALYZE'"
1656 " UNION SELECT 'VERBOSE'");
1657 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1658 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
1659 pg_strcasecmp(prev_wd, "FREEZE") == 0))
1660 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1661 " UNION SELECT 'ANALYZE'"
1662 " UNION SELECT 'VERBOSE'");
1663 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1664 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1665 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1666 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1667 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1668 " UNION SELECT 'VERBOSE'");
1669 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1670 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1671 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1672 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1673 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1674 " UNION SELECT 'ANALYZE'");
1675 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1676 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
1677 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1678 " UNION SELECT 'ANALYZE'");
1679 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1680 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1681 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1682 " UNION SELECT 'VERBOSE'");
1683 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1684 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
1685 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1686 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
1687 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1690 /* If the previous word is ANALYZE, produce list of tables */
1691 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1692 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1695 /* Simple case of the word before the where being the table name */
1696 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
1697 COMPLETE_WITH_ATTR(prev2_wd);
1700 /* TODO: also include SRF ? */
1701 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
1702 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
1703 pg_strcasecmp(prev3_wd, "\\copy") != 0)
1704 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1707 /* Backslash commands */
1708 /* TODO: \dc \dd \dl */
1709 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1710 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1711 else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1712 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
1713 else if (strcmp(prev_wd, "\\da") == 0)
1714 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
1715 else if (strcmp(prev_wd, "\\db") == 0)
1716 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1717 else if (strcmp(prev_wd, "\\dD") == 0)
1718 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
1719 else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1720 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1721 else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1722 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1723 else if (strcmp(prev_wd, "\\dn") == 0)
1724 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1725 else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1726 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1727 else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1728 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
1729 else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1730 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1731 else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1732 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1733 else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1734 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
1735 else if (strcmp(prev_wd, "\\du") == 0)
1736 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1737 else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1738 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
1739 else if (strcmp(prev_wd, "\\encoding") == 0)
1740 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
1741 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1742 COMPLETE_WITH_LIST(sql_commands);
1743 else if (strcmp(prev_wd, "\\pset") == 0)
1745 static const char *const my_list[] =
1746 {"format", "border", "expanded",
1747 "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1750 COMPLETE_WITH_LIST(my_list);
1752 else if (strcmp(prev_wd, "\\cd") == 0 ||
1753 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1754 strcmp(prev_wd, "\\g") == 0 ||
1755 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1756 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1757 strcmp(prev_wd, "\\s") == 0 ||
1758 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1760 matches = completion_matches(text, filename_completion_function);
1764 * Finally, we look through the list of "things", such as TABLE, INDEX
1765 * and check if that was the previous word. If so, execute the query
1766 * to get a list of them.
1772 for (i = 0; words_after_create[i].name; i++)
1774 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
1776 if (words_after_create[i].query)
1777 COMPLETE_WITH_QUERY(words_after_create[i].query);
1778 else if (words_after_create[i].squery)
1779 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
1787 * If we still don't have anything to match we have to fabricate some
1788 * sort of default list. If we were to just return NULL, readline
1789 * automatically attempts filename completion, and that's usually no
1792 if (matches == NULL)
1794 COMPLETE_WITH_CONST("");
1795 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1796 rl_completion_append_character = '\0';
1807 /* Return our Grand List O' Matches */
1813 /* GENERATOR FUNCTIONS
1815 These functions do all the actual work of completing the input. They get
1816 passed the text so far and the count how many times they have been called so
1817 far with the same text.
1818 If you read the above carefully, you'll see that these don't get called
1819 directly but through the readline interface.
1820 The return value is expected to be the full completion of the text, going
1821 through a list each time, or NULL if there are no more matches. The string
1822 will be free()'d by readline, so you must run it through strdup() or
1823 something of that sort.
1826 /* This one gives you one from a list of things you can put after CREATE or DROP
1830 create_command_generator(const char *text, int state)
1832 static int list_index,
1836 /* If this is the first time for this completion, init some values */
1840 string_length = strlen(text);
1843 /* find something that matches */
1844 while ((name = words_after_create[list_index++].name))
1845 if (pg_strncasecmp(name, text, string_length) == 0)
1846 return pg_strdup(name);
1848 /* if nothing matches, return NULL */
1853 /* The following two functions are wrappers for _complete_from_query */
1856 complete_from_query(const char *text, int state)
1858 return _complete_from_query(0, text, state);
1862 complete_from_schema_query(const char *text, int state)
1864 return _complete_from_query(1, text, state);
1868 /* This creates a list of matching things, according to a query pointed to
1869 by completion_charp.
1870 The query can be one of two kinds:
1871 - A simple query which must contain a %d and a %s, which will be replaced
1872 by the string length of the text and the text itself. The query may also
1873 have another %s in it, which will be replaced by the value of
1874 completion_info_charp.
1876 - A schema query used for completion of both schema and relation names;
1877 these are more complex and must contain in the following order:
1878 %d %s %d %s %d %s %s %d %s
1879 where %d is the string length of the text and %s the text itself.
1881 It is assumed that strings should be escaped to become SQL literals
1882 (that is, what is in the query is actually ... '%s' ...)
1884 See top of file for examples of both kinds of query.
1888 _complete_from_query(int is_schema_query, const char *text, int state)
1890 static int list_index,
1892 static PGresult *result = NULL;
1895 * If this is the first time for this completion, we fetch a list of
1896 * our "things" from the backend.
1900 PQExpBufferData query_buffer;
1905 string_length = strlen(text);
1907 /* Free any prior result */
1911 /* Set up suitably-escaped copies of textual inputs */
1912 e_text = pg_malloc(string_length * 2 + 1);
1913 PQescapeString(e_text, text, string_length);
1915 if (completion_info_charp)
1919 charp_len = strlen(completion_info_charp);
1920 e_info_charp = pg_malloc(charp_len * 2 + 1);
1921 PQescapeString(e_info_charp, completion_info_charp,
1925 e_info_charp = NULL;
1927 initPQExpBuffer(&query_buffer);
1929 if (is_schema_query)
1931 /* completion_squery gives us the pieces to assemble */
1932 const char *qualresult = completion_squery->qualresult;
1934 if (qualresult == NULL)
1935 qualresult = completion_squery->result;
1937 /* Get unqualified names matching the input-so-far */
1938 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
1939 completion_squery->result,
1940 completion_squery->catname);
1941 if (completion_squery->selcondition)
1942 appendPQExpBuffer(&query_buffer, "%s AND ",
1943 completion_squery->selcondition);
1944 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
1945 completion_squery->result,
1946 string_length, e_text);
1947 appendPQExpBuffer(&query_buffer, " AND %s",
1948 completion_squery->viscondition);
1951 * When fetching relation names, suppress system catalogs
1952 * unless the input-so-far begins with "pg_". This is a
1953 * compromise between not offering system catalogs for
1954 * completion at all, and having them swamp the result when
1955 * the input is just "p".
1957 if (strcmp(completion_squery->catname,
1958 "pg_catalog.pg_class c") == 0 &&
1959 strncmp(text, "pg_", 3) !=0)
1961 appendPQExpBuffer(&query_buffer,
1962 " AND c.relnamespace <> (SELECT oid FROM"
1963 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
1967 * Add in matching schema names, but only if there is more
1968 * than one potential match among schema names.
1970 appendPQExpBuffer(&query_buffer, "\nUNION\n"
1971 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
1972 "FROM pg_catalog.pg_namespace n "
1973 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
1974 string_length, e_text);
1975 appendPQExpBuffer(&query_buffer,
1976 " AND (SELECT pg_catalog.count(*)"
1977 " FROM pg_catalog.pg_namespace"
1978 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
1979 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
1980 string_length, e_text);
1983 * Add in matching qualified names, but only if there is
1984 * exactly one schema matching the input-so-far.
1986 appendPQExpBuffer(&query_buffer, "\nUNION\n"
1987 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
1988 "FROM %s, pg_catalog.pg_namespace n "
1989 "WHERE %s = n.oid AND ",
1991 completion_squery->catname,
1992 completion_squery->namespace);
1993 if (completion_squery->selcondition)
1994 appendPQExpBuffer(&query_buffer, "%s AND ",
1995 completion_squery->selcondition);
1996 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
1998 string_length, e_text);
2001 * This condition exploits the single-matching-schema rule to
2002 * speed up the query
2004 appendPQExpBuffer(&query_buffer,
2005 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
2006 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
2007 string_length, e_text);
2008 appendPQExpBuffer(&query_buffer,
2009 " AND (SELECT pg_catalog.count(*)"
2010 " FROM pg_catalog.pg_namespace"
2011 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2012 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
2013 string_length, e_text);
2015 /* If an addon query was provided, use it */
2016 if (completion_charp)
2017 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
2021 /* completion_charp is an sprintf-style format string */
2022 appendPQExpBuffer(&query_buffer, completion_charp,
2023 string_length, e_text, e_info_charp);
2026 /* Limit the number of records in the result */
2027 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
2028 completion_max_records);
2030 result = exec_query(query_buffer.data);
2032 termPQExpBuffer(&query_buffer);
2038 /* Find something that matches */
2039 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
2043 while (list_index < PQntuples(result) &&
2044 (item = PQgetvalue(result, list_index++, 0)))
2045 if (pg_strncasecmp(text, item, string_length) == 0)
2046 return pg_strdup(item);
2049 /* If nothing matches, free the db structure and return null */
2056 /* This function returns in order one of a fixed, NULL pointer terminated list
2057 of strings (if matching). This can be used if there are only a fixed number
2058 SQL words that can appear at certain spot.
2061 complete_from_list(const char *text, int state)
2063 static int string_length,
2066 static bool casesensitive;
2069 /* need to have a list */
2070 psql_assert(completion_charpp);
2072 /* Initialization */
2076 string_length = strlen(text);
2077 casesensitive = true;
2081 while ((item = completion_charpp[list_index++]))
2083 /* First pass is case sensitive */
2084 if (casesensitive && strncmp(text, item, string_length) == 0)
2087 return pg_strdup(item);
2090 /* Second pass is case insensitive, don't bother counting matches */
2091 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
2092 return pg_strdup(item);
2096 * No matches found. If we're not case insensitive already, lets
2097 * switch to being case insensitive and try again
2099 if (casesensitive && matches == 0)
2101 casesensitive = false;
2104 return (complete_from_list(text, state));
2107 /* If no more matches, return null. */
2112 /* This function returns one fixed string the first time even if it doesn't
2113 match what's there, and nothing the second time. This should be used if there
2114 is only one possibility that can appear at a certain spot, so misspellings
2115 will be overwritten.
2116 The string to be passed must be in completion_charp.
2119 complete_from_const(const char *text, int state)
2121 (void) text; /* We don't care about what was entered
2124 psql_assert(completion_charp);
2126 return pg_strdup(completion_charp);
2133 /* HELPER FUNCTIONS */
2137 * Execute a query and report any errors. This should be the preferred way of
2138 * talking to the database in this file.
2141 exec_query(const char *query)
2145 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
2148 result = PQexec(pset.db, query);
2150 if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
2153 psql_error("tab completion: %s failed - %s\n",
2154 query, PQresStatus(PQresultStatus(result)));
2166 * Return the word (space delimited) before point. Set skip > 0 to
2167 * skip that many words; e.g. skip=1 finds the word before the
2168 * previous one. Return value is NULL or a malloc'ed string.
2171 previous_word(int point, int skip)
2181 /* first we look for a space before the current word */
2182 for (i = point; i >= 0; i--)
2183 if (rl_line_buffer[i] == ' ')
2186 /* now find the first non-space which then constitutes the end */
2188 if (rl_line_buffer[i] != ' ')
2195 * If no end found we return null, because there is no word before
2202 * Otherwise we now look for the start. The start is either the
2203 * last character before any space going backwards from the end,
2204 * or it's simply character 0
2206 for (start = end; start > 0; start--)
2208 if (rl_line_buffer[start] == '"')
2209 inquotes = !inquotes;
2210 if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
2218 s = pg_malloc(end - start + 2);
2220 strncpy(s, &rl_line_buffer[start], end - start + 1);
2221 s[end - start + 1] = '\0';
2231 * Surround a string with single quotes. This works for both SQL and
2232 * psql internal. Currently disabled because it is reported not to
2233 * cooperate with certain versions of readline.
2236 quote_file_name(char *text, int match_type, char *quote_pointer)
2241 (void) quote_pointer; /* not used */
2243 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
2244 s = pg_malloc(length);
2246 strcpy(s + 1, text);
2247 if (match_type == SINGLE_MATCH)
2248 s[length - 2] = '\'';
2249 s[length - 1] = '\0';
2256 dequote_file_name(char *text, char quote_char)
2262 return pg_strdup(text);
2264 length = strlen(text);
2265 s = pg_malloc(length - 2 + 1);
2266 strncpy(s, text +1, length - 2);
2273 #endif /* USE_READLINE */