]> granicus.if.org Git - postgresql/blob - src/bin/psql/tab-complete.c
Trivial dead code removal: in _complete_from_query(), 'text' cannot be
[postgresql] / src / bin / psql / tab-complete.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2005, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.132 2005/06/21 00:48:33 neilc Exp $
7  */
8
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.
16  *
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:
22  *
23  *       $if psql
24  *       set disable-completion on
25  *       $endif
26  *
27  * See `man 3 readline' or `info readline' for the full details. Also,
28  * hence the
29  *
30  * BUGS:
31  *
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.)
36  *
37  * - Table or attribute names with spaces in it may confuse it.
38  *
39  * - Quotes, parenthesis, and other funny characters are not handled
40  *       all that gracefully.
41  *----------------------------------------------------------------------
42  */
43
44 #include "postgres_fe.h"
45 #include "tab-complete.h"
46 #include "input.h"
47
48 /* If we don't have this, we might as well forget about the whole thing: */
49 #ifdef USE_READLINE
50
51 #include <ctype.h>
52 #include "libpq-fe.h"
53 #include "pqexpbuffer.h"
54 #include "common.h"
55 #include "settings.h"
56
57
58 #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
59 #define filename_completion_function rl_filename_completion_function
60 #else
61 /* missing in some header files */
62 extern char *filename_completion_function();
63 #endif
64
65 #ifdef HAVE_RL_COMPLETION_MATCHES
66 #define completion_matches rl_completion_matches
67 #endif
68
69
70 /*
71  * This struct is used to define "schema queries", which are custom-built
72  * to obtain possibly-schema-qualified names of database objects.  There is
73  * enough similarity in the structure that we don't want to repeat it each
74  * time.  So we put the components of each query into this struct and
75  * assemble them with the common boilerplate in _complete_from_query().
76  */
77 typedef struct SchemaQuery
78 {
79         /*
80          * Name of catalog or catalogs to be queried, with alias, eg.
81          * "pg_catalog.pg_class c".  Note that "pg_namespace n" will be added.
82          */
83         const char *catname;
84
85         /*
86          * Selection condition --- only rows meeting this condition are
87          * candidates to display.  If catname mentions multiple tables,
88          * include the necessary join condition here.  For example, "c.relkind
89          * = 'r'". Write NULL (not an empty string) if not needed.
90          */
91         const char *selcondition;
92
93         /*
94          * Visibility condition --- which rows are visible without schema
95          * qualification?  For example,
96          * "pg_catalog.pg_table_is_visible(c.oid)".
97          */
98         const char *viscondition;
99
100         /*
101          * Namespace --- name of field to join to pg_namespace.oid. For
102          * example, "c.relnamespace".
103          */
104         const char *namespace;
105
106         /*
107          * Result --- the appropriately-quoted name to return, in the case of
108          * an unqualified name.  For example,
109          * "pg_catalog.quote_ident(c.relname)".
110          */
111         const char *result;
112
113         /*
114          * In some cases a different result must be used for qualified names.
115          * Enter that here, or write NULL if result can be used.
116          */
117         const char *qualresult;
118 } SchemaQuery;
119
120
121 /* Store maximum number of records we want from database queries
122  * (implemented via SELECT ... LIMIT xx).
123  */
124 static int      completion_max_records;
125
126 /*
127  * Communication variables set by COMPLETE_WITH_FOO macros and then used by
128  * the completion callback functions.  Ugly but there is no better way.
129  */
130 static const char *completion_charp;    /* to pass a string */
131 static const char *const * completion_charpp;   /* to pass a list of
132                                                                                                  * strings */
133 static const char *completion_info_charp;               /* to pass a second string */
134 static const SchemaQuery *completion_squery;    /* to pass a SchemaQuery */
135
136 /* A couple of macros to ease typing. You can use these to complete the given
137    string with
138    1) The results from a query you pass it. (Perhaps one of those below?)
139    2) The results from a schema query you pass it.
140    3) The items from a null-pointer-terminated list.
141    4) A string constant
142    5) The list of attributes to the given table.
143 */
144 #define COMPLETE_WITH_QUERY(query) \
145 do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
146 #define COMPLETE_WITH_SCHEMA_QUERY(query,addon) \
147 do { completion_squery = &(query); completion_charp = addon; matches = completion_matches(text, complete_from_schema_query); } while(0)
148 #define COMPLETE_WITH_LIST(list) \
149 do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
150 #define COMPLETE_WITH_CONST(string) \
151 do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
152 #define COMPLETE_WITH_ATTR(table) \
153 do {completion_charp = Query_for_list_of_attributes; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0)
154
155 /*
156  * Assembly instructions for schema queries
157  */
158
159 static const SchemaQuery Query_for_list_of_aggregates = {
160         /* catname */
161         "pg_catalog.pg_proc p",
162         /* selcondition */
163         "p.proisagg",
164         /* viscondition */
165         "pg_catalog.pg_function_is_visible(p.oid)",
166         /* namespace */
167         "p.pronamespace",
168         /* result */
169         "pg_catalog.quote_ident(p.proname)",
170         /* qualresult */
171         NULL
172 };
173
174 static const SchemaQuery Query_for_list_of_datatypes = {
175         /* catname */
176         "pg_catalog.pg_type t",
177         /* selcondition --- ignore table rowtypes and array types */
178         "(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         /* viscondition */
182         "pg_catalog.pg_type_is_visible(t.oid)",
183         /* namespace */
184         "t.typnamespace",
185         /* result */
186         "pg_catalog.format_type(t.oid, NULL)",
187         /* qualresult */
188         "pg_catalog.quote_ident(t.typname)"
189 };
190
191 static const SchemaQuery Query_for_list_of_domains = {
192         /* catname */
193         "pg_catalog.pg_type t",
194         /* selcondition */
195         "t.typtype = 'd'",
196         /* viscondition */
197         "pg_catalog.pg_type_is_visible(t.oid)",
198         /* namespace */
199         "t.typnamespace",
200         /* result */
201         "pg_catalog.quote_ident(t.typname)",
202         /* qualresult */
203         NULL
204 };
205
206 static const SchemaQuery Query_for_list_of_functions = {
207         /* catname */
208         "pg_catalog.pg_proc p",
209         /* selcondition */
210         NULL,
211         /* viscondition */
212         "pg_catalog.pg_function_is_visible(p.oid)",
213         /* namespace */
214         "p.pronamespace",
215         /* result */
216         "pg_catalog.quote_ident(p.proname)",
217         /* qualresult */
218         NULL
219 };
220
221 static const SchemaQuery Query_for_list_of_indexes = {
222         /* catname */
223         "pg_catalog.pg_class c",
224         /* selcondition */
225         "c.relkind IN ('i')",
226         /* viscondition */
227         "pg_catalog.pg_table_is_visible(c.oid)",
228         /* namespace */
229         "c.relnamespace",
230         /* result */
231         "pg_catalog.quote_ident(c.relname)",
232         /* qualresult */
233         NULL
234 };
235
236 static const SchemaQuery Query_for_list_of_sequences = {
237         /* catname */
238         "pg_catalog.pg_class c",
239         /* selcondition */
240         "c.relkind IN ('S')",
241         /* viscondition */
242         "pg_catalog.pg_table_is_visible(c.oid)",
243         /* namespace */
244         "c.relnamespace",
245         /* result */
246         "pg_catalog.quote_ident(c.relname)",
247         /* qualresult */
248         NULL
249 };
250
251 static const SchemaQuery Query_for_list_of_tables = {
252         /* catname */
253         "pg_catalog.pg_class c",
254         /* selcondition */
255         "c.relkind IN ('r')",
256         /* viscondition */
257         "pg_catalog.pg_table_is_visible(c.oid)",
258         /* namespace */
259         "c.relnamespace",
260         /* result */
261         "pg_catalog.quote_ident(c.relname)",
262         /* qualresult */
263         NULL
264 };
265
266 static const SchemaQuery Query_for_list_of_tisv = {
267         /* catname */
268         "pg_catalog.pg_class c",
269         /* selcondition */
270         "c.relkind IN ('r', 'i', 'S', 'v')",
271         /* viscondition */
272         "pg_catalog.pg_table_is_visible(c.oid)",
273         /* namespace */
274         "c.relnamespace",
275         /* result */
276         "pg_catalog.quote_ident(c.relname)",
277         /* qualresult */
278         NULL
279 };
280
281 static const SchemaQuery Query_for_list_of_tsv = {
282         /* catname */
283         "pg_catalog.pg_class c",
284         /* selcondition */
285         "c.relkind IN ('r', 'S', 'v')",
286         /* viscondition */
287         "pg_catalog.pg_table_is_visible(c.oid)",
288         /* namespace */
289         "c.relnamespace",
290         /* result */
291         "pg_catalog.quote_ident(c.relname)",
292         /* qualresult */
293         NULL
294 };
295
296 static const SchemaQuery Query_for_list_of_views = {
297         /* catname */
298         "pg_catalog.pg_class c",
299         /* selcondition */
300         "c.relkind IN ('v')",
301         /* viscondition */
302         "pg_catalog.pg_table_is_visible(c.oid)",
303         /* namespace */
304         "c.relnamespace",
305         /* result */
306         "pg_catalog.quote_ident(c.relname)",
307         /* qualresult */
308         NULL
309 };
310
311
312 /*
313  * Queries to get lists of names of various kinds of things, possibly
314  * restricted to names matching a partially entered name.  In these queries,
315  * %s will be replaced by the text entered so far (suitably escaped to
316  * become a SQL literal string).  %d will be replaced by the length of the
317  * string (in unescaped form).  A second %s, if present, will be replaced
318  * by a suitably-escaped version of the string provided in
319  * completion_info_charp.
320  *
321  * Beware that the allowed sequences of %s and %d are determined by
322  * _complete_from_query().
323  */
324
325 #define Query_for_list_of_attributes \
326 "SELECT pg_catalog.quote_ident(attname) "\
327 "  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
328 " WHERE c.oid = a.attrelid "\
329 "   AND a.attnum > 0 "\
330 "   AND NOT a.attisdropped "\
331 "   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
332 "   AND pg_catalog.quote_ident(relname)='%s' "\
333 "   AND pg_catalog.pg_table_is_visible(c.oid)"
334
335 #define Query_for_list_of_databases \
336 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
337 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
338
339 #define Query_for_list_of_tablespaces \
340 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
341 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
342
343 #define Query_for_list_of_encodings \
344 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
345 "   FROM pg_catalog.pg_conversion "\
346 "  WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
347
348 #define Query_for_list_of_languages \
349 "SELECT pg_catalog.quote_ident(lanname) "\
350 "  FROM pg_language "\
351 " WHERE lanname != 'internal' "\
352 "   AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
353
354 #define Query_for_list_of_schemas \
355 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
356 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
357
358 #define Query_for_list_of_system_relations \
359 "SELECT pg_catalog.quote_ident(relname) "\
360 "  FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
361 " WHERE c.relkind IN ('r', 'v', 's', 'S') "\
362 "   AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
363 "   AND c.relnamespace = n.oid "\
364 "   AND n.nspname = 'pg_catalog'"
365
366 #define Query_for_list_of_users \
367 " SELECT pg_catalog.quote_ident(usename) "\
368 "   FROM pg_catalog.pg_user "\
369 "  WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
370
371 #define Query_for_list_of_grant_users \
372 " SELECT pg_catalog.quote_ident(usename) "\
373 "   FROM pg_catalog.pg_user "\
374 "  WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"\
375 " UNION SELECT 'PUBLIC' UNION SELECT 'GROUP'"
376
377 /* the silly-looking length condition is just to eat up the current word */
378 #define Query_for_table_owning_index \
379 "SELECT pg_catalog.quote_ident(c1.relname) "\
380 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
381 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
382 "       and (%d = length('%s'))"\
383 "       and pg_catalog.quote_ident(c2.relname)='%s'"\
384 "       and pg_catalog.pg_table_is_visible(c2.oid)"
385
386 /* the silly-looking length condition is just to eat up the current word */
387 #define Query_for_index_of_table \
388 "SELECT pg_catalog.quote_ident(c2.relname) "\
389 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
390 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
391 "       and (%d = length('%s'))"\
392 "       and pg_catalog.quote_ident(c1.relname)='%s'"\
393 "       and pg_catalog.pg_table_is_visible(c2.oid)"
394
395 /* the silly-looking length condition is just to eat up the current word */
396 #define Query_for_list_of_tables_for_trigger \
397 "SELECT pg_catalog.quote_ident(relname) "\
398 "  FROM pg_catalog.pg_class"\
399 " WHERE (%d = length('%s'))"\
400 "   AND oid IN "\
401 "       (SELECT tgrelid FROM pg_catalog.pg_trigger "\
402 "         WHERE pg_catalog.quote_ident(tgname)='%s')"
403
404 /*
405  * This is a list of all "things" in Pgsql, which can show up after CREATE or
406  * DROP; and there is also a query to get a list of them.
407  */
408
409 typedef struct
410 {
411         const char *name;
412         const char *query;                      /* simple query, or NULL */
413         const SchemaQuery *squery;      /* schema query, or NULL */
414 } pgsql_thing_t;
415
416 static const pgsql_thing_t words_after_create[] = {
417         {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
418         {"CAST", NULL, NULL},           /* Casts have complex structures for
419                                                                  * names, so skip it */
420         /* CREATE CONSTRAINT TRIGGER is not supported here because it is designed to be used only by pg_dump. */
421         {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
422         {"DATABASE", Query_for_list_of_databases},
423         {"DOMAIN", NULL, &Query_for_list_of_domains},
424         {"FUNCTION", NULL, &Query_for_list_of_functions},
425         {"GROUP", "SELECT pg_catalog.quote_ident(groname) FROM pg_catalog.pg_group WHERE substring(pg_catalog.quote_ident(groname),1,%d)='%s'"},
426         {"LANGUAGE", Query_for_list_of_languages},
427         {"INDEX", NULL, &Query_for_list_of_indexes},
428         {"OPERATOR", NULL, NULL},       /* Querying for this is probably not such
429                                                                  * a good idea. */
430         {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
431         {"SCHEMA", Query_for_list_of_schemas},
432         {"SEQUENCE", NULL, &Query_for_list_of_sequences},
433         {"TABLE", NULL, &Query_for_list_of_tables},
434         {"TABLESPACE", Query_for_list_of_tablespaces},
435         {"TEMP", NULL, NULL},           /* for CREATE TEMP TABLE ... */
436         {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
437         {"TYPE", NULL, &Query_for_list_of_datatypes},
438         {"UNIQUE", NULL, NULL},         /* for CREATE UNIQUE INDEX ... */
439         {"USER", Query_for_list_of_users},
440         {"VIEW", NULL, &Query_for_list_of_views},
441         {NULL, NULL, NULL}                      /* end of list */
442 };
443
444
445 /* Forward declaration of functions */
446 static char **psql_completion(char *text, int start, int end);
447 static char *create_command_generator(const char *text, int state);
448 static char *complete_from_query(const char *text, int state);
449 static char *complete_from_schema_query(const char *text, int state);
450 static char *_complete_from_query(int is_schema_query,
451                                          const char *text, int state);
452 static char *complete_from_const(const char *text, int state);
453 static char *complete_from_list(const char *text, int state);
454
455 static PGresult *exec_query(const char *query);
456
457 static char *previous_word(int point, int skip);
458
459 #if 0
460 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
461 static char *dequote_file_name(char *text, char quote_char);
462 #endif
463
464
465 /* Initialize the readline library for our purposes. */
466 void
467 initialize_readline(void)
468 {
469         rl_readline_name = (char *) pset.progname;
470         rl_attempted_completion_function = (void *) psql_completion;
471
472         rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
473
474         completion_max_records = 1000;
475
476         /*
477          * There is a variable rl_completion_query_items for this but
478          * apparently it's not defined everywhere.
479          */
480 }
481
482
483 /* The completion function. Acc. to readline spec this gets passed the text
484    entered to far and its start and end in the readline buffer. The return value
485    is some partially obscure list format that can be generated by the readline
486    libraries completion_matches() function, so we don't have to worry about it.
487 */
488 static char **
489 psql_completion(char *text, int start, int end)
490 {
491         /* This is the variable we'll return. */
492         char      **matches = NULL;
493
494         /* These are going to contain some scannage of the input line. */
495         char       *prev_wd,
496                            *prev2_wd,
497                            *prev3_wd,
498                            *prev4_wd,
499                            *prev5_wd;
500
501         static const char *const sql_commands[] = {
502                 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
503                 "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE FROM", "DROP", "END", "EXECUTE",
504                 "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
505                 "PREPARE", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", "SAVEPOINT",
506                 "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
507         };
508
509         static const char *const pgsql_variables[] = {
510                 /* these SET arguments are known in gram.y */
511                 "CONSTRAINTS",
512                 "NAMES",
513                 "SESSION",
514                 "TRANSACTION",
515
516                 /*
517                  * the rest should match USERSET and possibly SUSET entries in
518                  * backend/utils/misc/guc.c.
519                  */
520                 "add_missing_from",
521                 "australian_timezones",
522                 "client_encoding",
523                 "client_min_messages",
524                 "commit_delay",
525                 "commit_siblings",
526                 "cpu_index_tuple_cost",
527                 "cpu_operator_cost",
528                 "cpu_tuple_cost",
529                 "DateStyle",
530                 "deadlock_timeout",
531                 "debug_pretty_print",
532                 "debug_print_parse",
533                 "debug_print_plan",
534                 "debug_print_rewritten",
535                 "default_statistics_target",
536                 "default_tablespace",
537                 "default_transaction_isolation",
538                 "default_transaction_read_only",
539                 "default_with_oids",
540                 "dynamic_library_path",
541                 "effective_cache_size",
542                 "enable_bitmapscan",
543                 "enable_hashagg",
544                 "enable_hashjoin",
545                 "enable_indexscan",
546                 "enable_mergejoin",
547                 "enable_nestloop",
548                 "enable_seqscan",
549                 "enable_sort",
550                 "enable_tidscan",
551                 "explain_pretty_print",
552                 "extra_float_digits",
553                 "from_collapse_limit",
554                 "fsync",
555                 "geqo",
556                 "geqo_effort",
557                 "geqo_generations",
558                 "geqo_pool_size",
559                 "geqo_selection_bias",
560                 "geqo_threshold",
561                 "join_collapse_limit",
562                 "lc_messages",
563                 "lc_monetary",
564                 "lc_numeric",
565                 "lc_time",
566                 "log_destination",
567                 "log_duration",
568                 "log_error_verbosity",
569                 "log_executor_stats",
570                 "log_min_duration_statement",
571                 "log_min_error_statement",
572                 "log_min_messages",
573                 "log_parser_stats",
574                 "log_planner_stats",
575                 "log_statement",
576                 "log_statement_stats",
577                 "maintenance_work_mem",
578                 "max_connections",
579                 "max_files_per_process",
580                 "max_fsm_pages",
581                 "max_fsm_relations",
582                 "max_locks_per_transaction",
583                 "max_stack_depth",
584                 "password_encryption",
585                 "port",
586                 "random_page_cost",
587                 "regex_flavor",
588                 "search_path",
589                 "shared_buffers",
590                 "seed",
591                 "server_encoding",
592                 "sql_inheritance",
593                 "ssl",
594                 "statement_timeout",
595                 "stats_block_level",
596                 "stats_command_string",
597                 "stats_reset_on_server_start",
598                 "stats_row_level",
599                 "stats_start_collector",
600                 "superuser_reserved_connections",
601                 "syslog_facility",
602                 "syslog_ident",
603                 "temp_buffers",
604                 "TimeZone",
605                 "trace_notify",
606                 "transform_null_equals",
607                 "unix_socket_directory",
608                 "unix_socket_group",
609                 "unix_socket_permissions",
610                 "wal_buffers",
611                 "wal_debug",
612                 "wal_sync_method",
613                 "work_mem",
614                 NULL
615         };
616
617         static const char *const backslash_commands[] = {
618                 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
619                 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
620                 "\\dg", "\\di", "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS",
621                 "\\dt", "\\dT", "\\dv", "\\du",
622                 "\\e", "\\echo", "\\encoding",
623                 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
624                 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
625                 "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
626                 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
627         };
628
629         (void) end;                                     /* not used */
630
631 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
632         rl_completion_append_character = ' ';
633 #endif
634
635         /* Clear a few things. */
636         completion_charp = NULL;
637         completion_charpp = NULL;
638         completion_info_charp = NULL;
639
640         /*
641          * Scan the input line before our current position for the last four
642          * words. According to those we'll make some smart decisions on what
643          * the user is probably intending to type. TODO: Use strtokx() to do
644          * this.
645          */
646         prev_wd = previous_word(start, 0);
647         prev2_wd = previous_word(start, 1);
648         prev3_wd = previous_word(start, 2);
649         prev4_wd = previous_word(start, 3);
650         prev5_wd = previous_word(start, 4);
651
652         /* If a backslash command was started, continue */
653         if (text[0] == '\\')
654                 COMPLETE_WITH_LIST(backslash_commands);
655
656         /* If no previous word, suggest one of the basic sql commands */
657         else if (!prev_wd)
658                 COMPLETE_WITH_LIST(sql_commands);
659
660 /* CREATE or DROP but not ALTER (TABLE|DOMAIN|GROUP) sth DROP */
661         /* complete with something you can create or drop */
662         else if (pg_strcasecmp(prev_wd, "CREATE") == 0 ||
663                          (pg_strcasecmp(prev_wd, "DROP") == 0 &&
664                           pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
665                           pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
666                           pg_strcasecmp(prev3_wd, "GROUP") != 0))
667                 matches = completion_matches(text, create_command_generator);
668
669 /* ALTER */
670
671         /*
672          * complete with what you can alter (TABLE, GROUP, USER, ...) unless
673          * we're in ALTER TABLE sth ALTER
674          */
675         else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
676                          pg_strcasecmp(prev3_wd, "TABLE") != 0)
677         {
678                 static const char *const list_ALTER[] =
679                 {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
680                         "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "SCHEMA", "SEQUENCE", "TABLE",
681                 "TABLESPACE", "TRIGGER", "TYPE", "USER", NULL};
682
683                 COMPLETE_WITH_LIST(list_ALTER);
684         }
685
686         /* ALTER AGGREGATE,CONVERSION,FUNCTION,SCHEMA <name> */
687         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
688                          (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
689                           pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
690                           pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
691                           pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
692         {
693                 static const char *const list_ALTERGEN[] =
694                 {"OWNER TO", "RENAME TO", NULL};
695
696                 COMPLETE_WITH_LIST(list_ALTERGEN);
697         }
698
699         /* ALTER DATABASE <name> */
700         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
701                          pg_strcasecmp(prev2_wd, "DATABASE") == 0)
702         {
703                 static const char *const list_ALTERDATABASE[] =
704                 {"RESET", "SET", "OWNER TO", "RENAME TO", NULL};
705
706                 COMPLETE_WITH_LIST(list_ALTERDATABASE);
707         }
708
709         /* ALTER INDEX <name> */
710         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
711                          pg_strcasecmp(prev2_wd, "INDEX") == 0)
712         {
713                 static const char *const list_ALTERINDEX[] =
714                 {"SET TABLESPACE", "OWNER TO", "RENAME TO", NULL};
715
716                 COMPLETE_WITH_LIST(list_ALTERINDEX);
717         }
718
719         /* ALTER LANGUAGE <name> */
720         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
721                          pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
722                 COMPLETE_WITH_CONST("RENAME TO");
723
724         /* ALTER USER <name> */
725         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
726                          pg_strcasecmp(prev2_wd, "USER") == 0)
727         {
728                 static const char *const list_ALTERUSER[] =
729                 {"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
730                  "NOCREATEUSER", "VALID UNTIL", "RENAME TO", "SET", "RESET", NULL};
731
732                 COMPLETE_WITH_LIST(list_ALTERUSER);
733         }
734
735         /* ALTER DOMAIN <name> */
736         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
737                          pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
738         {
739                 static const char *const list_ALTERDOMAIN[] =
740                 {"ADD", "DROP", "OWNER TO", "SET", NULL};
741
742                 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
743         }
744         /* ALTER DOMAIN <sth> DROP */
745         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
746                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
747                          pg_strcasecmp(prev_wd, "DROP") == 0)
748         {
749                 static const char *const list_ALTERDOMAIN2[] =
750                 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
751
752                 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
753         }
754         /* ALTER DOMAIN <sth> SET */
755         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
756                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
757                          pg_strcasecmp(prev_wd, "SET") == 0)
758         {
759                 static const char *const list_ALTERDOMAIN3[] =
760                 {"DEFAULT", "NOT NULL", NULL};
761
762                 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
763         }
764         /* ALTER SEQUENCE <name> */
765         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
766                          pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
767         {
768                         static const char *const list_ALTERSCHEMA[] =
769                         {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE", NULL};
770
771                         COMPLETE_WITH_LIST(list_ALTERSCHEMA);
772         }
773         /* ALTER SEQUENCE <name> NO */
774         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
775                          pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
776                          pg_strcasecmp(prev_wd, "NO") == 0)
777         {
778                         static const char *const list_ALTERSCHEMA2[] =
779                         {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
780
781                         COMPLETE_WITH_LIST(list_ALTERSCHEMA2);
782         }
783         /* ALTER TRIGGER <name>, add ON */
784         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
785                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
786                 COMPLETE_WITH_CONST("ON");
787
788         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
789                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
790         {
791                 completion_info_charp = prev2_wd;
792                 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
793         }
794
795         /*
796          * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
797          */
798         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
799                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
800                          pg_strcasecmp(prev_wd, "ON") == 0)
801                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
802
803         /* ALTER TRIGGER <name> ON <name> */
804         else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
805                          pg_strcasecmp(prev2_wd, "ON") == 0)
806                 COMPLETE_WITH_CONST("RENAME TO");
807
808         /*
809          * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
810          * RENAME, CLUSTER ON or OWNER
811          */
812         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
813                          pg_strcasecmp(prev2_wd, "TABLE") == 0)
814         {
815                 static const char *const list_ALTER2[] =
816                 {"ADD", "ALTER", "CLUSTER ON", "DROP", "RENAME", "OWNER TO",
817                 "SET", NULL};
818
819                 COMPLETE_WITH_LIST(list_ALTER2);
820         }
821         /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
822         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
823                          (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
824                           pg_strcasecmp(prev_wd, "RENAME") == 0))
825                 COMPLETE_WITH_ATTR(prev2_wd);
826
827         /* ALTER TABLE xxx RENAME yyy */
828         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
829                          pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
830                          pg_strcasecmp(prev_wd, "TO") != 0)
831                 COMPLETE_WITH_CONST("TO");
832
833         /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
834         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
835                          pg_strcasecmp(prev_wd, "DROP") == 0)
836         {
837                 static const char *const list_TABLEDROP[] =
838                 {"COLUMN", "CONSTRAINT", NULL};
839
840                 COMPLETE_WITH_LIST(list_TABLEDROP);
841         }
842         /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
843         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
844                          pg_strcasecmp(prev2_wd, "DROP") == 0 &&
845                          pg_strcasecmp(prev_wd, "COLUMN") == 0)
846                 COMPLETE_WITH_ATTR(prev3_wd);
847         /* ALTER TABLE ALTER [COLUMN] <foo> */
848         else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
849                           pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
850                          (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
851                           pg_strcasecmp(prev2_wd, "ALTER") == 0))
852         {
853                 /* DROP ... does not work well yet */
854                 static const char *const list_COLUMNALTER[] = 
855                 {"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
856                  "DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
857
858                 COMPLETE_WITH_LIST(list_COLUMNALTER);
859         }
860         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
861                          pg_strcasecmp(prev_wd, "CLUSTER") == 0)
862                 COMPLETE_WITH_CONST("ON");
863         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
864                          pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
865                          pg_strcasecmp(prev_wd, "ON") == 0)
866         {
867                 completion_info_charp = prev3_wd;
868                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
869         }
870         /* If we have TABLE <sth> SET, provide WITHOUT or TABLESPACE */
871         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
872                          pg_strcasecmp(prev_wd, "SET") == 0)
873         {
874                 static const char *const list_TABLESET[] =
875                 {"WITHOUT", "TABLESPACE", NULL};
876
877                 COMPLETE_WITH_LIST(list_TABLESET);
878         }
879         /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
880         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
881                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
882                          pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
883                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
884         /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
885         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
886                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
887                          pg_strcasecmp(prev_wd, "WITHOUT") == 0)
888         {
889                 static const char *const list_TABLESET2[] =
890                 {"CLUSTER", "OIDS", NULL};
891
892                 COMPLETE_WITH_LIST(list_TABLESET2);
893         }
894         /* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */
895         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
896                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
897         {
898                 static const char *const list_ALTERTSPC[] =
899                 {"RENAME TO", "OWNER TO", NULL};
900
901                 COMPLETE_WITH_LIST(list_ALTERTSPC);
902         }
903         /* complete ALTER TYPE <foo> with OWNER TO */
904         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
905                          pg_strcasecmp(prev2_wd, "TYPE") == 0)
906                 COMPLETE_WITH_CONST("OWNER TO");
907         /* complete ALTER GROUP <foo> */
908         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
909                          pg_strcasecmp(prev2_wd, "GROUP") == 0)
910         {
911                 static const char *const list_ALTERGROUP[] =
912                 {"ADD USER", "DROP USER", "RENAME TO", NULL};
913
914                 COMPLETE_WITH_LIST(list_ALTERGROUP);
915         }
916         /* complete ALTER GROUP <foo> ADD|DROP with USER */
917         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
918                          pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
919                          (pg_strcasecmp(prev_wd, "ADD") == 0 ||
920                           pg_strcasecmp(prev_wd, "DROP") == 0))
921                 COMPLETE_WITH_CONST("USER");
922         /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
923         else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
924                          (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
925                           pg_strcasecmp(prev2_wd, "DROP") == 0) &&
926                          pg_strcasecmp(prev_wd, "USER") == 0)
927                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
928
929 /* BEGIN, END, COMMIT, ABORT */
930         else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
931                          pg_strcasecmp(prev_wd, "END") == 0 ||
932                          pg_strcasecmp(prev_wd, "COMMIT") == 0 ||
933                          pg_strcasecmp(prev_wd, "ABORT") == 0)
934         {
935                 static const char *const list_TRANS[] =
936                 {"WORK", "TRANSACTION", NULL};
937
938                 COMPLETE_WITH_LIST(list_TRANS);
939         }
940 /* RELEASE SAVEPOINT */
941         else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
942                 COMPLETE_WITH_CONST("SAVEPOINT");
943 /* ROLLBACK*/
944         else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
945         {
946                 static const char *const list_TRANS[] =
947                 {"WORK", "TRANSACTION", "TO SAVEPOINT", NULL};
948
949                 COMPLETE_WITH_LIST(list_TRANS);
950         }
951 /* CLUSTER */
952
953         /*
954          * If the previous word is CLUSTER and not without produce list of
955          * indexes.
956          */
957         else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
958                          pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
959                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
960         /* If we have CLUSTER <sth>, then add "ON" */
961         else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
962                          pg_strcasecmp(prev_wd, "ON") != 0)
963                 COMPLETE_WITH_CONST("ON");
964
965         /*
966          * If we have CLUSTER <sth> ON, then add the correct tablename as
967          * well.
968          */
969         else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
970                          pg_strcasecmp(prev_wd, "ON") == 0)
971         {
972                 completion_info_charp = prev2_wd;
973                 COMPLETE_WITH_QUERY(Query_for_table_owning_index);
974         }
975
976 /* COMMENT */
977         else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
978                 COMPLETE_WITH_CONST("ON");
979         else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
980                          pg_strcasecmp(prev_wd, "ON") == 0)
981         {
982                 static const char *const list_COMMENT[] =
983                 {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
984                         "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
985                 "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
986
987                 COMPLETE_WITH_LIST(list_COMMENT);
988         }
989         else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
990                          pg_strcasecmp(prev3_wd, "ON") == 0)
991                 COMPLETE_WITH_CONST("IS");
992
993 /* COPY */
994
995         /*
996          * If we have COPY [BINARY] (which you'd have to type yourself), offer
997          * list of tables (Also cover the analogous backslash command)
998          */
999         else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1000                          pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1001                          (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1002                           pg_strcasecmp(prev_wd, "BINARY") == 0))
1003                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1004         /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1005         else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1006                          pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1007                          pg_strcasecmp(prev2_wd, "BINARY") == 0)
1008                 {
1009                         static const char *const list_FROMTO[] =
1010                         {"FROM", "TO", NULL};
1011
1012                         COMPLETE_WITH_LIST(list_FROMTO);
1013                 }
1014         /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1015         else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1016                           pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1017                           pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1018                          (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1019                           pg_strcasecmp(prev_wd, "TO") == 0))
1020                 matches = completion_matches(text, filename_completion_function);
1021
1022         /* Handle COPY|BINARY <sth> FROM|TO filename */
1023         else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1024                           pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1025                           pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1026                          (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1027                           pg_strcasecmp(prev2_wd, "TO") == 0))
1028                 {
1029                         static const char *const list_COPY[] =
1030                         {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", NULL};
1031
1032                         COMPLETE_WITH_LIST(list_COPY);
1033                 }
1034
1035         /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1036         else if (pg_strcasecmp(prev_wd, "CSV") == 0 && 
1037                          (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1038                           pg_strcasecmp(prev3_wd, "TO") == 0))
1039                 {
1040                         static const char *const list_CSV[] =
1041                         {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
1042
1043                         COMPLETE_WITH_LIST(list_CSV);
1044                 }
1045
1046 /* CREATE INDEX */
1047         /* First off we complete CREATE UNIQUE with "INDEX" */
1048         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1049                          pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1050                 COMPLETE_WITH_CONST("INDEX");
1051         /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
1052         else if (pg_strcasecmp(prev2_wd, "INDEX") == 0 &&
1053                          (pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1054                           pg_strcasecmp(prev3_wd, "UNIQUE") == 0))
1055                 COMPLETE_WITH_CONST("ON");
1056         /* Complete ... INDEX <name> ON with a list of tables  */
1057         else if (pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1058                          pg_strcasecmp(prev_wd, "ON") == 0)
1059                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1060
1061         /*
1062          * Complete INDEX <name> ON <table> with a list of table columns
1063          * (which should really be in parens)
1064          */
1065         else if (pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1066                          pg_strcasecmp(prev2_wd, "ON") == 0)
1067                 COMPLETE_WITH_ATTR(prev_wd);
1068         /* same if you put in USING */
1069         else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1070                          pg_strcasecmp(prev2_wd, "USING") == 0)
1071                 COMPLETE_WITH_ATTR(prev3_wd);
1072         /* Complete USING with an index method */
1073         else if (pg_strcasecmp(prev_wd, "USING") == 0)
1074         {
1075                 static const char *const index_mth[] =
1076                 {"BTREE", "RTREE", "HASH", "GIST", NULL};
1077
1078                 COMPLETE_WITH_LIST(index_mth);
1079         }
1080
1081 /* CREATE RULE */
1082         /* Complete "CREATE RULE <sth>" with "AS" */
1083         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1084                          pg_strcasecmp(prev2_wd, "RULE") == 0)
1085                 COMPLETE_WITH_CONST("AS");
1086         /* Complete "CREATE RULE <sth> AS with "ON" */
1087         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1088                          pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1089                          pg_strcasecmp(prev_wd, "AS") == 0)
1090                 COMPLETE_WITH_CONST("ON");
1091         /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1092         else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1093                          pg_strcasecmp(prev2_wd, "AS") == 0 &&
1094                          pg_strcasecmp(prev_wd, "ON") == 0)
1095         {
1096                 static const char *const rule_events[] =
1097                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1098
1099                 COMPLETE_WITH_LIST(rule_events);
1100         }
1101         /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1102         else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1103                          pg_strcasecmp(prev2_wd, "ON") == 0 &&
1104                          (toupper((unsigned char) prev_wd[4]) == 'T' ||
1105                           toupper((unsigned char) prev_wd[5]) == 'T'))
1106                 COMPLETE_WITH_CONST("TO");
1107         /* Complete "AS ON <sth> TO" with a table name */
1108         else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1109                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1110                          pg_strcasecmp(prev_wd, "TO") == 0)
1111                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1112
1113 /* CREATE TABLE */
1114         /* Complete CREATE TEMP with "TABLE" */
1115         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1116                          pg_strcasecmp(prev_wd, "TEMP") == 0)
1117                 COMPLETE_WITH_CONST("TABLE");
1118
1119 /* CREATE TABLESPACE */
1120         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1121                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1122         {
1123                 static const char *const list_CREATETABLESPACE[] =
1124                 {"OWNER", "LOCATION", NULL};
1125
1126                 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1127         }
1128         /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1129         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1130                          pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1131                          pg_strcasecmp(prev2_wd, "OWNER") == 0)
1132         {
1133                 COMPLETE_WITH_CONST("LOCATION");
1134         }
1135
1136 /* CREATE TRIGGER */
1137         /* is on the agenda . . . */
1138
1139 /* CREATE VIEW */
1140         /* Complete "CREATE VIEW <name>" with "AS" */
1141         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1142                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
1143                 COMPLETE_WITH_CONST("AS");
1144         /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1145         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1146                          pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1147                          pg_strcasecmp(prev_wd, "AS") == 0)
1148                 COMPLETE_WITH_CONST("SELECT");
1149
1150 /* DECLARE */
1151         else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1152         {
1153                         static const char *const list_DECLARE[] =
1154                         {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1155                         COMPLETE_WITH_LIST(list_DECLARE);
1156         }
1157
1158         else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1159         {
1160                         static const char *const list_DECLARECURSOR[] =
1161                         {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1162                         COMPLETE_WITH_LIST(list_DECLARECURSOR);
1163         }
1164
1165
1166 /* DELETE */
1167         /*
1168          * Complete DELETE with FROM (only if the word before that is not "ON"
1169          * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1170          */
1171         else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1172                          !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1173                            pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1174                            pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1175                            pg_strcasecmp(prev2_wd, "AFTER") == 0))
1176                 COMPLETE_WITH_CONST("FROM");
1177         /* Complete DELETE FROM with a list of tables */
1178         else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1179                          pg_strcasecmp(prev_wd, "FROM") == 0)
1180                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1181         /* Complete DELETE FROM <table> */
1182         else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1183                          pg_strcasecmp(prev2_wd, "FROM") == 0)
1184         {
1185                 static const char *const list_DELETE[] =
1186                 {"USING", "WHERE", "SET", NULL};
1187
1188                 COMPLETE_WITH_LIST(list_DELETE);
1189         }
1190         /* XXX: implement tab completion for DELETE ... USING */
1191
1192 /* DROP (when not the previous word) */
1193         /* DROP AGGREGATE */
1194         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1195                          pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1196                 COMPLETE_WITH_CONST("(");
1197
1198         /* DROP object with CASCADE / RESTRICT */
1199         else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1200                           (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1201                            pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1202                            pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1203                            pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1204                            pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1205                            pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1206                            pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1207                            pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1208                            pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1209                            pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1210                          (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1211                           pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1212                           prev_wd[strlen(prev_wd) - 1] == ')'))
1213         {
1214                         static const char *const list_DROPCR[] =
1215                         {"CASCADE", "RESTRICT", NULL};
1216                         COMPLETE_WITH_LIST(list_DROPCR);
1217         }
1218
1219 /* EXPLAIN */
1220         /*
1221          * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1222          */
1223         else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1224         {
1225                         static const char *const list_EXPLAIN[] =
1226                         {"SELECT","INSERT","DELETE","UPDATE","DECLARE","ANALYZE","VERBOSE",NULL};
1227                         COMPLETE_WITH_LIST(list_EXPLAIN);
1228         }
1229         else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1230                                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1231         {
1232                         static const char *const list_EXPLAIN[] =
1233                         {"SELECT","INSERT","DELETE","UPDATE","DECLARE","VERBOSE",NULL};
1234                         COMPLETE_WITH_LIST(list_EXPLAIN);
1235         }
1236         else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1237                          pg_strcasecmp(prev3_wd, "VACUUM") != 0 &&
1238                          pg_strcasecmp(prev4_wd, "VACUUM") != 0 &&
1239                          (pg_strcasecmp(prev2_wd, "ANALYZE") == 0 ||
1240                           pg_strcasecmp(prev2_wd, "EXPLAIN") == 0))
1241         {
1242                         static const char *const list_EXPLAIN[] =
1243                         {"SELECT","INSERT","DELETE","UPDATE","DECLARE",NULL};
1244                         COMPLETE_WITH_LIST(list_EXPLAIN);
1245         }
1246
1247 /* FETCH && MOVE */
1248         /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1249         else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1250                          pg_strcasecmp(prev_wd, "MOVE") == 0)
1251         {
1252                 static const char *const list_FETCH1[] =
1253                 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1254
1255                 COMPLETE_WITH_LIST(list_FETCH1);
1256         }
1257         /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1258         else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1259                          pg_strcasecmp(prev2_wd, "MOVE") == 0)
1260         {
1261                 static const char *const list_FETCH2[] =
1262                 {"ALL", "NEXT", "PRIOR", NULL};
1263
1264                 COMPLETE_WITH_LIST(list_FETCH2);
1265         }
1266
1267         /*
1268          * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are
1269          * equivalent, but we may as well tab-complete both: perhaps some
1270          * users prefer one variant or the other.
1271          */
1272         else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
1273                          pg_strcasecmp(prev3_wd, "MOVE") == 0)
1274         {
1275                 static const char *const list_FROMIN[] =
1276                 {"FROM", "IN", NULL};
1277
1278                 COMPLETE_WITH_LIST(list_FROMIN);
1279         }
1280
1281 /* GRANT && REVOKE*/
1282         /* Complete GRANT/REVOKE with a list of privileges */
1283         else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
1284                          pg_strcasecmp(prev_wd, "REVOKE") == 0)
1285         {
1286                 static const char *const list_privileg[] =
1287                 {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
1288                 "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
1289
1290                 COMPLETE_WITH_LIST(list_privileg);
1291         }
1292         /* Complete GRANT/REVOKE <sth> with "ON" */
1293         else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1294                          pg_strcasecmp(prev2_wd, "REVOKE") == 0)
1295                 COMPLETE_WITH_CONST("ON");
1296
1297         /*
1298          * Complete GRANT/REVOKE <sth> ON with a list of tables, views,
1299          * sequences, and indexes
1300          *
1301          * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result
1302          * via UNION; seems to work intuitively
1303          *
1304          * Note: GRANT/REVOKE can get quite complex; tab-completion as
1305          * implemented here will only work if the privilege list contains
1306          * exactly one privilege
1307          */
1308         else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
1309                           pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
1310                          pg_strcasecmp(prev_wd, "ON") == 0)
1311                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
1312                                                                    " UNION SELECT 'DATABASE'"
1313                                                                    " UNION SELECT 'FUNCTION'"
1314                                                                    " UNION SELECT 'LANGUAGE'"
1315                                                                    " UNION SELECT 'SCHEMA'"
1316                                                                    " UNION SELECT 'TABLESPACE'");
1317
1318         /* Complete "GRANT/REVOKE * ON * " with "TO" */
1319         else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1320                           pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1321                          pg_strcasecmp(prev2_wd, "ON") == 0)
1322         {
1323                 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1324                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1325                 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
1326                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1327                 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
1328                         COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1329                 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
1330                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1331                 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1332                         COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1333                 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
1334                         COMPLETE_WITH_CONST("TO");
1335                 else
1336                         COMPLETE_WITH_CONST("FROM");
1337         }
1338
1339         /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1340         else if (pg_strcasecmp(prev3_wd, "ON") == 0 &&
1341                          ((pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
1342                            pg_strcasecmp(prev_wd, "TO") == 0) ||
1343                           (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
1344                            pg_strcasecmp(prev_wd, "FROM") == 0)))
1345                 COMPLETE_WITH_QUERY(Query_for_list_of_grant_users);
1346
1347 /* GROUP BY */
1348         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1349                          pg_strcasecmp(prev_wd, "GROUP") == 0)
1350                 COMPLETE_WITH_CONST("BY");
1351
1352 /* INSERT */
1353         /* Complete INSERT with "INTO" */
1354         else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
1355                 COMPLETE_WITH_CONST("INTO");
1356         /* Complete INSERT INTO with table names */
1357         else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
1358                          pg_strcasecmp(prev_wd, "INTO") == 0)
1359                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1360         /* Complete "INSERT INTO <table> (" with attribute names */
1361         else if (rl_line_buffer[start - 1] == '(' &&
1362                          pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1363                          pg_strcasecmp(prev2_wd, "INTO") == 0)
1364                 COMPLETE_WITH_ATTR(prev_wd);
1365
1366         /*
1367          * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1368          * VALUES"
1369          */
1370         else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1371                          pg_strcasecmp(prev2_wd, "INTO") == 0)
1372         {
1373                 static const char *const list_INSERT[] =
1374                 {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1375
1376                 COMPLETE_WITH_LIST(list_INSERT);
1377         }
1378         /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1379         else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
1380                          pg_strcasecmp(prev3_wd, "INTO") == 0 &&
1381                          prev_wd[strlen(prev_wd) - 1] == ')')
1382         {
1383                 static const char *const list_INSERT[] =
1384                 {"SELECT", "VALUES", NULL};
1385
1386                 COMPLETE_WITH_LIST(list_INSERT);
1387         }
1388
1389         /* Insert an open parenthesis after "VALUES" */
1390         else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
1391                          pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
1392                 COMPLETE_WITH_CONST("(");
1393
1394 /* LOCK */
1395         /* Complete LOCK [TABLE] with a list of tables */
1396         else if (pg_strcasecmp(prev_wd, "LOCK") == 0 ||
1397                          (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
1398                           pg_strcasecmp(prev2_wd, "LOCK") == 0))
1399                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1400
1401         /* For the following, handle the case of a single table only for now */
1402
1403         /* Complete LOCK [TABLE] <table> with "IN" */
1404         else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
1405                           pg_strcasecmp(prev_wd, "TABLE")) ||
1406                          (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
1407                           pg_strcasecmp(prev3_wd, "LOCK") == 0))
1408                 COMPLETE_WITH_CONST("IN");
1409
1410         /* Complete LOCK [TABLE] <table> IN with a lock mode */
1411         else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
1412                          (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
1413                           (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1414                            pg_strcasecmp(prev4_wd, "LOCK") == 0)))
1415         {
1416                 static const char *const lock_modes[] =
1417                 {"ACCESS SHARE MODE",
1418                         "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1419                         "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1420                         "SHARE ROW EXCLUSIVE MODE",
1421                 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1422
1423                 COMPLETE_WITH_LIST(lock_modes);
1424         }
1425
1426 /* NOTIFY */
1427         else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
1428                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1429
1430 /* OWNER TO  - complete with available users*/
1431         else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
1432                          pg_strcasecmp(prev_wd, "TO") == 0)
1433                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1434
1435 /* ORDER BY */
1436         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1437                          pg_strcasecmp(prev_wd, "ORDER") == 0)
1438                 COMPLETE_WITH_CONST("BY");
1439         else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
1440                          pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
1441                          pg_strcasecmp(prev_wd, "BY") == 0)
1442                 COMPLETE_WITH_ATTR(prev3_wd);
1443
1444 /* PREPARE xx AS */
1445         else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
1446                          pg_strcasecmp(prev3_wd, "PREPARE") == 0)
1447         {
1448                 static const char *const list_PREPARE[] =
1449                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1450
1451                 COMPLETE_WITH_LIST(list_PREPARE);
1452         }
1453
1454
1455 /* REINDEX */
1456         else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
1457         {
1458                 static const char *const list_REINDEX[] =
1459                 {"TABLE", "DATABASE", "INDEX", NULL};
1460
1461                 COMPLETE_WITH_LIST(list_REINDEX);
1462         }
1463         else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
1464         {
1465                 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
1466                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1467                 else if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1468                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1469                 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
1470                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1471         }
1472
1473 /* SELECT */
1474         /* naah . . . */
1475
1476 /* SET, RESET, SHOW */
1477         /* Complete with a variable name */
1478         else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
1479                           pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
1480                          pg_strcasecmp(prev_wd, "RESET") == 0 ||
1481                          pg_strcasecmp(prev_wd, "SHOW") == 0)
1482                 COMPLETE_WITH_LIST(pgsql_variables);
1483         /* Complete "SET TRANSACTION" */
1484         else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
1485                           pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1486                          || (pg_strcasecmp(prev2_wd, "START") == 0
1487                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1488                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1489                                  && pg_strcasecmp(prev_wd, "WORK") == 0)
1490                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1491                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1492                          || (pg_strcasecmp(prev4_wd, "SESSION") == 0
1493                                  && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
1494                                  && pg_strcasecmp(prev2_wd, "AS") == 0
1495                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
1496         {
1497                 static const char *const my_list[] =
1498                 {"ISOLATION LEVEL", "READ", NULL};
1499
1500                 COMPLETE_WITH_LIST(my_list);
1501         }
1502         else if ((pg_strcasecmp(prev3_wd, "SET") == 0
1503                           || pg_strcasecmp(prev3_wd, "BEGIN") == 0
1504                           || pg_strcasecmp(prev3_wd, "START") == 0
1505                           || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
1506                                   && pg_strcasecmp(prev3_wd, "AS") == 0))
1507                          && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
1508                                  || pg_strcasecmp(prev2_wd, "WORK") == 0)
1509                          && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
1510                 COMPLETE_WITH_CONST("LEVEL");
1511         else if ((pg_strcasecmp(prev4_wd, "SET") == 0
1512                           || pg_strcasecmp(prev4_wd, "BEGIN") == 0
1513                           || pg_strcasecmp(prev4_wd, "START") == 0
1514                           || pg_strcasecmp(prev4_wd, "AS") == 0)
1515                          && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
1516                                  || pg_strcasecmp(prev3_wd, "WORK") == 0)
1517                          && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
1518                          && pg_strcasecmp(prev_wd, "LEVEL") == 0)
1519         {
1520                 static const char *const my_list[] =
1521                 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
1522
1523                 COMPLETE_WITH_LIST(my_list);
1524         }
1525         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1526                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1527                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1528                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1529                          pg_strcasecmp(prev_wd, "READ") == 0)
1530         {
1531                 static const char *const my_list[] =
1532                 {"UNCOMMITTED", "COMMITTED", NULL};
1533
1534                 COMPLETE_WITH_LIST(my_list);
1535         }
1536         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1537                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1538                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1539                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1540                          pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
1541                 COMPLETE_WITH_CONST("READ");
1542         else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
1543                           pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
1544                           pg_strcasecmp(prev3_wd, "START") == 0 ||
1545                           pg_strcasecmp(prev3_wd, "AS") == 0) &&
1546                          (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
1547                           pg_strcasecmp(prev2_wd, "WORK") == 0) &&
1548                          pg_strcasecmp(prev_wd, "READ") == 0)
1549         {
1550                 static const char *const my_list[] =
1551                 {"ONLY", "WRITE", NULL};
1552
1553                 COMPLETE_WITH_LIST(my_list);
1554         }
1555         /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1556         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1557                          pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1558         {
1559                 static const char *const constraint_list[] =
1560                 {"DEFERRED", "IMMEDIATE", NULL};
1561
1562                 COMPLETE_WITH_LIST(constraint_list);
1563         }
1564         /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1565         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1566                          pg_strcasecmp(prev_wd, "SESSION") == 0)
1567         {
1568                 static const char *const my_list[] =
1569                 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
1570
1571                 COMPLETE_WITH_LIST(my_list);
1572         }
1573         /* Complete SET SESSION AUTHORIZATION with username */
1574         else if (pg_strcasecmp(prev3_wd, "SET") == 0
1575                          && pg_strcasecmp(prev2_wd, "SESSION") == 0
1576                          && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1577                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1578         /* Complete SET <var> with "TO" */
1579         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1580                          pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
1581                          pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
1582                          pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
1583                 COMPLETE_WITH_CONST("TO");
1584         /* Suggest possible variable values */
1585         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1586                 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1587         {
1588                 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
1589                 {
1590                         static const char *const my_list[] =
1591                         {"ISO", "SQL", "Postgres", "German",
1592                          "YMD", "DMY", "MDY",
1593                          "US", "European", "NonEuropean",
1594                         "DEFAULT", NULL};
1595
1596                         COMPLETE_WITH_LIST(my_list);
1597                 }
1598                 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
1599                 {
1600                         static const char *const my_list[] =
1601                         {"ON", "OFF", "DEFAULT", NULL};
1602
1603                         COMPLETE_WITH_LIST(my_list);
1604                 }
1605                 else
1606                 {
1607                         static const char *const my_list[] =
1608                         {"DEFAULT", NULL};
1609
1610                         COMPLETE_WITH_LIST(my_list);
1611                 }
1612         }
1613
1614 /* START TRANSACTION */
1615         else if (pg_strcasecmp(prev_wd, "START") == 0)
1616                 COMPLETE_WITH_CONST("TRANSACTION");
1617
1618 /* TRUNCATE */
1619         else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
1620                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1621
1622 /* UNLISTEN */
1623         else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
1624                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s' UNION SELECT '*'");
1625
1626 /* UPDATE */
1627         /* If prev. word is UPDATE suggest a list of tables */
1628         else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
1629                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1630         /* Complete UPDATE <table> with "SET" */
1631         else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
1632                 COMPLETE_WITH_CONST("SET");
1633
1634         /*
1635          * If the previous word is SET (and it wasn't caught above as the
1636          * _first_ word) the word before it was (hopefully) a table name and
1637          * we'll now make a list of attributes.
1638          */
1639         else if (pg_strcasecmp(prev_wd, "SET") == 0)
1640                 COMPLETE_WITH_ATTR(prev2_wd);
1641
1642 /* UPDATE xx SET yy = */
1643         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1644                                          pg_strcasecmp(prev4_wd, "UPDATE") == 0)
1645                 COMPLETE_WITH_CONST("=");
1646
1647 /*
1648  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
1649  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
1650  */
1651         else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
1652                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1653                                                                    " UNION SELECT 'FULL'"
1654                                                                    " UNION SELECT 'FREEZE'"
1655                                                                    " UNION SELECT 'ANALYZE'"
1656                                                                    " UNION SELECT 'VERBOSE'");
1657         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1658                          (pg_strcasecmp(prev_wd, "FULL") == 0 ||
1659                           pg_strcasecmp(prev_wd, "FREEZE") == 0))
1660                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1661                                                                    " UNION SELECT 'ANALYZE'"
1662                                                                    " UNION SELECT 'VERBOSE'");
1663         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1664                          pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1665                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1666                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1667                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1668                                                                    " UNION SELECT 'VERBOSE'");
1669         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1670                          pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1671                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1672                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1673                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1674                                                                    " UNION SELECT 'ANALYZE'");
1675         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1676                          pg_strcasecmp(prev_wd, "VERBOSE") == 0)
1677                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1678                                                                    " UNION SELECT 'ANALYZE'");
1679         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1680                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1681                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1682                                                                    " UNION SELECT 'VERBOSE'");
1683         else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1684                           pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
1685                          (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1686                           pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
1687                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1688
1689 /* ANALZYE */
1690         /* If the previous word is ANALYZE, produce list of tables */
1691         else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1692                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1693
1694 /* WHERE */
1695         /* Simple case of the word before the where being the table name */
1696         else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
1697                 COMPLETE_WITH_ATTR(prev2_wd);
1698
1699 /* ... FROM ... */
1700 /* TODO: also include SRF ? */
1701         else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
1702                          pg_strcasecmp(prev3_wd, "COPY") != 0 &&
1703                          pg_strcasecmp(prev3_wd, "\\copy") != 0)
1704                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1705
1706
1707 /* Backslash commands */
1708 /* TODO:  \dc \dd \dl */
1709         else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1710                 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1711         else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1712                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
1713         else if (strcmp(prev_wd, "\\da") == 0)
1714                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
1715         else if (strcmp(prev_wd, "\\db") == 0)
1716                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1717         else if (strcmp(prev_wd, "\\dD") == 0)
1718                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
1719         else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1720                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1721         else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1722                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1723         else if (strcmp(prev_wd, "\\dn") == 0)
1724                 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1725         else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1726                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1727         else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1728                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
1729         else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1730                 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1731         else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1732                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1733         else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1734                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
1735         else if (strcmp(prev_wd, "\\du") == 0)
1736                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1737         else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1738                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
1739         else if (strcmp(prev_wd, "\\encoding") == 0)
1740                 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
1741         else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1742                 COMPLETE_WITH_LIST(sql_commands);
1743         else if (strcmp(prev_wd, "\\pset") == 0)
1744         {
1745                 static const char *const my_list[] =
1746                 {"format", "border", "expanded",
1747                         "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1748                 "recordsep", NULL};
1749
1750                 COMPLETE_WITH_LIST(my_list);
1751         }
1752         else if (strcmp(prev_wd, "\\cd") == 0 ||
1753                  strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1754                          strcmp(prev_wd, "\\g") == 0 ||
1755                          strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1756                   strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1757                          strcmp(prev_wd, "\\s") == 0 ||
1758                    strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1759                 )
1760                 matches = completion_matches(text, filename_completion_function);
1761
1762
1763         /*
1764          * Finally, we look through the list of "things", such as TABLE, INDEX
1765          * and check if that was the previous word. If so, execute the query
1766          * to get a list of them.
1767          */
1768         else
1769         {
1770                 int                     i;
1771
1772                 for (i = 0; words_after_create[i].name; i++)
1773                 {
1774                         if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
1775                         {
1776                                 if (words_after_create[i].query)
1777                                         COMPLETE_WITH_QUERY(words_after_create[i].query);
1778                                 else if (words_after_create[i].squery)
1779                                         COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
1780                                                                                            NULL);
1781                                 break;
1782                         }
1783                 }
1784         }
1785
1786         /*
1787          * If we still don't have anything to match we have to fabricate some
1788          * sort of default list. If we were to just return NULL, readline
1789          * automatically attempts filename completion, and that's usually no
1790          * good.
1791          */
1792         if (matches == NULL)
1793         {
1794                 COMPLETE_WITH_CONST("");
1795 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1796                 rl_completion_append_character = '\0';
1797 #endif
1798         }
1799
1800         /* free storage */
1801         free(prev_wd);
1802         free(prev2_wd);
1803         free(prev3_wd);
1804         free(prev4_wd);
1805         free(prev5_wd);
1806
1807         /* Return our Grand List O' Matches */
1808         return matches;
1809 }
1810
1811
1812
1813 /* GENERATOR FUNCTIONS
1814
1815    These functions do all the actual work of completing the input. They get
1816    passed the text so far and the count how many times they have been called so
1817    far with the same text.
1818    If you read the above carefully, you'll see that these don't get called
1819    directly but through the readline interface.
1820    The return value is expected to be the full completion of the text, going
1821    through a list each time, or NULL if there are no more matches. The string
1822    will be free()'d by readline, so you must run it through strdup() or
1823    something of that sort.
1824 */
1825
1826 /* This one gives you one from a list of things you can put after CREATE or DROP
1827    as defined above.
1828 */
1829 static char *
1830 create_command_generator(const char *text, int state)
1831 {
1832         static int      list_index,
1833                                 string_length;
1834         const char *name;
1835
1836         /* If this is the first time for this completion, init some values */
1837         if (state == 0)
1838         {
1839                 list_index = 0;
1840                 string_length = strlen(text);
1841         }
1842
1843         /* find something that matches */
1844         while ((name = words_after_create[list_index++].name))
1845                 if (pg_strncasecmp(name, text, string_length) == 0)
1846                         return pg_strdup(name);
1847
1848         /* if nothing matches, return NULL */
1849         return NULL;
1850 }
1851
1852
1853 /* The following two functions are wrappers for _complete_from_query */
1854
1855 static char *
1856 complete_from_query(const char *text, int state)
1857 {
1858         return _complete_from_query(0, text, state);
1859 }
1860
1861 static char *
1862 complete_from_schema_query(const char *text, int state)
1863 {
1864         return _complete_from_query(1, text, state);
1865 }
1866
1867
1868 /* This creates a list of matching things, according to a query pointed to
1869    by completion_charp.
1870    The query can be one of two kinds:
1871    - A simple query which must contain a %d and a %s, which will be replaced
1872    by the string length of the text and the text itself. The query may also
1873    have another %s in it, which will be replaced by the value of
1874    completion_info_charp.
1875          or:
1876    - A schema query used for completion of both schema and relation names;
1877    these are more complex and must contain in the following order:
1878          %d %s %d %s %d %s %s %d %s
1879    where %d is the string length of the text and %s the text itself.
1880
1881    It is assumed that strings should be escaped to become SQL literals
1882    (that is, what is in the query is actually ... '%s' ...)
1883
1884    See top of file for examples of both kinds of query.
1885 */
1886
1887 static char *
1888 _complete_from_query(int is_schema_query, const char *text, int state)
1889 {
1890         static int      list_index,
1891                                 string_length;
1892         static PGresult *result = NULL;
1893
1894         /*
1895          * If this is the first time for this completion, we fetch a list of
1896          * our "things" from the backend.
1897          */
1898         if (state == 0)
1899         {
1900                 PQExpBufferData query_buffer;
1901                 char       *e_text;
1902                 char       *e_info_charp;
1903
1904                 list_index = 0;
1905                 string_length = strlen(text);
1906
1907                 /* Free any prior result */
1908                 PQclear(result);
1909                 result = NULL;
1910
1911                 /* Set up suitably-escaped copies of textual inputs */
1912                 e_text = pg_malloc(string_length * 2 + 1);
1913                 PQescapeString(e_text, text, string_length);
1914
1915                 if (completion_info_charp)
1916                 {
1917                         size_t          charp_len;
1918
1919                         charp_len = strlen(completion_info_charp);
1920                         e_info_charp = pg_malloc(charp_len * 2 + 1);
1921                         PQescapeString(e_info_charp, completion_info_charp,
1922                                                    charp_len);
1923                 }
1924                 else
1925                         e_info_charp = NULL;
1926
1927                 initPQExpBuffer(&query_buffer);
1928
1929                 if (is_schema_query)
1930                 {
1931                         /* completion_squery gives us the pieces to assemble */
1932                         const char *qualresult = completion_squery->qualresult;
1933
1934                         if (qualresult == NULL)
1935                                 qualresult = completion_squery->result;
1936
1937                         /* Get unqualified names matching the input-so-far */
1938                         appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
1939                                                           completion_squery->result,
1940                                                           completion_squery->catname);
1941                         if (completion_squery->selcondition)
1942                                 appendPQExpBuffer(&query_buffer, "%s AND ",
1943                                                                   completion_squery->selcondition);
1944                         appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
1945                                                           completion_squery->result,
1946                                                           string_length, e_text);
1947                         appendPQExpBuffer(&query_buffer, " AND %s",
1948                                                           completion_squery->viscondition);
1949
1950                         /*
1951                          * When fetching relation names, suppress system catalogs
1952                          * unless the input-so-far begins with "pg_".  This is a
1953                          * compromise between not offering system catalogs for
1954                          * completion at all, and having them swamp the result when
1955                          * the input is just "p".
1956                          */
1957                         if (strcmp(completion_squery->catname,
1958                                            "pg_catalog.pg_class c") == 0 &&
1959                                 strncmp(text, "pg_", 3) !=0)
1960                         {
1961                                 appendPQExpBuffer(&query_buffer,
1962                                                                 " AND c.relnamespace <> (SELECT oid FROM"
1963                                 " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
1964                         }
1965
1966                         /*
1967                          * Add in matching schema names, but only if there is more
1968                          * than one potential match among schema names.
1969                          */
1970                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
1971                                            "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
1972                                                           "FROM pg_catalog.pg_namespace n "
1973                                                           "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
1974                                                           string_length, e_text);
1975                         appendPQExpBuffer(&query_buffer,
1976                                                           " AND (SELECT pg_catalog.count(*)"
1977                                                           " FROM pg_catalog.pg_namespace"
1978                                                           " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
1979                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
1980                                                           string_length, e_text);
1981
1982                         /*
1983                          * Add in matching qualified names, but only if there is
1984                          * exactly one schema matching the input-so-far.
1985                          */
1986                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
1987                                  "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
1988                                                           "FROM %s, pg_catalog.pg_namespace n "
1989                                                           "WHERE %s = n.oid AND ",
1990                                                           qualresult,
1991                                                           completion_squery->catname,
1992                                                           completion_squery->namespace);
1993                         if (completion_squery->selcondition)
1994                                 appendPQExpBuffer(&query_buffer, "%s AND ",
1995                                                                   completion_squery->selcondition);
1996                         appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
1997                                                           qualresult,
1998                                                           string_length, e_text);
1999
2000                         /*
2001                          * This condition exploits the single-matching-schema rule to
2002                          * speed up the query
2003                          */
2004                         appendPQExpBuffer(&query_buffer,
2005                                                           " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
2006                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
2007                                                           string_length, e_text);
2008                         appendPQExpBuffer(&query_buffer,
2009                                                           " AND (SELECT pg_catalog.count(*)"
2010                                                           " FROM pg_catalog.pg_namespace"
2011                                                           " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2012                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
2013                                                           string_length, e_text);
2014
2015                         /* If an addon query was provided, use it */
2016                         if (completion_charp)
2017                                 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
2018                 }
2019                 else
2020                 {
2021                         /* completion_charp is an sprintf-style format string */
2022                         appendPQExpBuffer(&query_buffer, completion_charp,
2023                                                           string_length, e_text, e_info_charp);
2024                 }
2025
2026                 /* Limit the number of records in the result */
2027                 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
2028                                                   completion_max_records);
2029
2030                 result = exec_query(query_buffer.data);
2031
2032                 termPQExpBuffer(&query_buffer);
2033                 free(e_text);
2034                 if (e_info_charp)
2035                         free(e_info_charp);
2036         }
2037
2038         /* Find something that matches */
2039         if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
2040         {
2041                 const char *item;
2042
2043                 while (list_index < PQntuples(result) &&
2044                            (item = PQgetvalue(result, list_index++, 0)))
2045                         if (pg_strncasecmp(text, item, string_length) == 0)
2046                                 return pg_strdup(item);
2047         }
2048
2049         /* If nothing matches, free the db structure and return null */
2050         PQclear(result);
2051         result = NULL;
2052         return NULL;
2053 }
2054
2055
2056 /* This function returns in order one of a fixed, NULL pointer terminated list
2057    of strings (if matching). This can be used if there are only a fixed number
2058    SQL words that can appear at certain spot.
2059 */
2060 static char *
2061 complete_from_list(const char *text, int state)
2062 {
2063         static int      string_length,
2064                                 list_index,
2065                                 matches;
2066         static bool casesensitive;
2067         const char *item;
2068
2069         /* need to have a list */
2070         psql_assert(completion_charpp);
2071
2072         /* Initialization */
2073         if (state == 0)
2074         {
2075                 list_index = 0;
2076                 string_length = strlen(text);
2077                 casesensitive = true;
2078                 matches = 0;
2079         }
2080
2081         while ((item = completion_charpp[list_index++]))
2082         {
2083                 /* First pass is case sensitive */
2084                 if (casesensitive && strncmp(text, item, string_length) == 0)
2085                 {
2086                         matches++;
2087                         return pg_strdup(item);
2088                 }
2089
2090                 /* Second pass is case insensitive, don't bother counting matches */
2091                 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
2092                         return pg_strdup(item);
2093         }
2094
2095         /*
2096          * No matches found. If we're not case insensitive already, lets
2097          * switch to being case insensitive and try again
2098          */
2099         if (casesensitive && matches == 0)
2100         {
2101                 casesensitive = false;
2102                 list_index = 0;
2103                 state++;
2104                 return (complete_from_list(text, state));
2105         }
2106
2107         /* If no more matches, return null. */
2108         return NULL;
2109 }
2110
2111
2112 /* This function returns one fixed string the first time even if it doesn't
2113    match what's there, and nothing the second time. This should be used if there
2114    is only one possibility that can appear at a certain spot, so misspellings
2115    will be overwritten.
2116    The string to be passed must be in completion_charp.
2117 */
2118 static char *
2119 complete_from_const(const char *text, int state)
2120 {
2121         (void) text;                            /* We don't care about what was entered
2122                                                                  * already. */
2123
2124         psql_assert(completion_charp);
2125         if (state == 0)
2126                 return pg_strdup(completion_charp);
2127         else
2128                 return NULL;
2129 }
2130
2131
2132
2133 /* HELPER FUNCTIONS */
2134
2135
2136 /*
2137  * Execute a query and report any errors. This should be the preferred way of
2138  * talking to the database in this file.
2139  */
2140 static PGresult *
2141 exec_query(const char *query)
2142 {
2143         PGresult   *result;
2144
2145         if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
2146                 return NULL;
2147
2148         result = PQexec(pset.db, query);
2149
2150         if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
2151         {
2152 #if 0
2153                 psql_error("tab completion: %s failed - %s\n",
2154                                    query, PQresStatus(PQresultStatus(result)));
2155 #endif
2156                 PQclear(result);
2157                 result = NULL;
2158         }
2159
2160         return result;
2161 }
2162
2163
2164
2165 /*
2166  * Return the word (space delimited) before point. Set skip > 0 to
2167  * skip that many words; e.g. skip=1 finds the word before the
2168  * previous one. Return value is NULL or a malloc'ed string.
2169  */
2170 static char *
2171 previous_word(int point, int skip)
2172 {
2173         int                     i,
2174                                 start = 0,
2175                                 end = -1,
2176                                 inquotes = 0;
2177         char       *s;
2178
2179         while (skip-- >= 0)
2180         {
2181                 /* first we look for a space before the current word */
2182                 for (i = point; i >= 0; i--)
2183                         if (rl_line_buffer[i] == ' ')
2184                                 break;
2185
2186                 /* now find the first non-space which then constitutes the end */
2187                 for (; i >= 0; i--)
2188                         if (rl_line_buffer[i] != ' ')
2189                         {
2190                                 end = i;
2191                                 break;
2192                         }
2193
2194                 /*
2195                  * If no end found we return null, because there is no word before
2196                  * the point
2197                  */
2198                 if (end == -1)
2199                         return NULL;
2200
2201                 /*
2202                  * Otherwise we now look for the start. The start is either the
2203                  * last character before any space going backwards from the end,
2204                  * or it's simply character 0
2205                  */
2206                 for (start = end; start > 0; start--)
2207                 {
2208                         if (rl_line_buffer[start] == '"')
2209                                 inquotes = !inquotes;
2210                         if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
2211                                 break;
2212                 }
2213
2214                 point = start;
2215         }
2216
2217         /* make a copy */
2218         s = pg_malloc(end - start + 2);
2219
2220         strncpy(s, &rl_line_buffer[start], end - start + 1);
2221         s[end - start + 1] = '\0';
2222
2223         return s;
2224 }
2225
2226
2227
2228 #if 0
2229
2230 /*
2231  * Surround a string with single quotes. This works for both SQL and
2232  * psql internal. Currently disabled because it is reported not to
2233  * cooperate with certain versions of readline.
2234  */
2235 static char *
2236 quote_file_name(char *text, int match_type, char *quote_pointer)
2237 {
2238         char       *s;
2239         size_t          length;
2240
2241         (void) quote_pointer;           /* not used */
2242
2243         length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
2244         s = pg_malloc(length);
2245         s[0] = '\'';
2246         strcpy(s + 1, text);
2247         if (match_type == SINGLE_MATCH)
2248                 s[length - 2] = '\'';
2249         s[length - 1] = '\0';
2250         return s;
2251 }
2252
2253
2254
2255 static char *
2256 dequote_file_name(char *text, char quote_char)
2257 {
2258         char       *s;
2259         size_t          length;
2260
2261         if (!quote_char)
2262                 return pg_strdup(text);
2263
2264         length = strlen(text);
2265         s = pg_malloc(length - 2 + 1);
2266         strncpy(s, text +1, length - 2);
2267         s[length] = '\0';
2268
2269         return s;
2270 }
2271 #endif   /* 0 */
2272
2273 #endif   /* USE_READLINE */