]> granicus.if.org Git - postgresql/blob - src/bin/psql/tab-complete.c
3efa97ad88f3160d9757d1a15e77a5c64dd0e688
[postgresql] / src / bin / psql / tab-complete.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2010, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/tab-complete.c
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 #include "stringutils.h"
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 /* word break characters */
70 #define WORD_BREAKS             "\t\n@$><=;|&{() "
71
72 /*
73  * This struct is used to define "schema queries", which are custom-built
74  * to obtain possibly-schema-qualified names of database objects.  There is
75  * enough similarity in the structure that we don't want to repeat it each
76  * time.  So we put the components of each query into this struct and
77  * assemble them with the common boilerplate in _complete_from_query().
78  */
79 typedef struct SchemaQuery
80 {
81         /*
82          * Name of catalog or catalogs to be queried, with alias, eg.
83          * "pg_catalog.pg_class c".  Note that "pg_namespace n" will be added.
84          */
85         const char *catname;
86
87         /*
88          * Selection condition --- only rows meeting this condition are candidates
89          * to display.  If catname mentions multiple tables, include the necessary
90          * join condition here.  For example, "c.relkind = 'r'". Write NULL (not
91          * an empty string) if not needed.
92          */
93         const char *selcondition;
94
95         /*
96          * Visibility condition --- which rows are visible without schema
97          * qualification?  For example, "pg_catalog.pg_table_is_visible(c.oid)".
98          */
99         const char *viscondition;
100
101         /*
102          * Namespace --- name of field to join to pg_namespace.oid. For example,
103          * "c.relnamespace".
104          */
105         const char *namespace;
106
107         /*
108          * Result --- the appropriately-quoted name to return, in the case of an
109          * unqualified name.  For example, "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 strings */
132 static const char *completion_info_charp;               /* to pass a second string */
133 static const char *completion_info_charp2;              /* to pass a third string */
134 static const SchemaQuery *completion_squery;    /* to pass a SchemaQuery */
135
136 /*
137  * A few macros to ease typing. You can use these to complete the given
138  * string with
139  * 1) The results from a query you pass it. (Perhaps one of those below?)
140  * 2) The results from a schema query you pass it.
141  * 3) The items from a null-pointer-terminated list.
142  * 4) A string constant.
143  * 5) The list of attributes of the given table (possibly schema-qualified).
144  */
145 #define COMPLETE_WITH_QUERY(query) \
146 do { \
147         completion_charp = query; \
148         matches = completion_matches(text, complete_from_query); \
149 } while (0)
150
151 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
152 do { \
153         completion_squery = &(query); \
154         completion_charp = addon; \
155         matches = completion_matches(text, complete_from_schema_query); \
156 } while (0)
157
158 #define COMPLETE_WITH_LIST(list) \
159 do { \
160         completion_charpp = list; \
161         matches = completion_matches(text, complete_from_list); \
162 } while (0)
163
164 #define COMPLETE_WITH_CONST(string) \
165 do { \
166         completion_charp = string; \
167         matches = completion_matches(text, complete_from_const); \
168 } while (0)
169
170 #define COMPLETE_WITH_ATTR(relation, addon) \
171 do { \
172         char   *_completion_schema; \
173         char   *_completion_table; \
174 \
175         _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
176                                                                  false, false, pset.encoding); \
177         (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
178                                    false, false, pset.encoding); \
179         _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
180                                                                 false, false, pset.encoding); \
181         if (_completion_table == NULL) \
182         { \
183                 completion_charp = Query_for_list_of_attributes  addon; \
184                 completion_info_charp = relation; \
185         } \
186         else \
187         { \
188                 completion_charp = Query_for_list_of_attributes_with_schema  addon; \
189                 completion_info_charp = _completion_table; \
190                 completion_info_charp2 = _completion_schema; \
191         } \
192         matches = completion_matches(text, complete_from_query); \
193 } while (0)
194
195 /*
196  * Assembly instructions for schema queries
197  */
198
199 static const SchemaQuery Query_for_list_of_aggregates = {
200         /* catname */
201         "pg_catalog.pg_proc p",
202         /* selcondition */
203         "p.proisagg",
204         /* viscondition */
205         "pg_catalog.pg_function_is_visible(p.oid)",
206         /* namespace */
207         "p.pronamespace",
208         /* result */
209         "pg_catalog.quote_ident(p.proname)",
210         /* qualresult */
211         NULL
212 };
213
214 static const SchemaQuery Query_for_list_of_datatypes = {
215         /* catname */
216         "pg_catalog.pg_type t",
217         /* selcondition --- ignore table rowtypes and array types */
218         "(t.typrelid = 0 "
219         " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
220         "AND t.typname !~ '^_'",
221         /* viscondition */
222         "pg_catalog.pg_type_is_visible(t.oid)",
223         /* namespace */
224         "t.typnamespace",
225         /* result */
226         "pg_catalog.format_type(t.oid, NULL)",
227         /* qualresult */
228         "pg_catalog.quote_ident(t.typname)"
229 };
230
231 static const SchemaQuery Query_for_list_of_domains = {
232         /* catname */
233         "pg_catalog.pg_type t",
234         /* selcondition */
235         "t.typtype = 'd'",
236         /* viscondition */
237         "pg_catalog.pg_type_is_visible(t.oid)",
238         /* namespace */
239         "t.typnamespace",
240         /* result */
241         "pg_catalog.quote_ident(t.typname)",
242         /* qualresult */
243         NULL
244 };
245
246 static const SchemaQuery Query_for_list_of_functions = {
247         /* catname */
248         "pg_catalog.pg_proc p",
249         /* selcondition */
250         NULL,
251         /* viscondition */
252         "pg_catalog.pg_function_is_visible(p.oid)",
253         /* namespace */
254         "p.pronamespace",
255         /* result */
256         "pg_catalog.quote_ident(p.proname)",
257         /* qualresult */
258         NULL
259 };
260
261 static const SchemaQuery Query_for_list_of_indexes = {
262         /* catname */
263         "pg_catalog.pg_class c",
264         /* selcondition */
265         "c.relkind IN ('i')",
266         /* viscondition */
267         "pg_catalog.pg_table_is_visible(c.oid)",
268         /* namespace */
269         "c.relnamespace",
270         /* result */
271         "pg_catalog.quote_ident(c.relname)",
272         /* qualresult */
273         NULL
274 };
275
276 static const SchemaQuery Query_for_list_of_sequences = {
277         /* catname */
278         "pg_catalog.pg_class c",
279         /* selcondition */
280         "c.relkind IN ('S')",
281         /* viscondition */
282         "pg_catalog.pg_table_is_visible(c.oid)",
283         /* namespace */
284         "c.relnamespace",
285         /* result */
286         "pg_catalog.quote_ident(c.relname)",
287         /* qualresult */
288         NULL
289 };
290
291 static const SchemaQuery Query_for_list_of_tables = {
292         /* catname */
293         "pg_catalog.pg_class c",
294         /* selcondition */
295         "c.relkind IN ('r')",
296         /* viscondition */
297         "pg_catalog.pg_table_is_visible(c.oid)",
298         /* namespace */
299         "c.relnamespace",
300         /* result */
301         "pg_catalog.quote_ident(c.relname)",
302         /* qualresult */
303         NULL
304 };
305
306 static const SchemaQuery Query_for_list_of_tisv = {
307         /* catname */
308         "pg_catalog.pg_class c",
309         /* selcondition */
310         "c.relkind IN ('r', 'i', 'S', 'v')",
311         /* viscondition */
312         "pg_catalog.pg_table_is_visible(c.oid)",
313         /* namespace */
314         "c.relnamespace",
315         /* result */
316         "pg_catalog.quote_ident(c.relname)",
317         /* qualresult */
318         NULL
319 };
320
321 static const SchemaQuery Query_for_list_of_tsv = {
322         /* catname */
323         "pg_catalog.pg_class c",
324         /* selcondition */
325         "c.relkind IN ('r', 'S', 'v')",
326         /* viscondition */
327         "pg_catalog.pg_table_is_visible(c.oid)",
328         /* namespace */
329         "c.relnamespace",
330         /* result */
331         "pg_catalog.quote_ident(c.relname)",
332         /* qualresult */
333         NULL
334 };
335
336 static const SchemaQuery Query_for_list_of_views = {
337         /* catname */
338         "pg_catalog.pg_class c",
339         /* selcondition */
340         "c.relkind IN ('v')",
341         /* viscondition */
342         "pg_catalog.pg_table_is_visible(c.oid)",
343         /* namespace */
344         "c.relnamespace",
345         /* result */
346         "pg_catalog.quote_ident(c.relname)",
347         /* qualresult */
348         NULL
349 };
350
351
352 /*
353  * Queries to get lists of names of various kinds of things, possibly
354  * restricted to names matching a partially entered name.  In these queries,
355  * the first %s will be replaced by the text entered so far (suitably escaped
356  * to become a SQL literal string).  %d will be replaced by the length of the
357  * string (in unescaped form).  A second and third %s, if present, will be
358  * replaced by a suitably-escaped version of the string provided in
359  * completion_info_charp.  A fourth and fifth %s are similarly replaced by
360  * completion_info_charp2.
361  *
362  * Beware that the allowed sequences of %s and %d are determined by
363  * _complete_from_query().
364  */
365
366 #define Query_for_list_of_attributes \
367 "SELECT pg_catalog.quote_ident(attname) "\
368 "  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
369 " WHERE c.oid = a.attrelid "\
370 "   AND a.attnum > 0 "\
371 "   AND NOT a.attisdropped "\
372 "   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
373 "   AND (pg_catalog.quote_ident(relname)='%s' "\
374 "        OR '\"' || relname || '\"'='%s') "\
375 "   AND pg_catalog.pg_table_is_visible(c.oid)"
376
377 #define Query_for_list_of_attributes_with_schema \
378 "SELECT pg_catalog.quote_ident(attname) "\
379 "  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
380 " WHERE c.oid = a.attrelid "\
381 "   AND n.oid = c.relnamespace "\
382 "   AND a.attnum > 0 "\
383 "   AND NOT a.attisdropped "\
384 "   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
385 "   AND (pg_catalog.quote_ident(relname)='%s' "\
386 "        OR '\"' || relname || '\"' ='%s') "\
387 "   AND (pg_catalog.quote_ident(nspname)='%s' "\
388 "        OR '\"' || nspname || '\"' ='%s') "
389
390 #define Query_for_list_of_template_databases \
391 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
392 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
393
394 #define Query_for_list_of_databases \
395 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
396 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
397
398 #define Query_for_list_of_tablespaces \
399 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
400 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
401
402 #define Query_for_list_of_encodings \
403 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
404 "   FROM pg_catalog.pg_conversion "\
405 "  WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
406
407 #define Query_for_list_of_languages \
408 "SELECT pg_catalog.quote_ident(lanname) "\
409 "  FROM pg_catalog.pg_language "\
410 " WHERE lanname != 'internal' "\
411 "   AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
412
413 #define Query_for_list_of_schemas \
414 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
415 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
416
417 #define Query_for_list_of_set_vars \
418 "SELECT name FROM "\
419 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
420 "  WHERE context IN ('user', 'superuser') "\
421 "  UNION ALL SELECT 'constraints' "\
422 "  UNION ALL SELECT 'transaction' "\
423 "  UNION ALL SELECT 'session' "\
424 "  UNION ALL SELECT 'role' "\
425 "  UNION ALL SELECT 'tablespace' "\
426 "  UNION ALL SELECT 'all') ss "\
427 " WHERE substring(name,1,%d)='%s'"
428
429 #define Query_for_list_of_show_vars \
430 "SELECT name FROM "\
431 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
432 "  UNION ALL SELECT 'session authorization' "\
433 "  UNION ALL SELECT 'all') ss "\
434 " WHERE substring(name,1,%d)='%s'"
435
436 #define Query_for_list_of_roles \
437 " SELECT pg_catalog.quote_ident(rolname) "\
438 "   FROM pg_catalog.pg_roles "\
439 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
440
441 #define Query_for_list_of_grant_roles \
442 " SELECT pg_catalog.quote_ident(rolname) "\
443 "   FROM pg_catalog.pg_roles "\
444 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
445 " UNION ALL SELECT 'PUBLIC'"
446
447 /* the silly-looking length condition is just to eat up the current word */
448 #define Query_for_table_owning_index \
449 "SELECT pg_catalog.quote_ident(c1.relname) "\
450 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
451 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
452 "       and (%d = pg_catalog.length('%s'))"\
453 "       and pg_catalog.quote_ident(c2.relname)='%s'"\
454 "       and pg_catalog.pg_table_is_visible(c2.oid)"
455
456 /* the silly-looking length condition is just to eat up the current word */
457 #define Query_for_index_of_table \
458 "SELECT pg_catalog.quote_ident(c2.relname) "\
459 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
460 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
461 "       and (%d = pg_catalog.length('%s'))"\
462 "       and pg_catalog.quote_ident(c1.relname)='%s'"\
463 "       and pg_catalog.pg_table_is_visible(c2.oid)"
464
465 /* the silly-looking length condition is just to eat up the current word */
466 #define Query_for_list_of_tables_for_trigger \
467 "SELECT pg_catalog.quote_ident(relname) "\
468 "  FROM pg_catalog.pg_class"\
469 " WHERE (%d = pg_catalog.length('%s'))"\
470 "   AND oid IN "\
471 "       (SELECT tgrelid FROM pg_catalog.pg_trigger "\
472 "         WHERE pg_catalog.quote_ident(tgname)='%s')"
473
474 #define Query_for_list_of_ts_configurations \
475 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
476 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
477
478 #define Query_for_list_of_ts_dictionaries \
479 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
480 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
481
482 #define Query_for_list_of_ts_parsers \
483 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
484 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
485
486 #define Query_for_list_of_ts_templates \
487 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
488 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
489
490 #define Query_for_list_of_fdws \
491 " SELECT pg_catalog.quote_ident(fdwname) "\
492 "   FROM pg_catalog.pg_foreign_data_wrapper "\
493 "  WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
494
495 #define Query_for_list_of_servers \
496 " SELECT pg_catalog.quote_ident(srvname) "\
497 "   FROM pg_catalog.pg_foreign_server "\
498 "  WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
499
500 #define Query_for_list_of_user_mappings \
501 " SELECT pg_catalog.quote_ident(usename) "\
502 "   FROM pg_catalog.pg_user_mappings "\
503 "  WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
504
505 #define Query_for_list_of_access_methods \
506 " SELECT pg_catalog.quote_ident(amname) "\
507 "   FROM pg_catalog.pg_am "\
508 "  WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
509
510 #define Query_for_list_of_arguments \
511 " SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
512 "   FROM pg_catalog.pg_proc "\
513 "  WHERE proname='%s'"
514
515 /*
516  * This is a list of all "things" in Pgsql, which can show up after CREATE or
517  * DROP; and there is also a query to get a list of them.
518  */
519
520 typedef struct
521 {
522         const char *name;
523         const char *query;                      /* simple query, or NULL */
524         const SchemaQuery *squery;      /* schema query, or NULL */
525         const bool      noshow;                 /* NULL or true if this word should not show
526                                                                  * up after CREATE or DROP */
527 } pgsql_thing_t;
528
529 static const pgsql_thing_t words_after_create[] = {
530         {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
531         {"CAST", NULL, NULL},           /* Casts have complex structures for names, so
532                                                                  * skip it */
533
534         /*
535          * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
536          * to be used only by pg_dump.
537          */
538         {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, true},
539         {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
540         {"DATABASE", Query_for_list_of_databases},
541         {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, true},
542         {"DOMAIN", NULL, &Query_for_list_of_domains},
543         {"FOREIGN DATA WRAPPER", NULL, NULL},
544         {"FUNCTION", NULL, &Query_for_list_of_functions},
545         {"GROUP", Query_for_list_of_roles},
546         {"LANGUAGE", Query_for_list_of_languages},
547         {"INDEX", NULL, &Query_for_list_of_indexes},
548         {"OPERATOR", NULL, NULL},       /* Querying for this is probably not such a
549                                                                  * good idea. */
550         {"PARSER", Query_for_list_of_ts_parsers, NULL, true},
551         {"ROLE", Query_for_list_of_roles},
552         {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
553         {"SCHEMA", Query_for_list_of_schemas},
554         {"SEQUENCE", NULL, &Query_for_list_of_sequences},
555         {"SERVER", Query_for_list_of_servers},
556         {"TABLE", NULL, &Query_for_list_of_tables},
557         {"TABLESPACE", Query_for_list_of_tablespaces},
558         {"TEMP", NULL, NULL},           /* for CREATE TEMP TABLE ... */
559         {"TEMPLATE", Query_for_list_of_ts_templates, NULL, true},
560         {"TEXT SEARCH", NULL, NULL},
561         {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
562         {"TYPE", NULL, &Query_for_list_of_datatypes},
563         {"UNIQUE", NULL, NULL},         /* for CREATE UNIQUE INDEX ... */
564         {"USER", Query_for_list_of_roles},
565         {"USER MAPPING FOR", NULL, NULL},
566         {"VIEW", NULL, &Query_for_list_of_views},
567         {NULL, NULL, NULL, false}       /* end of list */
568 };
569
570
571 /* Forward declaration of functions */
572 static char **psql_completion(char *text, int start, int end);
573 static char *create_command_generator(const char *text, int state);
574 static char *drop_command_generator(const char *text, int state);
575 static char *complete_from_query(const char *text, int state);
576 static char *complete_from_schema_query(const char *text, int state);
577 static char *_complete_from_query(int is_schema_query,
578                                          const char *text, int state);
579 static char *complete_from_const(const char *text, int state);
580 static char *complete_from_list(const char *text, int state);
581
582 static PGresult *exec_query(const char *query);
583
584 static char *previous_word(int point, int skip);
585
586 #if 0
587 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
588 static char *dequote_file_name(char *text, char quote_char);
589 #endif
590
591
592 /* Initialize the readline library for our purposes. */
593 void
594 initialize_readline(void)
595 {
596         rl_readline_name = (char *) pset.progname;
597         rl_attempted_completion_function = (void *) psql_completion;
598
599         rl_basic_word_break_characters = WORD_BREAKS;
600
601         completion_max_records = 1000;
602
603         /*
604          * There is a variable rl_completion_query_items for this but apparently
605          * it's not defined everywhere.
606          */
607 }
608
609
610 /* The completion function. Acc. to readline spec this gets passed the text
611    entered to far and its start and end in the readline buffer. The return value
612    is some partially obscure list format that can be generated by the readline
613    libraries completion_matches() function, so we don't have to worry about it.
614 */
615 static char **
616 psql_completion(char *text, int start, int end)
617 {
618         /* This is the variable we'll return. */
619         char      **matches = NULL;
620
621         /* These are going to contain some scannage of the input line. */
622         char       *prev_wd,
623                            *prev2_wd,
624                            *prev3_wd,
625                            *prev4_wd,
626                            *prev5_wd;
627
628         static const char *const sql_commands[] = {
629                 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
630                 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
631                 "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
632                 "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
633                 "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
634                 "SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TABLE", "TRUNCATE", "UNLISTEN",
635                 "UPDATE", "VACUUM", "VALUES", "WITH", NULL
636         };
637
638         static const char *const backslash_commands[] = {
639                 "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
640                 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\deu", "\\dew", "\\df",
641                 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl",
642                 "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
643                 "\\e", "\\echo", "\\ef", "\\encoding",
644                 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
645                 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
646                 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
647                 "\\set", "\\sf", "\\t", "\\T",
648                 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
649         };
650
651         (void) end;                                     /* not used */
652
653 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
654         rl_completion_append_character = ' ';
655 #endif
656
657         /* Clear a few things. */
658         completion_charp = NULL;
659         completion_charpp = NULL;
660         completion_info_charp = NULL;
661         completion_info_charp2 = NULL;
662
663         /*
664          * Scan the input line before our current position for the last five
665          * words. According to those we'll make some smart decisions on what the
666          * user is probably intending to type. TODO: Use strtokx() to do this.
667          */
668         prev_wd = previous_word(start, 0);
669         prev2_wd = previous_word(start, 1);
670         prev3_wd = previous_word(start, 2);
671         prev4_wd = previous_word(start, 3);
672         prev5_wd = previous_word(start, 4);
673
674         /* If a backslash command was started, continue */
675         if (text[0] == '\\')
676                 COMPLETE_WITH_LIST(backslash_commands);
677
678         /* If no previous word, suggest one of the basic sql commands */
679         else if (!prev_wd)
680                 COMPLETE_WITH_LIST(sql_commands);
681
682 /* CREATE */
683         /* complete with something you can create */
684         else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
685                 matches = completion_matches(text, create_command_generator);
686
687 /* DROP, but watch out for DROP embedded in other commands */
688         /* complete with something you can drop */
689         else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
690                          pg_strcasecmp(prev2_wd, "DROP") == 0)
691                 matches = completion_matches(text, drop_command_generator);
692
693 /* ALTER */
694
695         /*
696          * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
697          * in ALTER TABLE sth ALTER
698          */
699         else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
700                          pg_strcasecmp(prev3_wd, "TABLE") != 0)
701         {
702                 static const char *const list_ALTER[] =
703                 {"AGGREGATE", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", "FOREIGN DATA WRAPPER", "FUNCTION",
704                         "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR", "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
705                 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL};
706
707                 COMPLETE_WITH_LIST(list_ALTER);
708         }
709         /* ALTER AGGREGATE,FUNCTION <name> */
710         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
711                          (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
712                           pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
713                 COMPLETE_WITH_CONST("(");
714         /* ALTER AGGREGATE,FUNCTION <name> (...) */
715         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
716                          (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
717                           pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
718         {
719                 if (prev_wd[strlen(prev_wd) - 1] == ')')
720                 {
721                         static const char *const list_ALTERAGG[] =
722                         {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
723
724                         COMPLETE_WITH_LIST(list_ALTERAGG);
725                 }
726                 else
727                 {
728                         char       *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
729
730                         sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
731                         COMPLETE_WITH_QUERY(tmp_buf);
732                         free(tmp_buf);
733                 }
734         }
735
736         /* ALTER CONVERSION,SCHEMA <name> */
737         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
738                          (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
739                           pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
740         {
741                 static const char *const list_ALTERGEN[] =
742                 {"OWNER TO", "RENAME TO", NULL};
743
744                 COMPLETE_WITH_LIST(list_ALTERGEN);
745         }
746
747         /* ALTER DATABASE <name> */
748         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
749                          pg_strcasecmp(prev2_wd, "DATABASE") == 0)
750         {
751                 static const char *const list_ALTERDATABASE[] =
752                 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
753
754                 COMPLETE_WITH_LIST(list_ALTERDATABASE);
755         }
756
757         /* ALTER FOREIGN DATA WRAPPER <name> */
758         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
759                          pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
760                          pg_strcasecmp(prev3_wd, "DATA") == 0 &&
761                          pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
762         {
763                 static const char *const list_ALTER_FDW[] =
764                 {"VALIDATOR", "OPTIONS", "OWNER TO", NULL};
765
766                 COMPLETE_WITH_LIST(list_ALTER_FDW);
767         }
768
769         /* ALTER INDEX <name> */
770         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
771                          pg_strcasecmp(prev2_wd, "INDEX") == 0)
772         {
773                 static const char *const list_ALTERINDEX[] =
774                 {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
775
776                 COMPLETE_WITH_LIST(list_ALTERINDEX);
777         }
778         /* ALTER INDEX <name> SET */
779         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
780                          pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
781                          pg_strcasecmp(prev_wd, "SET") == 0)
782         {
783                 static const char *const list_ALTERINDEXSET[] =
784                 {"(", "TABLESPACE", NULL};
785
786                 COMPLETE_WITH_LIST(list_ALTERINDEXSET);
787         }
788         /* ALTER INDEX <name> RESET */
789         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
790                          pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
791                          pg_strcasecmp(prev_wd, "RESET") == 0)
792                 COMPLETE_WITH_CONST("(");
793         /* ALTER INDEX <foo> SET|RESET ( */
794         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
795                          pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
796                          (pg_strcasecmp(prev2_wd, "SET") == 0 ||
797                           pg_strcasecmp(prev2_wd, "RESET") == 0) &&
798                          pg_strcasecmp(prev_wd, "(") == 0)
799         {
800                 static const char *const list_INDEXOPTIONS[] =
801                 {"fillfactor", "fastupdate", NULL};
802
803                 COMPLETE_WITH_LIST(list_INDEXOPTIONS);
804         }
805
806         /* ALTER LANGUAGE <name> */
807         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
808                          pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
809         {
810                 static const char *const list_ALTERLANGUAGE[] =
811                 {"OWNER TO", "RENAME TO", NULL};
812
813                 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
814         }
815
816         /* ALTER LARGE OBJECT <oid> */
817         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
818                          pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
819                          pg_strcasecmp(prev2_wd, "OBJECT") == 0)
820         {
821                 static const char *const list_ALTERLARGEOBJECT[] =
822                 {"OWNER TO", NULL};
823
824                 COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
825         }
826
827         /* ALTER USER,ROLE <name> */
828         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
829                          !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
830                          (pg_strcasecmp(prev2_wd, "USER") == 0 ||
831                           pg_strcasecmp(prev2_wd, "ROLE") == 0))
832         {
833                 static const char *const list_ALTERUSER[] =
834                 {"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
835                         "NOCREATEUSER", "CREATEROLE", "NOCREATEROLE", "INHERIT", "NOINHERIT",
836                         "LOGIN", "NOLOGIN", "CONNECTION LIMIT", "VALID UNTIL", "RENAME TO",
837                 "SUPERUSER", "NOSUPERUSER", "SET", "RESET", NULL};
838
839                 COMPLETE_WITH_LIST(list_ALTERUSER);
840         }
841
842         /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
843         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
844                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
845                          (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
846         {
847                 COMPLETE_WITH_CONST("PASSWORD");
848         }
849         /* ALTER DEFAULT PRIVILEGES */
850         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
851                          pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
852                          pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
853         {
854                 static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
855                 {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
856
857                 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
858         }
859         /* ALTER DEFAULT PRIVILEGES FOR */
860         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
861                          pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
862                          pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
863                          pg_strcasecmp(prev_wd, "FOR") == 0)
864         {
865                 static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
866                 {"ROLE", "USER", NULL};
867
868                 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
869         }
870         /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
871         else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
872                          pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
873                          (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
874                           pg_strcasecmp(prev3_wd, "IN") == 0))
875         {
876                 static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
877                 {"GRANT", "REVOKE", NULL};
878
879                 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
880         }
881         /* ALTER DOMAIN <name> */
882         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
883                          pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
884         {
885                 static const char *const list_ALTERDOMAIN[] =
886                 {"ADD", "DROP", "OWNER TO", "SET", NULL};
887
888                 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
889         }
890         /* ALTER DOMAIN <sth> DROP */
891         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
892                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
893                          pg_strcasecmp(prev_wd, "DROP") == 0)
894         {
895                 static const char *const list_ALTERDOMAIN2[] =
896                 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
897
898                 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
899         }
900         /* ALTER DOMAIN <sth> SET */
901         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
902                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
903                          pg_strcasecmp(prev_wd, "SET") == 0)
904         {
905                 static const char *const list_ALTERDOMAIN3[] =
906                 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
907
908                 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
909         }
910         /* ALTER SEQUENCE <name> */
911         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
912                          pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
913         {
914                 static const char *const list_ALTERSEQUENCE[] =
915                 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
916                 "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
917
918                 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
919         }
920         /* ALTER SEQUENCE <name> NO */
921         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
922                          pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
923                          pg_strcasecmp(prev_wd, "NO") == 0)
924         {
925                 static const char *const list_ALTERSEQUENCE2[] =
926                 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
927
928                 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
929         }
930         /* ALTER SERVER <name> */
931         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
932                          pg_strcasecmp(prev2_wd, "SERVER") == 0)
933         {
934                 static const char *const list_ALTER_SERVER[] =
935                 {"VERSION", "OPTIONS", "OWNER TO", NULL};
936
937                 COMPLETE_WITH_LIST(list_ALTER_SERVER);
938         }
939         /* ALTER VIEW <name> */
940         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
941                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
942         {
943                 static const char *const list_ALTERVIEW[] =
944                 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
945
946                 COMPLETE_WITH_LIST(list_ALTERVIEW);
947         }
948         /* ALTER TRIGGER <name>, add ON */
949         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
950                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
951                 COMPLETE_WITH_CONST("ON");
952
953         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
954                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
955         {
956                 completion_info_charp = prev2_wd;
957                 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
958         }
959
960         /*
961          * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
962          */
963         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
964                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
965                          pg_strcasecmp(prev_wd, "ON") == 0)
966                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
967
968         /* ALTER TRIGGER <name> ON <name> */
969         else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
970                          pg_strcasecmp(prev2_wd, "ON") == 0)
971                 COMPLETE_WITH_CONST("RENAME TO");
972
973         /*
974          * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
975          * RENAME, CLUSTER ON or OWNER
976          */
977         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
978                          pg_strcasecmp(prev2_wd, "TABLE") == 0)
979         {
980                 static const char *const list_ALTER2[] =
981                 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
982                 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET", NULL};
983
984                 COMPLETE_WITH_LIST(list_ALTER2);
985         }
986         /* ALTER TABLE xxx ENABLE */
987         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
988                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
989                          pg_strcasecmp(prev_wd, "ENABLE") == 0)
990         {
991                 static const char *const list_ALTERENABLE[] =
992                 {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
993
994                 COMPLETE_WITH_LIST(list_ALTERENABLE);
995         }
996         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
997                          pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
998                          (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
999                           pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1000         {
1001                 static const char *const list_ALTERENABLE2[] =
1002                 {"RULE", "TRIGGER", NULL};
1003
1004                 COMPLETE_WITH_LIST(list_ALTERENABLE2);
1005         }
1006         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1007                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1008                          pg_strcasecmp(prev_wd, "DISABLE") == 0)
1009         {
1010                 static const char *const list_ALTERDISABLE[] =
1011                 {"RULE", "TRIGGER", NULL};
1012
1013                 COMPLETE_WITH_LIST(list_ALTERDISABLE);
1014         }
1015
1016         /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
1017         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1018                          (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
1019                           pg_strcasecmp(prev_wd, "RENAME") == 0))
1020                 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
1021
1022         /*
1023          * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1024          * columns
1025          */
1026         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1027                          (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1028                           pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1029                          pg_strcasecmp(prev_wd, "COLUMN") == 0)
1030                 COMPLETE_WITH_ATTR(prev3_wd, "");
1031
1032         /* ALTER TABLE xxx RENAME yyy */
1033         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1034                          pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1035                          pg_strcasecmp(prev_wd, "TO") != 0)
1036                 COMPLETE_WITH_CONST("TO");
1037
1038         /* ALTER TABLE xxx RENAME COLUMN yyy */
1039         else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1040                          pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1041                          pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
1042                          pg_strcasecmp(prev_wd, "TO") != 0)
1043                 COMPLETE_WITH_CONST("TO");
1044
1045         /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1046         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1047                          pg_strcasecmp(prev_wd, "DROP") == 0)
1048         {
1049                 static const char *const list_TABLEDROP[] =
1050                 {"COLUMN", "CONSTRAINT", NULL};
1051
1052                 COMPLETE_WITH_LIST(list_TABLEDROP);
1053         }
1054         /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
1055         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1056                          pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1057                          pg_strcasecmp(prev_wd, "COLUMN") == 0)
1058                 COMPLETE_WITH_ATTR(prev3_wd, "");
1059         /* ALTER TABLE ALTER [COLUMN] <foo> */
1060         else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1061                           pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1062                          (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1063                           pg_strcasecmp(prev2_wd, "ALTER") == 0))
1064         {
1065                 static const char *const list_COLUMNALTER[] =
1066                 {"TYPE", "SET", "RESET", "DROP", NULL};
1067
1068                 COMPLETE_WITH_LIST(list_COLUMNALTER);
1069         }
1070         /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1071         else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1072                            pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1073                           (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1074                            pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1075                          pg_strcasecmp(prev_wd, "SET") == 0)
1076         {
1077                 static const char *const list_COLUMNSET[] =
1078                 {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1079
1080                 COMPLETE_WITH_LIST(list_COLUMNSET);
1081         }
1082         /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1083         else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1084                            pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1085                           pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1086                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
1087                          pg_strcasecmp(prev_wd, "(") == 0)
1088         {
1089                 static const char *const list_COLUMNOPTIONS[] =
1090                 {"n_distinct", "n_distinct_inherited", NULL};
1091
1092                 COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1093         }
1094         /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1095         else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1096                            pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1097                           pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1098                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
1099                          pg_strcasecmp(prev_wd, "STORAGE") == 0)
1100         {
1101                 static const char *const list_COLUMNSTORAGE[] =
1102                 {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1103
1104                 COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1105         }
1106         /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1107         else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1108                            pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1109                           (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1110                            pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1111                          pg_strcasecmp(prev_wd, "DROP") == 0)
1112         {
1113                 static const char *const list_COLUMNDROP[] =
1114                 {"DEFAULT", "NOT NULL", NULL};
1115
1116                 COMPLETE_WITH_LIST(list_COLUMNDROP);
1117         }
1118         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1119                          pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1120                 COMPLETE_WITH_CONST("ON");
1121         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1122                          pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1123                          pg_strcasecmp(prev_wd, "ON") == 0)
1124         {
1125                 completion_info_charp = prev3_wd;
1126                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1127         }
1128         /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
1129         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1130                          pg_strcasecmp(prev_wd, "SET") == 0)
1131         {
1132                 static const char *const list_TABLESET[] =
1133                 {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
1134
1135                 COMPLETE_WITH_LIST(list_TABLESET);
1136         }
1137         /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1138         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1139                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
1140                          pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1141                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1142         /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1143         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1144                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
1145                          pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1146         {
1147                 static const char *const list_TABLESET2[] =
1148                 {"CLUSTER", "OIDS", NULL};
1149
1150                 COMPLETE_WITH_LIST(list_TABLESET2);
1151         }
1152         /* ALTER TABLE <foo> RESET */
1153         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1154                          pg_strcasecmp(prev_wd, "RESET") == 0)
1155                 COMPLETE_WITH_CONST("(");
1156         /* ALTER TABLE <foo> SET|RESET ( */
1157         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1158                          (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1159                           pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1160                          pg_strcasecmp(prev_wd, "(") == 0)
1161         {
1162                 static const char *const list_TABLEOPTIONS[] =
1163                 {
1164                         "autovacuum_analyze_scale_factor",
1165                         "autovacuum_analyze_threshold",
1166                         "autovacuum_enabled",
1167                         "autovacuum_freeze_max_age",
1168                         "autovacuum_freeze_min_age",
1169                         "autovacuum_freeze_table_age",
1170                         "autovacuum_vacuum_cost_delay",
1171                         "autovacuum_vacuum_cost_limit",
1172                         "autovacuum_vacuum_scale_factor",
1173                         "autovacuum_vacuum_threshold",
1174                         "fillfactor",
1175                         "toast.autovacuum_enabled",
1176                         "toast.autovacuum_freeze_max_age",
1177                         "toast.autovacuum_freeze_min_age",
1178                         "toast.autovacuum_freeze_table_age",
1179                         "toast.autovacuum_vacuum_cost_delay",
1180                         "toast.autovacuum_vacuum_cost_limit",
1181                         "toast.autovacuum_vacuum_scale_factor",
1182                         "toast.autovacuum_vacuum_threshold",
1183                         NULL
1184                 };
1185
1186                 COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1187         }
1188
1189         /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1190         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1191                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1192         {
1193                 static const char *const list_ALTERTSPC[] =
1194                 {"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1195
1196                 COMPLETE_WITH_LIST(list_ALTERTSPC);
1197         }
1198         /* ALTER TABLESPACE <foo> SET|RESET */
1199         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1200                          pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1201                          (pg_strcasecmp(prev_wd, "SET") == 0 ||
1202                           pg_strcasecmp(prev_wd, "RESET") == 0))
1203                 COMPLETE_WITH_CONST("(");
1204         /* ALTER TABLESPACE <foo> SET|RESET ( */
1205         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1206                          pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1207                          (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1208                           pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1209                          pg_strcasecmp(prev_wd, "(") == 0)
1210         {
1211                 static const char *const list_TABLESPACEOPTIONS[] =
1212                 {"seq_page_cost", "random_page_cost", NULL};
1213
1214                 COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1215         }
1216
1217         /* ALTER TEXT SEARCH */
1218         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1219                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1220                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
1221         {
1222                 static const char *const list_ALTERTEXTSEARCH[] =
1223                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1224
1225                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1226         }
1227         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1228                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1229                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1230                          (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1231                           pg_strcasecmp(prev2_wd, "PARSER") == 0))
1232                 COMPLETE_WITH_CONST("RENAME TO");
1233
1234         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1235                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1236                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1237                          pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1238         {
1239                 static const char *const list_ALTERTEXTSEARCH2[] =
1240                 {"OWNER TO", "RENAME TO", NULL};
1241
1242                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1243         }
1244
1245         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1246                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1247                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1248                          pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1249         {
1250                 static const char *const list_ALTERTEXTSEARCH3[] =
1251                 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", NULL};
1252
1253                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1254         }
1255
1256         /* complete ALTER TYPE <foo> with OWNER TO, SET SCHEMA */
1257         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1258                          pg_strcasecmp(prev2_wd, "TYPE") == 0)
1259         {
1260                 static const char *const list_ALTERTYPE[] =
1261                 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1262
1263                 COMPLETE_WITH_LIST(list_ALTERTYPE);
1264         }
1265         /* complete ALTER GROUP <foo> */
1266         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1267                          pg_strcasecmp(prev2_wd, "GROUP") == 0)
1268         {
1269                 static const char *const list_ALTERGROUP[] =
1270                 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1271
1272                 COMPLETE_WITH_LIST(list_ALTERGROUP);
1273         }
1274         /* complete ALTER GROUP <foo> ADD|DROP with USER */
1275         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1276                          pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1277                          (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1278                           pg_strcasecmp(prev_wd, "DROP") == 0))
1279                 COMPLETE_WITH_CONST("USER");
1280         /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1281         else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1282                          (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1283                           pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1284                          pg_strcasecmp(prev_wd, "USER") == 0)
1285                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1286
1287 /* BEGIN, END, ABORT */
1288         else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1289                          pg_strcasecmp(prev_wd, "END") == 0 ||
1290                          pg_strcasecmp(prev_wd, "ABORT") == 0)
1291         {
1292                 static const char *const list_TRANS[] =
1293                 {"WORK", "TRANSACTION", NULL};
1294
1295                 COMPLETE_WITH_LIST(list_TRANS);
1296         }
1297 /* COMMIT */
1298         else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1299         {
1300                 static const char *const list_COMMIT[] =
1301                 {"WORK", "TRANSACTION", "PREPARED", NULL};
1302
1303                 COMPLETE_WITH_LIST(list_COMMIT);
1304         }
1305 /* RELEASE SAVEPOINT */
1306         else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1307                 COMPLETE_WITH_CONST("SAVEPOINT");
1308 /* ROLLBACK*/
1309         else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1310         {
1311                 static const char *const list_TRANS[] =
1312                 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1313
1314                 COMPLETE_WITH_LIST(list_TRANS);
1315         }
1316 /* CLUSTER */
1317
1318         /*
1319          * If the previous word is CLUSTER and not without produce list of tables
1320          */
1321         else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1322                          pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1323                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1324         /* If we have CLUSTER <sth>, then add "USING" */
1325         else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1326                          pg_strcasecmp(prev_wd, "ON") != 0)
1327         {
1328                 COMPLETE_WITH_CONST("USING");
1329         }
1330
1331         /*
1332          * If we have CLUSTER <sth> USING, then add the index as well.
1333          */
1334         else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1335                          pg_strcasecmp(prev_wd, "USING") == 0)
1336         {
1337                 completion_info_charp = prev2_wd;
1338                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1339         }
1340
1341 /* COMMENT */
1342         else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1343                 COMPLETE_WITH_CONST("ON");
1344         else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1345                          pg_strcasecmp(prev_wd, "ON") == 0)
1346         {
1347                 static const char *const list_COMMENT[] =
1348                 {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
1349                         "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1350                         "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1351                 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1352
1353                 COMPLETE_WITH_LIST(list_COMMENT);
1354         }
1355         else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1356                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1357                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1358                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
1359         {
1360                 static const char *const list_TRANS2[] =
1361                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1362
1363                 COMPLETE_WITH_LIST(list_TRANS2);
1364         }
1365         else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1366                           pg_strcasecmp(prev3_wd, "ON") == 0) ||
1367                          (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1368                           pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1369                           pg_strcasecmp(prev3_wd, "SEARCH") == 0))
1370                 COMPLETE_WITH_CONST("IS");
1371
1372 /* COPY */
1373
1374         /*
1375          * If we have COPY [BINARY] (which you'd have to type yourself), offer
1376          * list of tables (Also cover the analogous backslash command)
1377          */
1378         else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1379                          pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1380                          (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1381                           pg_strcasecmp(prev_wd, "BINARY") == 0))
1382                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1383         /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1384         else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1385                          pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1386                          pg_strcasecmp(prev2_wd, "BINARY") == 0)
1387         {
1388                 static const char *const list_FROMTO[] =
1389                 {"FROM", "TO", NULL};
1390
1391                 COMPLETE_WITH_LIST(list_FROMTO);
1392         }
1393         /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1394         else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1395                           pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1396                           pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1397                          (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1398                           pg_strcasecmp(prev_wd, "TO") == 0))
1399                 matches = completion_matches(text, filename_completion_function);
1400
1401         /* Handle COPY|BINARY <sth> FROM|TO filename */
1402         else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1403                           pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1404                           pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1405                          (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1406                           pg_strcasecmp(prev2_wd, "TO") == 0))
1407         {
1408                 static const char *const list_COPY[] =
1409                 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", NULL};
1410
1411                 COMPLETE_WITH_LIST(list_COPY);
1412         }
1413
1414         /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1415         else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1416                          (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1417                           pg_strcasecmp(prev3_wd, "TO") == 0))
1418         {
1419                 static const char *const list_CSV[] =
1420                 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
1421
1422                 COMPLETE_WITH_LIST(list_CSV);
1423         }
1424
1425         /* CREATE DATABASE */
1426         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1427                          pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1428         {
1429                 static const char *const list_DATABASE[] =
1430                 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1431                 NULL};
1432
1433                 COMPLETE_WITH_LIST(list_DATABASE);
1434         }
1435
1436         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1437                          pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1438                          pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1439                 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1440
1441         /* CREATE FOREIGN DATA WRAPPER */
1442         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1443                          pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1444                          pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1445                          pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1446                 COMPLETE_WITH_CONST("VALIDATOR");
1447
1448         /* CREATE INDEX */
1449         /* First off we complete CREATE UNIQUE with "INDEX" */
1450         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1451                          pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1452                 COMPLETE_WITH_CONST("INDEX");
1453         /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
1454         else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
1455                          (pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
1456                           pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
1457                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1458                                                                    " UNION SELECT 'ON'"
1459                                                                    " UNION SELECT 'CONCURRENTLY'");
1460         /* Complete ... INDEX [<name>] ON with a list of tables  */
1461         else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1462                           pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1463                           pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
1464                          pg_strcasecmp(prev_wd, "ON") == 0)
1465                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1466         /* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
1467         else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1468                           pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
1469                          pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
1470                 COMPLETE_WITH_CONST("ON");
1471         /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
1472         else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1473                           pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
1474                          pg_strcasecmp(prev2_wd, "INDEX") == 0)
1475         {
1476                 static const char *const list_CREATE_INDEX[] =
1477                 {"CONCURRENTLY", "ON", NULL};
1478
1479                 COMPLETE_WITH_LIST(list_CREATE_INDEX);
1480         }
1481
1482         /*
1483          * Complete INDEX <name> ON <table> with a list of table columns (which
1484          * should really be in parens)
1485          */
1486         else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1487                           pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1488                           pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
1489                          pg_strcasecmp(prev2_wd, "ON") == 0)
1490         {
1491                 static const char *const list_CREATE_INDEX2[] =
1492                 {"(", "USING", NULL};
1493
1494                 COMPLETE_WITH_LIST(list_CREATE_INDEX2);
1495         }
1496         else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
1497                           pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1498                           pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
1499                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1500                          pg_strcasecmp(prev_wd, "(") == 0)
1501                 COMPLETE_WITH_ATTR(prev2_wd, "");
1502         /* same if you put in USING */
1503         else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1504                          pg_strcasecmp(prev3_wd, "USING") == 0 &&
1505                          pg_strcasecmp(prev_wd, "(") == 0)
1506                 COMPLETE_WITH_ATTR(prev4_wd, "");
1507         /* Complete USING with an index method */
1508         else if (pg_strcasecmp(prev_wd, "USING") == 0)
1509                 COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
1510         else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1511                          pg_strcasecmp(prev2_wd, "USING") == 0)
1512                 COMPLETE_WITH_CONST("(");
1513
1514 /* CREATE RULE */
1515         /* Complete "CREATE RULE <sth>" with "AS" */
1516         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1517                          pg_strcasecmp(prev2_wd, "RULE") == 0)
1518                 COMPLETE_WITH_CONST("AS");
1519         /* Complete "CREATE RULE <sth> AS with "ON" */
1520         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1521                          pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1522                          pg_strcasecmp(prev_wd, "AS") == 0)
1523                 COMPLETE_WITH_CONST("ON");
1524         /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1525         else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1526                          pg_strcasecmp(prev2_wd, "AS") == 0 &&
1527                          pg_strcasecmp(prev_wd, "ON") == 0)
1528         {
1529                 static const char *const rule_events[] =
1530                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1531
1532                 COMPLETE_WITH_LIST(rule_events);
1533         }
1534         /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1535         else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1536                          pg_strcasecmp(prev2_wd, "ON") == 0 &&
1537                          (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1538                           pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1539                 COMPLETE_WITH_CONST("TO");
1540         /* Complete "AS ON <sth> TO" with a table name */
1541         else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1542                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1543                          pg_strcasecmp(prev_wd, "TO") == 0)
1544                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1545
1546 /* CREATE SERVER <name> */
1547         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1548                          pg_strcasecmp(prev2_wd, "SERVER") == 0)
1549         {
1550                 static const char *const list_CREATE_SERVER[] =
1551                 {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
1552
1553                 COMPLETE_WITH_LIST(list_CREATE_SERVER);
1554         }
1555
1556 /* CREATE TABLE */
1557         /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
1558         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1559                          (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
1560                           pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
1561         {
1562                 static const char *const list_TEMP[] =
1563                 {"SEQUENCE", "TABLE", "VIEW", NULL};
1564
1565                 COMPLETE_WITH_LIST(list_TEMP);
1566         }
1567
1568 /* CREATE TABLESPACE */
1569         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1570                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1571         {
1572                 static const char *const list_CREATETABLESPACE[] =
1573                 {"OWNER", "LOCATION", NULL};
1574
1575                 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1576         }
1577         /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1578         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1579                          pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1580                          pg_strcasecmp(prev2_wd, "OWNER") == 0)
1581         {
1582                 COMPLETE_WITH_CONST("LOCATION");
1583         }
1584
1585 /* CREATE TEXT SEARCH */
1586         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1587                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1588                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
1589         {
1590                 static const char *const list_CREATETEXTSEARCH[] =
1591                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1592
1593                 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
1594         }
1595         else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1596                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1597                          pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1598                 COMPLETE_WITH_CONST("(");
1599
1600 /* CREATE TRIGGER */
1601         /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1602         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1603                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1604         {
1605                 static const char *const list_CREATETRIGGER[] =
1606                 {"BEFORE", "AFTER", NULL};
1607
1608                 COMPLETE_WITH_LIST(list_CREATETRIGGER);
1609         }
1610         /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
1611         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1612                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1613                          (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
1614                           pg_strcasecmp(prev_wd, "AFTER") == 0))
1615         {
1616                 static const char *const list_CREATETRIGGER_EVENTS[] =
1617                 {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
1618
1619                 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
1620         }
1621         /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1622         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1623                          pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1624                          (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1625                           pg_strcasecmp(prev2_wd, "AFTER") == 0))
1626         {
1627                 static const char *const list_CREATETRIGGER2[] =
1628                 {"ON", "OR", NULL};
1629
1630                 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1631         }
1632
1633         /*
1634          * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
1635          * tables
1636          */
1637         else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
1638                          (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
1639                           pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
1640                          pg_strcasecmp(prev_wd, "ON") == 0)
1641                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1642         /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
1643         else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0)
1644                 COMPLETE_WITH_CONST("PROCEDURE");
1645
1646 /* CREATE ROLE,USER,GROUP */
1647         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1648                          !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1649                          (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1650                           pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1651         {
1652                 static const char *const list_CREATEROLE[] =
1653                 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1654                         "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOINHERIT", "NOLOGIN", "NOCREATEDB",
1655                         "NOCREATEROLE", "NOCREATEUSER", "NOSUPERUSER", "ROLE", "SUPERUSER", "SYSID",
1656                 "UNENCRYPTED", NULL};
1657
1658                 COMPLETE_WITH_LIST(list_CREATEROLE);
1659         }
1660
1661         /*
1662          * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1663          * PASSWORD
1664          */
1665         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1666                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1667                           pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1668                          (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1669         {
1670                 COMPLETE_WITH_CONST("PASSWORD");
1671         }
1672         /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1673         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1674                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1675                           pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1676                          pg_strcasecmp(prev_wd, "IN") == 0)
1677         {
1678                 static const char *const list_CREATEROLE3[] =
1679                 {"GROUP", "ROLE", NULL};
1680
1681                 COMPLETE_WITH_LIST(list_CREATEROLE3);
1682         }
1683
1684 /* CREATE VIEW */
1685         /* Complete CREATE VIEW <name> with AS */
1686         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1687                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
1688                 COMPLETE_WITH_CONST("AS");
1689         /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1690         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1691                          pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1692                          pg_strcasecmp(prev_wd, "AS") == 0)
1693                 COMPLETE_WITH_CONST("SELECT");
1694
1695 /* DECLARE */
1696         else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1697         {
1698                 static const char *const list_DECLARE[] =
1699                 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1700
1701                 COMPLETE_WITH_LIST(list_DECLARE);
1702         }
1703
1704 /* CURSOR */
1705         else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1706         {
1707                 static const char *const list_DECLARECURSOR[] =
1708                 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1709
1710                 COMPLETE_WITH_LIST(list_DECLARECURSOR);
1711         }
1712
1713
1714 /* DELETE */
1715
1716         /*
1717          * Complete DELETE with FROM (only if the word before that is not "ON"
1718          * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1719          */
1720         else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1721                          !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1722                            pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1723                            pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1724                            pg_strcasecmp(prev2_wd, "AFTER") == 0))
1725                 COMPLETE_WITH_CONST("FROM");
1726         /* Complete DELETE FROM with a list of tables */
1727         else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1728                          pg_strcasecmp(prev_wd, "FROM") == 0)
1729                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1730         /* Complete DELETE FROM <table> */
1731         else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1732                          pg_strcasecmp(prev2_wd, "FROM") == 0)
1733         {
1734                 static const char *const list_DELETE[] =
1735                 {"USING", "WHERE", "SET", NULL};
1736
1737                 COMPLETE_WITH_LIST(list_DELETE);
1738         }
1739         /* XXX: implement tab completion for DELETE ... USING */
1740
1741 /* DISCARD */
1742         else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
1743         {
1744                 static const char *const list_DISCARD[] =
1745                 {"ALL", "PLANS", "TEMP", NULL};
1746
1747                 COMPLETE_WITH_LIST(list_DISCARD);
1748         }
1749
1750 /* DO */
1751
1752         /*
1753          * Complete DO with LANGUAGE.
1754          */
1755         else if (pg_strcasecmp(prev_wd, "DO") == 0)
1756         {
1757                 static const char *const list_DO[] =
1758                 {"LANGUAGE", NULL};
1759
1760                 COMPLETE_WITH_LIST(list_DO);
1761         }
1762
1763 /* DROP (when not the previous word) */
1764         /* DROP AGGREGATE */
1765         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1766                          pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1767                 COMPLETE_WITH_CONST("(");
1768
1769         /* DROP object with CASCADE / RESTRICT */
1770         else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1771                           (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1772                            pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1773                            pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1774                            pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1775                            pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1776                            pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1777                            pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1778                            pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
1779                            pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1780                            pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1781                            pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1782                          (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1783                           pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1784                           prev_wd[strlen(prev_wd) - 1] == ')') ||
1785                          (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
1786                           pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1787                           pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1788                           pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
1789                          (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
1790                           pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1791                           pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1792                           (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
1793                            pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
1794                            pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
1795                            pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
1796                 )
1797         {
1798                 if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1799                         pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
1800                 {
1801                         COMPLETE_WITH_CONST("(");
1802                 }
1803                 else
1804                 {
1805                         static const char *const list_DROPCR[] =
1806                         {"CASCADE", "RESTRICT", NULL};
1807
1808                         COMPLETE_WITH_LIST(list_DROPCR);
1809                 }
1810         }
1811         else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1812                          (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
1813                           pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
1814                          pg_strcasecmp(prev_wd, "(") == 0)
1815         {
1816                 char       *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
1817
1818                 sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
1819                 COMPLETE_WITH_QUERY(tmp_buf);
1820                 free(tmp_buf);
1821         }
1822         /* DROP OWNED BY */
1823         else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1824                          pg_strcasecmp(prev_wd, "OWNED") == 0)
1825                 COMPLETE_WITH_CONST("BY");
1826         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1827                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1828                          pg_strcasecmp(prev_wd, "BY") == 0)
1829                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1830         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1831                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1832                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
1833         {
1834
1835                 static const char *const list_ALTERTEXTSEARCH[] =
1836                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1837
1838                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1839         }
1840
1841 /* EXPLAIN */
1842
1843         /*
1844          * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1845          */
1846         else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1847         {
1848                 static const char *const list_EXPLAIN[] =
1849                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
1850
1851                 COMPLETE_WITH_LIST(list_EXPLAIN);
1852         }
1853         else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1854                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1855         {
1856                 static const char *const list_EXPLAIN[] =
1857                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
1858
1859                 COMPLETE_WITH_LIST(list_EXPLAIN);
1860         }
1861         else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1862                           pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
1863                          (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
1864                           pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
1865                           pg_strcasecmp(prev_wd, "VERBOSE") == 0))
1866         {
1867                 static const char *const list_EXPLAIN[] =
1868                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
1869
1870                 COMPLETE_WITH_LIST(list_EXPLAIN);
1871         }
1872
1873 /* FETCH && MOVE */
1874         /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1875         else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1876                          pg_strcasecmp(prev_wd, "MOVE") == 0)
1877         {
1878                 static const char *const list_FETCH1[] =
1879                 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1880
1881                 COMPLETE_WITH_LIST(list_FETCH1);
1882         }
1883         /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1884         else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1885                          pg_strcasecmp(prev2_wd, "MOVE") == 0)
1886         {
1887                 static const char *const list_FETCH2[] =
1888                 {"ALL", "NEXT", "PRIOR", NULL};
1889
1890                 COMPLETE_WITH_LIST(list_FETCH2);
1891         }
1892
1893         /*
1894          * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
1895          * but we may as well tab-complete both: perhaps some users prefer one
1896          * variant or the other.
1897          */
1898         else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
1899                          pg_strcasecmp(prev3_wd, "MOVE") == 0)
1900         {
1901                 static const char *const list_FROMIN[] =
1902                 {"FROM", "IN", NULL};
1903
1904                 COMPLETE_WITH_LIST(list_FROMIN);
1905         }
1906
1907 /* FOREIGN DATA WRAPPER */
1908         /* applies in ALTER/DROP FDW and in CREATE SERVER */
1909         else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
1910                          pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
1911                          pg_strcasecmp(prev2_wd, "DATA") == 0 &&
1912                          pg_strcasecmp(prev_wd, "WRAPPER") == 0)
1913                 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
1914
1915 /* GRANT && REVOKE*/
1916         /* Complete GRANT/REVOKE with a list of privileges */
1917         else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
1918                          pg_strcasecmp(prev_wd, "REVOKE") == 0)
1919         {
1920                 static const char *const list_privilege[] =
1921                 {"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
1922                         "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
1923                 "ALL", NULL};
1924
1925                 COMPLETE_WITH_LIST(list_privilege);
1926         }
1927         /* Complete GRANT/REVOKE <sth> with "ON" */
1928         else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1929                          pg_strcasecmp(prev2_wd, "REVOKE") == 0)
1930                 COMPLETE_WITH_CONST("ON");
1931
1932         /*
1933          * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
1934          * and indexes
1935          *
1936          * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
1937          * UNION; seems to work intuitively
1938          *
1939          * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
1940          * here will only work if the privilege list contains exactly one
1941          * privilege
1942          */
1943         else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
1944                           pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
1945                          pg_strcasecmp(prev_wd, "ON") == 0)
1946                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
1947                                                                    " UNION SELECT 'DATABASE'"
1948                                                                    " UNION SELECT 'FOREIGN DATA WRAPPER'"
1949                                                                    " UNION SELECT 'FOREIGN SERVER'"
1950                                                                    " UNION SELECT 'FUNCTION'"
1951                                                                    " UNION SELECT 'LANGUAGE'"
1952                                                                    " UNION SELECT 'LARGE OBJECT'"
1953                                                                    " UNION SELECT 'SCHEMA'"
1954                                                                    " UNION SELECT 'TABLESPACE'");
1955         else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1956                           pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1957                          pg_strcasecmp(prev2_wd, "ON") == 0 &&
1958                          pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1959         {
1960                 static const char *const list_privilege_foreign[] =
1961                 {"DATA WRAPPER", "SERVER", NULL};
1962
1963                 COMPLETE_WITH_LIST(list_privilege_foreign);
1964         }
1965
1966         /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
1967         else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1968                           pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1969                          pg_strcasecmp(prev2_wd, "ON") == 0)
1970         {
1971                 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1972                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1973                 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
1974                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1975                 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
1976                         COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1977                 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
1978                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1979                 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1980                         COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1981                 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
1982                         COMPLETE_WITH_CONST("TO");
1983                 else
1984                         COMPLETE_WITH_CONST("FROM");
1985         }
1986
1987         /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1988         else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
1989                          pg_strcasecmp(prev3_wd, "ON") == 0)
1990         {
1991                 if (pg_strcasecmp(prev_wd, "TO") == 0)
1992                         COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1993                 else
1994                         COMPLETE_WITH_CONST("TO");
1995         }
1996         else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
1997                          pg_strcasecmp(prev3_wd, "ON") == 0)
1998         {
1999                 if (pg_strcasecmp(prev_wd, "FROM") == 0)
2000                         COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2001                 else
2002                         COMPLETE_WITH_CONST("FROM");
2003         }
2004
2005 /* GROUP BY */
2006         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2007                          pg_strcasecmp(prev_wd, "GROUP") == 0)
2008                 COMPLETE_WITH_CONST("BY");
2009
2010 /* INSERT */
2011         /* Complete INSERT with "INTO" */
2012         else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
2013                 COMPLETE_WITH_CONST("INTO");
2014         /* Complete INSERT INTO with table names */
2015         else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
2016                          pg_strcasecmp(prev_wd, "INTO") == 0)
2017                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2018         /* Complete "INSERT INTO <table> (" with attribute names */
2019         else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2020                          pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2021                          pg_strcasecmp(prev_wd, "(") == 0)
2022                 COMPLETE_WITH_ATTR(prev2_wd, "");
2023
2024         /*
2025          * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
2026          * "TABLE" or "DEFAULT VALUES"
2027          */
2028         else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
2029                          pg_strcasecmp(prev2_wd, "INTO") == 0)
2030         {
2031                 static const char *const list_INSERT[] =
2032                 {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
2033
2034                 COMPLETE_WITH_LIST(list_INSERT);
2035         }
2036
2037         /*
2038          * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
2039          * "TABLE"
2040          */
2041         else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2042                          pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2043                          prev_wd[strlen(prev_wd) - 1] == ')')
2044         {
2045                 static const char *const list_INSERT[] =
2046                 {"SELECT", "TABLE", "VALUES", NULL};
2047
2048                 COMPLETE_WITH_LIST(list_INSERT);
2049         }
2050
2051         /* Insert an open parenthesis after "VALUES" */
2052         else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
2053                          pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
2054                 COMPLETE_WITH_CONST("(");
2055
2056 /* LOCK */
2057         /* Complete LOCK [TABLE] with a list of tables */
2058         else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
2059                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2060                                                                    " UNION SELECT 'TABLE'");
2061         else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2062                          pg_strcasecmp(prev2_wd, "LOCK") == 0)
2063                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
2064
2065         /* For the following, handle the case of a single table only for now */
2066
2067         /* Complete LOCK [TABLE] <table> with "IN" */
2068         else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
2069                           pg_strcasecmp(prev_wd, "TABLE")) ||
2070                          (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
2071                           pg_strcasecmp(prev3_wd, "LOCK") == 0))
2072                 COMPLETE_WITH_CONST("IN");
2073
2074         /* Complete LOCK [TABLE] <table> IN with a lock mode */
2075         else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
2076                          (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
2077                           (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
2078                            pg_strcasecmp(prev4_wd, "LOCK") == 0)))
2079         {
2080                 static const char *const lock_modes[] =
2081                 {"ACCESS SHARE MODE",
2082                         "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
2083                         "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
2084                         "SHARE ROW EXCLUSIVE MODE",
2085                 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
2086
2087                 COMPLETE_WITH_LIST(lock_modes);
2088         }
2089
2090 /* NOTIFY */
2091         else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
2092                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s'");
2093
2094 /* OPTIONS */
2095         else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
2096                 COMPLETE_WITH_CONST("(");
2097
2098 /* OWNER TO  - complete with available roles */
2099         else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
2100                          pg_strcasecmp(prev_wd, "TO") == 0)
2101                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2102
2103 /* ORDER BY */
2104         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2105                          pg_strcasecmp(prev_wd, "ORDER") == 0)
2106                 COMPLETE_WITH_CONST("BY");
2107         else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
2108                          pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
2109                          pg_strcasecmp(prev_wd, "BY") == 0)
2110                 COMPLETE_WITH_ATTR(prev3_wd, "");
2111
2112 /* PREPARE xx AS */
2113         else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
2114                          pg_strcasecmp(prev3_wd, "PREPARE") == 0)
2115         {
2116                 static const char *const list_PREPARE[] =
2117                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2118
2119                 COMPLETE_WITH_LIST(list_PREPARE);
2120         }
2121
2122 /*
2123  * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
2124  * managers, not for manual use in interactive sessions.
2125  */
2126
2127 /* REASSIGN OWNED BY xxx TO yyy */
2128         else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
2129                 COMPLETE_WITH_CONST("OWNED");
2130         else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
2131                          pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
2132                 COMPLETE_WITH_CONST("BY");
2133         else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
2134                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2135                          pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
2136                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2137         else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
2138                          pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
2139                          pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
2140                 COMPLETE_WITH_CONST("TO");
2141         else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
2142                          pg_strcasecmp(prev3_wd, "BY") == 0 &&
2143                          pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
2144                          pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
2145                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2146
2147 /* REINDEX */
2148         else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
2149         {
2150                 static const char *const list_REINDEX[] =
2151                 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
2152
2153                 COMPLETE_WITH_LIST(list_REINDEX);
2154         }
2155         else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
2156         {
2157                 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
2158                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2159                 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
2160                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2161                 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
2162                                  pg_strcasecmp(prev_wd, "DATABASE") == 0)
2163                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2164         }
2165
2166 /* SELECT */
2167         /* naah . . . */
2168
2169 /* SET, RESET, SHOW */
2170         /* Complete with a variable name */
2171         else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
2172                           pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
2173                          pg_strcasecmp(prev_wd, "RESET") == 0)
2174                 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
2175         else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
2176                 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
2177         /* Complete "SET TRANSACTION" */
2178         else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
2179                           pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2180                          || (pg_strcasecmp(prev2_wd, "START") == 0
2181                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2182                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2183                                  && pg_strcasecmp(prev_wd, "WORK") == 0)
2184                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2185                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2186                          || (pg_strcasecmp(prev4_wd, "SESSION") == 0
2187                                  && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
2188                                  && pg_strcasecmp(prev2_wd, "AS") == 0
2189                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
2190         {
2191                 static const char *const my_list[] =
2192                 {"ISOLATION LEVEL", "READ", NULL};
2193
2194                 COMPLETE_WITH_LIST(my_list);
2195         }
2196         else if ((pg_strcasecmp(prev3_wd, "SET") == 0
2197                           || pg_strcasecmp(prev3_wd, "BEGIN") == 0
2198                           || pg_strcasecmp(prev3_wd, "START") == 0
2199                           || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
2200                                   && pg_strcasecmp(prev3_wd, "AS") == 0))
2201                          && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
2202                                  || pg_strcasecmp(prev2_wd, "WORK") == 0)
2203                          && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
2204                 COMPLETE_WITH_CONST("LEVEL");
2205         else if ((pg_strcasecmp(prev4_wd, "SET") == 0
2206                           || pg_strcasecmp(prev4_wd, "BEGIN") == 0
2207                           || pg_strcasecmp(prev4_wd, "START") == 0
2208                           || pg_strcasecmp(prev4_wd, "AS") == 0)
2209                          && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
2210                                  || pg_strcasecmp(prev3_wd, "WORK") == 0)
2211                          && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
2212                          && pg_strcasecmp(prev_wd, "LEVEL") == 0)
2213         {
2214                 static const char *const my_list[] =
2215                 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
2216
2217                 COMPLETE_WITH_LIST(my_list);
2218         }
2219         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2220                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2221                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2222                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2223                          pg_strcasecmp(prev_wd, "READ") == 0)
2224         {
2225                 static const char *const my_list[] =
2226                 {"UNCOMMITTED", "COMMITTED", NULL};
2227
2228                 COMPLETE_WITH_LIST(my_list);
2229         }
2230         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2231                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2232                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2233                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2234                          pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
2235                 COMPLETE_WITH_CONST("READ");
2236         else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
2237                           pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
2238                           pg_strcasecmp(prev3_wd, "START") == 0 ||
2239                           pg_strcasecmp(prev3_wd, "AS") == 0) &&
2240                          (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
2241                           pg_strcasecmp(prev2_wd, "WORK") == 0) &&
2242                          pg_strcasecmp(prev_wd, "READ") == 0)
2243         {
2244                 static const char *const my_list[] =
2245                 {"ONLY", "WRITE", NULL};
2246
2247                 COMPLETE_WITH_LIST(my_list);
2248         }
2249         /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
2250         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2251                          pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
2252         {
2253                 static const char *const constraint_list[] =
2254                 {"DEFERRED", "IMMEDIATE", NULL};
2255
2256                 COMPLETE_WITH_LIST(constraint_list);
2257         }
2258         /* Complete SET ROLE */
2259         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2260                          pg_strcasecmp(prev_wd, "ROLE") == 0)
2261                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2262         /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
2263         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2264                          pg_strcasecmp(prev_wd, "SESSION") == 0)
2265         {
2266                 static const char *const my_list[] =
2267                 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
2268
2269                 COMPLETE_WITH_LIST(my_list);
2270         }
2271         /* Complete SET SESSION AUTHORIZATION with username */
2272         else if (pg_strcasecmp(prev3_wd, "SET") == 0
2273                          && pg_strcasecmp(prev2_wd, "SESSION") == 0
2274                          && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
2275                 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
2276         /* Complete RESET SESSION with AUTHORIZATION */
2277         else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
2278                          pg_strcasecmp(prev_wd, "SESSION") == 0)
2279                 COMPLETE_WITH_CONST("AUTHORIZATION");
2280         /* Complete SET <var> with "TO" */
2281         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2282                          pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
2283                          pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
2284                          pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
2285                          prev_wd[strlen(prev_wd) - 1] != ')' &&
2286                          pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
2287                 COMPLETE_WITH_CONST("TO");
2288         /* Suggest possible variable values */
2289         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2290                          (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
2291         {
2292                 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
2293                 {
2294                         static const char *const my_list[] =
2295                         {"ISO", "SQL", "Postgres", "German",
2296                                 "YMD", "DMY", "MDY",
2297                                 "US", "European", "NonEuropean",
2298                         "DEFAULT", NULL};
2299
2300                         COMPLETE_WITH_LIST(my_list);
2301                 }
2302                 else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
2303                 {
2304                         static const char *const my_list[] =
2305                         {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
2306
2307                         COMPLETE_WITH_LIST(my_list);
2308                 }
2309                 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
2310                 {
2311                         static const char *const my_list[] =
2312                         {"ON", "OFF", "DEFAULT", NULL};
2313
2314                         COMPLETE_WITH_LIST(my_list);
2315                 }
2316                 else
2317                 {
2318                         static const char *const my_list[] =
2319                         {"DEFAULT", NULL};
2320
2321                         COMPLETE_WITH_LIST(my_list);
2322                 }
2323         }
2324
2325 /* START TRANSACTION */
2326         else if (pg_strcasecmp(prev_wd, "START") == 0)
2327                 COMPLETE_WITH_CONST("TRANSACTION");
2328
2329 /* TRUNCATE */
2330         else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
2331                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2332
2333 /* UNLISTEN */
2334         else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
2335                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s' UNION SELECT '*'");
2336
2337 /* UPDATE */
2338         /* If prev. word is UPDATE suggest a list of tables */
2339         else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
2340                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2341         /* Complete UPDATE <table> with "SET" */
2342         else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
2343                 COMPLETE_WITH_CONST("SET");
2344
2345         /*
2346          * If the previous word is SET (and it wasn't caught above as the _first_
2347          * word) the word before it was (hopefully) a table name and we'll now
2348          * make a list of attributes.
2349          */
2350         else if (pg_strcasecmp(prev_wd, "SET") == 0)
2351                 COMPLETE_WITH_ATTR(prev2_wd, "");
2352
2353 /* UPDATE xx SET yy = */
2354         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2355                          pg_strcasecmp(prev4_wd, "UPDATE") == 0)
2356                 COMPLETE_WITH_CONST("=");
2357
2358 /* USER MAPPING */
2359         else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
2360                           pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2361                           pg_strcasecmp(prev3_wd, "DROP") == 0) &&
2362                          pg_strcasecmp(prev2_wd, "USER") == 0 &&
2363                          pg_strcasecmp(prev_wd, "MAPPING") == 0)
2364                 COMPLETE_WITH_CONST("FOR");
2365         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2366                          pg_strcasecmp(prev3_wd, "USER") == 0 &&
2367                          pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2368                          pg_strcasecmp(prev_wd, "FOR") == 0)
2369                 COMPLETE_WITH_QUERY(Query_for_list_of_roles
2370                                                         " UNION SELECT 'CURRENT_USER'"
2371                                                         " UNION SELECT 'PUBLIC'"
2372                                                         " UNION SELECT 'USER'");
2373         else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
2374                           pg_strcasecmp(prev4_wd, "DROP") == 0) &&
2375                          pg_strcasecmp(prev3_wd, "USER") == 0 &&
2376                          pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2377                          pg_strcasecmp(prev_wd, "FOR") == 0)
2378                 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2379         else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
2380                           pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
2381                           pg_strcasecmp(prev5_wd, "DROP") == 0) &&
2382                          pg_strcasecmp(prev4_wd, "USER") == 0 &&
2383                          pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
2384                          pg_strcasecmp(prev2_wd, "FOR") == 0)
2385                 COMPLETE_WITH_CONST("SERVER");
2386
2387 /*
2388  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
2389  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
2390  */
2391         else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
2392                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2393                                                                    " UNION SELECT 'FULL'"
2394                                                                    " UNION SELECT 'FREEZE'"
2395                                                                    " UNION SELECT 'ANALYZE'"
2396                                                                    " UNION SELECT 'VERBOSE'");
2397         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2398                          (pg_strcasecmp(prev_wd, "FULL") == 0 ||
2399                           pg_strcasecmp(prev_wd, "FREEZE") == 0))
2400                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2401                                                                    " UNION SELECT 'ANALYZE'"
2402                                                                    " UNION SELECT 'VERBOSE'");
2403         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2404                          pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2405                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2406                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2407                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2408                                                                    " UNION SELECT 'VERBOSE'");
2409         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2410                          pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2411                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2412                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2413                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2414                                                                    " UNION SELECT 'ANALYZE'");
2415         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2416                          pg_strcasecmp(prev_wd, "VERBOSE") == 0)
2417                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2418                                                                    " UNION SELECT 'ANALYZE'");
2419         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2420                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2421                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2422                                                                    " UNION SELECT 'VERBOSE'");
2423         else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2424                           pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
2425                          (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2426                           pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
2427                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2428
2429 /* WITH [RECURSIVE] */
2430         else if (pg_strcasecmp(prev_wd, "WITH") == 0)
2431                 COMPLETE_WITH_CONST("RECURSIVE");
2432
2433 /* ANALYZE */
2434         /* If the previous word is ANALYZE, produce list of tables */
2435         else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2436                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2437
2438 /* WHERE */
2439         /* Simple case of the word before the where being the table name */
2440         else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
2441                 COMPLETE_WITH_ATTR(prev2_wd, "");
2442
2443 /* ... FROM ... */
2444 /* TODO: also include SRF ? */
2445         else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
2446                          pg_strcasecmp(prev3_wd, "COPY") != 0 &&
2447                          pg_strcasecmp(prev3_wd, "\\copy") != 0)
2448                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
2449
2450
2451 /* Backslash commands */
2452 /* TODO:  \dc \dd \dl */
2453         else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
2454                 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2455
2456         else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
2457                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
2458         else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
2459                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2460         else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
2461                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2462         else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
2463                 COMPLETE_WITH_QUERY(Query_for_list_of_servers);
2464         else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
2465                 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2466         else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
2467                 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2468
2469         else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
2470                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2471         else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
2472                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
2473         else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
2474                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
2475         else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
2476                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
2477         /* must be at end of \dF */
2478         else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
2479                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
2480
2481         else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
2482                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2483         else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
2484                 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2485         else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0)
2486                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
2487         else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
2488                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
2489         else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
2490                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2491         else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
2492                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2493         else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0)
2494                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2495         else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
2496                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2497
2498         /* must be at end of \d list */
2499         else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
2500                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
2501
2502         else if (strcmp(prev_wd, "\\ef") == 0)
2503                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2504
2505         else if (strcmp(prev_wd, "\\encoding") == 0)
2506                 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
2507         else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
2508                 COMPLETE_WITH_LIST(sql_commands);
2509         else if (strcmp(prev_wd, "\\password") == 0)
2510                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2511         else if (strcmp(prev_wd, "\\pset") == 0)
2512         {
2513                 static const char *const my_list[] =
2514                 {"format", "border", "expanded",
2515                         "null", "fieldsep", "tuples_only", "title", "tableattr",
2516                 "linestyle", "pager", "recordsep", NULL};
2517
2518                 COMPLETE_WITH_LIST(my_list);
2519         }
2520         else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
2521                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2522         else if (strcmp(prev_wd, "\\cd") == 0 ||
2523                          strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
2524                          strcmp(prev_wd, "\\g") == 0 ||
2525                   strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
2526                          strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
2527                          strcmp(prev_wd, "\\s") == 0 ||
2528                          strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
2529                 )
2530                 matches = completion_matches(text, filename_completion_function);
2531
2532
2533         /*
2534          * Finally, we look through the list of "things", such as TABLE, INDEX and
2535          * check if that was the previous word. If so, execute the query to get a
2536          * list of them.
2537          */
2538         else
2539         {
2540                 int                     i;
2541
2542                 for (i = 0; words_after_create[i].name; i++)
2543                 {
2544                         if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
2545                         {
2546                                 if (words_after_create[i].query)
2547                                         COMPLETE_WITH_QUERY(words_after_create[i].query);
2548                                 else if (words_after_create[i].squery)
2549                                         COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
2550                                                                                            NULL);
2551                                 break;
2552                         }
2553                 }
2554         }
2555
2556         /*
2557          * If we still don't have anything to match we have to fabricate some sort
2558          * of default list. If we were to just return NULL, readline automatically
2559          * attempts filename completion, and that's usually no good.
2560          */
2561         if (matches == NULL)
2562         {
2563                 COMPLETE_WITH_CONST("");
2564 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
2565                 rl_completion_append_character = '\0';
2566 #endif
2567         }
2568
2569         /* free storage */
2570         free(prev_wd);
2571         free(prev2_wd);
2572         free(prev3_wd);
2573         free(prev4_wd);
2574         free(prev5_wd);
2575
2576         /* Return our Grand List O' Matches */
2577         return matches;
2578 }
2579
2580
2581
2582 /* GENERATOR FUNCTIONS
2583
2584    These functions do all the actual work of completing the input. They get
2585    passed the text so far and the count how many times they have been called so
2586    far with the same text.
2587    If you read the above carefully, you'll see that these don't get called
2588    directly but through the readline interface.
2589    The return value is expected to be the full completion of the text, going
2590    through a list each time, or NULL if there are no more matches. The string
2591    will be free()'d by readline, so you must run it through strdup() or
2592    something of that sort.
2593 */
2594
2595 /* This one gives you one from a list of things you can put after CREATE
2596    as defined above.
2597 */
2598 static char *
2599 create_command_generator(const char *text, int state)
2600 {
2601         static int      list_index,
2602                                 string_length;
2603         const char *name;
2604
2605         /* If this is the first time for this completion, init some values */
2606         if (state == 0)
2607         {
2608                 list_index = 0;
2609                 string_length = strlen(text);
2610         }
2611
2612         /* find something that matches */
2613         while ((name = words_after_create[list_index++].name))
2614         {
2615                 if ((pg_strncasecmp(name, text, string_length) == 0) && !words_after_create[list_index - 1].noshow)
2616                         return pg_strdup(name);
2617         }
2618         /* if nothing matches, return NULL */
2619         return NULL;
2620 }
2621
2622 /*
2623  * This function gives you a list of things you can put after a DROP command.
2624  * Very similar to create_command_generator, but has an additional entry for
2625  * OWNED BY.  (We do it this way in order not to duplicate the
2626  * words_after_create list.)
2627  */
2628 static char *
2629 drop_command_generator(const char *text, int state)
2630 {
2631         static int      list_index,
2632                                 string_length;
2633         const char *name;
2634
2635         if (state == 0)
2636         {
2637                 /* If this is the first time for this completion, init some values */
2638                 list_index = 0;
2639                 string_length = strlen(text);
2640
2641                 /*
2642                  * DROP can be followed by "OWNED BY", which is not found in the list
2643                  * for CREATE matches, so make it the first state. (We do not make it
2644                  * the last state because it would be more difficult to detect when we
2645                  * have to return NULL instead.)
2646                  *
2647                  * Make sure we advance to the next state.
2648                  */
2649                 list_index++;
2650                 if (pg_strncasecmp("OWNED", text, string_length) == 0)
2651                         return pg_strdup("OWNED");
2652         }
2653
2654         /*
2655          * In subsequent attempts, try to complete with the same items we use for
2656          * CREATE
2657          */
2658         while ((name = words_after_create[list_index++ - 1].name))
2659         {
2660                 if ((pg_strncasecmp(name, text, string_length) == 0) && (!words_after_create[list_index - 2].noshow))
2661                         return pg_strdup(name);
2662         }
2663
2664         /* if nothing matches, return NULL */
2665         return NULL;
2666 }
2667
2668 /* The following two functions are wrappers for _complete_from_query */
2669
2670 static char *
2671 complete_from_query(const char *text, int state)
2672 {
2673         return _complete_from_query(0, text, state);
2674 }
2675
2676 static char *
2677 complete_from_schema_query(const char *text, int state)
2678 {
2679         return _complete_from_query(1, text, state);
2680 }
2681
2682
2683 /* This creates a list of matching things, according to a query pointed to
2684    by completion_charp.
2685    The query can be one of two kinds:
2686    - A simple query which must contain a %d and a %s, which will be replaced
2687    by the string length of the text and the text itself. The query may also
2688    have up to four more %s in it; the first two such will be replaced by the
2689    value of completion_info_charp, the next two by the value of
2690    completion_info_charp2.
2691          or:
2692    - A schema query used for completion of both schema and relation names;
2693    these are more complex and must contain in the following order:
2694          %d %s %d %s %d %s %s %d %s
2695    where %d is the string length of the text and %s the text itself.
2696
2697    It is assumed that strings should be escaped to become SQL literals
2698    (that is, what is in the query is actually ... '%s' ...)
2699
2700    See top of file for examples of both kinds of query.
2701 */
2702
2703 static char *
2704 _complete_from_query(int is_schema_query, const char *text, int state)
2705 {
2706         static int      list_index,
2707                                 string_length;
2708         static PGresult *result = NULL;
2709
2710         /*
2711          * If this is the first time for this completion, we fetch a list of our
2712          * "things" from the backend.
2713          */
2714         if (state == 0)
2715         {
2716                 PQExpBufferData query_buffer;
2717                 char       *e_text;
2718                 char       *e_info_charp;
2719                 char       *e_info_charp2;
2720
2721                 list_index = 0;
2722                 string_length = strlen(text);
2723
2724                 /* Free any prior result */
2725                 PQclear(result);
2726                 result = NULL;
2727
2728                 /* Set up suitably-escaped copies of textual inputs */
2729                 e_text = pg_malloc(string_length * 2 + 1);
2730                 PQescapeString(e_text, text, string_length);
2731
2732                 if (completion_info_charp)
2733                 {
2734                         size_t          charp_len;
2735
2736                         charp_len = strlen(completion_info_charp);
2737                         e_info_charp = pg_malloc(charp_len * 2 + 1);
2738                         PQescapeString(e_info_charp, completion_info_charp,
2739                                                    charp_len);
2740                 }
2741                 else
2742                         e_info_charp = NULL;
2743
2744                 if (completion_info_charp2)
2745                 {
2746                         size_t          charp_len;
2747
2748                         charp_len = strlen(completion_info_charp2);
2749                         e_info_charp2 = pg_malloc(charp_len * 2 + 1);
2750                         PQescapeString(e_info_charp2, completion_info_charp2,
2751                                                    charp_len);
2752                 }
2753                 else
2754                         e_info_charp2 = NULL;
2755
2756                 initPQExpBuffer(&query_buffer);
2757
2758                 if (is_schema_query)
2759                 {
2760                         /* completion_squery gives us the pieces to assemble */
2761                         const char *qualresult = completion_squery->qualresult;
2762
2763                         if (qualresult == NULL)
2764                                 qualresult = completion_squery->result;
2765
2766                         /* Get unqualified names matching the input-so-far */
2767                         appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
2768                                                           completion_squery->result,
2769                                                           completion_squery->catname);
2770                         if (completion_squery->selcondition)
2771                                 appendPQExpBuffer(&query_buffer, "%s AND ",
2772                                                                   completion_squery->selcondition);
2773                         appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
2774                                                           completion_squery->result,
2775                                                           string_length, e_text);
2776                         appendPQExpBuffer(&query_buffer, " AND %s",
2777                                                           completion_squery->viscondition);
2778
2779                         /*
2780                          * When fetching relation names, suppress system catalogs unless
2781                          * the input-so-far begins with "pg_".  This is a compromise
2782                          * between not offering system catalogs for completion at all, and
2783                          * having them swamp the result when the input is just "p".
2784                          */
2785                         if (strcmp(completion_squery->catname,
2786                                            "pg_catalog.pg_class c") == 0 &&
2787                                 strncmp(text, "pg_", 3) !=0)
2788                         {
2789                                 appendPQExpBuffer(&query_buffer,
2790                                                                   " AND c.relnamespace <> (SELECT oid FROM"
2791                                    " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
2792                         }
2793
2794                         /*
2795                          * Add in matching schema names, but only if there is more than
2796                          * one potential match among schema names.
2797                          */
2798                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
2799                                                    "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
2800                                                           "FROM pg_catalog.pg_namespace n "
2801                                                           "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
2802                                                           string_length, e_text);
2803                         appendPQExpBuffer(&query_buffer,
2804                                                           " AND (SELECT pg_catalog.count(*)"
2805                                                           " FROM pg_catalog.pg_namespace"
2806                         " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2807                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
2808                                                           string_length, e_text);
2809
2810                         /*
2811                          * Add in matching qualified names, but only if there is exactly
2812                          * one schema matching the input-so-far.
2813                          */
2814                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
2815                                          "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
2816                                                           "FROM %s, pg_catalog.pg_namespace n "
2817                                                           "WHERE %s = n.oid AND ",
2818                                                           qualresult,
2819                                                           completion_squery->catname,
2820                                                           completion_squery->namespace);
2821                         if (completion_squery->selcondition)
2822                                 appendPQExpBuffer(&query_buffer, "%s AND ",
2823                                                                   completion_squery->selcondition);
2824                         appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
2825                                                           qualresult,
2826                                                           string_length, e_text);
2827
2828                         /*
2829                          * This condition exploits the single-matching-schema rule to
2830                          * speed up the query
2831                          */
2832                         appendPQExpBuffer(&query_buffer,
2833                         " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
2834                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
2835                                                           string_length, e_text);
2836                         appendPQExpBuffer(&query_buffer,
2837                                                           " AND (SELECT pg_catalog.count(*)"
2838                                                           " FROM pg_catalog.pg_namespace"
2839                         " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2840                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
2841                                                           string_length, e_text);
2842
2843                         /* If an addon query was provided, use it */
2844                         if (completion_charp)
2845                                 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
2846                 }
2847                 else
2848                 {
2849                         /* completion_charp is an sprintf-style format string */
2850                         appendPQExpBuffer(&query_buffer, completion_charp,
2851                                                           string_length, e_text,
2852                                                           e_info_charp, e_info_charp,
2853                                                           e_info_charp2, e_info_charp2);
2854                 }
2855
2856                 /* Limit the number of records in the result */
2857                 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
2858                                                   completion_max_records);
2859
2860                 result = exec_query(query_buffer.data);
2861
2862                 termPQExpBuffer(&query_buffer);
2863                 free(e_text);
2864                 if (e_info_charp)
2865                         free(e_info_charp);
2866                 if (e_info_charp2)
2867                         free(e_info_charp2);
2868         }
2869
2870         /* Find something that matches */
2871         if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
2872         {
2873                 const char *item;
2874
2875                 while (list_index < PQntuples(result) &&
2876                            (item = PQgetvalue(result, list_index++, 0)))
2877                         if (pg_strncasecmp(text, item, string_length) == 0)
2878                                 return pg_strdup(item);
2879         }
2880
2881         /* If nothing matches, free the db structure and return null */
2882         PQclear(result);
2883         result = NULL;
2884         return NULL;
2885 }
2886
2887
2888 /* This function returns in order one of a fixed, NULL pointer terminated list
2889    of strings (if matching). This can be used if there are only a fixed number
2890    SQL words that can appear at certain spot.
2891 */
2892 static char *
2893 complete_from_list(const char *text, int state)
2894 {
2895         static int      string_length,
2896                                 list_index,
2897                                 matches;
2898         static bool casesensitive;
2899         const char *item;
2900
2901         /* need to have a list */
2902         psql_assert(completion_charpp);
2903
2904         /* Initialization */
2905         if (state == 0)
2906         {
2907                 list_index = 0;
2908                 string_length = strlen(text);
2909                 casesensitive = true;
2910                 matches = 0;
2911         }
2912
2913         while ((item = completion_charpp[list_index++]))
2914         {
2915                 /* First pass is case sensitive */
2916                 if (casesensitive && strncmp(text, item, string_length) == 0)
2917                 {
2918                         matches++;
2919                         return pg_strdup(item);
2920                 }
2921
2922                 /* Second pass is case insensitive, don't bother counting matches */
2923                 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
2924                         return pg_strdup(item);
2925         }
2926
2927         /*
2928          * No matches found. If we're not case insensitive already, lets switch to
2929          * being case insensitive and try again
2930          */
2931         if (casesensitive && matches == 0)
2932         {
2933                 casesensitive = false;
2934                 list_index = 0;
2935                 state++;
2936                 return complete_from_list(text, state);
2937         }
2938
2939         /* If no more matches, return null. */
2940         return NULL;
2941 }
2942
2943
2944 /* This function returns one fixed string the first time even if it doesn't
2945    match what's there, and nothing the second time. This should be used if there
2946    is only one possibility that can appear at a certain spot, so misspellings
2947    will be overwritten.
2948    The string to be passed must be in completion_charp.
2949 */
2950 static char *
2951 complete_from_const(const char *text, int state)
2952 {
2953         (void) text;                            /* We don't care about what was entered
2954                                                                  * already. */
2955
2956         psql_assert(completion_charp);
2957         if (state == 0)
2958                 return pg_strdup(completion_charp);
2959         else
2960                 return NULL;
2961 }
2962
2963
2964
2965 /* HELPER FUNCTIONS */
2966
2967
2968 /*
2969  * Execute a query and report any errors. This should be the preferred way of
2970  * talking to the database in this file.
2971  */
2972 static PGresult *
2973 exec_query(const char *query)
2974 {
2975         PGresult   *result;
2976
2977         if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
2978                 return NULL;
2979
2980         result = PQexec(pset.db, query);
2981
2982         if (PQresultStatus(result) != PGRES_TUPLES_OK)
2983         {
2984 #if 0
2985                 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
2986                                    PQerrorMessage(pset.db), query);
2987 #endif
2988                 PQclear(result);
2989                 result = NULL;
2990         }
2991
2992         return result;
2993 }
2994
2995
2996
2997 /*
2998  * Return the word (space delimited) before point. Set skip > 0 to
2999  * skip that many words; e.g. skip=1 finds the word before the
3000  * previous one. Return value is NULL or a malloc'ed string.
3001  */
3002 static char *
3003 previous_word(int point, int skip)
3004 {
3005         int                     i,
3006                                 start = 0,
3007                                 end = -1,
3008                                 inquotes = 0;
3009         char       *s;
3010         const char *buf = rl_line_buffer;       /* alias */
3011
3012         /* first we look for a space or a parenthesis before the current word */
3013         for (i = point - 1; i >= 0; i--)
3014                 if (strchr(WORD_BREAKS, buf[i]))
3015                         break;
3016         point = i;
3017
3018         while (skip-- >= 0)
3019         {
3020                 int                     parentheses = 0;
3021
3022                 /* now find the first non-space which then constitutes the end */
3023                 for (i = point; i >= 0; i--)
3024                         if (buf[i] != ' ')
3025                         {
3026                                 end = i;
3027                                 break;
3028                         }
3029
3030                 /*
3031                  * If no end found we return null, because there is no word before the
3032                  * point
3033                  */
3034                 if (end == -1)
3035                         return NULL;
3036
3037                 /*
3038                  * Otherwise we now look for the start. The start is either the last
3039                  * character before any space going backwards from the end, or it's
3040                  * simply character 0. We also handle open quotes and parentheses.
3041                  */
3042                 for (start = end; start > 0; start--)
3043                 {
3044                         if (buf[start] == '"')
3045                                 inquotes = !inquotes;
3046                         if (inquotes == 0)
3047                         {
3048                                 if (buf[start] == ')')
3049                                         parentheses++;
3050                                 else if (buf[start] == '(')
3051                                 {
3052                                         if (--parentheses <= 0)
3053                                                 break;
3054                                 }
3055                                 else if (parentheses == 0 &&
3056                                                  strchr(WORD_BREAKS, buf[start - 1]))
3057                                         break;
3058                         }
3059                 }
3060
3061                 point = start - 1;
3062         }
3063
3064         /* make a copy */
3065         s = pg_malloc(end - start + 2);
3066         strlcpy(s, &buf[start], end - start + 2);
3067
3068         return s;
3069 }
3070
3071 #if 0
3072
3073 /*
3074  * Surround a string with single quotes. This works for both SQL and
3075  * psql internal. Currently disabled because it is reported not to
3076  * cooperate with certain versions of readline.
3077  */
3078 static char *
3079 quote_file_name(char *text, int match_type, char *quote_pointer)
3080 {
3081         char       *s;
3082         size_t          length;
3083
3084         (void) quote_pointer;           /* not used */
3085
3086         length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
3087         s = pg_malloc(length);
3088         s[0] = '\'';
3089         strcpy(s + 1, text);
3090         if (match_type == SINGLE_MATCH)
3091                 s[length - 2] = '\'';
3092         s[length - 1] = '\0';
3093         return s;
3094 }
3095
3096
3097
3098 static char *
3099 dequote_file_name(char *text, char quote_char)
3100 {
3101         char       *s;
3102         size_t          length;
3103
3104         if (!quote_char)
3105                 return pg_strdup(text);
3106
3107         length = strlen(text);
3108         s = pg_malloc(length - 2 + 1);
3109         strlcpy(s, text +1, length - 2 + 1);
3110
3111         return s;
3112 }
3113 #endif   /* 0 */
3114
3115 #endif   /* USE_READLINE */