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.79 2003/06/11 22:13:22 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.
496 "australian_timezones",
498 "client_min_messages",
501 "cpu_index_tuple_cost",
506 "debug_pretty_print",
509 "debug_print_rewritten",
510 "default_statistics_target",
511 "default_transaction_isolation",
512 "default_transaction_read_only",
513 "dynamic_library_path",
514 "effective_cache_size",
523 "explain_pretty_print",
524 "extra_float_digits",
525 "from_collapse_limit",
532 "geqo_selection_bias",
534 "join_collapse_limit",
535 "krb_server_keyfile",
541 "log_executor_stats",
542 "log_min_duration_statement",
543 "log_min_error_statement",
548 "log_statement_stats",
551 "max_files_per_process",
554 "max_locks_per_transaction",
555 "password_encryption",
568 "stats_command_string",
569 "stats_reset_on_server_start",
571 "stats_start_collector",
572 "superuser_reserved_connections",
579 "transform_null_equals",
580 "unix_socket_directory",
582 "unix_socket_permissions",
590 static char *backslash_commands[] = {
591 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
592 "\\d", "\\da", "\\dc", "\\dC", "\\dd", "\\dD", "\\df", "\\di",
593 "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT",
595 "\\e", "\\echo", "\\encoding",
596 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
597 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
598 "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
599 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
602 (void) end; /* not used */
604 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
605 rl_completion_append_character = ' ';
608 /* Clear a few things. */
609 completion_charp = NULL;
610 completion_charpp = NULL;
611 completion_info_charp = NULL;
614 * Scan the input line before our current position for the last four
615 * words. According to those we'll make some smart decisions on what
616 * the user is probably intending to type. TODO: Use strtokx() to do
619 prev_wd = previous_word(start, 0);
620 prev2_wd = previous_word(start, 1);
621 prev3_wd = previous_word(start, 2);
622 prev4_wd = previous_word(start, 3);
624 /* If a backslash command was started, continue */
626 COMPLETE_WITH_LIST(backslash_commands);
628 /* If no previous word, suggest one of the basic sql commands */
630 COMPLETE_WITH_LIST(sql_commands);
632 /* CREATE or DROP but not ALTER TABLE sth DROP */
633 /* complete with something you can create or drop */
634 else if (strcasecmp(prev_wd, "CREATE") == 0 ||
635 (strcasecmp(prev_wd, "DROP") == 0 &&
636 strcasecmp(prev3_wd,"TABLE") != 0 ))
637 matches = completion_matches(text, create_command_generator);
640 /* complete with what you can alter (TABLE, GROUP, USER, ...)
641 * unless we're in ALTER TABLE sth ALTER*/
642 else if (strcasecmp(prev_wd, "ALTER") == 0 &&
643 strcasecmp(prev3_wd, "TABLE") != 0 )
645 char *list_ALTER[] = {"DATABASE", "GROUP", "SCHEMA", "TABLE",
646 "TRIGGER", "USER", NULL};
648 COMPLETE_WITH_LIST(list_ALTER);
651 /* ALTER DATABASE <name> */
652 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
653 strcasecmp(prev2_wd, "DATABASE") == 0)
655 char *list_ALTERDATABASE[] = {"RESET", "SET", NULL};
657 COMPLETE_WITH_LIST(list_ALTERDATABASE);
659 /* ALTER TRIGGER <name>, add ON */
660 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
661 strcasecmp(prev2_wd, "TRIGGER") == 0)
662 COMPLETE_WITH_CONST("ON");
665 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
667 else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
668 strcasecmp(prev3_wd, "TRIGGER") == 0 &&
669 strcasecmp(prev_wd, "ON") == 0)
670 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
673 * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
676 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
677 strcasecmp(prev2_wd, "TABLE") == 0)
679 char *list_ALTER2[] = {"ADD", "ALTER", "DROP", "RENAME",
682 COMPLETE_WITH_LIST(list_ALTER2);
684 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
685 else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
686 (strcasecmp(prev_wd, "ALTER") == 0 ||
687 strcasecmp(prev_wd, "RENAME") == 0))
688 COMPLETE_WITH_ATTR(prev2_wd);
690 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
691 else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
692 strcasecmp(prev_wd, "DROP") == 0)
694 char *list_TABLEDROP[] = {"COLUMN", "CONSTRAINT", NULL};
695 COMPLETE_WITH_LIST(list_TABLEDROP);
697 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
698 else if (strcasecmp(prev4_wd, "TABLE") == 0 &&
699 strcasecmp(prev2_wd, "DROP") == 0 &&
700 strcasecmp(prev_wd, "COLUMN") == 0)
701 COMPLETE_WITH_ATTR(prev3_wd);
703 /* complete ALTER GROUP <foo> with ADD or DROP */
704 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
705 strcasecmp(prev2_wd, "GROUP") == 0)
707 char *list_ALTERGROUP[] = {"ADD", "DROP", NULL};
709 COMPLETE_WITH_LIST(list_ALTERGROUP);
711 /* complete ALTER GROUP <foo> ADD|DROP with USER */
712 else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
713 strcasecmp(prev3_wd, "GROUP") == 0 &&
714 (strcasecmp(prev_wd, "ADD") == 0 ||
715 strcasecmp(prev_wd, "DROP") == 0))
716 COMPLETE_WITH_CONST("USER");
717 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
718 else if (strcasecmp(prev4_wd, "GROUP") == 0 &&
719 (strcasecmp(prev2_wd, "ADD") == 0 ||
720 strcasecmp(prev2_wd, "DROP") == 0) &&
721 strcasecmp(prev_wd, "USER") == 0)
722 COMPLETE_WITH_QUERY(Query_for_list_of_users);
725 /* If the previous word is ANALYZE, produce list of tables. */
726 else if (strcasecmp(prev_wd, "ANALYZE") == 0)
727 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
728 /* If we have ANALYZE <table>, complete with semicolon. */
729 else if (strcasecmp(prev2_wd, "ANALYZE") == 0)
730 COMPLETE_WITH_CONST(";");
733 /* If the previous word is CLUSTER, produce list of indexes. */
734 else if (strcasecmp(prev_wd, "CLUSTER") == 0)
735 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
736 /* If we have CLUSTER <sth>, then add "ON" */
737 else if (strcasecmp(prev2_wd, "CLUSTER") == 0)
738 COMPLETE_WITH_CONST("ON");
741 * If we have CLUSTER <sth> ON, then add the correct tablename as
744 else if (strcasecmp(prev3_wd, "CLUSTER") == 0 &&
745 strcasecmp(prev_wd, "ON") == 0)
747 char query_buffer[BUF_SIZE]; /* Some room to build
750 if (snprintf(query_buffer, BUF_SIZE,
751 "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)",
753 ERROR_QUERY_TOO_LONG;
755 COMPLETE_WITH_QUERY(query_buffer);
759 else if (strcasecmp(prev_wd, "COMMENT") == 0)
760 COMPLETE_WITH_CONST("ON");
761 else if (strcasecmp(prev2_wd, "COMMENT") == 0 &&
762 strcasecmp(prev_wd, "ON") == 0)
764 char *list_COMMENT[] =
765 {"DATABASE", "INDEX", "RULE", "SCHEMA", "SEQUENCE", "TABLE",
766 "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR",
767 "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
769 COMPLETE_WITH_LIST(list_COMMENT);
771 else if (strcasecmp(prev4_wd, "COMMENT") == 0 &&
772 strcasecmp(prev3_wd, "ON") == 0)
773 COMPLETE_WITH_CONST("IS");
778 * If we have COPY [BINARY] (which you'd have to type yourself), offer
779 * list of tables (Also cover the analogous backslash command)
781 else if (strcasecmp(prev_wd, "COPY") == 0 ||
782 strcasecmp(prev_wd, "\\copy") == 0 ||
783 (strcasecmp(prev2_wd, "COPY") == 0 &&
784 strcasecmp(prev_wd, "BINARY") == 0))
785 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
786 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
787 else if (strcasecmp(prev2_wd, "COPY") == 0 ||
788 strcasecmp(prev2_wd, "\\copy") == 0 ||
789 strcasecmp(prev2_wd, "BINARY") == 0)
791 char *list_FROMTO[] = {"FROM", "TO", NULL};
793 COMPLETE_WITH_LIST(list_FROMTO);
797 /* First off we complete CREATE UNIQUE with "INDEX" */
798 else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
799 strcasecmp(prev_wd, "UNIQUE") == 0)
800 COMPLETE_WITH_CONST("INDEX");
801 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
802 else if (strcasecmp(prev2_wd, "INDEX") == 0 &&
803 (strcasecmp(prev3_wd, "CREATE") == 0 ||
804 strcasecmp(prev3_wd, "UNIQUE") == 0))
805 COMPLETE_WITH_CONST("ON");
806 /* Complete ... INDEX <name> ON with a list of tables */
807 else if (strcasecmp(prev3_wd, "INDEX") == 0 &&
808 strcasecmp(prev_wd, "ON") == 0)
809 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
812 * Complete INDEX <name> ON <table> with a list of table columns
813 * (which should really be in parens)
815 else if (strcasecmp(prev4_wd, "INDEX") == 0 &&
816 strcasecmp(prev2_wd, "ON") == 0)
817 COMPLETE_WITH_ATTR(prev_wd);
818 /* same if you put in USING */
819 else if (strcasecmp(prev4_wd, "ON") == 0 &&
820 strcasecmp(prev2_wd, "USING") == 0)
821 COMPLETE_WITH_ATTR(prev3_wd);
822 /* Complete USING with an index method */
823 else if (strcasecmp(prev_wd, "USING") == 0)
825 char *index_mth[] = {"BTREE", "RTREE", "HASH", "GIST", NULL};
827 COMPLETE_WITH_LIST(index_mth);
831 /* Complete "CREATE RULE <sth>" with "AS" */
832 else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
833 strcasecmp(prev2_wd, "RULE") == 0)
834 COMPLETE_WITH_CONST("AS");
835 /* Complete "CREATE RULE <sth> AS with "ON" */
836 else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
837 strcasecmp(prev3_wd, "RULE") == 0 &&
838 strcasecmp(prev_wd, "AS") == 0)
839 COMPLETE_WITH_CONST("ON");
840 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
841 else if (strcasecmp(prev4_wd, "RULE") == 0 &&
842 strcasecmp(prev2_wd, "AS") == 0 &&
843 strcasecmp(prev_wd, "ON") == 0)
845 char *rule_events[] = {"SELECT", "UPDATE", "INSERT",
848 COMPLETE_WITH_LIST(rule_events);
850 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
851 else if (strcasecmp(prev3_wd, "AS") == 0 &&
852 strcasecmp(prev2_wd, "ON") == 0 &&
853 (toupper((unsigned char) prev_wd[4]) == 'T' ||
854 toupper((unsigned char) prev_wd[5]) == 'T'))
855 COMPLETE_WITH_CONST("TO");
856 /* Complete "AS ON <sth> TO" with a table name */
857 else if (strcasecmp(prev4_wd, "AS") == 0 &&
858 strcasecmp(prev3_wd, "ON") == 0 &&
859 strcasecmp(prev_wd, "TO") == 0)
860 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
863 /* Complete CREATE TEMP with "TABLE" */
864 else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
865 strcasecmp(prev_wd, "TEMP") == 0)
866 COMPLETE_WITH_CONST("TABLE");
869 /* is on the agenda . . . */
872 /* Complete "CREATE VIEW <name>" with "AS" */
873 else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
874 strcasecmp(prev2_wd, "VIEW") == 0)
875 COMPLETE_WITH_CONST("AS");
876 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
877 else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
878 strcasecmp(prev3_wd, "VIEW") == 0 &&
879 strcasecmp(prev_wd, "AS") == 0)
880 COMPLETE_WITH_CONST("SELECT");
885 * Complete DELETE with FROM (only if the word before that is not "ON"
886 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
888 else if (strcasecmp(prev_wd, "DELETE") == 0 &&
889 !(strcasecmp(prev2_wd, "ON") == 0 ||
890 strcasecmp(prev2_wd, "GRANT") == 0 ||
891 strcasecmp(prev2_wd, "BEFORE") == 0 ||
892 strcasecmp(prev2_wd, "AFTER") == 0))
893 COMPLETE_WITH_CONST("FROM");
894 /* Complete DELETE FROM with a list of tables */
895 else if (strcasecmp(prev2_wd, "DELETE") == 0 &&
896 strcasecmp(prev_wd, "FROM") == 0)
897 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
898 /* Complete DELETE FROM <table> with "WHERE" (perhaps a safe idea?) */
899 else if (strcasecmp(prev3_wd, "DELETE") == 0 &&
900 strcasecmp(prev2_wd, "FROM") == 0)
901 COMPLETE_WITH_CONST("WHERE");
906 * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with
907 * the list of SQL commands
909 else if (strcasecmp(prev_wd, "EXPLAIN") == 0 ||
910 (strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
911 strcasecmp(prev_wd, "VERBOSE") == 0))
912 COMPLETE_WITH_LIST(sql_commands);
915 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
916 else if (strcasecmp(prev_wd, "FETCH") == 0 ||
917 strcasecmp(prev_wd, "MOVE") == 0)
919 char *list_FETCH1[] = {"FORWARD", "BACKWARD", "RELATIVE", NULL};
921 COMPLETE_WITH_LIST(list_FETCH1);
923 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
924 else if (strcasecmp(prev2_wd, "FETCH") == 0 ||
925 strcasecmp(prev2_wd, "MOVE") == 0)
927 char *list_FETCH2[] = {"ALL", "NEXT", "PRIOR", NULL};
929 COMPLETE_WITH_LIST(list_FETCH2);
933 * Complete FETCH <sth1> <sth2> with "FROM" or "TO". (Is there a
934 * difference? If not, remove one.)
936 else if (strcasecmp(prev3_wd, "FETCH") == 0 ||
937 strcasecmp(prev3_wd, "MOVE") == 0)
939 char *list_FROMTO[] = {"FROM", "TO", NULL};
941 COMPLETE_WITH_LIST(list_FROMTO);
945 /* Complete GRANT/REVOKE with a list of privileges */
946 else if (strcasecmp(prev_wd, "GRANT") == 0 ||
947 strcasecmp(prev_wd, "REVOKE") == 0)
949 char *list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES", "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
951 COMPLETE_WITH_LIST(list_privileg);
953 /* Complete GRANT/REVOKE <sth> with "ON" */
954 else if (strcasecmp(prev2_wd, "GRANT") == 0 ||
955 strcasecmp(prev2_wd, "REVOKE") == 0)
956 COMPLETE_WITH_CONST("ON");
959 * Complete GRANT/REVOKE <sth> ON with a list of tables, views,
960 * sequences, and indexes
962 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result
963 * via UNION; seems to work intuitively
965 * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
966 * here will only work if the privilege list contains exactly one privilege
968 else if ((strcasecmp(prev3_wd, "GRANT") == 0 ||
969 strcasecmp(prev3_wd, "REVOKE") == 0) &&
970 strcasecmp(prev_wd, "ON") == 0)
971 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
972 " WHERE relkind in ('r','S','v') "
973 " AND substr(relname,1,%d)='%s' "
974 " AND pg_catalog.pg_table_is_visible(c.oid) "
975 " AND relnamespace = n.oid "
976 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
978 "SELECT 'DATABASE' AS relname "
980 "SELECT 'FUNCTION' AS relname "
982 "SELECT 'LANGUAGE' AS relname "
984 "SELECT 'SCHEMA' AS relname ");
986 /* Complete "GRANT/REVOKE * ON * " with "TO" */
987 else if ((strcasecmp(prev4_wd, "GRANT") == 0 ||
988 strcasecmp(prev4_wd, "REVOKE") == 0) &&
989 strcasecmp(prev2_wd, "ON") == 0)
991 if(strcasecmp(prev_wd, "DATABASE") == 0)
992 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
993 else if(strcasecmp(prev_wd, "FUNCTION") == 0)
994 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
995 else if(strcasecmp(prev_wd, "LANGUAGE") == 0)
996 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
997 else if(strcasecmp(prev_wd, "SCHEMA") == 0)
998 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1000 COMPLETE_WITH_CONST("TO");
1004 * TODO: to complete with user name we need prev5_wd -- wait for a
1005 * more general solution there
1006 * same for GRANT <sth> ON { DATABASE | FUNCTION | LANGUAGE | SCHEMA } xxx TO
1010 /* Complete INSERT with "INTO" */
1011 else if (strcasecmp(prev_wd, "INSERT") == 0)
1012 COMPLETE_WITH_CONST("INTO");
1013 /* Complete INSERT INTO with table names */
1014 else if (strcasecmp(prev2_wd, "INSERT") == 0 &&
1015 strcasecmp(prev_wd, "INTO") == 0)
1016 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1017 /* Complete "INSERT INTO <table> (" with attribute names */
1018 else if (rl_line_buffer[start - 1] == '(' &&
1019 strcasecmp(prev3_wd, "INSERT") == 0 &&
1020 strcasecmp(prev2_wd, "INTO") == 0)
1021 COMPLETE_WITH_ATTR(prev_wd);
1024 * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1027 else if (strcasecmp(prev3_wd, "INSERT") == 0 &&
1028 strcasecmp(prev2_wd, "INTO") == 0)
1030 char *list_INSERT[] = {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1032 COMPLETE_WITH_LIST(list_INSERT);
1034 /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1035 else if (strcasecmp(prev4_wd, "INSERT") == 0 &&
1036 strcasecmp(prev3_wd, "INTO") == 0 &&
1037 prev_wd[strlen(prev_wd) - 1] == ')')
1039 char *list_INSERT[] = {"SELECT", "VALUES", NULL};
1041 COMPLETE_WITH_LIST(list_INSERT);
1044 /* Insert an open parenthesis after "VALUES" */
1045 else if (strcasecmp(prev_wd, "VALUES") == 0 &&
1046 strcasecmp(prev2_wd, "DEFAULT") != 0)
1047 COMPLETE_WITH_CONST("(");
1050 /* Complete LOCK [TABLE] with a list of tables */
1051 else if (strcasecmp(prev_wd, "LOCK") == 0 ||
1052 (strcasecmp(prev_wd, "TABLE") == 0 &&
1053 strcasecmp(prev2_wd, "LOCK") == 0))
1054 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1056 /* For the following, handle the case of a single table only for now */
1058 /* Complete LOCK [TABLE] <table> with "IN" */
1059 else if ((strcasecmp(prev2_wd, "LOCK") == 0 &&
1060 strcasecmp(prev_wd, "TABLE")) ||
1061 (strcasecmp(prev2_wd, "TABLE") == 0 &&
1062 strcasecmp(prev3_wd, "LOCK") == 0))
1063 COMPLETE_WITH_CONST("IN");
1065 /* Complete LOCK [TABLE] <table> IN with a lock mode */
1066 else if (strcasecmp(prev_wd, "IN") == 0 &&
1067 (strcasecmp(prev3_wd, "LOCK") == 0 ||
1068 (strcasecmp(prev3_wd, "TABLE") == 0 &&
1069 strcasecmp(prev4_wd, "LOCK") == 0)))
1071 char *lock_modes[] = {"ACCESS SHARE MODE",
1072 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1073 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1074 "SHARE ROW EXCLUSIVE MODE",
1075 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1077 COMPLETE_WITH_LIST(lock_modes);
1081 else if (strcasecmp(prev_wd, "NOTIFY") == 0)
1082 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s'");
1085 else if (strcasecmp(prev_wd, "REINDEX") == 0)
1087 char *list_REINDEX[] = {"TABLE", "DATABASE", "INDEX", NULL};
1089 COMPLETE_WITH_LIST(list_REINDEX);
1091 else if (strcasecmp(prev2_wd, "REINDEX") == 0)
1093 if (strcasecmp(prev_wd, "TABLE") == 0)
1094 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1095 else if (strcasecmp(prev_wd, "DATABASE") == 0)
1096 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1097 else if (strcasecmp(prev_wd, "INDEX") == 0)
1098 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1104 /* SET, RESET, SHOW */
1105 /* Complete with a variable name */
1106 else if ((strcasecmp(prev_wd, "SET") == 0 &&
1107 strcasecmp(prev3_wd, "UPDATE") != 0) ||
1108 strcasecmp(prev_wd, "RESET") == 0 ||
1109 strcasecmp(prev_wd, "SHOW") == 0)
1110 COMPLETE_WITH_LIST(pgsql_variables);
1111 /* Complete "SET TRANSACTION" */
1112 else if ((strcasecmp(prev2_wd, "SET") == 0 &&
1113 strcasecmp(prev_wd, "TRANSACTION") == 0) ||
1114 (strcasecmp(prev4_wd, "SESSION") == 0 &&
1115 strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 &&
1116 strcasecmp(prev2_wd, "AS") == 0 &&
1117 strcasecmp(prev_wd, "TRANSACTION") == 0))
1119 char *my_list[] = {"ISOLATION", "READ", NULL};
1121 COMPLETE_WITH_LIST(my_list);
1123 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1124 strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1125 strcasecmp(prev_wd, "ISOLATION") == 0)
1126 COMPLETE_WITH_CONST("LEVEL");
1127 else if ((strcasecmp(prev4_wd, "SET") == 0 ||
1128 strcasecmp(prev4_wd, "AS") == 0) &&
1129 strcasecmp(prev3_wd, "TRANSACTION") == 0 &&
1130 strcasecmp(prev2_wd, "ISOLATION") == 0 &&
1131 strcasecmp(prev_wd, "LEVEL") == 0)
1133 char *my_list[] = {"READ", "SERIALIZABLE", NULL};
1135 COMPLETE_WITH_LIST(my_list);
1137 else if (strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
1138 strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1139 strcasecmp(prev2_wd, "LEVEL") == 0 &&
1140 strcasecmp(prev_wd, "READ") == 0)
1141 COMPLETE_WITH_CONST("COMMITTED");
1142 else if ((strcasecmp(prev3_wd, "SET") == 0 ||
1143 strcasecmp(prev3_wd, "AS") == 0) &&
1144 strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1145 strcasecmp(prev_wd, "READ") == 0)
1147 char *my_list[] = {"ONLY", "WRITE", NULL};
1149 COMPLETE_WITH_LIST(my_list);
1151 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1152 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1153 strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1155 char *constraint_list[] = {"DEFERRED", "IMMEDIATE", NULL};
1157 COMPLETE_WITH_LIST(constraint_list);
1159 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1160 else if (strcasecmp(prev2_wd, "SET") == 0 &&
1161 strcasecmp(prev_wd, "SESSION") == 0)
1163 char *my_list[] = {"AUTHORIZATION",
1164 "CHARACTERISTICS AS TRANSACTION",
1167 COMPLETE_WITH_LIST(my_list);
1169 /* Complete SET SESSION AUTHORIZATION with username */
1170 else if (strcasecmp(prev3_wd, "SET") == 0
1171 && strcasecmp(prev2_wd, "SESSION") == 0
1172 && strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1173 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1174 /* Complete SET <var> with "TO" */
1175 else if (strcasecmp(prev2_wd, "SET") == 0 &&
1176 strcasecmp(prev4_wd, "UPDATE") != 0)
1177 COMPLETE_WITH_CONST("TO");
1178 /* Suggest possible variable values */
1179 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1180 (strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1182 if (strcasecmp(prev2_wd, "DateStyle") == 0)
1184 char *my_list[] = {"'ISO'", "'SQL'", "'Postgres'",
1185 "'European'", "'NonEuropean'", "'German'", "DEFAULT", NULL};
1187 COMPLETE_WITH_LIST(my_list);
1189 else if (strcasecmp(prev2_wd, "GEQO") == 0)
1191 char *my_list[] = {"ON", "OFF", "DEFAULT", NULL};
1193 COMPLETE_WITH_LIST(my_list);
1197 char *my_list[] = {"DEFAULT", NULL};
1199 COMPLETE_WITH_LIST(my_list);
1204 else if (strcasecmp(prev_wd, "TRUNCATE") == 0)
1205 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1208 else if (strcasecmp(prev_wd, "UNLISTEN") == 0)
1209 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s' UNION SELECT '*'::name");
1212 /* If prev. word is UPDATE suggest a list of tables */
1213 else if (strcasecmp(prev_wd, "UPDATE") == 0)
1214 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1215 /* Complete UPDATE <table> with "SET" */
1216 else if (strcasecmp(prev2_wd, "UPDATE") == 0)
1217 COMPLETE_WITH_CONST("SET");
1220 * If the previous word is SET (and it wasn't caught above as the
1221 * _first_ word) the word before it was (hopefully) a table name and
1222 * we'll now make a list of attributes.
1224 else if (strcasecmp(prev_wd, "SET") == 0)
1225 COMPLETE_WITH_ATTR(prev2_wd);
1228 else if (strcasecmp(prev_wd, "VACUUM") == 0)
1229 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");
1230 else if (strcasecmp(prev2_wd, "VACUUM") == 0 &&
1231 (strcasecmp(prev_wd, "FULL") == 0 ||
1232 strcasecmp(prev_wd, "ANALYZE") == 0))
1233 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1236 /* Simple case of the word before the where being the table name */
1237 else if (strcasecmp(prev_wd, "WHERE") == 0)
1238 COMPLETE_WITH_ATTR(prev2_wd);
1241 /* TODO: also include SRF ? */
1242 else if (strcasecmp(prev_wd, "FROM") == 0)
1243 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1246 /* Backslash commands */
1247 /* TODO: \dc \dd \dl */
1248 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1249 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1250 else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1251 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv);
1252 else if (strcmp(prev_wd, "\\da") == 0)
1253 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates);
1254 else if (strcmp(prev_wd, "\\dD") == 0)
1255 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains);
1256 else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1257 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
1258 else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1259 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1260 else if (strcmp(prev_wd, "\\dn") == 0)
1261 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1262 else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1263 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1264 else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1265 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
1266 else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1267 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1268 else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1269 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1270 else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1271 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
1272 else if (strcmp(prev_wd, "\\du") == 0)
1273 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1274 else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1275 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
1276 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1277 COMPLETE_WITH_LIST(sql_commands);
1278 else if (strcmp(prev_wd, "\\pset") == 0)
1280 char *my_list[] = {"format", "border", "expanded",
1281 "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1284 COMPLETE_WITH_LIST(my_list);
1286 else if (strcmp(prev_wd, "\\cd") == 0 ||
1287 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1288 strcmp(prev_wd, "\\g") == 0 ||
1289 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1290 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1291 strcmp(prev_wd, "\\s") == 0 ||
1292 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1294 matches = completion_matches(text, filename_completion_function);
1298 * Finally, we look through the list of "things", such as TABLE, INDEX
1299 * and check if that was the previous word. If so, execute the query
1300 * to get a list of them.
1306 for (i = 0; words_after_create[i].name; i++)
1307 if (strcasecmp(prev_wd, words_after_create[i].name) == 0)
1309 if(words_after_create[i].with_schema == WITH_SCHEMA)
1310 COMPLETE_WITH_SCHEMA_QUERY(words_after_create[i].query);
1312 COMPLETE_WITH_QUERY(words_after_create[i].query);
1319 * If we still don't have anything to match we have to fabricate some
1320 * sort of default list. If we were to just return NULL, readline
1321 * automatically attempts filename completion, and that's usually no
1324 if (matches == NULL)
1326 COMPLETE_WITH_CONST("");
1327 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1328 rl_completion_append_character = '\0';
1339 /* Return our Grand List O' Matches */
1345 /* GENERATOR FUNCTIONS
1347 These functions do all the actual work of completing the input. They get
1348 passed the text so far and the count how many times they have been called so
1349 far with the same text.
1350 If you read the above carefully, you'll see that these don't get called
1351 directly but through the readline interface.
1352 The return value is expected to be the full completion of the text, going
1353 through a list each time, or NULL if there are no more matches. The string
1354 will be free()'d be readline, so you must run it through strdup() or
1355 something of that sort.
1358 /* This one gives you one from a list of things you can put after CREATE or DROP
1362 create_command_generator(const char *text, int state)
1364 static int list_index,
1368 /* If this is the first time for this completion, init some values */
1372 string_length = strlen(text);
1375 /* find something that matches */
1376 while ((name = words_after_create[list_index++].name))
1377 if (strncasecmp(name, text, string_length) == 0)
1378 return xstrdup(name);
1380 /* if nothing matches, return NULL */
1385 /* The following two functions are wrappers for _complete_from_query */
1388 complete_from_query(const char *text, int state)
1390 return _complete_from_query(0, text, state);
1394 complete_from_schema_query(const char *text, int state)
1396 return _complete_from_query(1, text, state);
1400 /* This creates a list of matching things, according to a query pointed to
1401 by completion_charp.
1402 The query can be one of two kinds:
1403 - A simple query which must contain a %d and a %s, which will be replaced
1404 by the string length of the text and the text itself. The query may also
1405 have another %s in it, which will be replaced by the value of
1406 completion_info_charp.
1408 - A schema query used for completion of both schema and relation names;
1409 these are more complex and must contain in the following order:
1410 %d %s %d %s %d %s %s %d %s
1411 where %d is the string length of the text and %s the text itself.
1413 See top of file for examples of both kinds of query.
1417 _complete_from_query(int is_schema_query, const char *text, int state)
1419 static int list_index,
1421 static PGresult *result = NULL;
1422 char query_buffer[BUF_SIZE];
1426 * If this is the first time for this completion, we fetch a list of
1427 * our "things" from the backend.
1432 string_length = strlen(text);
1434 /* Need to have a query */
1435 if (completion_charp == NULL)
1440 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)
1442 ERROR_QUERY_TOO_LONG;
1447 if (snprintf(query_buffer, BUF_SIZE, completion_charp, string_length, text, completion_info_charp) == -1)
1449 ERROR_QUERY_TOO_LONG;
1454 result = exec_query(query_buffer);
1457 /* Find something that matches */
1458 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
1459 while (list_index < PQntuples(result) &&
1460 (item = PQgetvalue(result, list_index++, 0)))
1461 if (strncasecmp(text, item, string_length) == 0)
1462 return xstrdup(item);
1464 /* If nothing matches, free the db structure and return null */
1471 /* This function returns in order one of a fixed, NULL pointer terminated list
1472 of strings (if matching). This can be used if there are only a fixed number
1473 SQL words that can appear at certain spot.
1476 complete_from_list(const char *text, int state)
1478 static int string_length,
1481 static bool casesensitive;
1484 /* need to have a list */
1485 #ifdef USE_ASSERT_CHECKING
1486 assert(completion_charpp);
1489 /* Initialization */
1493 string_length = strlen(text);
1494 casesensitive = true;
1498 while ((item = completion_charpp[list_index++]))
1500 /* First pass is case sensitive */
1501 if (casesensitive && strncmp(text, item, string_length) == 0)
1504 return xstrdup(item);
1507 /* Second pass is case insensitive, don't bother counting matches */
1508 if (!casesensitive && strncasecmp(text, item, string_length) == 0)
1509 return xstrdup(item);
1513 * No matches found. If we're not case insensitive already, lets switch
1514 * to being case insensitive and try again
1516 if (casesensitive && matches == 0)
1518 casesensitive = false;
1521 return (complete_from_list(text, state));
1524 /* If no more matches, return null. */
1529 /* This function returns one fixed string the first time even if it doesn't
1530 match what's there, and nothing the second time. This should be used if there
1531 is only one possibility that can appear at a certain spot, so misspellings
1532 will be overwritten.
1533 The string to be passed must be in completion_charp.
1536 complete_from_const(const char *text, int state)
1538 (void) text; /* We don't care about what was entered
1541 #ifdef USE_ASSERT_CHECKING
1542 assert(completion_charp);
1545 return xstrdup(completion_charp);
1552 /* HELPER FUNCTIONS */
1555 /* Execute a query and report any errors. This should be the preferred way of
1556 talking to the database in this file.
1557 Note that the query passed in here must not have a semicolon at the end
1558 because we need to append LIMIT xxx.
1561 exec_query(char *query)
1564 char query_buffer[BUF_SIZE];
1566 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
1568 #ifdef USE_ASSERT_CHECKING
1569 assert(query[strlen(query) - 1] != ';');
1572 if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d;", query, completion_max_records) == -1)
1574 ERROR_QUERY_TOO_LONG;
1578 result = PQexec(pset.db, query);
1580 if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
1583 psql_error("tab completion: %s failed - %s\n",
1584 query, PQresStatus(PQresultStatus(result)));
1595 /* Return the word (space delimited) before point. Set skip > 0 to skip that
1596 many words; e.g. skip=1 finds the word before the previous one.
1599 previous_word(int point, int skip)
1609 /* first we look for a space before the current word */
1610 for (i = point; i >= 0; i--)
1611 if (rl_line_buffer[i] == ' ')
1614 /* now find the first non-space which then constitutes the end */
1616 if (rl_line_buffer[i] != ' ')
1623 * If no end found we return null, because there is no word before
1630 * Otherwise we now look for the start. The start is either the
1631 * last character before any space going backwards from the end,
1632 * or it's simply character 0
1634 for (start = end; start > 0; start--)
1636 if (rl_line_buffer[start] == '"')
1637 inquotes = !inquotes;
1638 if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
1646 s = (char *) malloc(end - start + 2);
1649 psql_error("out of memory\n");
1650 if (!pset.cur_cmd_interactive)
1656 strncpy(s, &rl_line_buffer[start], end - start + 1);
1657 s[end - start + 1] = '\0';
1667 * Surround a string with single quotes. This works for both SQL and
1668 * psql internal. Currently disable because it is reported not to
1669 * cooperate with certain versions of readline.
1672 quote_file_name(char *text, int match_type, char *quote_pointer)
1677 (void) quote_pointer; /* not used */
1679 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
1682 strcpy(s + 1, text);
1683 if (match_type == SINGLE_MATCH)
1684 s[length - 2] = '\'';
1685 s[length - 1] = '\0';
1692 dequote_file_name(char *text, char quote_char)
1698 return xstrdup(text);
1700 length = strlen(text);
1701 s = malloc(length - 2 + 1);
1702 strncpy(s, text +1, length - 2);
1709 #endif /* USE_READLINE */