2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2007, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.161 2007/04/08 00:26:34 momjian 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"
57 #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
58 #define filename_completion_function rl_filename_completion_function
60 /* missing in some header files */
61 extern char *filename_completion_function();
64 #ifdef HAVE_RL_COMPLETION_MATCHES
65 #define completion_matches rl_completion_matches
70 * This struct is used to define "schema queries", which are custom-built
71 * to obtain possibly-schema-qualified names of database objects. There is
72 * enough similarity in the structure that we don't want to repeat it each
73 * time. So we put the components of each query into this struct and
74 * assemble them with the common boilerplate in _complete_from_query().
76 typedef struct SchemaQuery
79 * Name of catalog or catalogs to be queried, with alias, eg.
80 * "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
85 * Selection condition --- only rows meeting this condition are candidates
86 * to display. If catname mentions multiple tables, include the necessary
87 * join condition here. For example, "c.relkind = 'r'". Write NULL (not
88 * an empty string) if not needed.
90 const char *selcondition;
93 * Visibility condition --- which rows are visible without schema
94 * qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
96 const char *viscondition;
99 * Namespace --- name of field to join to pg_namespace.oid. For example,
102 const char *namespace;
105 * Result --- the appropriately-quoted name to return, in the case of an
106 * unqualified name. For example, "pg_catalog.quote_ident(c.relname)".
111 * In some cases a different result must be used for qualified names.
112 * Enter that here, or write NULL if result can be used.
114 const char *qualresult;
118 /* Store maximum number of records we want from database queries
119 * (implemented via SELECT ... LIMIT xx).
121 static int completion_max_records;
124 * Communication variables set by COMPLETE_WITH_FOO macros and then used by
125 * the completion callback functions. Ugly but there is no better way.
127 static const char *completion_charp; /* to pass a string */
128 static const char *const * completion_charpp; /* to pass a list of strings */
129 static const char *completion_info_charp; /* to pass a second string */
130 static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
132 /* A couple of macros to ease typing. You can use these to complete the given
134 1) The results from a query you pass it. (Perhaps one of those below?)
135 2) The results from a schema query you pass it.
136 3) The items from a null-pointer-terminated list.
138 5) The list of attributes to the given table.
140 #define COMPLETE_WITH_QUERY(query) \
141 do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
142 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
143 do { completion_squery = &(query); completion_charp = addon; matches = completion_matches(text, complete_from_schema_query); } while(0)
144 #define COMPLETE_WITH_LIST(list) \
145 do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
146 #define COMPLETE_WITH_CONST(string) \
147 do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
148 #define COMPLETE_WITH_ATTR(table, addon) \
149 do {completion_charp = Query_for_list_of_attributes addon; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0)
152 * Assembly instructions for schema queries
155 static const SchemaQuery Query_for_list_of_aggregates = {
157 "pg_catalog.pg_proc p",
161 "pg_catalog.pg_function_is_visible(p.oid)",
165 "pg_catalog.quote_ident(p.proname)",
170 static const SchemaQuery Query_for_list_of_datatypes = {
172 "pg_catalog.pg_type t",
173 /* selcondition --- ignore table rowtypes and array types */
175 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
176 "AND t.typname !~ '^_'",
178 "pg_catalog.pg_type_is_visible(t.oid)",
182 "pg_catalog.format_type(t.oid, NULL)",
184 "pg_catalog.quote_ident(t.typname)"
187 static const SchemaQuery Query_for_list_of_domains = {
189 "pg_catalog.pg_type t",
193 "pg_catalog.pg_type_is_visible(t.oid)",
197 "pg_catalog.quote_ident(t.typname)",
202 static const SchemaQuery Query_for_list_of_functions = {
204 "pg_catalog.pg_proc p",
208 "pg_catalog.pg_function_is_visible(p.oid)",
212 "pg_catalog.quote_ident(p.proname)",
217 static const SchemaQuery Query_for_list_of_indexes = {
219 "pg_catalog.pg_class c",
221 "c.relkind IN ('i')",
223 "pg_catalog.pg_table_is_visible(c.oid)",
227 "pg_catalog.quote_ident(c.relname)",
232 static const SchemaQuery Query_for_list_of_sequences = {
234 "pg_catalog.pg_class c",
236 "c.relkind IN ('S')",
238 "pg_catalog.pg_table_is_visible(c.oid)",
242 "pg_catalog.quote_ident(c.relname)",
247 static const SchemaQuery Query_for_list_of_tables = {
249 "pg_catalog.pg_class c",
251 "c.relkind IN ('r')",
253 "pg_catalog.pg_table_is_visible(c.oid)",
257 "pg_catalog.quote_ident(c.relname)",
262 static const SchemaQuery Query_for_list_of_tisv = {
264 "pg_catalog.pg_class c",
266 "c.relkind IN ('r', 'i', 'S', 'v')",
268 "pg_catalog.pg_table_is_visible(c.oid)",
272 "pg_catalog.quote_ident(c.relname)",
277 static const SchemaQuery Query_for_list_of_tsv = {
279 "pg_catalog.pg_class c",
281 "c.relkind IN ('r', 'S', 'v')",
283 "pg_catalog.pg_table_is_visible(c.oid)",
287 "pg_catalog.quote_ident(c.relname)",
292 static const SchemaQuery Query_for_list_of_views = {
294 "pg_catalog.pg_class c",
296 "c.relkind IN ('v')",
298 "pg_catalog.pg_table_is_visible(c.oid)",
302 "pg_catalog.quote_ident(c.relname)",
309 * Queries to get lists of names of various kinds of things, possibly
310 * restricted to names matching a partially entered name. In these queries,
311 * %s will be replaced by the text entered so far (suitably escaped to
312 * become a SQL literal string). %d will be replaced by the length of the
313 * string (in unescaped form). A second %s, if present, will be replaced
314 * by a suitably-escaped version of the string provided in
315 * completion_info_charp.
317 * Beware that the allowed sequences of %s and %d are determined by
318 * _complete_from_query().
321 #define Query_for_list_of_attributes \
322 "SELECT pg_catalog.quote_ident(attname) "\
323 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
324 " WHERE c.oid = a.attrelid "\
325 " AND a.attnum > 0 "\
326 " AND NOT a.attisdropped "\
327 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
328 " AND pg_catalog.quote_ident(relname)='%s' "\
329 " AND pg_catalog.pg_table_is_visible(c.oid)"
331 #define Query_for_list_of_databases \
332 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
333 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
335 #define Query_for_list_of_tablespaces \
336 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
337 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
339 #define Query_for_list_of_encodings \
340 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
341 " FROM pg_catalog.pg_conversion "\
342 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
344 #define Query_for_list_of_languages \
345 "SELECT pg_catalog.quote_ident(lanname) "\
346 " FROM pg_language "\
347 " WHERE lanname != 'internal' "\
348 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
350 #define Query_for_list_of_schemas \
351 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
352 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
354 #define Query_for_list_of_set_vars \
356 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
357 " WHERE context IN ('user', 'superuser') "\
358 " UNION ALL SELECT 'constraints' "\
359 " UNION ALL SELECT 'transaction' "\
360 " UNION ALL SELECT 'session' "\
361 " UNION ALL SELECT 'role' "\
362 " UNION ALL SELECT 'all') ss "\
363 " WHERE substring(name,1,%d)='%s'"
365 #define Query_for_list_of_show_vars \
367 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
368 " UNION ALL SELECT 'session authorization' "\
369 " UNION ALL SELECT 'all') ss "\
370 " WHERE substring(name,1,%d)='%s'"
373 * Note: As of Pg 8.2, we no longer use relkind 's', but we keep it here
374 * for compatibility with older servers
376 #define Query_for_list_of_system_relations \
377 "SELECT pg_catalog.quote_ident(relname) "\
378 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
379 " WHERE c.relkind IN ('r', 'v', 's', 'S') "\
380 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
381 " AND c.relnamespace = n.oid "\
382 " AND n.nspname = 'pg_catalog'"
384 #define Query_for_list_of_roles \
385 " SELECT pg_catalog.quote_ident(rolname) "\
386 " FROM pg_catalog.pg_roles "\
387 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
389 #define Query_for_list_of_grant_roles \
390 " SELECT pg_catalog.quote_ident(rolname) "\
391 " FROM pg_catalog.pg_roles "\
392 " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
393 " UNION ALL SELECT 'PUBLIC'"
395 /* the silly-looking length condition is just to eat up the current word */
396 #define Query_for_table_owning_index \
397 "SELECT pg_catalog.quote_ident(c1.relname) "\
398 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
399 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
400 " and (%d = length('%s'))"\
401 " and pg_catalog.quote_ident(c2.relname)='%s'"\
402 " and pg_catalog.pg_table_is_visible(c2.oid)"
404 /* the silly-looking length condition is just to eat up the current word */
405 #define Query_for_index_of_table \
406 "SELECT pg_catalog.quote_ident(c2.relname) "\
407 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
408 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
409 " and (%d = length('%s'))"\
410 " and pg_catalog.quote_ident(c1.relname)='%s'"\
411 " and pg_catalog.pg_table_is_visible(c2.oid)"
413 /* the silly-looking length condition is just to eat up the current word */
414 #define Query_for_list_of_tables_for_trigger \
415 "SELECT pg_catalog.quote_ident(relname) "\
416 " FROM pg_catalog.pg_class"\
417 " WHERE (%d = length('%s'))"\
419 " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
420 " WHERE pg_catalog.quote_ident(tgname)='%s')"
423 * This is a list of all "things" in Pgsql, which can show up after CREATE or
424 * DROP; and there is also a query to get a list of them.
430 const char *query; /* simple query, or NULL */
431 const SchemaQuery *squery; /* schema query, or NULL */
434 static const pgsql_thing_t words_after_create[] = {
435 {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
436 {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
440 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
441 * to be used only by pg_dump.
443 {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
444 {"DATABASE", Query_for_list_of_databases},
445 {"DOMAIN", NULL, &Query_for_list_of_domains},
446 {"FUNCTION", NULL, &Query_for_list_of_functions},
447 {"GROUP", Query_for_list_of_roles},
448 {"LANGUAGE", Query_for_list_of_languages},
449 {"INDEX", NULL, &Query_for_list_of_indexes},
450 {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
452 {"ROLE", Query_for_list_of_roles},
453 {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
454 {"SCHEMA", Query_for_list_of_schemas},
455 {"SEQUENCE", NULL, &Query_for_list_of_sequences},
456 {"TABLE", NULL, &Query_for_list_of_tables},
457 {"TABLESPACE", Query_for_list_of_tablespaces},
458 {"TEMP", NULL, NULL}, /* for CREATE TEMP TABLE ... */
459 {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
460 {"TYPE", NULL, &Query_for_list_of_datatypes},
461 {"UNIQUE", NULL, NULL}, /* for CREATE UNIQUE INDEX ... */
462 {"USER", Query_for_list_of_roles},
463 {"VIEW", NULL, &Query_for_list_of_views},
464 {NULL, NULL, NULL} /* end of list */
468 /* Forward declaration of functions */
469 static char **psql_completion(char *text, int start, int end);
470 static char *create_command_generator(const char *text, int state);
471 static char *drop_command_generator(const char *text, int state);
472 static char *complete_from_query(const char *text, int state);
473 static char *complete_from_schema_query(const char *text, int state);
474 static char *_complete_from_query(int is_schema_query,
475 const char *text, int state);
476 static char *complete_from_const(const char *text, int state);
477 static char *complete_from_list(const char *text, int state);
479 static PGresult *exec_query(const char *query);
481 static char *previous_word(int point, int skip);
483 static int find_open_parenthesis(int end);
486 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
487 static char *dequote_file_name(char *text, char quote_char);
491 /* Initialize the readline library for our purposes. */
493 initialize_readline(void)
495 rl_readline_name = (char *) pset.progname;
496 rl_attempted_completion_function = (void *) psql_completion;
498 rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
500 completion_max_records = 1000;
503 * There is a variable rl_completion_query_items for this but apparently
504 * it's not defined everywhere.
509 /* The completion function. Acc. to readline spec this gets passed the text
510 entered to far and its start and end in the readline buffer. The return value
511 is some partially obscure list format that can be generated by the readline
512 libraries completion_matches() function, so we don't have to worry about it.
515 psql_completion(char *text, int start, int end)
517 /* This is the variable we'll return. */
518 char **matches = NULL;
520 /* These are going to contain some scannage of the input line. */
527 static const char *const sql_commands[] = {
528 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
529 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
530 "DELETE FROM", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", "GRANT",
531 "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
532 "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
533 "SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN",
534 "UPDATE", "VACUUM", NULL
537 static const char *const backslash_commands[] = {
538 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
539 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
540 "\\dg", "\\di", "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS",
541 "\\dt", "\\dT", "\\dv", "\\du",
542 "\\e", "\\echo", "\\encoding",
543 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
544 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
545 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
546 "\\set", "\\t", "\\T",
547 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
550 (void) end; /* not used */
552 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
553 rl_completion_append_character = ' ';
556 /* Clear a few things. */
557 completion_charp = NULL;
558 completion_charpp = NULL;
559 completion_info_charp = NULL;
562 * Scan the input line before our current position for the last four
563 * words. According to those we'll make some smart decisions on what the
564 * user is probably intending to type. TODO: Use strtokx() to do this.
566 prev_wd = previous_word(start, 0);
567 prev2_wd = previous_word(start, 1);
568 prev3_wd = previous_word(start, 2);
569 prev4_wd = previous_word(start, 3);
570 prev5_wd = previous_word(start, 4);
572 /* If a backslash command was started, continue */
574 COMPLETE_WITH_LIST(backslash_commands);
576 /* If no previous word, suggest one of the basic sql commands */
578 COMPLETE_WITH_LIST(sql_commands);
581 /* complete with something you can create */
582 else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
583 matches = completion_matches(text, create_command_generator);
585 /* DROP, except ALTER (TABLE|DOMAIN|GROUP) sth DROP */
586 /* complete with something you can drop */
587 else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
588 pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
589 pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
590 pg_strcasecmp(prev3_wd, "GROUP") != 0)
591 matches = completion_matches(text, drop_command_generator);
596 * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
597 * in ALTER TABLE sth ALTER
599 else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
600 pg_strcasecmp(prev3_wd, "TABLE") != 0)
602 static const char *const list_ALTER[] =
603 {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
604 "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SEQUENCE", "TABLE",
605 "TABLESPACE", "TRIGGER", "TYPE", "USER", NULL};
607 COMPLETE_WITH_LIST(list_ALTER);
609 /* ALTER AGGREGATE,FUNCTION <name> */
610 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
611 (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
612 pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
614 static const char *const list_ALTERAGG[] =
615 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
617 COMPLETE_WITH_LIST(list_ALTERAGG);
620 /* ALTER CONVERSION,SCHEMA <name> */
621 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
622 (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
623 pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
625 static const char *const list_ALTERGEN[] =
626 {"OWNER TO", "RENAME TO", NULL};
628 COMPLETE_WITH_LIST(list_ALTERGEN);
631 /* ALTER DATABASE <name> */
632 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
633 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
635 static const char *const list_ALTERDATABASE[] =
636 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
638 COMPLETE_WITH_LIST(list_ALTERDATABASE);
641 /* ALTER INDEX <name> */
642 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
643 pg_strcasecmp(prev2_wd, "INDEX") == 0)
645 static const char *const list_ALTERINDEX[] =
646 {"SET TABLESPACE", "OWNER TO", "RENAME TO", NULL};
648 COMPLETE_WITH_LIST(list_ALTERINDEX);
651 /* ALTER LANGUAGE <name> */
652 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
653 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
655 static const char *const list_ALTERLANGUAGE[] =
656 {"OWNER TO", "RENAME TO", NULL};
658 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
661 /* ALTER USER,ROLE <name> */
662 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
663 (pg_strcasecmp(prev2_wd, "USER") == 0 ||
664 pg_strcasecmp(prev2_wd, "ROLE") == 0))
666 static const char *const list_ALTERUSER[] =
667 {"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
668 "NOCREATEUSER", "CREATEROLE", "NOCREATEROLE", "INHERIT", "NOINHERIT",
669 "LOGIN", "NOLOGIN", "CONNECTION LIMIT", "VALID UNTIL", "RENAME TO",
670 "SUPERUSER", "NOSUPERUSER", "SET", "RESET", NULL};
672 COMPLETE_WITH_LIST(list_ALTERUSER);
675 /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
676 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
677 (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
678 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
680 COMPLETE_WITH_CONST("PASSWORD");
682 /* ALTER DOMAIN <name> */
683 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
684 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
686 static const char *const list_ALTERDOMAIN[] =
687 {"ADD", "DROP", "OWNER TO", "SET", NULL};
689 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
691 /* ALTER DOMAIN <sth> DROP */
692 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
693 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
694 pg_strcasecmp(prev_wd, "DROP") == 0)
696 static const char *const list_ALTERDOMAIN2[] =
697 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
699 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
701 /* ALTER DOMAIN <sth> SET */
702 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
703 pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
704 pg_strcasecmp(prev_wd, "SET") == 0)
706 static const char *const list_ALTERDOMAIN3[] =
707 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
709 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
711 /* ALTER SEQUENCE <name> */
712 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
713 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
715 static const char *const list_ALTERSEQUENCE[] =
716 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
719 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
721 /* ALTER SEQUENCE <name> NO */
722 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
723 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
724 pg_strcasecmp(prev_wd, "NO") == 0)
726 static const char *const list_ALTERSEQUENCE2[] =
727 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
729 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
731 /* ALTER TRIGGER <name>, add ON */
732 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
733 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
734 COMPLETE_WITH_CONST("ON");
736 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
737 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
739 completion_info_charp = prev2_wd;
740 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
744 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
746 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
747 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
748 pg_strcasecmp(prev_wd, "ON") == 0)
749 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
751 /* ALTER TRIGGER <name> ON <name> */
752 else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
753 pg_strcasecmp(prev2_wd, "ON") == 0)
754 COMPLETE_WITH_CONST("RENAME TO");
757 * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
758 * RENAME, CLUSTER ON or OWNER
760 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
761 pg_strcasecmp(prev2_wd, "TABLE") == 0)
763 static const char *const list_ALTER2[] =
764 {"ADD", "ALTER", "CLUSTER ON", "DROP", "RENAME", "OWNER TO",
767 COMPLETE_WITH_LIST(list_ALTER2);
769 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
770 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
771 (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
772 pg_strcasecmp(prev_wd, "RENAME") == 0))
773 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
776 * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
779 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
780 (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
781 pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
782 pg_strcasecmp(prev_wd, "COLUMN") == 0)
783 COMPLETE_WITH_ATTR(prev3_wd, "");
785 /* ALTER TABLE xxx RENAME yyy */
786 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
787 pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
788 pg_strcasecmp(prev_wd, "TO") != 0)
789 COMPLETE_WITH_CONST("TO");
791 /* ALTER TABLE xxx RENAME COLUMN yyy */
792 else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
793 pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
794 pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
795 pg_strcasecmp(prev_wd, "TO") != 0)
796 COMPLETE_WITH_CONST("TO");
798 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
799 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
800 pg_strcasecmp(prev_wd, "DROP") == 0)
802 static const char *const list_TABLEDROP[] =
803 {"COLUMN", "CONSTRAINT", NULL};
805 COMPLETE_WITH_LIST(list_TABLEDROP);
807 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
808 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
809 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
810 pg_strcasecmp(prev_wd, "COLUMN") == 0)
811 COMPLETE_WITH_ATTR(prev3_wd, "");
812 /* ALTER TABLE ALTER [COLUMN] <foo> */
813 else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
814 pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
815 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
816 pg_strcasecmp(prev2_wd, "ALTER") == 0))
818 /* DROP ... does not work well yet */
819 static const char *const list_COLUMNALTER[] =
820 {"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
821 "DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
823 COMPLETE_WITH_LIST(list_COLUMNALTER);
825 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0)
826 COMPLETE_WITH_CONST("ON");
827 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
828 pg_strcasecmp(prev_wd, "ON") == 0)
830 completion_info_charp = prev3_wd;
831 COMPLETE_WITH_QUERY(Query_for_index_of_table);
833 /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
834 else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
835 pg_strcasecmp(prev_wd, "SET") == 0)
837 static const char *const list_TABLESET[] =
838 {"WITHOUT", "TABLESPACE", "SCHEMA", NULL};
840 COMPLETE_WITH_LIST(list_TABLESET);
842 /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
843 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
844 pg_strcasecmp(prev2_wd, "SET") == 0 &&
845 pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
846 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
847 /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
848 else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
849 pg_strcasecmp(prev2_wd, "SET") == 0 &&
850 pg_strcasecmp(prev_wd, "WITHOUT") == 0)
852 static const char *const list_TABLESET2[] =
853 {"CLUSTER", "OIDS", NULL};
855 COMPLETE_WITH_LIST(list_TABLESET2);
857 /* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */
858 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
859 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
861 static const char *const list_ALTERTSPC[] =
862 {"RENAME TO", "OWNER TO", NULL};
864 COMPLETE_WITH_LIST(list_ALTERTSPC);
866 /* complete ALTER TYPE <foo> with OWNER TO, SET SCHEMA */
867 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
868 pg_strcasecmp(prev2_wd, "TYPE") == 0)
870 static const char *const list_ALTERTYPE[] =
871 {"OWNER TO", "SET SCHEMA", NULL};
873 COMPLETE_WITH_LIST(list_ALTERTYPE);
875 /* complete ALTER GROUP <foo> */
876 else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
877 pg_strcasecmp(prev2_wd, "GROUP") == 0)
879 static const char *const list_ALTERGROUP[] =
880 {"ADD USER", "DROP USER", "RENAME TO", NULL};
882 COMPLETE_WITH_LIST(list_ALTERGROUP);
884 /* complete ALTER GROUP <foo> ADD|DROP with USER */
885 else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
886 pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
887 (pg_strcasecmp(prev_wd, "ADD") == 0 ||
888 pg_strcasecmp(prev_wd, "DROP") == 0))
889 COMPLETE_WITH_CONST("USER");
890 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
891 else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
892 (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
893 pg_strcasecmp(prev2_wd, "DROP") == 0) &&
894 pg_strcasecmp(prev_wd, "USER") == 0)
895 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
897 /* BEGIN, END, ABORT */
898 else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
899 pg_strcasecmp(prev_wd, "END") == 0 ||
900 pg_strcasecmp(prev_wd, "ABORT") == 0)
902 static const char *const list_TRANS[] =
903 {"WORK", "TRANSACTION", NULL};
905 COMPLETE_WITH_LIST(list_TRANS);
908 else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
910 static const char *const list_COMMIT[] =
911 {"WORK", "TRANSACTION", "PREPARED", NULL};
913 COMPLETE_WITH_LIST(list_COMMIT);
915 /* RELEASE SAVEPOINT */
916 else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
917 COMPLETE_WITH_CONST("SAVEPOINT");
919 else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
921 static const char *const list_TRANS[] =
922 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
924 COMPLETE_WITH_LIST(list_TRANS);
929 * If the previous word is CLUSTER and not without produce list of
932 else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
933 pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
934 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
935 /* If we have CLUSTER <sth>, then add "USING" */
936 else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
937 pg_strcasecmp(prev_wd, "ON") != 0) {
938 COMPLETE_WITH_CONST("USING");
942 * If we have CLUSTER <sth> ORDER BY, then add the index as well.
944 else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
945 pg_strcasecmp(prev_wd, "USING") == 0)
947 completion_info_charp = prev2_wd;
948 COMPLETE_WITH_QUERY(Query_for_index_of_table);
952 else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
953 COMPLETE_WITH_CONST("ON");
954 else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
955 pg_strcasecmp(prev_wd, "ON") == 0)
957 static const char *const list_COMMENT[] =
958 {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
959 "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
960 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
961 "TABLESPACE", "ROLE", NULL};
963 COMPLETE_WITH_LIST(list_COMMENT);
965 else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
966 pg_strcasecmp(prev3_wd, "ON") == 0)
967 COMPLETE_WITH_CONST("IS");
972 * If we have COPY [BINARY] (which you'd have to type yourself), offer
973 * list of tables (Also cover the analogous backslash command)
975 else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
976 pg_strcasecmp(prev_wd, "\\copy") == 0 ||
977 (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
978 pg_strcasecmp(prev_wd, "BINARY") == 0))
979 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
980 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
981 else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
982 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
983 pg_strcasecmp(prev2_wd, "BINARY") == 0)
985 static const char *const list_FROMTO[] =
986 {"FROM", "TO", NULL};
988 COMPLETE_WITH_LIST(list_FROMTO);
990 /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
991 else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
992 pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
993 pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
994 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
995 pg_strcasecmp(prev_wd, "TO") == 0))
996 matches = completion_matches(text, filename_completion_function);
998 /* Handle COPY|BINARY <sth> FROM|TO filename */
999 else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1000 pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1001 pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1002 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1003 pg_strcasecmp(prev2_wd, "TO") == 0))
1005 static const char *const list_COPY[] =
1006 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", NULL};
1008 COMPLETE_WITH_LIST(list_COPY);
1011 /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1012 else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1013 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1014 pg_strcasecmp(prev3_wd, "TO") == 0))
1016 static const char *const list_CSV[] =
1017 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
1019 COMPLETE_WITH_LIST(list_CSV);
1022 /* CREATE DATABASE */
1023 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1024 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1026 static const char *const list_DATABASE[] =
1027 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1030 COMPLETE_WITH_LIST(list_DATABASE);
1034 /* First off we complete CREATE UNIQUE with "INDEX" */
1035 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1036 pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1037 COMPLETE_WITH_CONST("INDEX");
1038 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
1039 else if (pg_strcasecmp(prev2_wd, "INDEX") == 0 &&
1040 (pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1041 pg_strcasecmp(prev3_wd, "UNIQUE") == 0))
1042 COMPLETE_WITH_CONST("ON");
1043 /* Complete ... INDEX <name> ON with a list of tables */
1044 else if (pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1045 pg_strcasecmp(prev_wd, "ON") == 0)
1046 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1049 * Complete INDEX <name> ON <table> with a list of table columns (which
1050 * should really be in parens)
1052 else if (pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1053 pg_strcasecmp(prev2_wd, "ON") == 0)
1055 if (find_open_parenthesis(end))
1056 COMPLETE_WITH_ATTR(prev_wd, "");
1058 COMPLETE_WITH_CONST("(");
1060 else if (pg_strcasecmp(prev5_wd, "INDEX") == 0 &&
1061 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1062 pg_strcasecmp(prev_wd, "(") == 0)
1063 COMPLETE_WITH_ATTR(prev2_wd, "");
1064 /* same if you put in USING */
1065 else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1066 pg_strcasecmp(prev2_wd, "USING") == 0)
1067 COMPLETE_WITH_ATTR(prev3_wd, "");
1068 /* Complete USING with an index method */
1069 else if (pg_strcasecmp(prev_wd, "USING") == 0)
1071 static const char *const index_mth[] =
1072 {"BTREE", "HASH", "GIST", NULL};
1074 COMPLETE_WITH_LIST(index_mth);
1078 /* Complete "CREATE RULE <sth>" with "AS" */
1079 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1080 pg_strcasecmp(prev2_wd, "RULE") == 0)
1081 COMPLETE_WITH_CONST("AS");
1082 /* Complete "CREATE RULE <sth> AS with "ON" */
1083 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1084 pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1085 pg_strcasecmp(prev_wd, "AS") == 0)
1086 COMPLETE_WITH_CONST("ON");
1087 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1088 else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1089 pg_strcasecmp(prev2_wd, "AS") == 0 &&
1090 pg_strcasecmp(prev_wd, "ON") == 0)
1092 static const char *const rule_events[] =
1093 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1095 COMPLETE_WITH_LIST(rule_events);
1097 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1098 else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1099 pg_strcasecmp(prev2_wd, "ON") == 0 &&
1100 (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1101 pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1102 COMPLETE_WITH_CONST("TO");
1103 /* Complete "AS ON <sth> TO" with a table name */
1104 else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1105 pg_strcasecmp(prev3_wd, "ON") == 0 &&
1106 pg_strcasecmp(prev_wd, "TO") == 0)
1107 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1110 /* Complete CREATE TEMP with "TABLE" */
1111 else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1112 pg_strcasecmp(prev_wd, "TEMP") == 0)
1113 COMPLETE_WITH_CONST("TABLE");
1115 /* CREATE TABLESPACE */
1116 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1117 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1119 static const char *const list_CREATETABLESPACE[] =
1120 {"OWNER", "LOCATION", NULL};
1122 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1124 /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1125 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1126 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1127 pg_strcasecmp(prev2_wd, "OWNER") == 0)
1129 COMPLETE_WITH_CONST("LOCATION");
1132 /* CREATE TRIGGER */
1133 /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1134 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1135 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1137 static const char *const list_CREATETRIGGER[] =
1138 {"BEFORE", "AFTER", NULL};
1140 COMPLETE_WITH_LIST(list_CREATETRIGGER);
1142 /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1143 else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1144 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1145 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1146 pg_strcasecmp(prev2_wd, "AFTER") == 0))
1148 static const char *const list_CREATETRIGGER2[] =
1151 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1154 /* CREATE ROLE,USER,GROUP */
1155 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1156 (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1157 pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1159 static const char *const list_CREATEROLE[] =
1160 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1161 "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOINHERIT", "NOLOGIN", "NOCREATEDB",
1162 "NOCREATEROLE", "NOCREATEUSER", "NOSUPERUSER", "ROLE", "SUPERUSER", "SYSID",
1163 "UNENCRYPTED", NULL};
1165 COMPLETE_WITH_LIST(list_CREATEROLE);
1169 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1172 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1173 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1174 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1175 (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1177 COMPLETE_WITH_CONST("PASSWORD");
1179 /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1180 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1181 (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1182 pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1183 pg_strcasecmp(prev_wd, "IN") == 0)
1185 static const char *const list_CREATEROLE3[] =
1186 {"GROUP", "ROLE", NULL};
1188 COMPLETE_WITH_LIST(list_CREATEROLE3);
1192 /* Complete CREATE VIEW <name> with AS */
1193 else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1194 pg_strcasecmp(prev2_wd, "VIEW") == 0)
1195 COMPLETE_WITH_CONST("AS");
1196 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1197 else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1198 pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1199 pg_strcasecmp(prev_wd, "AS") == 0)
1200 COMPLETE_WITH_CONST("SELECT");
1203 else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1205 static const char *const list_DECLARE[] =
1206 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1208 COMPLETE_WITH_LIST(list_DECLARE);
1211 else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1213 static const char *const list_DECLARECURSOR[] =
1214 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1216 COMPLETE_WITH_LIST(list_DECLARECURSOR);
1223 * Complete DELETE with FROM (only if the word before that is not "ON"
1224 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1226 else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1227 !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1228 pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1229 pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1230 pg_strcasecmp(prev2_wd, "AFTER") == 0))
1231 COMPLETE_WITH_CONST("FROM");
1232 /* Complete DELETE FROM with a list of tables */
1233 else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1234 pg_strcasecmp(prev_wd, "FROM") == 0)
1235 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1236 /* Complete DELETE FROM <table> */
1237 else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1238 pg_strcasecmp(prev2_wd, "FROM") == 0)
1240 static const char *const list_DELETE[] =
1241 {"USING", "WHERE", "SET", NULL};
1243 COMPLETE_WITH_LIST(list_DELETE);
1245 /* XXX: implement tab completion for DELETE ... USING */
1247 /* DROP (when not the previous word) */
1248 /* DROP AGGREGATE */
1249 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1250 pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1251 COMPLETE_WITH_CONST("(");
1253 /* DROP object with CASCADE / RESTRICT */
1254 else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1255 (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1256 pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1257 pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1258 pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1259 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1260 pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1261 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1262 pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1263 pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1264 pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1265 (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1266 pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1267 prev_wd[strlen(prev_wd) - 1] == ')'))
1269 if ((pg_strcasecmp(prev3_wd, "DROP") == 0) && (pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
1271 if (find_open_parenthesis(end))
1273 static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1274 char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev_wd));
1276 sprintf(tmp_buf, func_args_query, prev_wd);
1277 COMPLETE_WITH_QUERY(tmp_buf);
1282 COMPLETE_WITH_CONST("(");
1287 static const char *const list_DROPCR[] =
1288 {"CASCADE", "RESTRICT", NULL};
1290 COMPLETE_WITH_LIST(list_DROPCR);
1293 else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1294 pg_strcasecmp(prev3_wd, "FUNCTION") == 0 &&
1295 pg_strcasecmp(prev_wd, "(") == 0)
1297 static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1298 char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev2_wd));
1300 sprintf(tmp_buf, func_args_query, prev2_wd);
1301 COMPLETE_WITH_QUERY(tmp_buf);
1305 else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1306 pg_strcasecmp(prev_wd, "OWNED") == 0)
1307 COMPLETE_WITH_CONST("BY");
1308 else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1309 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1310 pg_strcasecmp(prev_wd, "BY") == 0)
1311 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1318 * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1320 else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1322 static const char *const list_EXPLAIN[] =
1323 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
1325 COMPLETE_WITH_LIST(list_EXPLAIN);
1327 else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1328 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1330 static const char *const list_EXPLAIN[] =
1331 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
1333 COMPLETE_WITH_LIST(list_EXPLAIN);
1335 else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1336 pg_strcasecmp(prev3_wd, "VACUUM") != 0 &&
1337 pg_strcasecmp(prev4_wd, "VACUUM") != 0 &&
1338 (pg_strcasecmp(prev2_wd, "ANALYZE") == 0 ||
1339 pg_strcasecmp(prev2_wd, "EXPLAIN") == 0))
1341 static const char *const list_EXPLAIN[] =
1342 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
1344 COMPLETE_WITH_LIST(list_EXPLAIN);
1348 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1349 else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1350 pg_strcasecmp(prev_wd, "MOVE") == 0)
1352 static const char *const list_FETCH1[] =
1353 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1355 COMPLETE_WITH_LIST(list_FETCH1);
1357 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1358 else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1359 pg_strcasecmp(prev2_wd, "MOVE") == 0)
1361 static const char *const list_FETCH2[] =
1362 {"ALL", "NEXT", "PRIOR", NULL};
1364 COMPLETE_WITH_LIST(list_FETCH2);
1368 * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
1369 * but we may as well tab-complete both: perhaps some users prefer one
1370 * variant or the other.
1372 else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
1373 pg_strcasecmp(prev3_wd, "MOVE") == 0)
1375 static const char *const list_FROMIN[] =
1376 {"FROM", "IN", NULL};
1378 COMPLETE_WITH_LIST(list_FROMIN);
1381 /* GRANT && REVOKE*/
1382 /* Complete GRANT/REVOKE with a list of privileges */
1383 else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
1384 pg_strcasecmp(prev_wd, "REVOKE") == 0)
1386 static const char *const list_privileg[] =
1387 {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
1388 "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
1391 COMPLETE_WITH_LIST(list_privileg);
1393 /* Complete GRANT/REVOKE <sth> with "ON" */
1394 else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1395 pg_strcasecmp(prev2_wd, "REVOKE") == 0)
1396 COMPLETE_WITH_CONST("ON");
1399 * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
1402 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
1403 * UNION; seems to work intuitively
1405 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
1406 * here will only work if the privilege list contains exactly one
1409 else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
1410 pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
1411 pg_strcasecmp(prev_wd, "ON") == 0)
1412 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
1413 " UNION SELECT 'DATABASE'"
1414 " UNION SELECT 'FUNCTION'"
1415 " UNION SELECT 'LANGUAGE'"
1416 " UNION SELECT 'SCHEMA'"
1417 " UNION SELECT 'TABLESPACE'");
1419 /* Complete "GRANT/REVOKE * ON * " with "TO" */
1420 else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1421 pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1422 pg_strcasecmp(prev2_wd, "ON") == 0)
1424 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1425 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1426 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
1427 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1428 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
1429 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1430 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
1431 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1432 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1433 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1434 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
1435 COMPLETE_WITH_CONST("TO");
1437 COMPLETE_WITH_CONST("FROM");
1440 /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1441 else if (pg_strcasecmp(prev3_wd, "ON") == 0 &&
1442 ((pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
1443 pg_strcasecmp(prev_wd, "TO") == 0) ||
1444 (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
1445 pg_strcasecmp(prev_wd, "FROM") == 0)))
1446 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1449 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1450 pg_strcasecmp(prev_wd, "GROUP") == 0)
1451 COMPLETE_WITH_CONST("BY");
1454 /* Complete INSERT with "INTO" */
1455 else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
1456 COMPLETE_WITH_CONST("INTO");
1457 /* Complete INSERT INTO with table names */
1458 else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
1459 pg_strcasecmp(prev_wd, "INTO") == 0)
1460 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1461 /* Complete "INSERT INTO <table> (" with attribute names */
1462 else if (rl_line_buffer[start - 1] == '(' &&
1463 pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1464 pg_strcasecmp(prev2_wd, "INTO") == 0)
1465 COMPLETE_WITH_ATTR(prev_wd, "");
1468 * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1471 else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1472 pg_strcasecmp(prev2_wd, "INTO") == 0)
1474 static const char *const list_INSERT[] =
1475 {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1477 COMPLETE_WITH_LIST(list_INSERT);
1479 /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1480 else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
1481 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
1482 prev_wd[strlen(prev_wd) - 1] == ')')
1484 static const char *const list_INSERT[] =
1485 {"SELECT", "VALUES", NULL};
1487 COMPLETE_WITH_LIST(list_INSERT);
1490 /* Insert an open parenthesis after "VALUES" */
1491 else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
1492 pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
1493 COMPLETE_WITH_CONST("(");
1496 /* Complete LOCK [TABLE] with a list of tables */
1497 else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
1498 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1499 " UNION SELECT 'TABLE'");
1500 else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
1501 pg_strcasecmp(prev2_wd, "LOCK") == 0)
1502 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1504 /* For the following, handle the case of a single table only for now */
1506 /* Complete LOCK [TABLE] <table> with "IN" */
1507 else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
1508 pg_strcasecmp(prev_wd, "TABLE")) ||
1509 (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
1510 pg_strcasecmp(prev3_wd, "LOCK") == 0))
1511 COMPLETE_WITH_CONST("IN");
1513 /* Complete LOCK [TABLE] <table> IN with a lock mode */
1514 else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
1515 (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
1516 (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1517 pg_strcasecmp(prev4_wd, "LOCK") == 0)))
1519 static const char *const lock_modes[] =
1520 {"ACCESS SHARE MODE",
1521 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1522 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1523 "SHARE ROW EXCLUSIVE MODE",
1524 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1526 COMPLETE_WITH_LIST(lock_modes);
1530 else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
1531 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1533 /* OWNER TO - complete with available roles */
1534 else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
1535 pg_strcasecmp(prev_wd, "TO") == 0)
1536 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1539 else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1540 pg_strcasecmp(prev_wd, "ORDER") == 0)
1541 COMPLETE_WITH_CONST("BY");
1542 else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
1543 pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
1544 pg_strcasecmp(prev_wd, "BY") == 0)
1545 COMPLETE_WITH_ATTR(prev3_wd, "");
1548 else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
1549 pg_strcasecmp(prev3_wd, "PREPARE") == 0)
1551 static const char *const list_PREPARE[] =
1552 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1554 COMPLETE_WITH_LIST(list_PREPARE);
1557 /* REASSIGN OWNED BY xxx TO yyy */
1558 else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
1559 COMPLETE_WITH_CONST("OWNED");
1560 else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
1561 pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
1562 COMPLETE_WITH_CONST("BY");
1563 else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
1564 pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1565 pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
1566 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1567 else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
1568 pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
1569 pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
1570 COMPLETE_WITH_CONST("TO");
1571 else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
1572 pg_strcasecmp(prev3_wd, "BY") == 0 &&
1573 pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
1574 pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
1575 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1578 else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
1580 static const char *const list_REINDEX[] =
1581 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
1583 COMPLETE_WITH_LIST(list_REINDEX);
1585 else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
1587 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
1588 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1589 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
1590 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1591 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
1592 pg_strcasecmp(prev_wd, "DATABASE") == 0)
1593 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1599 /* SET, RESET, SHOW */
1600 /* Complete with a variable name */
1601 else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
1602 pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
1603 pg_strcasecmp(prev_wd, "RESET") == 0)
1604 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
1605 else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
1606 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
1607 /* Complete "SET TRANSACTION" */
1608 else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
1609 pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1610 || (pg_strcasecmp(prev2_wd, "START") == 0
1611 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1612 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1613 && pg_strcasecmp(prev_wd, "WORK") == 0)
1614 || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1615 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1616 || (pg_strcasecmp(prev4_wd, "SESSION") == 0
1617 && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
1618 && pg_strcasecmp(prev2_wd, "AS") == 0
1619 && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
1621 static const char *const my_list[] =
1622 {"ISOLATION LEVEL", "READ", NULL};
1624 COMPLETE_WITH_LIST(my_list);
1626 else if ((pg_strcasecmp(prev3_wd, "SET") == 0
1627 || pg_strcasecmp(prev3_wd, "BEGIN") == 0
1628 || pg_strcasecmp(prev3_wd, "START") == 0
1629 || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
1630 && pg_strcasecmp(prev3_wd, "AS") == 0))
1631 && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
1632 || pg_strcasecmp(prev2_wd, "WORK") == 0)
1633 && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
1634 COMPLETE_WITH_CONST("LEVEL");
1635 else if ((pg_strcasecmp(prev4_wd, "SET") == 0
1636 || pg_strcasecmp(prev4_wd, "BEGIN") == 0
1637 || pg_strcasecmp(prev4_wd, "START") == 0
1638 || pg_strcasecmp(prev4_wd, "AS") == 0)
1639 && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
1640 || pg_strcasecmp(prev3_wd, "WORK") == 0)
1641 && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
1642 && pg_strcasecmp(prev_wd, "LEVEL") == 0)
1644 static const char *const my_list[] =
1645 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
1647 COMPLETE_WITH_LIST(my_list);
1649 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1650 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1651 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1652 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1653 pg_strcasecmp(prev_wd, "READ") == 0)
1655 static const char *const my_list[] =
1656 {"UNCOMMITTED", "COMMITTED", NULL};
1658 COMPLETE_WITH_LIST(my_list);
1660 else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1661 pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1662 pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1663 pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1664 pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
1665 COMPLETE_WITH_CONST("READ");
1666 else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
1667 pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
1668 pg_strcasecmp(prev3_wd, "START") == 0 ||
1669 pg_strcasecmp(prev3_wd, "AS") == 0) &&
1670 (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
1671 pg_strcasecmp(prev2_wd, "WORK") == 0) &&
1672 pg_strcasecmp(prev_wd, "READ") == 0)
1674 static const char *const my_list[] =
1675 {"ONLY", "WRITE", NULL};
1677 COMPLETE_WITH_LIST(my_list);
1679 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1680 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1681 pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1683 static const char *const constraint_list[] =
1684 {"DEFERRED", "IMMEDIATE", NULL};
1686 COMPLETE_WITH_LIST(constraint_list);
1688 /* Complete SET ROLE */
1689 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1690 pg_strcasecmp(prev_wd, "ROLE") == 0)
1691 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1692 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1693 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1694 pg_strcasecmp(prev_wd, "SESSION") == 0)
1696 static const char *const my_list[] =
1697 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
1699 COMPLETE_WITH_LIST(my_list);
1701 /* Complete SET SESSION AUTHORIZATION with username */
1702 else if (pg_strcasecmp(prev3_wd, "SET") == 0
1703 && pg_strcasecmp(prev2_wd, "SESSION") == 0
1704 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1705 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
1706 /* Complete RESET SESSION with AUTHORIZATION */
1707 else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
1708 pg_strcasecmp(prev_wd, "SESSION") == 0)
1709 COMPLETE_WITH_CONST("AUTHORIZATION");
1710 /* Complete SET <var> with "TO" */
1711 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1712 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
1713 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
1714 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
1715 COMPLETE_WITH_CONST("TO");
1716 /* Suggest possible variable values */
1717 else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1718 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1720 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
1722 static const char *const my_list[] =
1723 {"ISO", "SQL", "Postgres", "German",
1724 "YMD", "DMY", "MDY",
1725 "US", "European", "NonEuropean",
1728 COMPLETE_WITH_LIST(my_list);
1730 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
1732 static const char *const my_list[] =
1733 {"ON", "OFF", "DEFAULT", NULL};
1735 COMPLETE_WITH_LIST(my_list);
1739 static const char *const my_list[] =
1742 COMPLETE_WITH_LIST(my_list);
1746 /* START TRANSACTION */
1747 else if (pg_strcasecmp(prev_wd, "START") == 0)
1748 COMPLETE_WITH_CONST("TRANSACTION");
1751 else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
1752 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1755 else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
1756 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 '*'");
1759 /* If prev. word is UPDATE suggest a list of tables */
1760 else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
1761 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1762 /* Complete UPDATE <table> with "SET" */
1763 else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
1764 COMPLETE_WITH_CONST("SET");
1767 * If the previous word is SET (and it wasn't caught above as the _first_
1768 * word) the word before it was (hopefully) a table name and we'll now
1769 * make a list of attributes.
1771 else if (pg_strcasecmp(prev_wd, "SET") == 0)
1772 COMPLETE_WITH_ATTR(prev2_wd, "");
1774 /* UPDATE xx SET yy = */
1775 else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1776 pg_strcasecmp(prev4_wd, "UPDATE") == 0)
1777 COMPLETE_WITH_CONST("=");
1780 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
1781 * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
1783 else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
1784 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1785 " UNION SELECT 'FULL'"
1786 " UNION SELECT 'FREEZE'"
1787 " UNION SELECT 'ANALYZE'"
1788 " UNION SELECT 'VERBOSE'");
1789 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1790 (pg_strcasecmp(prev_wd, "FULL") == 0 ||
1791 pg_strcasecmp(prev_wd, "FREEZE") == 0))
1792 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1793 " UNION SELECT 'ANALYZE'"
1794 " UNION SELECT 'VERBOSE'");
1795 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1796 pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1797 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1798 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1799 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1800 " UNION SELECT 'VERBOSE'");
1801 else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1802 pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1803 (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1804 pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1805 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1806 " UNION SELECT 'ANALYZE'");
1807 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1808 pg_strcasecmp(prev_wd, "VERBOSE") == 0)
1809 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1810 " UNION SELECT 'ANALYZE'");
1811 else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1812 pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1813 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1814 " UNION SELECT 'VERBOSE'");
1815 else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1816 pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
1817 (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1818 pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
1819 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1822 /* If the previous word is ANALYZE, produce list of tables */
1823 else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1824 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1827 /* Simple case of the word before the where being the table name */
1828 else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
1829 COMPLETE_WITH_ATTR(prev2_wd, "");
1832 /* TODO: also include SRF ? */
1833 else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
1834 pg_strcasecmp(prev3_wd, "COPY") != 0 &&
1835 pg_strcasecmp(prev3_wd, "\\copy") != 0)
1836 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1839 /* Backslash commands */
1840 /* TODO: \dc \dd \dl */
1841 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1842 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1843 else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1844 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
1845 else if (strcmp(prev_wd, "\\da") == 0)
1846 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
1847 else if (strcmp(prev_wd, "\\db") == 0)
1848 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1849 else if (strcmp(prev_wd, "\\dD") == 0)
1850 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
1851 else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1852 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1853 else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1854 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1855 else if (strcmp(prev_wd, "\\dn") == 0)
1856 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1857 else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1858 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1859 else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1860 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
1861 else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1862 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1863 else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1864 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1865 else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1866 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
1867 else if (strcmp(prev_wd, "\\du") == 0)
1868 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1869 else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1870 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
1871 else if (strcmp(prev_wd, "\\encoding") == 0)
1872 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
1873 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1874 COMPLETE_WITH_LIST(sql_commands);
1875 else if (strcmp(prev_wd, "\\password") == 0)
1876 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1877 else if (strcmp(prev_wd, "\\pset") == 0)
1879 static const char *const my_list[] =
1880 {"format", "border", "expanded",
1881 "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1884 COMPLETE_WITH_LIST(my_list);
1886 else if (strcmp(prev_wd, "\\cd") == 0 ||
1887 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1888 strcmp(prev_wd, "\\g") == 0 ||
1889 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1890 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1891 strcmp(prev_wd, "\\s") == 0 ||
1892 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1894 matches = completion_matches(text, filename_completion_function);
1898 * Finally, we look through the list of "things", such as TABLE, INDEX and
1899 * check if that was the previous word. If so, execute the query to get a
1906 for (i = 0; words_after_create[i].name; i++)
1908 if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
1910 if (words_after_create[i].query)
1911 COMPLETE_WITH_QUERY(words_after_create[i].query);
1912 else if (words_after_create[i].squery)
1913 COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
1921 * If we still don't have anything to match we have to fabricate some sort
1922 * of default list. If we were to just return NULL, readline automatically
1923 * attempts filename completion, and that's usually no good.
1925 if (matches == NULL)
1927 COMPLETE_WITH_CONST("");
1928 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1929 rl_completion_append_character = '\0';
1940 /* Return our Grand List O' Matches */
1946 /* GENERATOR FUNCTIONS
1948 These functions do all the actual work of completing the input. They get
1949 passed the text so far and the count how many times they have been called so
1950 far with the same text.
1951 If you read the above carefully, you'll see that these don't get called
1952 directly but through the readline interface.
1953 The return value is expected to be the full completion of the text, going
1954 through a list each time, or NULL if there are no more matches. The string
1955 will be free()'d by readline, so you must run it through strdup() or
1956 something of that sort.
1959 /* This one gives you one from a list of things you can put after CREATE
1963 create_command_generator(const char *text, int state)
1965 static int list_index,
1969 /* If this is the first time for this completion, init some values */
1973 string_length = strlen(text);
1976 /* find something that matches */
1977 while ((name = words_after_create[list_index++].name))
1978 if (pg_strncasecmp(name, text, string_length) == 0)
1979 return pg_strdup(name);
1981 /* if nothing matches, return NULL */
1986 * This function gives you a list of things you can put after a DROP command.
1987 * Very similar to create_command_generator, but has an additional entry for
1988 * OWNED BY. (We do it this way in order not to duplicate the
1989 * words_after_create list.)
1992 drop_command_generator(const char *text, int state)
1994 static int list_index,
2000 /* If this is the first time for this completion, init some values */
2002 string_length = strlen(text);
2005 * DROP can be followed by "OWNED BY", which is not found in the list
2006 * for CREATE matches, so make it the first state. (We do not make it
2007 * the last state because it would be more difficult to detect when we
2008 * have to return NULL instead.)
2010 * Make sure we advance to the next state.
2013 if (pg_strncasecmp("OWNED", text, string_length) == 0)
2014 return pg_strdup("OWNED");
2018 * In subsequent attempts, try to complete with the same items we use for
2021 while ((name = words_after_create[list_index++ - 1].name))
2023 if (pg_strncasecmp(name, text, string_length) == 0)
2024 return pg_strdup(name);
2027 /* if nothing matches, return NULL */
2031 /* The following two functions are wrappers for _complete_from_query */
2034 complete_from_query(const char *text, int state)
2036 return _complete_from_query(0, text, state);
2040 complete_from_schema_query(const char *text, int state)
2042 return _complete_from_query(1, text, state);
2046 /* This creates a list of matching things, according to a query pointed to
2047 by completion_charp.
2048 The query can be one of two kinds:
2049 - A simple query which must contain a %d and a %s, which will be replaced
2050 by the string length of the text and the text itself. The query may also
2051 have another %s in it, which will be replaced by the value of
2052 completion_info_charp.
2054 - A schema query used for completion of both schema and relation names;
2055 these are more complex and must contain in the following order:
2056 %d %s %d %s %d %s %s %d %s
2057 where %d is the string length of the text and %s the text itself.
2059 It is assumed that strings should be escaped to become SQL literals
2060 (that is, what is in the query is actually ... '%s' ...)
2062 See top of file for examples of both kinds of query.
2066 _complete_from_query(int is_schema_query, const char *text, int state)
2068 static int list_index,
2070 static PGresult *result = NULL;
2073 * If this is the first time for this completion, we fetch a list of our
2074 * "things" from the backend.
2078 PQExpBufferData query_buffer;
2083 string_length = strlen(text);
2085 /* Free any prior result */
2089 /* Set up suitably-escaped copies of textual inputs */
2090 e_text = pg_malloc(string_length * 2 + 1);
2091 PQescapeString(e_text, text, string_length);
2093 if (completion_info_charp)
2097 charp_len = strlen(completion_info_charp);
2098 e_info_charp = pg_malloc(charp_len * 2 + 1);
2099 PQescapeString(e_info_charp, completion_info_charp,
2103 e_info_charp = NULL;
2105 initPQExpBuffer(&query_buffer);
2107 if (is_schema_query)
2109 /* completion_squery gives us the pieces to assemble */
2110 const char *qualresult = completion_squery->qualresult;
2112 if (qualresult == NULL)
2113 qualresult = completion_squery->result;
2115 /* Get unqualified names matching the input-so-far */
2116 appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
2117 completion_squery->result,
2118 completion_squery->catname);
2119 if (completion_squery->selcondition)
2120 appendPQExpBuffer(&query_buffer, "%s AND ",
2121 completion_squery->selcondition);
2122 appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
2123 completion_squery->result,
2124 string_length, e_text);
2125 appendPQExpBuffer(&query_buffer, " AND %s",
2126 completion_squery->viscondition);
2129 * When fetching relation names, suppress system catalogs unless
2130 * the input-so-far begins with "pg_". This is a compromise
2131 * between not offering system catalogs for completion at all, and
2132 * having them swamp the result when the input is just "p".
2134 if (strcmp(completion_squery->catname,
2135 "pg_catalog.pg_class c") == 0 &&
2136 strncmp(text, "pg_", 3) !=0)
2138 appendPQExpBuffer(&query_buffer,
2139 " AND c.relnamespace <> (SELECT oid FROM"
2140 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
2144 * Add in matching schema names, but only if there is more than
2145 * one potential match among schema names.
2147 appendPQExpBuffer(&query_buffer, "\nUNION\n"
2148 "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
2149 "FROM pg_catalog.pg_namespace n "
2150 "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
2151 string_length, e_text);
2152 appendPQExpBuffer(&query_buffer,
2153 " AND (SELECT pg_catalog.count(*)"
2154 " FROM pg_catalog.pg_namespace"
2155 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2156 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
2157 string_length, e_text);
2160 * Add in matching qualified names, but only if there is exactly
2161 * one schema matching the input-so-far.
2163 appendPQExpBuffer(&query_buffer, "\nUNION\n"
2164 "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
2165 "FROM %s, pg_catalog.pg_namespace n "
2166 "WHERE %s = n.oid AND ",
2168 completion_squery->catname,
2169 completion_squery->namespace);
2170 if (completion_squery->selcondition)
2171 appendPQExpBuffer(&query_buffer, "%s AND ",
2172 completion_squery->selcondition);
2173 appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
2175 string_length, e_text);
2178 * This condition exploits the single-matching-schema rule to
2179 * speed up the query
2181 appendPQExpBuffer(&query_buffer,
2182 " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
2183 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
2184 string_length, e_text);
2185 appendPQExpBuffer(&query_buffer,
2186 " AND (SELECT pg_catalog.count(*)"
2187 " FROM pg_catalog.pg_namespace"
2188 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2189 " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
2190 string_length, e_text);
2192 /* If an addon query was provided, use it */
2193 if (completion_charp)
2194 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
2198 /* completion_charp is an sprintf-style format string */
2199 appendPQExpBuffer(&query_buffer, completion_charp,
2200 string_length, e_text, e_info_charp);
2203 /* Limit the number of records in the result */
2204 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
2205 completion_max_records);
2207 result = exec_query(query_buffer.data);
2209 termPQExpBuffer(&query_buffer);
2215 /* Find something that matches */
2216 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
2220 while (list_index < PQntuples(result) &&
2221 (item = PQgetvalue(result, list_index++, 0)))
2222 if (pg_strncasecmp(text, item, string_length) == 0)
2223 return pg_strdup(item);
2226 /* If nothing matches, free the db structure and return null */
2233 /* This function returns in order one of a fixed, NULL pointer terminated list
2234 of strings (if matching). This can be used if there are only a fixed number
2235 SQL words that can appear at certain spot.
2238 complete_from_list(const char *text, int state)
2240 static int string_length,
2243 static bool casesensitive;
2246 /* need to have a list */
2247 psql_assert(completion_charpp);
2249 /* Initialization */
2253 string_length = strlen(text);
2254 casesensitive = true;
2258 while ((item = completion_charpp[list_index++]))
2260 /* First pass is case sensitive */
2261 if (casesensitive && strncmp(text, item, string_length) == 0)
2264 return pg_strdup(item);
2267 /* Second pass is case insensitive, don't bother counting matches */
2268 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
2269 return pg_strdup(item);
2273 * No matches found. If we're not case insensitive already, lets switch to
2274 * being case insensitive and try again
2276 if (casesensitive && matches == 0)
2278 casesensitive = false;
2281 return complete_from_list(text, state);
2284 /* If no more matches, return null. */
2289 /* This function returns one fixed string the first time even if it doesn't
2290 match what's there, and nothing the second time. This should be used if there
2291 is only one possibility that can appear at a certain spot, so misspellings
2292 will be overwritten.
2293 The string to be passed must be in completion_charp.
2296 complete_from_const(const char *text, int state)
2298 (void) text; /* We don't care about what was entered
2301 psql_assert(completion_charp);
2303 return pg_strdup(completion_charp);
2310 /* HELPER FUNCTIONS */
2314 * Execute a query and report any errors. This should be the preferred way of
2315 * talking to the database in this file.
2318 exec_query(const char *query)
2322 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
2325 result = PQexec(pset.db, query);
2327 if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
2330 psql_error("tab completion: %s failed - %s\n",
2331 query, PQresStatus(PQresultStatus(result)));
2343 * Return the word (space delimited) before point. Set skip > 0 to
2344 * skip that many words; e.g. skip=1 finds the word before the
2345 * previous one. Return value is NULL or a malloc'ed string.
2348 previous_word(int point, int skip)
2358 /* first we look for a space before the current word */
2359 for (i = point; i >= 0; i--)
2360 if (rl_line_buffer[i] == ' ')
2363 /* now find the first non-space which then constitutes the end */
2365 if (rl_line_buffer[i] != ' ')
2372 * If no end found we return null, because there is no word before the
2379 * Otherwise we now look for the start. The start is either the last
2380 * character before any space going backwards from the end, or it's
2381 * simply character 0
2383 for (start = end; start > 0; start--)
2385 if (rl_line_buffer[start] == '"')
2386 inquotes = !inquotes;
2387 if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
2395 s = pg_malloc(end - start + 2);
2396 strlcpy(s, &rl_line_buffer[start], end - start + 2);
2401 /* Find the parenthesis after the last word */
2405 find_open_parenthesis(int end)
2409 while ((rl_line_buffer[i] != ' ') && (i >= 0))
2411 if (rl_line_buffer[i] == '(')
2415 while ((rl_line_buffer[i] == ' ') && (i >= 0))
2419 if (rl_line_buffer[i] == '(')
2430 * Surround a string with single quotes. This works for both SQL and
2431 * psql internal. Currently disabled because it is reported not to
2432 * cooperate with certain versions of readline.
2435 quote_file_name(char *text, int match_type, char *quote_pointer)
2440 (void) quote_pointer; /* not used */
2442 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
2443 s = pg_malloc(length);
2445 strcpy(s + 1, text);
2446 if (match_type == SINGLE_MATCH)
2447 s[length - 2] = '\'';
2448 s[length - 1] = '\0';
2455 dequote_file_name(char *text, char quote_char)
2461 return pg_strdup(text);
2463 length = strlen(text);
2464 s = pg_malloc(length - 2 + 1);
2465 strlcpy(s, text +1, length - 2 + 1);
2471 #endif /* USE_READLINE */