2 * psql - the PostgreSQL interactive terminal
4 * Copyright 2000-2002 by PostgreSQL Global Development Group
6 * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.78 2003/06/11 18:01:14 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 tuples returned gets limited, in most default
19 * installations to 101, 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 things 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"
49 /* If we don't have this, we might as well forget about the whole thing: */
53 #ifdef USE_ASSERT_CHECKING
62 #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
63 #define filename_completion_function rl_filename_completion_function
65 /* missing in some header files */
66 extern char *filename_completion_function();
69 #ifdef HAVE_RL_COMPLETION_MATCHES
70 #define completion_matches rl_completion_matches
74 #define ERROR_QUERY_TOO_LONG /* empty */
77 /* Forward declaration of functions */
78 static char **psql_completion(char *text, int start, int end);
79 static char *create_command_generator(const char *text, int state);
80 static char *complete_from_query(const char *text, int state);
81 static char *complete_from_schema_query(const char *text, int state);
82 static char *_complete_from_query(int is_schema_query,
83 const char *text, int state);
84 static char *complete_from_const(const char *text, int state);
85 static char *complete_from_list(const char *text, int state);
87 static PGresult *exec_query(char *query);
88 char *quote_file_name(char *text, int match_type, char *quote_pointer);
90 /*static char * dequote_file_name(char *text, char quote_char);*/
91 static char *previous_word(int point, int skip);
93 /* These variables are used to pass information into the completion functions.
94 Realizing that this is the cardinal sin of programming, I don't see a better
96 char *completion_charp; /* if you need to pass a string */
97 char **completion_charpp; /* if you need to pass a list of strings */
98 char *completion_info_charp; /* if you need to pass another
101 /* Store how many records from a database query we want to return at most
102 (implemented via SELECT ... LIMIT xx). */
103 static int completion_max_records;
106 /* Initialize the readline library for our purposes. */
108 initialize_readline(void)
110 rl_readline_name = pset.progname;
111 rl_attempted_completion_function = (void *) psql_completion;
113 rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
115 completion_max_records = 100;
118 * There is a variable rl_completion_query_items for this but
119 * apparently it's not defined everywhere.
125 * Queries to get lists of names of various kinds of things, possibly
126 * restricted to names matching a partially entered name. In these queries,
127 * the %s will be replaced by the text entered so far, the %d by its length.
130 #define Query_for_list_of_aggregates \
131 " SELECT DISTINCT proname " \
132 " FROM pg_catalog.pg_proc" \
134 " AND substr(proname,1,%d)='%s'" \
136 " SELECT nspname || '.' AS relname" \
137 " FROM pg_catalog.pg_namespace" \
138 " WHERE substr(nspname,1,%d)='%s'" \
140 " SELECT DISTINCT nspname || '.' || proname AS relname" \
141 " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n" \
143 " AND substr(nspname || '.' || proname,1,%d)='%s'" \
144 " AND pronamespace = n.oid" \
145 " AND ('%s' ~ '^.*\\\\.' "\
147 " FROM pg_catalog.pg_namespace "\
148 " WHERE substr(nspname,1,%d)='%s' "\
149 " HAVING COUNT(nspname)=1))"
151 #define Query_for_list_of_attributes \
152 "SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
153 " WHERE c.oid = a.attrelid "\
154 " AND a.attnum > 0 "\
155 " AND NOT a.attisdropped "\
156 " AND substr(a.attname,1,%d)='%s' "\
157 " AND c.relname='%s' "\
158 " AND pg_catalog.pg_table_is_visible(c.oid)"
160 #define Query_for_list_of_databases \
161 "SELECT datname FROM pg_catalog.pg_database "\
162 " WHERE substr(datname,1,%d)='%s'"
164 #define Query_for_list_of_datatypes \
165 " SELECT pg_catalog.format_type(t.oid, NULL) "\
166 " FROM pg_catalog.pg_type t "\
167 " WHERE (t.typrelid = 0 "\
168 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "\
169 " AND t.typname !~ '^_' "\
170 " AND substr(pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
172 " SELECT nspname || '.' AS relname "\
173 " FROM pg_catalog.pg_namespace "\
174 " WHERE substr(nspname,1,%d)='%s' "\
176 " SELECT nspname || '.' || pg_catalog.format_type(t.oid, NULL) AS relname "\
177 " FROM pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
178 " WHERE(t.typrelid = 0 "\
179 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "\
180 " AND t.typname !~ '^_' "\
181 " AND substr(nspname || '.' || pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
182 " AND typnamespace = n.oid "\
183 " AND ('%s' ~ '^.*\\\\.' "\
185 " FROM pg_catalog.pg_namespace "\
186 " WHERE substr(nspname,1,%d)='%s' "\
187 " HAVING COUNT(nspname)=1))"
189 #define Query_for_list_of_domains \
191 " FROM pg_catalog.pg_type t "\
192 " WHERE typtype = 'd' "\
193 " AND substr(typname,1,%d)='%s' "\
195 " SELECT nspname || '.' "\
196 " FROM pg_catalog.pg_namespace "\
197 " WHERE substr(nspname,1,%d)='%s' "\
199 " SELECT nspname || '.' || pg_catalog.format_type(t.oid, NULL) "\
200 " FROM pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
201 " WHERE typtype = 'd' "\
202 " AND substr(nspname || '.' || typname,1,%d)='%s' "\
203 " AND typnamespace = n.oid "\
204 " AND ('%s' ~ '^.*\\\\.' "\
206 " FROM pg_catalog.pg_namespace "\
207 " WHERE substr(nspname,1,%d)='%s' "\
208 " HAVING COUNT(nspname)=1))"
210 #define Query_for_list_of_functions \
211 " SELECT DISTINCT proname || '()' "\
212 " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
213 " WHERE substr(proname,1,%d)='%s'"\
214 " AND pg_catalog.pg_function_is_visible(p.oid) "\
215 " AND pronamespace = n.oid "\
217 " SELECT nspname || '.' "\
218 " FROM pg_catalog.pg_namespace "\
219 " WHERE substr(nspname,1,%d)='%s' "\
221 " SELECT nspname || '.' || proname "\
222 " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
223 " WHERE substr(nspname || '.' || proname,1,%d)='%s' "\
224 " AND pronamespace = n.oid "\
225 " AND ('%s' ~ '^.*\\\\.' "\
227 " FROM pg_catalog.pg_namespace "\
228 " WHERE substr(nspname,1,%d)='%s' "\
229 " HAVING COUNT(nspname)=1))"
231 #define Query_for_list_of_indexes \
233 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
234 " WHERE relkind='i' "\
235 " AND substr(relname,1,%d)='%s' "\
236 " AND pg_catalog.pg_table_is_visible(c.oid) "\
237 " AND relnamespace = n.oid "\
238 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
240 " SELECT nspname || '.' "\
241 " FROM pg_catalog.pg_namespace "\
242 " WHERE substr(nspname,1,%d)='%s' "\
244 " SELECT nspname || '.' || relname "\
245 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
246 " WHERE relkind='i' "\
247 " AND substr(nspname || '.' || relname,1,%d)='%s' "\
248 " AND relnamespace = n.oid "\
249 " AND ('%s' ~ '^.*\\\\.' "\
251 " FROM pg_catalog.pg_namespace "\
252 " WHERE substr(nspname,1,%d)='%s' "\
253 " HAVING COUNT(nspname)=1))"
256 #define Query_for_list_of_languages \
258 " FROM pg_language "\
259 " WHERE lanname != 'internal' "\
260 " AND substr(lanname,1,%d)='%s' "
262 #define Query_for_list_of_schemas \
263 "SELECT nspname FROM pg_catalog.pg_namespace "\
264 " WHERE substr(nspname,1,%d)='%s'"
266 #define Query_for_list_of_sequences \
268 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
269 " WHERE relkind='S' "\
270 " AND substr(relname,1,%d)='%s' "\
271 " AND pg_catalog.pg_table_is_visible(c.oid) "\
272 " AND relnamespace = n.oid "\
273 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
275 " SELECT nspname || '.' "\
276 " FROM pg_catalog.pg_namespace "\
277 " WHERE substr(nspname,1,%d)='%s' "\
279 " SELECT nspname || '.' || relname "\
280 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
281 " WHERE relkind='S' "\
282 " AND substr(nspname || '.' || relname,1,%d)='%s' "\
283 " AND relnamespace = n.oid "\
284 " AND ('%s' ~ '^.*\\\\.' "\
286 " FROM pg_catalog.pg_namespace "\
287 " WHERE substr(nspname,1,%d)='%s' "\
288 " HAVING COUNT(nspname)=1))"
290 #define Query_for_list_of_system_relations \
291 "SELECT c.relname FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
292 " WHERE (c.relkind='r' OR c.relkind='v' OR c.relkind='s' OR c.relkind='S') "\
293 " AND substr(c.relname,1,%d)='%s' "\
294 " AND pg_catalog.pg_table_is_visible(c.oid)"\
295 " AND relnamespace = n.oid "\
296 " AND n.nspname = 'pg_catalog'"
298 #define Query_for_list_of_tables \
300 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
301 " WHERE relkind='r' "\
302 " AND substr(relname,1,%d)='%s' "\
303 " AND pg_catalog.pg_table_is_visible(c.oid) "\
304 " AND relnamespace = n.oid "\
305 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
307 " SELECT nspname || '.' "\
308 " FROM pg_catalog.pg_namespace "\
309 " WHERE substr(nspname || '.',1,%d)='%s' "\
311 " SELECT nspname || '.' || relname "\
312 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
313 " WHERE relkind='r' "\
314 " AND substr(nspname || '.' || relname,1,%d)='%s' "\
315 " AND relnamespace = n.oid "\
316 " AND ('%s' ~ '^.*\\\\.' "\
318 " FROM pg_catalog.pg_namespace n1 "\
319 " WHERE substr(nspname ||'.',1,%d)='%s' "\
320 " HAVING COUNT(nspname)=1))"
322 #define Query_for_list_of_tisv \
324 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
325 " WHERE (relkind='r' OR relkind='i' OR relkind='S' OR relkind='v') "\
326 " AND substr(relname,1,%d)='%s' "\
327 " AND pg_catalog.pg_table_is_visible(c.oid) "\
328 " AND relnamespace = n.oid "\
329 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
331 " SELECT nspname || '.' "\
332 " FROM pg_catalog.pg_namespace "\
333 " WHERE substr(nspname,1,%d)='%s' "\
335 " SELECT nspname || '.' || relname "\
336 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
337 " WHERE (relkind='r' OR relkind='i' OR relkind='S' OR relkind='v') "\
338 " AND substr(nspname || '.' || relname,1,%d)='%s' "\
339 " AND relnamespace = n.oid "\
340 " AND ('%s' ~ '^.*\\\\.' "\
342 " FROM pg_catalog.pg_namespace "\
343 " WHERE substr(nspname,1,%d)='%s' "\
344 " HAVING COUNT(nspname)=1))"
346 #define Query_for_list_of_tsv \
348 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
349 " WHERE (relkind='r' OR relkind='S' OR relkind='v') "\
350 " AND substr(relname,1,%d)='%s' "\
351 " AND pg_catalog.pg_table_is_visible(c.oid) "\
352 " AND relnamespace = n.oid "\
353 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
355 " SELECT nspname || '.' "\
356 " FROM pg_catalog.pg_namespace "\
357 " WHERE substr(nspname,1,%d)='%s' "\
359 " SELECT nspname || '.' || relname "\
360 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
361 " WHERE (relkind='r' OR relkind='S' OR relkind='v') "\
362 " AND substr(nspname || '.' || relname,1,%d)='%s' "\
363 " AND relnamespace = n.oid "\
364 " AND ('%s' ~ '^.*\\\\.' "\
366 " FROM pg_catalog.pg_namespace "\
367 " WHERE substr(nspname,1,%d)='%s' "\
368 " HAVING COUNT(nspname)=1))"
370 #define Query_for_list_of_views \
372 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
373 " WHERE relkind='v'"\
374 " AND substr(relname,1,%d)='%s' "\
375 " AND pg_catalog.pg_table_is_visible(c.oid) "\
376 " AND relnamespace = n.oid "\
377 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
379 " SELECT nspname || '.' "\
380 " FROM pg_catalog.pg_namespace "\
381 " WHERE substr(nspname,1,%d)='%s' "\
383 " SELECT nspname || '.' || relname "\
384 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
385 " WHERE relkind='v' "\
386 " AND substr(nspname || '.' || relname,1,%d)='%s' "\
387 " AND relnamespace = n.oid "\
388 " AND ('%s' ~ '^.*\\\\.' "\
390 " FROM pg_catalog.pg_namespace "\
391 " WHERE substr(nspname,1,%d)='%s' "\
392 " HAVING COUNT(nspname)=1))"
394 #define Query_for_list_of_users \
396 " FROM pg_catalog.pg_user "\
397 " WHERE substr(usename,1,%d)='%s'"
399 /* This is a list of all "things" in Pgsql, which can show up after CREATE or
400 DROP; and there is also a query to get a list of them.
403 #define WITH_SCHEMA 1
413 pgsql_thing_t words_after_create[] = {
414 {"AGGREGATE", WITH_SCHEMA, Query_for_list_of_aggregates},
415 {"CAST", NO_SCHEMA, NULL}, /* Casts have complex structures for namees, so skip it */
416 {"CONVERSION", NO_SCHEMA, "SELECT conname FROM pg_catalog.pg_conversion WHERE substr(conname,1,%d)='%s'"},
417 {"DATABASE", NO_SCHEMA, Query_for_list_of_databases},
418 {"DOMAIN", WITH_SCHEMA, Query_for_list_of_domains},
419 {"FUNCTION", WITH_SCHEMA, Query_for_list_of_functions},
420 {"GROUP", NO_SCHEMA, "SELECT groname FROM pg_catalog.pg_group WHERE substr(groname,1,%d)='%s'"},
421 {"LANGUAGE", NO_SCHEMA, Query_for_list_of_languages},
422 {"INDEX", WITH_SCHEMA, Query_for_list_of_indexes},
423 {"OPERATOR", NO_SCHEMA, NULL}, /* Querying for this is probably not such
425 {"RULE", NO_SCHEMA, "SELECT rulename FROM pg_catalog.pg_rules WHERE substr(rulename,1,%d)='%s'"},
426 {"SCHEMA", NO_SCHEMA, Query_for_list_of_schemas},
427 {"SEQUENCE", WITH_SCHEMA, Query_for_list_of_sequences},
428 {"TABLE", WITH_SCHEMA, Query_for_list_of_tables},
429 {"TEMP", NO_SCHEMA, NULL}, /* for CREATE TEMP TABLE ... */
430 {"TRIGGER", NO_SCHEMA, "SELECT tgname FROM pg_catalog.pg_trigger WHERE substr(tgname,1,%d)='%s'"},
431 {"TYPE", WITH_SCHEMA, Query_for_list_of_datatypes },
432 {"UNIQUE", NO_SCHEMA, NULL}, /* for CREATE UNIQUE INDEX ... */
433 {"USER", NO_SCHEMA, Query_for_list_of_users},
434 {"VIEW", WITH_SCHEMA, Query_for_list_of_views},
435 {NULL, NO_SCHEMA, NULL} /* end of list */
439 /* A couple of macros to ease typing. You can use these to complete the given
441 1) The results from a query you pass it. (Perhaps one of those above?)
442 2) The results from a schema query you pass it.
443 3) The items from a null-pointer-terminated list.
445 5) The list of attributes to the given table.
447 #define COMPLETE_WITH_QUERY(query) \
448 do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
449 #define COMPLETE_WITH_SCHEMA_QUERY(query) \
450 do { completion_charp = query; matches = completion_matches(text, complete_from_schema_query); } while(0)
451 #define COMPLETE_WITH_LIST(list) \
452 do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
453 #define COMPLETE_WITH_CONST(string) \
454 do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
455 #define COMPLETE_WITH_ATTR(table) \
456 do {completion_charp = Query_for_list_of_attributes; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0)
459 /* The completion function. Acc. to readline spec this gets passed the text
460 entered to far and its start and end in the readline buffer. The return value
461 is some partially obscure list format that can be generated by the readline
462 libraries completion_matches() function, so we don't have to worry about it.
465 psql_completion(char *text, int start, int end)
467 /* This is the variable we'll return. */
468 char **matches = NULL;
470 /* These are going to contain some scannage of the input line. */
476 static char *sql_commands[] = {
477 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
478 "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE", "DROP", "EXECUTE",
479 "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
480 "PREPARE", "REINDEX", "RESET", "REVOKE", "ROLLBACK", "SELECT", "SET", "SHOW",
481 "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
484 static char *pgsql_variables[] = {
485 /* these SET arguments are known in gram.y */
492 * the rest should match USERSET and possibly SUSET entries in
493 * backend/utils/misc/guc.c.
495 "australian_timezones",
497 "client_min_messages",
500 "cpu_index_tuple_cost",
505 "debug_pretty_print",
508 "debug_print_rewritten",
509 "default_statistics_target",
510 "default_transaction_isolation",
511 "default_transaction_read_only",
512 "dynamic_library_path",
513 "effective_cache_size",
522 "explain_pretty_print",
523 "extra_float_digits",
524 "from_collapse_limit",
531 "geqo_selection_bias",
533 "join_collapse_limit",
534 "krb_server_keyfile",
540 "log_executor_stats",
541 "log_min_duration_statement",
542 "log_min_error_statement",
547 "log_statement_stats",
550 "max_files_per_process",
553 "max_locks_per_transaction",
554 "password_encryption",
567 "stats_command_string",
568 "stats_reset_on_server_start",
570 "stats_start_collector",
571 "superuser_reserved_connections",
578 "transform_null_equals",
579 "unix_socket_directory",
581 "unix_socket_permissions",
589 static char *backslash_commands[] = {
590 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
591 "\\d", "\\da", "\\dc", "\\dC", "\\dd", "\\dD", "\\df", "\\di",
592 "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT",
594 "\\e", "\\echo", "\\encoding",
595 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
596 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
597 "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
598 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
601 (void) end; /* not used */
603 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
604 rl_completion_append_character = ' ';
607 /* Clear a few things. */
608 completion_charp = NULL;
609 completion_charpp = NULL;
610 completion_info_charp = NULL;
613 * Scan the input line before our current position for the last four
614 * words. According to those we'll make some smart decisions on what
615 * the user is probably intending to type. TODO: Use strtokx() to do
618 prev_wd = previous_word(start, 0);
619 prev2_wd = previous_word(start, 1);
620 prev3_wd = previous_word(start, 2);
621 prev4_wd = previous_word(start, 3);
623 /* If a backslash command was started, continue */
625 COMPLETE_WITH_LIST(backslash_commands);
627 /* If no previous word, suggest one of the basic sql commands */
629 COMPLETE_WITH_LIST(sql_commands);
631 /* CREATE or DROP but not ALTER TABLE sth DROP */
632 /* complete with something you can create or drop */
633 else if (strcasecmp(prev_wd, "CREATE") == 0 ||
634 (strcasecmp(prev_wd, "DROP") == 0 &&
635 strcasecmp(prev3_wd,"TABLE") != 0 ))
636 matches = completion_matches(text, create_command_generator);
639 /* complete with what you can alter (TABLE, GROUP, USER, ...)
640 * unless we're in ALTER TABLE sth ALTER*/
641 else if (strcasecmp(prev_wd, "ALTER") == 0 &&
642 strcasecmp(prev3_wd, "TABLE") != 0 )
644 char *list_ALTER[] = {"DATABASE", "GROUP", "SCHEMA", "TABLE",
645 "TRIGGER", "USER", NULL};
647 COMPLETE_WITH_LIST(list_ALTER);
650 /* ALTER DATABASE <name> */
651 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
652 strcasecmp(prev2_wd, "DATABASE") == 0)
654 char *list_ALTERDATABASE[] = {"RESET", "SET", NULL};
656 COMPLETE_WITH_LIST(list_ALTERDATABASE);
658 /* ALTER TRIGGER <name>, add ON */
659 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
660 strcasecmp(prev2_wd, "TRIGGER") == 0)
661 COMPLETE_WITH_CONST("ON");
664 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
666 else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
667 strcasecmp(prev3_wd, "TRIGGER") == 0 &&
668 strcasecmp(prev_wd, "ON") == 0)
669 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
672 * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
675 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
676 strcasecmp(prev2_wd, "TABLE") == 0)
678 char *list_ALTER2[] = {"ADD", "ALTER", "DROP", "RENAME",
681 COMPLETE_WITH_LIST(list_ALTER2);
683 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
684 else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
685 (strcasecmp(prev_wd, "ALTER") == 0 ||
686 strcasecmp(prev_wd, "RENAME") == 0))
687 COMPLETE_WITH_ATTR(prev2_wd);
689 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
690 else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
691 strcasecmp(prev_wd, "DROP") == 0)
693 char *list_TABLEDROP[] = {"COLUMN", "CONSTRAINT", NULL};
694 COMPLETE_WITH_LIST(list_TABLEDROP);
696 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
697 else if (strcasecmp(prev4_wd, "TABLE") == 0 &&
698 strcasecmp(prev2_wd, "DROP") == 0 &&
699 strcasecmp(prev_wd, "COLUMN") == 0)
700 COMPLETE_WITH_ATTR(prev3_wd);
702 /* complete ALTER GROUP <foo> with ADD or DROP */
703 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
704 strcasecmp(prev2_wd, "GROUP") == 0)
706 char *list_ALTERGROUP[] = {"ADD", "DROP", NULL};
708 COMPLETE_WITH_LIST(list_ALTERGROUP);
710 /* complete ALTER GROUP <foo> ADD|DROP with USER */
711 else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
712 strcasecmp(prev3_wd, "GROUP") == 0 &&
713 (strcasecmp(prev_wd, "ADD") == 0 ||
714 strcasecmp(prev_wd, "DROP") == 0))
715 COMPLETE_WITH_CONST("USER");
716 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
717 else if (strcasecmp(prev4_wd, "GROUP") == 0 &&
718 (strcasecmp(prev2_wd, "ADD") == 0 ||
719 strcasecmp(prev2_wd, "DROP") == 0) &&
720 strcasecmp(prev_wd, "USER") == 0)
721 COMPLETE_WITH_QUERY(Query_for_list_of_users);
724 /* If the previous word is ANALYZE, produce list of tables. */
725 else if (strcasecmp(prev_wd, "ANALYZE") == 0)
726 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
727 /* If we have ANALYZE <table>, complete with semicolon. */
728 else if (strcasecmp(prev2_wd, "ANALYZE") == 0)
729 COMPLETE_WITH_CONST(";");
732 /* If the previous word is CLUSTER, produce list of indexes. */
733 else if (strcasecmp(prev_wd, "CLUSTER") == 0)
734 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
735 /* If we have CLUSTER <sth>, then add "ON" */
736 else if (strcasecmp(prev2_wd, "CLUSTER") == 0)
737 COMPLETE_WITH_CONST("ON");
740 * If we have CLUSTER <sth> ON, then add the correct tablename as
743 else if (strcasecmp(prev3_wd, "CLUSTER") == 0 &&
744 strcasecmp(prev_wd, "ON") == 0)
746 char query_buffer[BUF_SIZE]; /* Some room to build
749 if (snprintf(query_buffer, BUF_SIZE,
750 "SELECT c1.relname FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid and c2.relname='%s' and pg_catalog.pg_table_is_visible(c2.oid)",
752 ERROR_QUERY_TOO_LONG;
754 COMPLETE_WITH_QUERY(query_buffer);
758 else if (strcasecmp(prev_wd, "COMMENT") == 0)
759 COMPLETE_WITH_CONST("ON");
760 else if (strcasecmp(prev2_wd, "COMMENT") == 0 &&
761 strcasecmp(prev_wd, "ON") == 0)
763 char *list_COMMENT[] =
764 {"DATABASE", "INDEX", "RULE", "SCHEMA", "SEQUENCE", "TABLE",
765 "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR",
766 "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
768 COMPLETE_WITH_LIST(list_COMMENT);
770 else if (strcasecmp(prev4_wd, "COMMENT") == 0 &&
771 strcasecmp(prev3_wd, "ON") == 0)
772 COMPLETE_WITH_CONST("IS");
777 * If we have COPY [BINARY] (which you'd have to type yourself), offer
778 * list of tables (Also cover the analogous backslash command)
780 else if (strcasecmp(prev_wd, "COPY") == 0 ||
781 strcasecmp(prev_wd, "\\copy") == 0 ||
782 (strcasecmp(prev2_wd, "COPY") == 0 &&
783 strcasecmp(prev_wd, "BINARY") == 0))
784 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
785 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
786 else if (strcasecmp(prev2_wd, "COPY") == 0 ||
787 strcasecmp(prev2_wd, "\\copy") == 0 ||
788 strcasecmp(prev2_wd, "BINARY") == 0)
790 char *list_FROMTO[] = {"FROM", "TO", NULL};
792 COMPLETE_WITH_LIST(list_FROMTO);
796 /* First off we complete CREATE UNIQUE with "INDEX" */
797 else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
798 strcasecmp(prev_wd, "UNIQUE") == 0)
799 COMPLETE_WITH_CONST("INDEX");
800 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
801 else if (strcasecmp(prev2_wd, "INDEX") == 0 &&
802 (strcasecmp(prev3_wd, "CREATE") == 0 ||
803 strcasecmp(prev3_wd, "UNIQUE") == 0))
804 COMPLETE_WITH_CONST("ON");
805 /* Complete ... INDEX <name> ON with a list of tables */
806 else if (strcasecmp(prev3_wd, "INDEX") == 0 &&
807 strcasecmp(prev_wd, "ON") == 0)
808 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
811 * Complete INDEX <name> ON <table> with a list of table columns
812 * (which should really be in parens)
814 else if (strcasecmp(prev4_wd, "INDEX") == 0 &&
815 strcasecmp(prev2_wd, "ON") == 0)
816 COMPLETE_WITH_ATTR(prev_wd);
817 /* same if you put in USING */
818 else if (strcasecmp(prev4_wd, "ON") == 0 &&
819 strcasecmp(prev2_wd, "USING") == 0)
820 COMPLETE_WITH_ATTR(prev3_wd);
821 /* Complete USING with an index method */
822 else if (strcasecmp(prev_wd, "USING") == 0)
824 char *index_mth[] = {"BTREE", "RTREE", "HASH", "GIST", NULL};
826 COMPLETE_WITH_LIST(index_mth);
830 /* Complete "CREATE RULE <sth>" with "AS" */
831 else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
832 strcasecmp(prev2_wd, "RULE") == 0)
833 COMPLETE_WITH_CONST("AS");
834 /* Complete "CREATE RULE <sth> AS with "ON" */
835 else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
836 strcasecmp(prev3_wd, "RULE") == 0 &&
837 strcasecmp(prev_wd, "AS") == 0)
838 COMPLETE_WITH_CONST("ON");
839 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
840 else if (strcasecmp(prev4_wd, "RULE") == 0 &&
841 strcasecmp(prev2_wd, "AS") == 0 &&
842 strcasecmp(prev_wd, "ON") == 0)
844 char *rule_events[] = {"SELECT", "UPDATE", "INSERT",
847 COMPLETE_WITH_LIST(rule_events);
849 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
850 else if (strcasecmp(prev3_wd, "AS") == 0 &&
851 strcasecmp(prev2_wd, "ON") == 0 &&
852 (toupper((unsigned char) prev_wd[4]) == 'T' ||
853 toupper((unsigned char) prev_wd[5]) == 'T'))
854 COMPLETE_WITH_CONST("TO");
855 /* Complete "AS ON <sth> TO" with a table name */
856 else if (strcasecmp(prev4_wd, "AS") == 0 &&
857 strcasecmp(prev3_wd, "ON") == 0 &&
858 strcasecmp(prev_wd, "TO") == 0)
859 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
862 /* Complete CREATE TEMP with "TABLE" */
863 else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
864 strcasecmp(prev_wd, "TEMP") == 0)
865 COMPLETE_WITH_CONST("TABLE");
868 /* is on the agenda . . . */
871 /* Complete "CREATE VIEW <name>" with "AS" */
872 else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
873 strcasecmp(prev2_wd, "VIEW") == 0)
874 COMPLETE_WITH_CONST("AS");
875 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
876 else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
877 strcasecmp(prev3_wd, "VIEW") == 0 &&
878 strcasecmp(prev_wd, "AS") == 0)
879 COMPLETE_WITH_CONST("SELECT");
884 * Complete DELETE with FROM (only if the word before that is not "ON"
885 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
887 else if (strcasecmp(prev_wd, "DELETE") == 0 &&
888 !(strcasecmp(prev2_wd, "ON") == 0 ||
889 strcasecmp(prev2_wd, "GRANT") == 0 ||
890 strcasecmp(prev2_wd, "BEFORE") == 0 ||
891 strcasecmp(prev2_wd, "AFTER") == 0))
892 COMPLETE_WITH_CONST("FROM");
893 /* Complete DELETE FROM with a list of tables */
894 else if (strcasecmp(prev2_wd, "DELETE") == 0 &&
895 strcasecmp(prev_wd, "FROM") == 0)
896 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
897 /* Complete DELETE FROM <table> with "WHERE" (perhaps a safe idea?) */
898 else if (strcasecmp(prev3_wd, "DELETE") == 0 &&
899 strcasecmp(prev2_wd, "FROM") == 0)
900 COMPLETE_WITH_CONST("WHERE");
905 * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with
906 * the list of SQL commands
908 else if (strcasecmp(prev_wd, "EXPLAIN") == 0 ||
909 (strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
910 strcasecmp(prev_wd, "VERBOSE") == 0))
911 COMPLETE_WITH_LIST(sql_commands);
914 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
915 else if (strcasecmp(prev_wd, "FETCH") == 0 ||
916 strcasecmp(prev_wd, "MOVE") == 0)
918 char *list_FETCH1[] = {"FORWARD", "BACKWARD", "RELATIVE", NULL};
920 COMPLETE_WITH_LIST(list_FETCH1);
922 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
923 else if (strcasecmp(prev2_wd, "FETCH") == 0 ||
924 strcasecmp(prev2_wd, "MOVE") == 0)
926 char *list_FETCH2[] = {"ALL", "NEXT", "PRIOR", NULL};
928 COMPLETE_WITH_LIST(list_FETCH2);
932 * Complete FETCH <sth1> <sth2> with "FROM" or "TO". (Is there a
933 * difference? If not, remove one.)
935 else if (strcasecmp(prev3_wd, "FETCH") == 0 ||
936 strcasecmp(prev3_wd, "MOVE") == 0)
938 char *list_FROMTO[] = {"FROM", "TO", NULL};
940 COMPLETE_WITH_LIST(list_FROMTO);
944 /* Complete GRANT/REVOKE with a list of privileges */
945 else if (strcasecmp(prev_wd, "GRANT") == 0 ||
946 strcasecmp(prev_wd, "REVOKE") == 0)
948 char *list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES", "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
950 COMPLETE_WITH_LIST(list_privileg);
952 /* Complete GRANT/REVOKE <sth> with "ON" */
953 else if (strcasecmp(prev2_wd, "GRANT") == 0 ||
954 strcasecmp(prev2_wd, "REVOKE") == 0)
955 COMPLETE_WITH_CONST("ON");
958 * Complete GRANT/REVOKE <sth> ON with a list of tables, views,
959 * sequences, and indexes
961 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result
962 * via UNION; seems to work intuitively
964 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
965 * here will only work if the privilege list contains exactly one privilege
967 else if ((strcasecmp(prev3_wd, "GRANT") == 0 ||
968 strcasecmp(prev3_wd, "REVOKE") == 0) &&
969 strcasecmp(prev_wd, "ON") == 0)
970 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
971 " WHERE relkind in ('r','S','v') "
972 " AND substr(relname,1,%d)='%s' "
973 " AND pg_catalog.pg_table_is_visible(c.oid) "
974 " AND relnamespace = n.oid "
975 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
977 "SELECT 'DATABASE' AS relname "
979 "SELECT 'FUNCTION' AS relname "
981 "SELECT 'LANGUAGE' AS relname "
983 "SELECT 'SCHEMA' AS relname ");
985 /* Complete "GRANT/REVOKE * ON * " with "TO" */
986 else if ((strcasecmp(prev4_wd, "GRANT") == 0 ||
987 strcasecmp(prev4_wd, "REVOKE") == 0) &&
988 strcasecmp(prev2_wd, "ON") == 0)
990 if(strcasecmp(prev_wd, "DATABASE") == 0)
991 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
992 else if(strcasecmp(prev_wd, "FUNCTION") == 0)
993 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
994 else if(strcasecmp(prev_wd, "LANGUAGE") == 0)
995 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
996 else if(strcasecmp(prev_wd, "SCHEMA") == 0)
997 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
999 COMPLETE_WITH_CONST("TO");
1003 * TODO: to complete with user name we need prev5_wd -- wait for a
1004 * more general solution there
1005 * same for GRANT <sth> ON { DATABASE | FUNCTION | LANGUAGE | SCHEMA } xxx TO
1009 /* Complete INSERT with "INTO" */
1010 else if (strcasecmp(prev_wd, "INSERT") == 0)
1011 COMPLETE_WITH_CONST("INTO");
1012 /* Complete INSERT INTO with table names */
1013 else if (strcasecmp(prev2_wd, "INSERT") == 0 &&
1014 strcasecmp(prev_wd, "INTO") == 0)
1015 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1016 /* Complete "INSERT INTO <table> (" with attribute names */
1017 else if (rl_line_buffer[start - 1] == '(' &&
1018 strcasecmp(prev3_wd, "INSERT") == 0 &&
1019 strcasecmp(prev2_wd, "INTO") == 0)
1020 COMPLETE_WITH_ATTR(prev_wd);
1023 * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1026 else if (strcasecmp(prev3_wd, "INSERT") == 0 &&
1027 strcasecmp(prev2_wd, "INTO") == 0)
1029 char *list_INSERT[] = {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1031 COMPLETE_WITH_LIST(list_INSERT);
1033 /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1034 else if (strcasecmp(prev4_wd, "INSERT") == 0 &&
1035 strcasecmp(prev3_wd, "INTO") == 0 &&
1036 prev_wd[strlen(prev_wd) - 1] == ')')
1038 char *list_INSERT[] = {"SELECT", "VALUES", NULL};
1040 COMPLETE_WITH_LIST(list_INSERT);
1043 /* Insert an open parenthesis after "VALUES" */
1044 else if (strcasecmp(prev_wd, "VALUES") == 0 &&
1045 strcasecmp(prev2_wd, "DEFAULT") != 0)
1046 COMPLETE_WITH_CONST("(");
1049 /* Complete LOCK [TABLE] with a list of tables */
1050 else if (strcasecmp(prev_wd, "LOCK") == 0 ||
1051 (strcasecmp(prev_wd, "TABLE") == 0 &&
1052 strcasecmp(prev2_wd, "LOCK") == 0))
1053 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1055 /* For the following, handle the case of a single table only for now */
1057 /* Complete LOCK [TABLE] <table> with "IN" */
1058 else if ((strcasecmp(prev2_wd, "LOCK") == 0 &&
1059 strcasecmp(prev_wd, "TABLE")) ||
1060 (strcasecmp(prev2_wd, "TABLE") == 0 &&
1061 strcasecmp(prev3_wd, "LOCK") == 0))
1062 COMPLETE_WITH_CONST("IN");
1064 /* Complete LOCK [TABLE] <table> IN with a lock mode */
1065 else if (strcasecmp(prev_wd, "IN") == 0 &&
1066 (strcasecmp(prev3_wd, "LOCK") == 0 ||
1067 (strcasecmp(prev3_wd, "TABLE") == 0 &&
1068 strcasecmp(prev4_wd, "LOCK") == 0)))
1070 char *lock_modes[] = {"ACCESS SHARE MODE",
1071 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1072 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1073 "SHARE ROW EXCLUSIVE MODE",
1074 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1076 COMPLETE_WITH_LIST(lock_modes);
1080 else if (strcasecmp(prev_wd, "NOTIFY") == 0)
1081 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s'");
1084 else if (strcasecmp(prev_wd, "REINDEX") == 0)
1086 char *list_REINDEX[] = {"TABLE", "DATABASE", "INDEX", NULL};
1088 COMPLETE_WITH_LIST(list_REINDEX);
1090 else if (strcasecmp(prev2_wd, "REINDEX") == 0)
1092 if (strcasecmp(prev_wd, "TABLE") == 0)
1093 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1094 else if (strcasecmp(prev_wd, "DATABASE") == 0)
1095 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1096 else if (strcasecmp(prev_wd, "INDEX") == 0)
1097 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1103 /* SET, RESET, SHOW */
1104 /* Complete with a variable name */
1105 else if ((strcasecmp(prev_wd, "SET") == 0 &&
1106 strcasecmp(prev3_wd, "UPDATE") != 0) ||
1107 strcasecmp(prev_wd, "RESET") == 0 ||
1108 strcasecmp(prev_wd, "SHOW") == 0)
1109 COMPLETE_WITH_LIST(pgsql_variables);
1110 /* Complete "SET TRANSACTION" */
1111 else if ((strcasecmp(prev2_wd, "SET") == 0 &&
1112 strcasecmp(prev_wd, "TRANSACTION") == 0) ||
1113 (strcasecmp(prev4_wd, "SESSION") == 0 &&
1114 strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 &&
1115 strcasecmp(prev2_wd, "AS") == 0 &&
1116 strcasecmp(prev_wd, "TRANSACTION") == 0))
1118 char *my_list[] = {"ISOLATION", "READ", NULL};
1120 COMPLETE_WITH_LIST(my_list);
1122 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1123 strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1124 strcasecmp(prev_wd, "ISOLATION") == 0)
1125 COMPLETE_WITH_CONST("LEVEL");
1126 else if ((strcasecmp(prev4_wd, "SET") == 0 ||
1127 strcasecmp(prev4_wd, "AS") == 0) &&
1128 strcasecmp(prev3_wd, "TRANSACTION") == 0 &&
1129 strcasecmp(prev2_wd, "ISOLATION") == 0 &&
1130 strcasecmp(prev_wd, "LEVEL") == 0)
1132 char *my_list[] = {"READ", "SERIALIZABLE", NULL};
1134 COMPLETE_WITH_LIST(my_list);
1136 else if (strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
1137 strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1138 strcasecmp(prev2_wd, "LEVEL") == 0 &&
1139 strcasecmp(prev_wd, "READ") == 0)
1140 COMPLETE_WITH_CONST("COMMITTED");
1141 else if ((strcasecmp(prev3_wd, "SET") == 0 ||
1142 strcasecmp(prev3_wd, "AS") == 0) &&
1143 strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1144 strcasecmp(prev_wd, "READ") == 0)
1146 char *my_list[] = {"ONLY", "WRITE", NULL};
1148 COMPLETE_WITH_LIST(my_list);
1150 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1151 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1152 strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1154 char *constraint_list[] = {"DEFERRED", "IMMEDIATE", NULL};
1156 COMPLETE_WITH_LIST(constraint_list);
1158 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1159 else if (strcasecmp(prev2_wd, "SET") == 0 &&
1160 strcasecmp(prev_wd, "SESSION") == 0)
1162 char *my_list[] = {"AUTHORIZATION",
1163 "CHARACTERISTICS AS TRANSACTION",
1166 COMPLETE_WITH_LIST(my_list);
1168 /* Complete SET SESSION AUTHORIZATION with username */
1169 else if (strcasecmp(prev3_wd, "SET") == 0
1170 && strcasecmp(prev2_wd, "SESSION") == 0
1171 && strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1172 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1173 /* Complete SET <var> with "TO" */
1174 else if (strcasecmp(prev2_wd, "SET") == 0 &&
1175 strcasecmp(prev4_wd, "UPDATE") != 0)
1176 COMPLETE_WITH_CONST("TO");
1177 /* Suggest possible variable values */
1178 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1179 (strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1181 if (strcasecmp(prev2_wd, "DateStyle") == 0)
1183 char *my_list[] = {"'ISO'", "'SQL'", "'Postgres'",
1184 "'European'", "'NonEuropean'", "'German'", "DEFAULT", NULL};
1186 COMPLETE_WITH_LIST(my_list);
1188 else if (strcasecmp(prev2_wd, "GEQO") == 0)
1190 char *my_list[] = {"ON", "OFF", "DEFAULT", NULL};
1192 COMPLETE_WITH_LIST(my_list);
1196 char *my_list[] = {"DEFAULT", NULL};
1198 COMPLETE_WITH_LIST(my_list);
1203 else if (strcasecmp(prev_wd, "TRUNCATE") == 0)
1204 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1207 else if (strcasecmp(prev_wd, "UNLISTEN") == 0)
1208 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s' UNION SELECT '*'::name");
1211 /* If prev. word is UPDATE suggest a list of tables */
1212 else if (strcasecmp(prev_wd, "UPDATE") == 0)
1213 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1214 /* Complete UPDATE <table> with "SET" */
1215 else if (strcasecmp(prev2_wd, "UPDATE") == 0)
1216 COMPLETE_WITH_CONST("SET");
1219 * If the previous word is SET (and it wasn't caught above as the
1220 * _first_ word) the word before it was (hopefully) a table name and
1221 * we'll now make a list of attributes.
1223 else if (strcasecmp(prev_wd, "SET") == 0)
1224 COMPLETE_WITH_ATTR(prev2_wd);
1227 else if (strcasecmp(prev_wd, "VACUUM") == 0)
1228 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class WHERE relkind='r' and substr(relname,1,%d)='%s' and pg_catalog.pg_table_is_visible(oid) UNION SELECT 'FULL'::name UNION SELECT 'ANALYZE'::name");
1229 else if (strcasecmp(prev2_wd, "VACUUM") == 0 &&
1230 (strcasecmp(prev_wd, "FULL") == 0 ||
1231 strcasecmp(prev_wd, "ANALYZE") == 0))
1232 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1235 /* Simple case of the word before the where being the table name */
1236 else if (strcasecmp(prev_wd, "WHERE") == 0)
1237 COMPLETE_WITH_ATTR(prev2_wd);
1240 /* TODO: also include SRF ? */
1241 else if (strcasecmp(prev_wd, "FROM") == 0)
1242 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1245 /* Backslash commands */
1246 /* TODO: \dc \dd \dl */
1247 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1248 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1249 else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1250 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv);
1251 else if (strcmp(prev_wd, "\\da") == 0)
1252 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates);
1253 else if (strcmp(prev_wd, "\\dD") == 0)
1254 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains);
1255 else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1256 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
1257 else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1258 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1259 else if (strcmp(prev_wd, "\\dn") == 0)
1260 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1261 else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1262 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1263 else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1264 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
1265 else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1266 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1267 else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1268 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1269 else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1270 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
1271 else if (strcmp(prev_wd, "\\du") == 0)
1272 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1273 else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1274 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
1275 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1276 COMPLETE_WITH_LIST(sql_commands);
1277 else if (strcmp(prev_wd, "\\pset") == 0)
1279 char *my_list[] = {"format", "border", "expanded",
1280 "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1283 COMPLETE_WITH_LIST(my_list);
1285 else if (strcmp(prev_wd, "\\cd") == 0 ||
1286 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1287 strcmp(prev_wd, "\\g") == 0 ||
1288 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1289 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1290 strcmp(prev_wd, "\\s") == 0 ||
1291 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1293 matches = completion_matches(text, filename_completion_function);
1297 * Finally, we look through the list of "things", such as TABLE, INDEX
1298 * and check if that was the previous word. If so, execute the query
1299 * to get a list of them.
1305 for (i = 0; words_after_create[i].name; i++)
1306 if (strcasecmp(prev_wd, words_after_create[i].name) == 0)
1308 if(words_after_create[i].with_schema == WITH_SCHEMA)
1309 COMPLETE_WITH_SCHEMA_QUERY(words_after_create[i].query);
1311 COMPLETE_WITH_QUERY(words_after_create[i].query);
1318 * If we still don't have anything to match we have to fabricate some
1319 * sort of default list. If we were to just return NULL, readline
1320 * automatically attempts filename completion, and that's usually no
1323 if (matches == NULL)
1325 COMPLETE_WITH_CONST("");
1326 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1327 rl_completion_append_character = '\0';
1338 /* Return our Grand List O' Matches */
1344 /* GENERATOR FUNCTIONS
1346 These functions do all the actual work of completing the input. They get
1347 passed the text so far and the count how many times they have been called so
1348 far with the same text.
1349 If you read the above carefully, you'll see that these don't get called
1350 directly but through the readline interface.
1351 The return value is expected to be the full completion of the text, going
1352 through a list each time, or NULL if there are no more matches. The string
1353 will be free()'d be readline, so you must run it through strdup() or
1354 something of that sort.
1357 /* This one gives you one from a list of things you can put after CREATE or DROP
1361 create_command_generator(const char *text, int state)
1363 static int list_index,
1367 /* If this is the first time for this completion, init some values */
1371 string_length = strlen(text);
1374 /* find something that matches */
1375 while ((name = words_after_create[list_index++].name))
1376 if (strncasecmp(name, text, string_length) == 0)
1377 return xstrdup(name);
1379 /* if nothing matches, return NULL */
1384 /* The following two functions are wrappers for _complete_from_query */
1387 complete_from_query(const char *text, int state)
1389 return _complete_from_query(0, text, state);
1393 complete_from_schema_query(const char *text, int state)
1395 return _complete_from_query(1, text, state);
1399 /* This creates a list of matching things, according to a query pointed to
1400 by completion_charp.
1401 The query can be one of two kinds:
1402 - A simple query which must contain a %d and a %s, which will be replaced
1403 by the string length of the text and the text itself. The query may also
1404 have another %s in it, which will be replaced by the value of
1405 completion_info_charp.
1407 - A schema query used for completion of both schema and relation names;
1408 these are more complex and must contain in the following order:
1409 %d %s %d %s %d %s %s %d %s
1410 where %d is the string length of the text and %s the text itself.
1412 See top of file for examples of both kinds of query.
1416 _complete_from_query(int is_schema_query, const char *text, int state)
1418 static int list_index,
1420 static PGresult *result = NULL;
1421 char query_buffer[BUF_SIZE];
1425 * If this is the first time for this completion, we fetch a list of
1426 * our "things" from the backend.
1431 string_length = strlen(text);
1433 /* Need to have a query */
1434 if (completion_charp == NULL)
1439 if (snprintf(query_buffer, BUF_SIZE, completion_charp, string_length, text, string_length, text, string_length, text, text, string_length, text,string_length,text) == -1)
1441 ERROR_QUERY_TOO_LONG;
1446 if (snprintf(query_buffer, BUF_SIZE, completion_charp, string_length, text, completion_info_charp) == -1)
1448 ERROR_QUERY_TOO_LONG;
1453 result = exec_query(query_buffer);
1456 /* Find something that matches */
1457 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
1458 while (list_index < PQntuples(result) &&
1459 (item = PQgetvalue(result, list_index++, 0)))
1460 if (strncasecmp(text, item, string_length) == 0)
1461 return xstrdup(item);
1463 /* If nothing matches, free the db structure and return null */
1470 /* This function returns in order one of a fixed, NULL pointer terminated list
1471 of strings (if matching). This can be used if there are only a fixed number
1472 SQL words that can appear at certain spot.
1475 complete_from_list(const char *text, int state)
1477 static int string_length,
1480 static bool casesensitive;
1483 /* need to have a list */
1484 #ifdef USE_ASSERT_CHECKING
1485 assert(completion_charpp);
1488 /* Initialization */
1492 string_length = strlen(text);
1493 casesensitive = true;
1497 while ((item = completion_charpp[list_index++]))
1499 /* First pass is case sensitive */
1500 if (casesensitive && strncmp(text, item, string_length) == 0)
1503 return xstrdup(item);
1506 /* Second pass is case insensitive, don't bother counting matches */
1507 if (!casesensitive && strncasecmp(text, item, string_length) == 0)
1508 return xstrdup(item);
1512 * No matches found. If we're not case insensitive already, lets switch
1513 * to being case insensitive and try again
1515 if (casesensitive && matches == 0)
1517 casesensitive = false;
1520 return (complete_from_list(text, state));
1523 /* If no more matches, return null. */
1528 /* This function returns one fixed string the first time even if it doesn't
1529 match what's there, and nothing the second time. This should be used if there
1530 is only one possibility that can appear at a certain spot, so misspellings
1531 will be overwritten.
1532 The string to be passed must be in completion_charp.
1535 complete_from_const(const char *text, int state)
1537 (void) text; /* We don't care about what was entered
1540 #ifdef USE_ASSERT_CHECKING
1541 assert(completion_charp);
1544 return xstrdup(completion_charp);
1551 /* HELPER FUNCTIONS */
1554 /* Execute a query and report any errors. This should be the preferred way of
1555 talking to the database in this file.
1556 Note that the query passed in here must not have a semicolon at the end
1557 because we need to append LIMIT xxx.
1560 exec_query(char *query)
1563 char query_buffer[BUF_SIZE];
1565 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
1567 #ifdef USE_ASSERT_CHECKING
1568 assert(query[strlen(query) - 1] != ';');
1571 if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d;", query, completion_max_records) == -1)
1573 ERROR_QUERY_TOO_LONG;
1577 result = PQexec(pset.db, query);
1579 if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
1582 psql_error("tab completion: %s failed - %s\n",
1583 query, PQresStatus(PQresultStatus(result)));
1594 /* Return the word (space delimited) before point. Set skip > 0 to skip that
1595 many words; e.g. skip=1 finds the word before the previous one.
1598 previous_word(int point, int skip)
1608 /* first we look for a space before the current word */
1609 for (i = point; i >= 0; i--)
1610 if (rl_line_buffer[i] == ' ')
1613 /* now find the first non-space which then constitutes the end */
1615 if (rl_line_buffer[i] != ' ')
1622 * If no end found we return null, because there is no word before
1629 * Otherwise we now look for the start. The start is either the
1630 * last character before any space going backwards from the end,
1631 * or it's simply character 0
1633 for (start = end; start > 0; start--)
1635 if (rl_line_buffer[start] == '"')
1636 inquotes = !inquotes;
1637 if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
1645 s = (char *) malloc(end - start + 2);
1648 psql_error("out of memory\n");
1649 if (!pset.cur_cmd_interactive)
1655 strncpy(s, &rl_line_buffer[start], end - start + 1);
1656 s[end - start + 1] = '\0';
1666 * Surround a string with single quotes. This works for both SQL and
1667 * psql internal. Currently disable because it is reported not to
1668 * cooperate with certain versions of readline.
1671 quote_file_name(char *text, int match_type, char *quote_pointer)
1676 (void) quote_pointer; /* not used */
1678 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
1681 strcpy(s + 1, text);
1682 if (match_type == SINGLE_MATCH)
1683 s[length - 2] = '\'';
1684 s[length - 1] = '\0';
1691 dequote_file_name(char *text, char quote_char)
1697 return xstrdup(text);
1699 length = strlen(text);
1700 s = malloc(length - 2 + 1);
1701 strncpy(s, text +1, length - 2);
1708 #endif /* USE_READLINE */