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