2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2003, PostgreSQL Global Development Group
6 * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.89 2003/10/17 11:52:06 petere Exp $
9 /*----------------------------------------------------------------------
10 * This file implements a somewhat more sophisticated readline "TAB
11 * completion" in psql. It is not intended to be AI, to replace
12 * learning SQL, or to relieve you from thinking about what you're
13 * doing. Also it does not always give you all the syntactically legal
14 * completions, only those that are the most common or the ones that
15 * the programmer felt most like implementing.
17 * CAVEAT: Tab completion causes queries to be sent to the backend.
18 * The number of tuples returned gets limited, in most default
19 * installations to 1000, but if you still don't like this prospect,
20 * you can turn off tab completion in your ~/.inputrc (or else
21 * ${INPUTRC}) file so:
24 * set disable-completion on
27 * See `man 3 readline' or `info readline' for the full details. Also,
32 * - If you split your queries across lines, this whole thing gets
33 * confused. (To fix this, one would have to read psql's query
34 * buffer rather than readline's line buffer, which would require
35 * some major revisions of things.)
37 * - Table or attribute names with spaces in it may confuse it.
39 * - Quotes, parenthesis, and other funny characters are not handled
40 * all that gracefully.
41 *----------------------------------------------------------------------
44 #include "postgres_fe.h"
45 #include "tab-complete.h"
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);
89 static char *previous_word(int point, int skip);
92 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
93 static char *dequote_file_name(char *text, char quote_char);
96 /* These variables are used to pass information into the completion functions.
97 Realizing that this is the cardinal sin of programming, I don't see a better
99 static char *completion_charp; /* if you need to pass a string */
100 static char **completion_charpp; /* if you need to pass a list of strings */
101 static char *completion_info_charp; /* if you need to pass another
104 /* Store how many records from a database query we want to return at most
105 (implemented via SELECT ... LIMIT xx). */
106 static int completion_max_records;
109 /* Initialize the readline library for our purposes. */
111 initialize_readline(void)
113 rl_readline_name = pset.progname;
114 rl_attempted_completion_function = (void *) psql_completion;
116 rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
118 completion_max_records = 1000;
121 * There is a variable rl_completion_query_items for this but
122 * apparently it's not defined everywhere.
128 * Queries to get lists of names of various kinds of things, possibly
129 * restricted to names matching a partially entered name. In these queries,
130 * %s will be replaced by the text entered so far (suitably escaped to
131 * become a SQL literal string). %d will be replaced by the length of the
132 * string (in unescaped form). Beware that the allowed sequences of %s and
133 * %d are determined by _complete_from_query().
136 #define Query_for_list_of_aggregates \
137 " SELECT pg_catalog.quote_ident(proname) " \
138 " FROM pg_catalog.pg_proc p" \
140 " AND substring(pg_catalog.quote_ident(proname),1,%d)='%s'" \
141 " AND pg_catalog.pg_function_is_visible(p.oid) "\
143 " SELECT pg_catalog.quote_ident(nspname) || '.'" \
144 " FROM pg_catalog.pg_namespace" \
145 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s'" \
147 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname)" \
148 " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n" \
150 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname),1,%d)='%s'" \
151 " AND pronamespace = n.oid" \
152 " AND ('%s' ~ '\\\\.' "\
154 " FROM pg_catalog.pg_namespace "\
155 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
156 " HAVING COUNT(nspname)=1))"
158 #define Query_for_list_of_attributes \
159 "SELECT pg_catalog.quote_ident(attname) "\
160 " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
161 " WHERE c.oid = a.attrelid "\
162 " AND a.attnum > 0 "\
163 " AND NOT a.attisdropped "\
164 " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
165 " AND pg_catalog.quote_ident(relname)='%s' "\
166 " AND pg_catalog.pg_table_is_visible(c.oid)"
168 #define Query_for_list_of_databases \
169 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
170 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
172 #define Query_for_list_of_datatypes \
173 " SELECT pg_catalog.format_type(t.oid, NULL) "\
174 " FROM pg_catalog.pg_type t "\
175 " WHERE (t.typrelid = 0 "\
176 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "\
177 " AND t.typname !~ '^_' "\
178 " AND substring(pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
179 " AND pg_catalog.pg_type_is_visible(t.oid) "\
181 " SELECT pg_catalog.quote_ident(nspname) || '.'"\
182 " FROM pg_catalog.pg_namespace "\
183 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
185 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.format_type(t.oid, NULL)"\
186 " FROM pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
187 " WHERE(t.typrelid = 0 "\
188 " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "\
189 " AND t.typname !~ '^_' "\
190 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
191 " AND typnamespace = n.oid "\
192 " AND ('%s' ~ '\\\\.' "\
194 " FROM pg_catalog.pg_namespace "\
195 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
196 " HAVING COUNT(nspname)=1))"
198 #define Query_for_list_of_domains \
199 " SELECT pg_catalog.quote_ident(typname) "\
200 " FROM pg_catalog.pg_type t "\
201 " WHERE typtype = 'd' "\
202 " AND substring(pg_catalog.quote_ident(typname),1,%d)='%s' "\
203 " AND pg_catalog.pg_type_is_visible(t.oid) "\
205 " SELECT pg_catalog.quote_ident(nspname) || '.'"\
206 " FROM pg_catalog.pg_namespace "\
207 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
209 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(typname)"\
210 " FROM pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
211 " WHERE typtype = 'd' "\
212 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(typname),1,%d)='%s' "\
213 " AND typnamespace = n.oid "\
214 " AND ('%s' ~ '\\\\.' "\
216 " FROM pg_catalog.pg_namespace "\
217 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
218 " HAVING COUNT(nspname)=1))"
220 #define Query_for_list_of_encodings \
221 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
222 " FROM pg_catalog.pg_conversion "\
223 " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
225 #define Query_for_list_of_functions \
226 " SELECT pg_catalog.quote_ident(proname) "\
227 " FROM pg_catalog.pg_proc p "\
228 " WHERE substring(pg_catalog.quote_ident(proname),1,%d)='%s'"\
229 " AND pg_catalog.pg_function_is_visible(p.oid) "\
231 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
232 " FROM pg_catalog.pg_namespace "\
233 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
235 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname) "\
236 " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
237 " WHERE substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname),1,%d)='%s' "\
238 " AND pronamespace = n.oid "\
239 " AND ('%s' ~ '\\\\.' "\
241 " FROM pg_catalog.pg_namespace "\
242 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
243 " HAVING COUNT(nspname)=1))"
245 #define Query_for_list_of_indexes \
246 " SELECT pg_catalog.quote_ident(relname) "\
247 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
248 " WHERE relkind='i' "\
249 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
250 " AND pg_catalog.pg_table_is_visible(c.oid) "\
251 " AND relnamespace = n.oid "\
252 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
254 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
255 " FROM pg_catalog.pg_namespace "\
256 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
258 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
259 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
260 " WHERE relkind='i' "\
261 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
262 " AND relnamespace = n.oid "\
263 " AND ('%s' ~ '\\\\.' "\
265 " FROM pg_catalog.pg_namespace "\
266 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
267 " HAVING COUNT(nspname)=1))"
270 #define Query_for_list_of_languages \
271 "SELECT pg_catalog.quote_ident(lanname) "\
272 " FROM pg_language "\
273 " WHERE lanname != 'internal' "\
274 " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
276 #define Query_for_list_of_schemas \
277 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
278 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
280 #define Query_for_list_of_sequences \
281 " SELECT pg_catalog.quote_ident(relname) "\
282 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
283 " WHERE relkind='S' "\
284 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
285 " AND pg_catalog.pg_table_is_visible(c.oid) "\
286 " AND relnamespace = n.oid "\
287 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
289 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
290 " FROM pg_catalog.pg_namespace "\
291 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
293 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
294 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
295 " WHERE relkind='S' "\
296 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
297 " AND relnamespace = n.oid "\
298 " AND ('%s' ~ '\\\\.' "\
300 " FROM pg_catalog.pg_namespace "\
301 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
302 " HAVING COUNT(nspname)=1))"
304 #define Query_for_list_of_system_relations \
305 "SELECT pg_catalog.quote_ident(relname) "\
306 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
307 " WHERE (c.relkind='r' OR c.relkind='v' OR c.relkind='s' OR c.relkind='S') "\
308 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
309 " AND pg_catalog.pg_table_is_visible(c.oid)"\
310 " AND relnamespace = n.oid "\
311 " AND n.nspname = 'pg_catalog'"
313 #define Query_for_list_of_tables \
314 " SELECT pg_catalog.quote_ident(relname) "\
315 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
316 " WHERE relkind='r' "\
317 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
318 " AND pg_catalog.pg_table_is_visible(c.oid) "\
319 " AND relnamespace = n.oid "\
320 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
322 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
323 " FROM pg_catalog.pg_namespace "\
324 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
326 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
327 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
328 " WHERE relkind='r' "\
329 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
330 " AND relnamespace = n.oid "\
331 " AND ('%s' ~ '\\\\.' "\
333 " FROM pg_catalog.pg_namespace "\
334 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
335 " HAVING COUNT(nspname)=1))"
337 #define Query_for_list_of_tisv \
338 " SELECT pg_catalog.quote_ident(relname) "\
339 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
340 " WHERE (relkind='r' OR relkind='i' OR relkind='S' OR relkind='v') "\
341 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
342 " AND pg_catalog.pg_table_is_visible(c.oid) "\
343 " AND relnamespace = n.oid "\
344 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
346 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
347 " FROM pg_catalog.pg_namespace "\
348 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
350 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
351 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
352 " WHERE (relkind='r' OR relkind='i' OR relkind='S' OR relkind='v') "\
353 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
354 " AND relnamespace = n.oid "\
355 " AND ('%s' ~ '\\\\.' "\
357 " FROM pg_catalog.pg_namespace "\
358 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
359 " HAVING COUNT(nspname)=1))"
361 #define Query_for_list_of_tsv \
362 " SELECT pg_catalog.quote_ident(relname) "\
363 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
364 " WHERE (relkind='r' OR relkind='S' OR relkind='v') "\
365 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
366 " AND pg_catalog.pg_table_is_visible(c.oid) "\
367 " AND relnamespace = n.oid "\
368 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
370 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
371 " FROM pg_catalog.pg_namespace "\
372 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
374 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
375 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
376 " WHERE (relkind='r' OR relkind='S' OR relkind='v') "\
377 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
378 " AND relnamespace = n.oid "\
379 " AND ('%s' ~ '\\\\.' "\
381 " FROM pg_catalog.pg_namespace "\
382 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
383 " HAVING COUNT(nspname)=1))"
385 #define Query_for_list_of_views \
386 " SELECT pg_catalog.quote_ident(relname) "\
387 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
388 " WHERE relkind='v'"\
389 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
390 " AND pg_catalog.pg_table_is_visible(c.oid) "\
391 " AND relnamespace = n.oid "\
392 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
394 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
395 " FROM pg_catalog.pg_namespace "\
396 " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
398 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
399 " FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
400 " WHERE relkind='v' "\
401 " AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
402 " AND relnamespace = n.oid "\
403 " AND ('%s' ~ '\\\\.' "\
405 " FROM pg_catalog.pg_namespace "\
406 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
407 " HAVING COUNT(nspname)=1))"
409 #define Query_for_list_of_users \
410 " SELECT pg_catalog.quote_ident(usename) "\
411 " FROM pg_catalog.pg_user "\
412 " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
414 /* the silly-looking length condition is just to eat up the current word */
415 #define Query_for_table_owning_index \
416 "SELECT pg_catalog.quote_ident(c1.relname) "\
417 " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
418 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
419 " and (%d = length('%s'))"\
420 " and pg_catalog.quote_ident(c2.relname)='%s'"\
421 " and pg_catalog.pg_table_is_visible(c2.oid)"
423 /* This is a list of all "things" in Pgsql, which can show up after CREATE or
424 DROP; and there is also a query to get a list of them.
427 #define WITH_SCHEMA 1
437 pgsql_thing_t words_after_create[] = {
438 {"AGGREGATE", WITH_SCHEMA, Query_for_list_of_aggregates},
439 {"CAST", NO_SCHEMA, NULL}, /* Casts have complex structures for
440 * namees, so skip it */
441 {"CONVERSION", NO_SCHEMA, "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
442 {"DATABASE", NO_SCHEMA, Query_for_list_of_databases},
443 {"DOMAIN", WITH_SCHEMA, Query_for_list_of_domains},
444 {"FUNCTION", WITH_SCHEMA, Query_for_list_of_functions},
445 {"GROUP", NO_SCHEMA, "SELECT pg_catalog.quote_ident(groname) FROM pg_catalog.pg_group WHERE substring(pg_catalog.quote_ident(groname),1,%d)='%s'"},
446 {"LANGUAGE", NO_SCHEMA, Query_for_list_of_languages},
447 {"INDEX", WITH_SCHEMA, Query_for_list_of_indexes},
448 {"OPERATOR", NO_SCHEMA, NULL}, /* Querying for this is probably
449 * not such a good idea. */
450 {"RULE", NO_SCHEMA, "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
451 {"SCHEMA", NO_SCHEMA, Query_for_list_of_schemas},
452 {"SEQUENCE", WITH_SCHEMA, Query_for_list_of_sequences},
453 {"TABLE", WITH_SCHEMA, Query_for_list_of_tables},
454 {"TEMP", NO_SCHEMA, NULL}, /* for CREATE TEMP TABLE ... */
455 {"TRIGGER", NO_SCHEMA, "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
456 {"TYPE", WITH_SCHEMA, Query_for_list_of_datatypes},
457 {"UNIQUE", NO_SCHEMA, NULL}, /* for CREATE UNIQUE INDEX ... */
458 {"USER", NO_SCHEMA, Query_for_list_of_users},
459 {"VIEW", WITH_SCHEMA, Query_for_list_of_views},
460 {NULL, NO_SCHEMA, NULL} /* end of list */
464 /* A couple of macros to ease typing. You can use these to complete the given
466 1) The results from a query you pass it. (Perhaps one of those above?)
467 2) The results from a schema query you pass it.
468 3) The items from a null-pointer-terminated list.
470 5) The list of attributes to the given table.
472 #define COMPLETE_WITH_QUERY(query) \
473 do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
474 #define COMPLETE_WITH_SCHEMA_QUERY(query) \
475 do { completion_charp = query; matches = completion_matches(text, complete_from_schema_query); } while(0)
476 #define COMPLETE_WITH_LIST(list) \
477 do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
478 #define COMPLETE_WITH_CONST(string) \
479 do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
480 #define COMPLETE_WITH_ATTR(table) \
481 do {completion_charp = Query_for_list_of_attributes; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0)
484 /* The completion function. Acc. to readline spec this gets passed the text
485 entered to far and its start and end in the readline buffer. The return value
486 is some partially obscure list format that can be generated by the readline
487 libraries completion_matches() function, so we don't have to worry about it.
490 psql_completion(char *text, int start, int end)
492 /* This is the variable we'll return. */
493 char **matches = NULL;
495 /* These are going to contain some scannage of the input line. */
501 static char *sql_commands[] = {
502 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
503 "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE", "DROP", "EXECUTE",
504 "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
505 "PREPARE", "REINDEX", "RESET", "REVOKE", "ROLLBACK", "SELECT", "SET", "SHOW",
506 "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
509 static char *pgsql_variables[] = {
510 /* these SET arguments are known in gram.y */
517 * the rest should match USERSET and possibly SUSET entries in
518 * backend/utils/misc/guc.c.
521 "australian_timezones",
523 "client_min_messages",
526 "cpu_index_tuple_cost",
531 "debug_pretty_print",
534 "debug_print_rewritten",
535 "default_statistics_target",
536 "default_transaction_isolation",
537 "default_transaction_read_only",
538 "dynamic_library_path",
539 "effective_cache_size",
548 "explain_pretty_print",
549 "extra_float_digits",
550 "from_collapse_limit",
556 "geqo_selection_bias",
558 "join_collapse_limit",
559 "krb_server_keyfile",
565 "log_error_verbosity",
566 "log_executor_stats",
567 "log_min_duration_statement",
568 "log_min_error_statement",
573 "log_statement_stats",
576 "max_files_per_process",
579 "max_locks_per_transaction",
580 "password_encryption",
593 "stats_command_string",
594 "stats_reset_on_server_start",
596 "stats_start_collector",
597 "superuser_reserved_connections",
604 "transform_null_equals",
605 "unix_socket_directory",
607 "unix_socket_permissions",
615 static char *backslash_commands[] = {
616 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
617 "\\d", "\\da", "\\dc", "\\dC", "\\dd", "\\dD", "\\df", "\\di",
618 "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT",
620 "\\e", "\\echo", "\\encoding",
621 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
622 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
623 "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
624 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
627 (void) end; /* not used */
629 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
630 rl_completion_append_character = ' ';
633 /* Clear a few things. */
634 completion_charp = NULL;
635 completion_charpp = NULL;
636 completion_info_charp = NULL;
639 * Scan the input line before our current position for the last four
640 * words. According to those we'll make some smart decisions on what
641 * the user is probably intending to type. TODO: Use strtokx() to do
644 prev_wd = previous_word(start, 0);
645 prev2_wd = previous_word(start, 1);
646 prev3_wd = previous_word(start, 2);
647 prev4_wd = previous_word(start, 3);
649 /* If a backslash command was started, continue */
651 COMPLETE_WITH_LIST(backslash_commands);
653 /* If no previous word, suggest one of the basic sql commands */
655 COMPLETE_WITH_LIST(sql_commands);
657 /* CREATE or DROP but not ALTER TABLE sth DROP */
658 /* complete with something you can create or drop */
659 else if (strcasecmp(prev_wd, "CREATE") == 0 ||
660 (strcasecmp(prev_wd, "DROP") == 0 &&
661 strcasecmp(prev3_wd, "TABLE") != 0))
662 matches = completion_matches(text, create_command_generator);
667 * complete with what you can alter (TABLE, GROUP, USER, ...) unless
668 * we're in ALTER TABLE sth ALTER
670 else if (strcasecmp(prev_wd, "ALTER") == 0 &&
671 strcasecmp(prev3_wd, "TABLE") != 0)
673 char *list_ALTER[] = {"DATABASE", "GROUP", "SCHEMA", "TABLE",
674 "TRIGGER", "USER", NULL};
676 COMPLETE_WITH_LIST(list_ALTER);
679 /* ALTER DATABASE <name> */
680 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
681 strcasecmp(prev2_wd, "DATABASE") == 0)
683 char *list_ALTERDATABASE[] = {"RESET", "SET", NULL};
685 COMPLETE_WITH_LIST(list_ALTERDATABASE);
687 /* ALTER TRIGGER <name>, add ON */
688 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
689 strcasecmp(prev2_wd, "TRIGGER") == 0)
690 COMPLETE_WITH_CONST("ON");
693 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
695 else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
696 strcasecmp(prev3_wd, "TRIGGER") == 0 &&
697 strcasecmp(prev_wd, "ON") == 0)
698 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
701 * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
704 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
705 strcasecmp(prev2_wd, "TABLE") == 0)
707 char *list_ALTER2[] = {"ADD", "ALTER", "DROP", "RENAME",
710 COMPLETE_WITH_LIST(list_ALTER2);
712 /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
713 else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
714 (strcasecmp(prev_wd, "ALTER") == 0 ||
715 strcasecmp(prev_wd, "RENAME") == 0))
716 COMPLETE_WITH_ATTR(prev2_wd);
718 /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
719 else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
720 strcasecmp(prev_wd, "DROP") == 0)
722 char *list_TABLEDROP[] = {"COLUMN", "CONSTRAINT", NULL};
724 COMPLETE_WITH_LIST(list_TABLEDROP);
726 /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
727 else if (strcasecmp(prev4_wd, "TABLE") == 0 &&
728 strcasecmp(prev2_wd, "DROP") == 0 &&
729 strcasecmp(prev_wd, "COLUMN") == 0)
730 COMPLETE_WITH_ATTR(prev3_wd);
732 /* complete ALTER GROUP <foo> with ADD or DROP */
733 else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
734 strcasecmp(prev2_wd, "GROUP") == 0)
736 char *list_ALTERGROUP[] = {"ADD", "DROP", NULL};
738 COMPLETE_WITH_LIST(list_ALTERGROUP);
740 /* complete ALTER GROUP <foo> ADD|DROP with USER */
741 else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
742 strcasecmp(prev3_wd, "GROUP") == 0 &&
743 (strcasecmp(prev_wd, "ADD") == 0 ||
744 strcasecmp(prev_wd, "DROP") == 0))
745 COMPLETE_WITH_CONST("USER");
746 /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
747 else if (strcasecmp(prev4_wd, "GROUP") == 0 &&
748 (strcasecmp(prev2_wd, "ADD") == 0 ||
749 strcasecmp(prev2_wd, "DROP") == 0) &&
750 strcasecmp(prev_wd, "USER") == 0)
751 COMPLETE_WITH_QUERY(Query_for_list_of_users);
754 /* If the previous word is ANALYZE, produce list of tables. */
755 else if (strcasecmp(prev_wd, "ANALYZE") == 0)
756 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
757 /* If we have ANALYZE <table>, complete with semicolon. */
758 else if (strcasecmp(prev2_wd, "ANALYZE") == 0)
759 COMPLETE_WITH_CONST(";");
762 /* If the previous word is CLUSTER, produce list of indexes. */
763 else if (strcasecmp(prev_wd, "CLUSTER") == 0)
764 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
765 /* If we have CLUSTER <sth>, then add "ON" */
766 else if (strcasecmp(prev2_wd, "CLUSTER") == 0)
767 COMPLETE_WITH_CONST("ON");
770 * If we have CLUSTER <sth> ON, then add the correct tablename as
773 else if (strcasecmp(prev3_wd, "CLUSTER") == 0 &&
774 strcasecmp(prev_wd, "ON") == 0)
776 completion_info_charp = prev2_wd;
777 COMPLETE_WITH_QUERY(Query_for_table_owning_index);
781 else if (strcasecmp(prev_wd, "COMMENT") == 0)
782 COMPLETE_WITH_CONST("ON");
783 else if (strcasecmp(prev2_wd, "COMMENT") == 0 &&
784 strcasecmp(prev_wd, "ON") == 0)
786 char *list_COMMENT[] =
787 {"DATABASE", "INDEX", "RULE", "SCHEMA", "SEQUENCE", "TABLE",
788 "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR",
789 "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
791 COMPLETE_WITH_LIST(list_COMMENT);
793 else if (strcasecmp(prev4_wd, "COMMENT") == 0 &&
794 strcasecmp(prev3_wd, "ON") == 0)
795 COMPLETE_WITH_CONST("IS");
800 * If we have COPY [BINARY] (which you'd have to type yourself), offer
801 * list of tables (Also cover the analogous backslash command)
803 else if (strcasecmp(prev_wd, "COPY") == 0 ||
804 strcasecmp(prev_wd, "\\copy") == 0 ||
805 (strcasecmp(prev2_wd, "COPY") == 0 &&
806 strcasecmp(prev_wd, "BINARY") == 0))
807 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
808 /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
809 else if (strcasecmp(prev2_wd, "COPY") == 0 ||
810 strcasecmp(prev2_wd, "\\copy") == 0 ||
811 strcasecmp(prev2_wd, "BINARY") == 0)
813 char *list_FROMTO[] = {"FROM", "TO", NULL};
815 COMPLETE_WITH_LIST(list_FROMTO);
819 /* First off we complete CREATE UNIQUE with "INDEX" */
820 else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
821 strcasecmp(prev_wd, "UNIQUE") == 0)
822 COMPLETE_WITH_CONST("INDEX");
823 /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
824 else if (strcasecmp(prev2_wd, "INDEX") == 0 &&
825 (strcasecmp(prev3_wd, "CREATE") == 0 ||
826 strcasecmp(prev3_wd, "UNIQUE") == 0))
827 COMPLETE_WITH_CONST("ON");
828 /* Complete ... INDEX <name> ON with a list of tables */
829 else if (strcasecmp(prev3_wd, "INDEX") == 0 &&
830 strcasecmp(prev_wd, "ON") == 0)
831 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
834 * Complete INDEX <name> ON <table> with a list of table columns
835 * (which should really be in parens)
837 else if (strcasecmp(prev4_wd, "INDEX") == 0 &&
838 strcasecmp(prev2_wd, "ON") == 0)
839 COMPLETE_WITH_ATTR(prev_wd);
840 /* same if you put in USING */
841 else if (strcasecmp(prev4_wd, "ON") == 0 &&
842 strcasecmp(prev2_wd, "USING") == 0)
843 COMPLETE_WITH_ATTR(prev3_wd);
844 /* Complete USING with an index method */
845 else if (strcasecmp(prev_wd, "USING") == 0)
847 char *index_mth[] = {"BTREE", "RTREE", "HASH", "GIST", NULL};
849 COMPLETE_WITH_LIST(index_mth);
853 /* Complete "CREATE RULE <sth>" with "AS" */
854 else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
855 strcasecmp(prev2_wd, "RULE") == 0)
856 COMPLETE_WITH_CONST("AS");
857 /* Complete "CREATE RULE <sth> AS with "ON" */
858 else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
859 strcasecmp(prev3_wd, "RULE") == 0 &&
860 strcasecmp(prev_wd, "AS") == 0)
861 COMPLETE_WITH_CONST("ON");
862 /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
863 else if (strcasecmp(prev4_wd, "RULE") == 0 &&
864 strcasecmp(prev2_wd, "AS") == 0 &&
865 strcasecmp(prev_wd, "ON") == 0)
867 char *rule_events[] = {"SELECT", "UPDATE", "INSERT",
870 COMPLETE_WITH_LIST(rule_events);
872 /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
873 else if (strcasecmp(prev3_wd, "AS") == 0 &&
874 strcasecmp(prev2_wd, "ON") == 0 &&
875 (toupper((unsigned char) prev_wd[4]) == 'T' ||
876 toupper((unsigned char) prev_wd[5]) == 'T'))
877 COMPLETE_WITH_CONST("TO");
878 /* Complete "AS ON <sth> TO" with a table name */
879 else if (strcasecmp(prev4_wd, "AS") == 0 &&
880 strcasecmp(prev3_wd, "ON") == 0 &&
881 strcasecmp(prev_wd, "TO") == 0)
882 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
885 /* Complete CREATE TEMP with "TABLE" */
886 else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
887 strcasecmp(prev_wd, "TEMP") == 0)
888 COMPLETE_WITH_CONST("TABLE");
891 /* is on the agenda . . . */
894 /* Complete "CREATE VIEW <name>" with "AS" */
895 else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
896 strcasecmp(prev2_wd, "VIEW") == 0)
897 COMPLETE_WITH_CONST("AS");
898 /* Complete "CREATE VIEW <sth> AS with "SELECT" */
899 else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
900 strcasecmp(prev3_wd, "VIEW") == 0 &&
901 strcasecmp(prev_wd, "AS") == 0)
902 COMPLETE_WITH_CONST("SELECT");
907 * Complete DELETE with FROM (only if the word before that is not "ON"
908 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
910 else if (strcasecmp(prev_wd, "DELETE") == 0 &&
911 !(strcasecmp(prev2_wd, "ON") == 0 ||
912 strcasecmp(prev2_wd, "GRANT") == 0 ||
913 strcasecmp(prev2_wd, "BEFORE") == 0 ||
914 strcasecmp(prev2_wd, "AFTER") == 0))
915 COMPLETE_WITH_CONST("FROM");
916 /* Complete DELETE FROM with a list of tables */
917 else if (strcasecmp(prev2_wd, "DELETE") == 0 &&
918 strcasecmp(prev_wd, "FROM") == 0)
919 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
920 /* Complete DELETE FROM <table> with "WHERE" (perhaps a safe idea?) */
921 else if (strcasecmp(prev3_wd, "DELETE") == 0 &&
922 strcasecmp(prev2_wd, "FROM") == 0)
923 COMPLETE_WITH_CONST("WHERE");
928 * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with
929 * the list of SQL commands
931 else if (strcasecmp(prev_wd, "EXPLAIN") == 0 ||
932 (strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
933 strcasecmp(prev_wd, "VERBOSE") == 0))
934 COMPLETE_WITH_LIST(sql_commands);
937 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
938 else if (strcasecmp(prev_wd, "FETCH") == 0 ||
939 strcasecmp(prev_wd, "MOVE") == 0)
941 char *list_FETCH1[] = {"FORWARD", "BACKWARD", "RELATIVE", NULL};
943 COMPLETE_WITH_LIST(list_FETCH1);
945 /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
946 else if (strcasecmp(prev2_wd, "FETCH") == 0 ||
947 strcasecmp(prev2_wd, "MOVE") == 0)
949 char *list_FETCH2[] = {"ALL", "NEXT", "PRIOR", NULL};
951 COMPLETE_WITH_LIST(list_FETCH2);
955 * Complete FETCH <sth1> <sth2> with "FROM" or "TO". (Is there a
956 * difference? If not, remove one.)
958 else if (strcasecmp(prev3_wd, "FETCH") == 0 ||
959 strcasecmp(prev3_wd, "MOVE") == 0)
961 char *list_FROMTO[] = {"FROM", "TO", NULL};
963 COMPLETE_WITH_LIST(list_FROMTO);
967 /* Complete GRANT/REVOKE with a list of privileges */
968 else if (strcasecmp(prev_wd, "GRANT") == 0 ||
969 strcasecmp(prev_wd, "REVOKE") == 0)
971 char *list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES", "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
973 COMPLETE_WITH_LIST(list_privileg);
975 /* Complete GRANT/REVOKE <sth> with "ON" */
976 else if (strcasecmp(prev2_wd, "GRANT") == 0 ||
977 strcasecmp(prev2_wd, "REVOKE") == 0)
978 COMPLETE_WITH_CONST("ON");
981 * Complete GRANT/REVOKE <sth> ON with a list of tables, views,
982 * sequences, and indexes
984 * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result
985 * via UNION; seems to work intuitively
987 * Note: GRANT/REVOKE can get quite complex; tab-completion as
988 * implemented here will only work if the privilege list contains
989 * exactly one privilege
991 else if ((strcasecmp(prev3_wd, "GRANT") == 0 ||
992 strcasecmp(prev3_wd, "REVOKE") == 0) &&
993 strcasecmp(prev_wd, "ON") == 0)
994 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
995 " WHERE relkind in ('r','S','v') "
996 " AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "
997 " AND pg_catalog.pg_table_is_visible(c.oid) "
998 " AND relnamespace = n.oid "
999 " AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
1001 "SELECT 'DATABASE' "
1003 "SELECT 'FUNCTION' "
1005 "SELECT 'LANGUAGE' "
1007 "SELECT 'SCHEMA' ");
1009 /* Complete "GRANT/REVOKE * ON * " with "TO" */
1010 else if ((strcasecmp(prev4_wd, "GRANT") == 0 ||
1011 strcasecmp(prev4_wd, "REVOKE") == 0) &&
1012 strcasecmp(prev2_wd, "ON") == 0)
1014 if (strcasecmp(prev_wd, "DATABASE") == 0)
1015 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1016 else if (strcasecmp(prev_wd, "FUNCTION") == 0)
1017 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
1018 else if (strcasecmp(prev_wd, "LANGUAGE") == 0)
1019 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1020 else if (strcasecmp(prev_wd, "SCHEMA") == 0)
1021 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1023 COMPLETE_WITH_CONST("TO");
1027 * TODO: to complete with user name we need prev5_wd -- wait for a
1028 * more general solution there same for GRANT <sth> ON { DATABASE |
1029 * FUNCTION | LANGUAGE | SCHEMA } xxx TO
1033 /* Complete INSERT with "INTO" */
1034 else if (strcasecmp(prev_wd, "INSERT") == 0)
1035 COMPLETE_WITH_CONST("INTO");
1036 /* Complete INSERT INTO with table names */
1037 else if (strcasecmp(prev2_wd, "INSERT") == 0 &&
1038 strcasecmp(prev_wd, "INTO") == 0)
1039 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1040 /* Complete "INSERT INTO <table> (" with attribute names */
1041 else if (rl_line_buffer[start - 1] == '(' &&
1042 strcasecmp(prev3_wd, "INSERT") == 0 &&
1043 strcasecmp(prev2_wd, "INTO") == 0)
1044 COMPLETE_WITH_ATTR(prev_wd);
1047 * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1050 else if (strcasecmp(prev3_wd, "INSERT") == 0 &&
1051 strcasecmp(prev2_wd, "INTO") == 0)
1053 char *list_INSERT[] = {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1055 COMPLETE_WITH_LIST(list_INSERT);
1057 /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1058 else if (strcasecmp(prev4_wd, "INSERT") == 0 &&
1059 strcasecmp(prev3_wd, "INTO") == 0 &&
1060 prev_wd[strlen(prev_wd) - 1] == ')')
1062 char *list_INSERT[] = {"SELECT", "VALUES", NULL};
1064 COMPLETE_WITH_LIST(list_INSERT);
1067 /* Insert an open parenthesis after "VALUES" */
1068 else if (strcasecmp(prev_wd, "VALUES") == 0 &&
1069 strcasecmp(prev2_wd, "DEFAULT") != 0)
1070 COMPLETE_WITH_CONST("(");
1073 /* Complete LOCK [TABLE] with a list of tables */
1074 else if (strcasecmp(prev_wd, "LOCK") == 0 ||
1075 (strcasecmp(prev_wd, "TABLE") == 0 &&
1076 strcasecmp(prev2_wd, "LOCK") == 0))
1077 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1079 /* For the following, handle the case of a single table only for now */
1081 /* Complete LOCK [TABLE] <table> with "IN" */
1082 else if ((strcasecmp(prev2_wd, "LOCK") == 0 &&
1083 strcasecmp(prev_wd, "TABLE")) ||
1084 (strcasecmp(prev2_wd, "TABLE") == 0 &&
1085 strcasecmp(prev3_wd, "LOCK") == 0))
1086 COMPLETE_WITH_CONST("IN");
1088 /* Complete LOCK [TABLE] <table> IN with a lock mode */
1089 else if (strcasecmp(prev_wd, "IN") == 0 &&
1090 (strcasecmp(prev3_wd, "LOCK") == 0 ||
1091 (strcasecmp(prev3_wd, "TABLE") == 0 &&
1092 strcasecmp(prev4_wd, "LOCK") == 0)))
1094 char *lock_modes[] = {"ACCESS SHARE MODE",
1095 "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1096 "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1097 "SHARE ROW EXCLUSIVE MODE",
1098 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1100 COMPLETE_WITH_LIST(lock_modes);
1104 else if (strcasecmp(prev_wd, "NOTIFY") == 0)
1105 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1108 else if (strcasecmp(prev_wd, "REINDEX") == 0)
1110 char *list_REINDEX[] = {"TABLE", "DATABASE", "INDEX", NULL};
1112 COMPLETE_WITH_LIST(list_REINDEX);
1114 else if (strcasecmp(prev2_wd, "REINDEX") == 0)
1116 if (strcasecmp(prev_wd, "TABLE") == 0)
1117 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1118 else if (strcasecmp(prev_wd, "DATABASE") == 0)
1119 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1120 else if (strcasecmp(prev_wd, "INDEX") == 0)
1121 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1127 /* SET, RESET, SHOW */
1128 /* Complete with a variable name */
1129 else if ((strcasecmp(prev_wd, "SET") == 0 &&
1130 strcasecmp(prev3_wd, "UPDATE") != 0) ||
1131 strcasecmp(prev_wd, "RESET") == 0 ||
1132 strcasecmp(prev_wd, "SHOW") == 0)
1133 COMPLETE_WITH_LIST(pgsql_variables);
1134 /* Complete "SET TRANSACTION" */
1135 else if ((strcasecmp(prev2_wd, "SET") == 0 &&
1136 strcasecmp(prev_wd, "TRANSACTION") == 0) ||
1137 (strcasecmp(prev4_wd, "SESSION") == 0 &&
1138 strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 &&
1139 strcasecmp(prev2_wd, "AS") == 0 &&
1140 strcasecmp(prev_wd, "TRANSACTION") == 0))
1142 char *my_list[] = {"ISOLATION", "READ", NULL};
1144 COMPLETE_WITH_LIST(my_list);
1146 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1147 strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1148 strcasecmp(prev_wd, "ISOLATION") == 0)
1149 COMPLETE_WITH_CONST("LEVEL");
1150 else if ((strcasecmp(prev4_wd, "SET") == 0 ||
1151 strcasecmp(prev4_wd, "AS") == 0) &&
1152 strcasecmp(prev3_wd, "TRANSACTION") == 0 &&
1153 strcasecmp(prev2_wd, "ISOLATION") == 0 &&
1154 strcasecmp(prev_wd, "LEVEL") == 0)
1156 char *my_list[] = {"READ", "SERIALIZABLE", NULL};
1158 COMPLETE_WITH_LIST(my_list);
1160 else if (strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
1161 strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1162 strcasecmp(prev2_wd, "LEVEL") == 0 &&
1163 strcasecmp(prev_wd, "READ") == 0)
1164 COMPLETE_WITH_CONST("COMMITTED");
1165 else if ((strcasecmp(prev3_wd, "SET") == 0 ||
1166 strcasecmp(prev3_wd, "AS") == 0) &&
1167 strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1168 strcasecmp(prev_wd, "READ") == 0)
1170 char *my_list[] = {"ONLY", "WRITE", NULL};
1172 COMPLETE_WITH_LIST(my_list);
1174 /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1175 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1176 strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1178 char *constraint_list[] = {"DEFERRED", "IMMEDIATE", NULL};
1180 COMPLETE_WITH_LIST(constraint_list);
1182 /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1183 else if (strcasecmp(prev2_wd, "SET") == 0 &&
1184 strcasecmp(prev_wd, "SESSION") == 0)
1186 char *my_list[] = {"AUTHORIZATION",
1187 "CHARACTERISTICS AS TRANSACTION",
1190 COMPLETE_WITH_LIST(my_list);
1192 /* Complete SET SESSION AUTHORIZATION with username */
1193 else if (strcasecmp(prev3_wd, "SET") == 0
1194 && strcasecmp(prev2_wd, "SESSION") == 0
1195 && strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1196 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1197 /* Complete SET <var> with "TO" */
1198 else if (strcasecmp(prev2_wd, "SET") == 0 &&
1199 strcasecmp(prev4_wd, "UPDATE") != 0)
1200 COMPLETE_WITH_CONST("TO");
1201 /* Suggest possible variable values */
1202 else if (strcasecmp(prev3_wd, "SET") == 0 &&
1203 (strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1205 if (strcasecmp(prev2_wd, "DateStyle") == 0)
1207 char *my_list[] = {"ISO", "SQL", "Postgres", "German",
1208 "YMD", "DMY", "MDY",
1209 "US", "European", "NonEuropean",
1212 COMPLETE_WITH_LIST(my_list);
1214 else if (strcasecmp(prev2_wd, "GEQO") == 0)
1216 char *my_list[] = {"ON", "OFF", "DEFAULT", NULL};
1218 COMPLETE_WITH_LIST(my_list);
1222 char *my_list[] = {"DEFAULT", NULL};
1224 COMPLETE_WITH_LIST(my_list);
1229 else if (strcasecmp(prev_wd, "TRUNCATE") == 0)
1230 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1233 else if (strcasecmp(prev_wd, "UNLISTEN") == 0)
1234 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s' UNION SELECT '*'");
1237 /* If prev. word is UPDATE suggest a list of tables */
1238 else if (strcasecmp(prev_wd, "UPDATE") == 0)
1239 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1240 /* Complete UPDATE <table> with "SET" */
1241 else if (strcasecmp(prev2_wd, "UPDATE") == 0)
1242 COMPLETE_WITH_CONST("SET");
1245 * If the previous word is SET (and it wasn't caught above as the
1246 * _first_ word) the word before it was (hopefully) a table name and
1247 * we'll now make a list of attributes.
1249 else if (strcasecmp(prev_wd, "SET") == 0)
1250 COMPLETE_WITH_ATTR(prev2_wd);
1253 else if (strcasecmp(prev_wd, "VACUUM") == 0)
1254 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_class WHERE relkind='r' and substring(pg_catalog.quote_ident(relname),1,%d)='%s' and pg_catalog.pg_table_is_visible(oid) UNION SELECT 'FULL' UNION SELECT 'ANALYZE' UNION SELECT 'VERBOSE'");
1255 else if (strcasecmp(prev2_wd, "VACUUM") == 0 &&
1256 (strcasecmp(prev_wd, "FULL") == 0 ||
1257 strcasecmp(prev_wd, "ANALYZE") == 0 ||
1258 strcasecmp(prev_wd, "VERBOSE") == 0))
1259 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1262 /* Simple case of the word before the where being the table name */
1263 else if (strcasecmp(prev_wd, "WHERE") == 0)
1264 COMPLETE_WITH_ATTR(prev2_wd);
1267 /* TODO: also include SRF ? */
1268 else if (strcasecmp(prev_wd, "FROM") == 0)
1269 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1272 /* Backslash commands */
1273 /* TODO: \dc \dd \dl */
1274 else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1275 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1276 else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1277 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv);
1278 else if (strcmp(prev_wd, "\\da") == 0)
1279 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates);
1280 else if (strcmp(prev_wd, "\\dD") == 0)
1281 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains);
1282 else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1283 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
1284 else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1285 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1286 else if (strcmp(prev_wd, "\\dn") == 0)
1287 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1288 else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1289 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1290 else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1291 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
1292 else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1293 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1294 else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1295 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1296 else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1297 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
1298 else if (strcmp(prev_wd, "\\du") == 0)
1299 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1300 else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1301 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
1302 else if (strcmp(prev_wd, "\\encoding") == 0)
1303 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
1304 else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1305 COMPLETE_WITH_LIST(sql_commands);
1306 else if (strcmp(prev_wd, "\\pset") == 0)
1308 char *my_list[] = {"format", "border", "expanded",
1309 "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1312 COMPLETE_WITH_LIST(my_list);
1314 else if (strcmp(prev_wd, "\\cd") == 0 ||
1315 strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1316 strcmp(prev_wd, "\\g") == 0 ||
1317 strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1318 strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1319 strcmp(prev_wd, "\\s") == 0 ||
1320 strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1322 matches = completion_matches(text, filename_completion_function);
1326 * Finally, we look through the list of "things", such as TABLE, INDEX
1327 * and check if that was the previous word. If so, execute the query
1328 * to get a list of them.
1334 for (i = 0; words_after_create[i].name; i++)
1335 if (strcasecmp(prev_wd, words_after_create[i].name) == 0)
1337 if (words_after_create[i].with_schema == WITH_SCHEMA)
1338 COMPLETE_WITH_SCHEMA_QUERY(words_after_create[i].query);
1340 COMPLETE_WITH_QUERY(words_after_create[i].query);
1347 * If we still don't have anything to match we have to fabricate some
1348 * sort of default list. If we were to just return NULL, readline
1349 * automatically attempts filename completion, and that's usually no
1352 if (matches == NULL)
1354 COMPLETE_WITH_CONST("");
1355 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1356 rl_completion_append_character = '\0';
1367 /* Return our Grand List O' Matches */
1373 /* GENERATOR FUNCTIONS
1375 These functions do all the actual work of completing the input. They get
1376 passed the text so far and the count how many times they have been called so
1377 far with the same text.
1378 If you read the above carefully, you'll see that these don't get called
1379 directly but through the readline interface.
1380 The return value is expected to be the full completion of the text, going
1381 through a list each time, or NULL if there are no more matches. The string
1382 will be free()'d be readline, so you must run it through strdup() or
1383 something of that sort.
1386 /* This one gives you one from a list of things you can put after CREATE or DROP
1390 create_command_generator(const char *text, int state)
1392 static int list_index,
1396 /* If this is the first time for this completion, init some values */
1400 string_length = strlen(text);
1403 /* find something that matches */
1404 while ((name = words_after_create[list_index++].name))
1405 if (strncasecmp(name, text, string_length) == 0)
1406 return xstrdup(name);
1408 /* if nothing matches, return NULL */
1413 /* The following two functions are wrappers for _complete_from_query */
1416 complete_from_query(const char *text, int state)
1418 return _complete_from_query(0, text, state);
1422 complete_from_schema_query(const char *text, int state)
1424 return _complete_from_query(1, text, state);
1428 /* This creates a list of matching things, according to a query pointed to
1429 by completion_charp.
1430 The query can be one of two kinds:
1431 - A simple query which must contain a %d and a %s, which will be replaced
1432 by the string length of the text and the text itself. The query may also
1433 have another %s in it, which will be replaced by the value of
1434 completion_info_charp.
1436 - A schema query used for completion of both schema and relation names;
1437 these are more complex and must contain in the following order:
1438 %d %s %d %s %d %s %s %d %s
1439 where %d is the string length of the text and %s the text itself.
1441 It is assumed that strings should be escaped to become SQL literals
1442 (that is, what is in the query is actually ... '%s' ...)
1444 See top of file for examples of both kinds of query.
1448 _complete_from_query(int is_schema_query, const char *text, int state)
1450 static int list_index,
1452 static PGresult *result = NULL;
1455 * If this is the first time for this completion, we fetch a list of
1456 * our "things" from the backend.
1460 char query_buffer[BUF_SIZE];
1465 string_length = strlen(text);
1467 /* Free any prior result */
1471 /* Need to have a query */
1472 if (completion_charp == NULL)
1475 /* Set up suitably-escaped copies of textual inputs */
1478 e_text = (char *) malloc(strlen(text) * 2 + 1);
1481 PQescapeString(e_text, text, strlen(text));
1486 if (completion_info_charp)
1488 e_info_charp = (char *)
1489 malloc(strlen(completion_info_charp) * 2 + 1);
1496 PQescapeString(e_info_charp, completion_info_charp,
1497 strlen(completion_info_charp));
1500 e_info_charp = NULL;
1502 if (is_schema_query)
1504 if (snprintf(query_buffer, BUF_SIZE, completion_charp,
1505 string_length, e_text,
1506 string_length, e_text,
1507 string_length, e_text,
1509 string_length, e_text,
1510 string_length, e_text) == -1)
1511 ERROR_QUERY_TOO_LONG;
1513 result = exec_query(query_buffer);
1517 if (snprintf(query_buffer, BUF_SIZE, completion_charp,
1518 string_length, e_text, e_info_charp) == -1)
1519 ERROR_QUERY_TOO_LONG;
1521 result = exec_query(query_buffer);
1530 /* Find something that matches */
1531 if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
1535 while (list_index < PQntuples(result) &&
1536 (item = PQgetvalue(result, list_index++, 0)))
1537 if (strncasecmp(text, item, string_length) == 0)
1538 return xstrdup(item);
1541 /* If nothing matches, free the db structure and return null */
1548 /* This function returns in order one of a fixed, NULL pointer terminated list
1549 of strings (if matching). This can be used if there are only a fixed number
1550 SQL words that can appear at certain spot.
1553 complete_from_list(const char *text, int state)
1555 static int string_length,
1558 static bool casesensitive;
1561 /* need to have a list */
1562 #ifdef USE_ASSERT_CHECKING
1563 assert(completion_charpp);
1566 /* Initialization */
1570 string_length = strlen(text);
1571 casesensitive = true;
1575 while ((item = completion_charpp[list_index++]))
1577 /* First pass is case sensitive */
1578 if (casesensitive && strncmp(text, item, string_length) == 0)
1581 return xstrdup(item);
1584 /* Second pass is case insensitive, don't bother counting matches */
1585 if (!casesensitive && strncasecmp(text, item, string_length) == 0)
1586 return xstrdup(item);
1590 * No matches found. If we're not case insensitive already, lets
1591 * switch to being case insensitive and try again
1593 if (casesensitive && matches == 0)
1595 casesensitive = false;
1598 return (complete_from_list(text, state));
1601 /* If no more matches, return null. */
1606 /* This function returns one fixed string the first time even if it doesn't
1607 match what's there, and nothing the second time. This should be used if there
1608 is only one possibility that can appear at a certain spot, so misspellings
1609 will be overwritten.
1610 The string to be passed must be in completion_charp.
1613 complete_from_const(const char *text, int state)
1615 (void) text; /* We don't care about what was entered
1618 #ifdef USE_ASSERT_CHECKING
1619 assert(completion_charp);
1622 return xstrdup(completion_charp);
1629 /* HELPER FUNCTIONS */
1632 /* Execute a query and report any errors. This should be the preferred way of
1633 talking to the database in this file.
1634 Note that the query passed in here must not have a semicolon at the end
1635 because we need to append LIMIT xxx.
1638 exec_query(char *query)
1641 char query_buffer[BUF_SIZE];
1643 if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
1645 #ifdef USE_ASSERT_CHECKING
1646 assert(query[strlen(query) - 1] != ';');
1649 if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d",
1650 query, completion_max_records) == -1)
1652 ERROR_QUERY_TOO_LONG;
1656 result = PQexec(pset.db, query_buffer);
1658 if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
1661 psql_error("tab completion: %s failed - %s\n",
1662 query_buffer, PQresStatus(PQresultStatus(result)));
1673 /* Return the word (space delimited) before point. Set skip > 0 to skip that
1674 many words; e.g. skip=1 finds the word before the previous one.
1677 previous_word(int point, int skip)
1687 /* first we look for a space before the current word */
1688 for (i = point; i >= 0; i--)
1689 if (rl_line_buffer[i] == ' ')
1692 /* now find the first non-space which then constitutes the end */
1694 if (rl_line_buffer[i] != ' ')
1701 * If no end found we return null, because there is no word before
1708 * Otherwise we now look for the start. The start is either the
1709 * last character before any space going backwards from the end,
1710 * or it's simply character 0
1712 for (start = end; start > 0; start--)
1714 if (rl_line_buffer[start] == '"')
1715 inquotes = !inquotes;
1716 if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
1724 s = (char *) malloc(end - start + 2);
1727 psql_error("out of memory\n");
1728 if (!pset.cur_cmd_interactive)
1734 strncpy(s, &rl_line_buffer[start], end - start + 1);
1735 s[end - start + 1] = '\0';
1745 * Surround a string with single quotes. This works for both SQL and
1746 * psql internal. Currently disable because it is reported not to
1747 * cooperate with certain versions of readline.
1750 quote_file_name(char *text, int match_type, char *quote_pointer)
1755 (void) quote_pointer; /* not used */
1757 length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
1760 strcpy(s + 1, text);
1761 if (match_type == SINGLE_MATCH)
1762 s[length - 2] = '\'';
1763 s[length - 1] = '\0';
1770 dequote_file_name(char *text, char quote_char)
1776 return xstrdup(text);
1778 length = strlen(text);
1779 s = malloc(length - 2 + 1);
1780 strncpy(s, text +1, length - 2);
1787 #endif /* USE_READLINE */