]> granicus.if.org Git - postgresql/blob - src/bin/psql/tab-complete.c
5c74ae19ec26998421cb0d109d87a7c5efd112ae
[postgresql] / src / bin / psql / tab-complete.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2015, 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 static bool completion_case_sensitive;  /* completion is case sensitive */
136
137 /*
138  * A few macros to ease typing. You can use these to complete the given
139  * string with
140  * 1) The results from a query you pass it. (Perhaps one of those below?)
141  * 2) The results from a schema query you pass it.
142  * 3) The items from a null-pointer-terminated list.
143  * 4) A string constant.
144  * 5) The list of attributes of the given table (possibly schema-qualified).
145  * 6/ The list of arguments to the given function (possibly schema-qualified).
146  */
147 #define COMPLETE_WITH_QUERY(query) \
148 do { \
149         completion_charp = query; \
150         matches = completion_matches(text, complete_from_query); \
151 } while (0)
152
153 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
154 do { \
155         completion_squery = &(query); \
156         completion_charp = addon; \
157         matches = completion_matches(text, complete_from_schema_query); \
158 } while (0)
159
160 #define COMPLETE_WITH_LIST_CS(list) \
161 do { \
162         completion_charpp = list; \
163         completion_case_sensitive = true; \
164         matches = completion_matches(text, complete_from_list); \
165 } while (0)
166
167 #define COMPLETE_WITH_LIST(list) \
168 do { \
169         completion_charpp = list; \
170         completion_case_sensitive = false; \
171         matches = completion_matches(text, complete_from_list); \
172 } while (0)
173
174 #define COMPLETE_WITH_CONST(string) \
175 do { \
176         completion_charp = string; \
177         completion_case_sensitive = false; \
178         matches = completion_matches(text, complete_from_const); \
179 } while (0)
180
181 #define COMPLETE_WITH_ATTR(relation, addon) \
182 do { \
183         char   *_completion_schema; \
184         char   *_completion_table; \
185 \
186         _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
187                                                                  false, false, pset.encoding); \
188         (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
189                                    false, false, pset.encoding); \
190         _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
191                                                                 false, false, pset.encoding); \
192         if (_completion_table == NULL) \
193         { \
194                 completion_charp = Query_for_list_of_attributes  addon; \
195                 completion_info_charp = relation; \
196         } \
197         else \
198         { \
199                 completion_charp = Query_for_list_of_attributes_with_schema  addon; \
200                 completion_info_charp = _completion_table; \
201                 completion_info_charp2 = _completion_schema; \
202         } \
203         matches = completion_matches(text, complete_from_query); \
204 } while (0)
205
206 #define COMPLETE_WITH_FUNCTION_ARG(function) \
207 do { \
208         char   *_completion_schema; \
209         char   *_completion_function; \
210 \
211         _completion_schema = strtokx(function, " \t\n\r", ".", "\"", 0, \
212                                                                  false, false, pset.encoding); \
213         (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
214                                    false, false, pset.encoding); \
215         _completion_function = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
216                                                                    false, false, pset.encoding); \
217         if (_completion_function == NULL) \
218         { \
219                 completion_charp = Query_for_list_of_arguments; \
220                 completion_info_charp = function; \
221         } \
222         else \
223         { \
224                 completion_charp = Query_for_list_of_arguments_with_schema; \
225                 completion_info_charp = _completion_function; \
226                 completion_info_charp2 = _completion_schema; \
227         } \
228         matches = completion_matches(text, complete_from_query); \
229 } while (0)
230
231 /*
232  * Assembly instructions for schema queries
233  */
234
235 static const SchemaQuery Query_for_list_of_aggregates = {
236         /* catname */
237         "pg_catalog.pg_proc p",
238         /* selcondition */
239         "p.proisagg",
240         /* viscondition */
241         "pg_catalog.pg_function_is_visible(p.oid)",
242         /* namespace */
243         "p.pronamespace",
244         /* result */
245         "pg_catalog.quote_ident(p.proname)",
246         /* qualresult */
247         NULL
248 };
249
250 static const SchemaQuery Query_for_list_of_datatypes = {
251         /* catname */
252         "pg_catalog.pg_type t",
253         /* selcondition --- ignore table rowtypes and array types */
254         "(t.typrelid = 0 "
255         " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
256         "AND t.typname !~ '^_'",
257         /* viscondition */
258         "pg_catalog.pg_type_is_visible(t.oid)",
259         /* namespace */
260         "t.typnamespace",
261         /* result */
262         "pg_catalog.format_type(t.oid, NULL)",
263         /* qualresult */
264         "pg_catalog.quote_ident(t.typname)"
265 };
266
267 static const SchemaQuery Query_for_list_of_domains = {
268         /* catname */
269         "pg_catalog.pg_type t",
270         /* selcondition */
271         "t.typtype = 'd'",
272         /* viscondition */
273         "pg_catalog.pg_type_is_visible(t.oid)",
274         /* namespace */
275         "t.typnamespace",
276         /* result */
277         "pg_catalog.quote_ident(t.typname)",
278         /* qualresult */
279         NULL
280 };
281
282 static const SchemaQuery Query_for_list_of_functions = {
283         /* catname */
284         "pg_catalog.pg_proc p",
285         /* selcondition */
286         NULL,
287         /* viscondition */
288         "pg_catalog.pg_function_is_visible(p.oid)",
289         /* namespace */
290         "p.pronamespace",
291         /* result */
292         "pg_catalog.quote_ident(p.proname)",
293         /* qualresult */
294         NULL
295 };
296
297 static const SchemaQuery Query_for_list_of_indexes = {
298         /* catname */
299         "pg_catalog.pg_class c",
300         /* selcondition */
301         "c.relkind IN ('i')",
302         /* viscondition */
303         "pg_catalog.pg_table_is_visible(c.oid)",
304         /* namespace */
305         "c.relnamespace",
306         /* result */
307         "pg_catalog.quote_ident(c.relname)",
308         /* qualresult */
309         NULL
310 };
311
312 static const SchemaQuery Query_for_list_of_sequences = {
313         /* catname */
314         "pg_catalog.pg_class c",
315         /* selcondition */
316         "c.relkind IN ('S')",
317         /* viscondition */
318         "pg_catalog.pg_table_is_visible(c.oid)",
319         /* namespace */
320         "c.relnamespace",
321         /* result */
322         "pg_catalog.quote_ident(c.relname)",
323         /* qualresult */
324         NULL
325 };
326
327 static const SchemaQuery Query_for_list_of_foreign_tables = {
328         /* catname */
329         "pg_catalog.pg_class c",
330         /* selcondition */
331         "c.relkind IN ('f')",
332         /* viscondition */
333         "pg_catalog.pg_table_is_visible(c.oid)",
334         /* namespace */
335         "c.relnamespace",
336         /* result */
337         "pg_catalog.quote_ident(c.relname)",
338         /* qualresult */
339         NULL
340 };
341
342 static const SchemaQuery Query_for_list_of_tables = {
343         /* catname */
344         "pg_catalog.pg_class c",
345         /* selcondition */
346         "c.relkind IN ('r')",
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_constraints_with_schema = {
358         /* catname */
359         "pg_catalog.pg_constraint c",
360         /* selcondition */
361         "c.conrelid <> 0",
362         /* viscondition */
363         "true",                                         /* there is no pg_constraint_is_visible */
364         /* namespace */
365         "c.connamespace",
366         /* result */
367         "pg_catalog.quote_ident(c.conname)",
368         /* qualresult */
369         NULL
370 };
371
372 /* Relations supporting INSERT, UPDATE or DELETE */
373 static const SchemaQuery Query_for_list_of_updatables = {
374         /* catname */
375         "pg_catalog.pg_class c",
376         /* selcondition */
377         "c.relkind IN ('r', 'f', 'v')",
378         /* viscondition */
379         "pg_catalog.pg_table_is_visible(c.oid)",
380         /* namespace */
381         "c.relnamespace",
382         /* result */
383         "pg_catalog.quote_ident(c.relname)",
384         /* qualresult */
385         NULL
386 };
387
388 static const SchemaQuery Query_for_list_of_relations = {
389         /* catname */
390         "pg_catalog.pg_class c",
391         /* selcondition */
392         NULL,
393         /* viscondition */
394         "pg_catalog.pg_table_is_visible(c.oid)",
395         /* namespace */
396         "c.relnamespace",
397         /* result */
398         "pg_catalog.quote_ident(c.relname)",
399         /* qualresult */
400         NULL
401 };
402
403 static const SchemaQuery Query_for_list_of_tsvmf = {
404         /* catname */
405         "pg_catalog.pg_class c",
406         /* selcondition */
407         "c.relkind IN ('r', 'S', 'v', 'm', 'f')",
408         /* viscondition */
409         "pg_catalog.pg_table_is_visible(c.oid)",
410         /* namespace */
411         "c.relnamespace",
412         /* result */
413         "pg_catalog.quote_ident(c.relname)",
414         /* qualresult */
415         NULL
416 };
417
418 static const SchemaQuery Query_for_list_of_tmf = {
419         /* catname */
420         "pg_catalog.pg_class c",
421         /* selcondition */
422         "c.relkind IN ('r', 'm', 'f')",
423         /* viscondition */
424         "pg_catalog.pg_table_is_visible(c.oid)",
425         /* namespace */
426         "c.relnamespace",
427         /* result */
428         "pg_catalog.quote_ident(c.relname)",
429         /* qualresult */
430         NULL
431 };
432
433 static const SchemaQuery Query_for_list_of_tm = {
434         /* catname */
435         "pg_catalog.pg_class c",
436         /* selcondition */
437         "c.relkind IN ('r', 'm')",
438         /* viscondition */
439         "pg_catalog.pg_table_is_visible(c.oid)",
440         /* namespace */
441         "c.relnamespace",
442         /* result */
443         "pg_catalog.quote_ident(c.relname)",
444         /* qualresult */
445         NULL
446 };
447
448 static const SchemaQuery Query_for_list_of_views = {
449         /* catname */
450         "pg_catalog.pg_class c",
451         /* selcondition */
452         "c.relkind IN ('v')",
453         /* viscondition */
454         "pg_catalog.pg_table_is_visible(c.oid)",
455         /* namespace */
456         "c.relnamespace",
457         /* result */
458         "pg_catalog.quote_ident(c.relname)",
459         /* qualresult */
460         NULL
461 };
462
463 static const SchemaQuery Query_for_list_of_matviews = {
464         /* catname */
465         "pg_catalog.pg_class c",
466         /* selcondition */
467         "c.relkind IN ('m')",
468         /* viscondition */
469         "pg_catalog.pg_table_is_visible(c.oid)",
470         /* namespace */
471         "c.relnamespace",
472         /* result */
473         "pg_catalog.quote_ident(c.relname)",
474         /* qualresult */
475         NULL
476 };
477
478
479 /*
480  * Queries to get lists of names of various kinds of things, possibly
481  * restricted to names matching a partially entered name.  In these queries,
482  * the first %s will be replaced by the text entered so far (suitably escaped
483  * to become a SQL literal string).  %d will be replaced by the length of the
484  * string (in unescaped form).  A second and third %s, if present, will be
485  * replaced by a suitably-escaped version of the string provided in
486  * completion_info_charp.  A fourth and fifth %s are similarly replaced by
487  * completion_info_charp2.
488  *
489  * Beware that the allowed sequences of %s and %d are determined by
490  * _complete_from_query().
491  */
492
493 #define Query_for_list_of_attributes \
494 "SELECT pg_catalog.quote_ident(attname) "\
495 "  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
496 " WHERE c.oid = a.attrelid "\
497 "   AND a.attnum > 0 "\
498 "   AND NOT a.attisdropped "\
499 "   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
500 "   AND (pg_catalog.quote_ident(relname)='%s' "\
501 "        OR '\"' || relname || '\"'='%s') "\
502 "   AND pg_catalog.pg_table_is_visible(c.oid)"
503
504 #define Query_for_list_of_attributes_with_schema \
505 "SELECT pg_catalog.quote_ident(attname) "\
506 "  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
507 " WHERE c.oid = a.attrelid "\
508 "   AND n.oid = c.relnamespace "\
509 "   AND a.attnum > 0 "\
510 "   AND NOT a.attisdropped "\
511 "   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
512 "   AND (pg_catalog.quote_ident(relname)='%s' "\
513 "        OR '\"' || relname || '\"' ='%s') "\
514 "   AND (pg_catalog.quote_ident(nspname)='%s' "\
515 "        OR '\"' || nspname || '\"' ='%s') "
516
517 #define Query_for_list_of_template_databases \
518 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
519 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
520
521 #define Query_for_list_of_databases \
522 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
523 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
524
525 #define Query_for_list_of_tablespaces \
526 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
527 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
528
529 #define Query_for_list_of_encodings \
530 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
531 "   FROM pg_catalog.pg_conversion "\
532 "  WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
533
534 #define Query_for_list_of_languages \
535 "SELECT pg_catalog.quote_ident(lanname) "\
536 "  FROM pg_catalog.pg_language "\
537 " WHERE lanname != 'internal' "\
538 "   AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
539
540 #define Query_for_list_of_schemas \
541 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
542 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
543
544 #define Query_for_list_of_alter_system_set_vars \
545 "SELECT name FROM "\
546 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
547 "  WHERE context != 'internal') ss "\
548 " WHERE substring(name,1,%d)='%s'"\
549 " UNION ALL SELECT 'all' ss"
550
551 #define Query_for_list_of_set_vars \
552 "SELECT name FROM "\
553 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
554 "  WHERE context IN ('user', 'superuser') "\
555 "  UNION ALL SELECT 'constraints' "\
556 "  UNION ALL SELECT 'transaction' "\
557 "  UNION ALL SELECT 'session' "\
558 "  UNION ALL SELECT 'role' "\
559 "  UNION ALL SELECT 'tablespace' "\
560 "  UNION ALL SELECT 'all') ss "\
561 " WHERE substring(name,1,%d)='%s'"
562
563 #define Query_for_list_of_show_vars \
564 "SELECT name FROM "\
565 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
566 "  UNION ALL SELECT 'session authorization' "\
567 "  UNION ALL SELECT 'all') ss "\
568 " WHERE substring(name,1,%d)='%s'"
569
570 #define Query_for_list_of_roles \
571 " SELECT pg_catalog.quote_ident(rolname) "\
572 "   FROM pg_catalog.pg_roles "\
573 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
574
575 #define Query_for_list_of_grant_roles \
576 " SELECT pg_catalog.quote_ident(rolname) "\
577 "   FROM pg_catalog.pg_roles "\
578 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
579 " UNION ALL SELECT 'PUBLIC'"
580
581 /* the silly-looking length condition is just to eat up the current word */
582 #define Query_for_table_owning_index \
583 "SELECT pg_catalog.quote_ident(c1.relname) "\
584 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
585 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
586 "       and (%d = pg_catalog.length('%s'))"\
587 "       and pg_catalog.quote_ident(c2.relname)='%s'"\
588 "       and pg_catalog.pg_table_is_visible(c2.oid)"
589
590 /* the silly-looking length condition is just to eat up the current word */
591 #define Query_for_index_of_table \
592 "SELECT pg_catalog.quote_ident(c2.relname) "\
593 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
594 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
595 "       and (%d = pg_catalog.length('%s'))"\
596 "       and pg_catalog.quote_ident(c1.relname)='%s'"\
597 "       and pg_catalog.pg_table_is_visible(c2.oid)"
598
599 /* the silly-looking length condition is just to eat up the current word */
600 #define Query_for_constraint_of_table \
601 "SELECT pg_catalog.quote_ident(conname) "\
602 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_constraint con "\
603 " WHERE c1.oid=conrelid and (%d = pg_catalog.length('%s'))"\
604 "       and pg_catalog.quote_ident(c1.relname)='%s'"\
605 "       and pg_catalog.pg_table_is_visible(c1.oid)"
606
607 #define Query_for_all_table_constraints \
608 "SELECT pg_catalog.quote_ident(conname) "\
609 "  FROM pg_catalog.pg_constraint c "\
610 " WHERE c.conrelid <> 0 "
611
612 /* the silly-looking length condition is just to eat up the current word */
613 #define Query_for_constraint_of_type \
614 "SELECT pg_catalog.quote_ident(conname) "\
615 "  FROM pg_catalog.pg_type t, pg_catalog.pg_constraint con "\
616 " WHERE t.oid=contypid and (%d = pg_catalog.length('%s'))"\
617 "       and pg_catalog.quote_ident(t.typname)='%s'"\
618 "       and pg_catalog.pg_type_is_visible(t.oid)"
619
620 /* the silly-looking length condition is just to eat up the current word */
621 #define Query_for_list_of_tables_for_constraint \
622 "SELECT pg_catalog.quote_ident(relname) "\
623 "  FROM pg_catalog.pg_class"\
624 " WHERE (%d = pg_catalog.length('%s'))"\
625 "   AND oid IN "\
626 "       (SELECT conrelid FROM pg_catalog.pg_constraint "\
627 "         WHERE pg_catalog.quote_ident(conname)='%s')"
628
629 /* the silly-looking length condition is just to eat up the current word */
630 #define Query_for_rule_of_table \
631 "SELECT pg_catalog.quote_ident(rulename) "\
632 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_rewrite "\
633 " WHERE c1.oid=ev_class and (%d = pg_catalog.length('%s'))"\
634 "       and pg_catalog.quote_ident(c1.relname)='%s'"\
635 "       and pg_catalog.pg_table_is_visible(c1.oid)"
636
637 /* the silly-looking length condition is just to eat up the current word */
638 #define Query_for_list_of_tables_for_rule \
639 "SELECT pg_catalog.quote_ident(relname) "\
640 "  FROM pg_catalog.pg_class"\
641 " WHERE (%d = pg_catalog.length('%s'))"\
642 "   AND oid IN "\
643 "       (SELECT ev_class FROM pg_catalog.pg_rewrite "\
644 "         WHERE pg_catalog.quote_ident(rulename)='%s')"
645
646 /* the silly-looking length condition is just to eat up the current word */
647 #define Query_for_trigger_of_table \
648 "SELECT pg_catalog.quote_ident(tgname) "\
649 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_trigger "\
650 " WHERE c1.oid=tgrelid and (%d = pg_catalog.length('%s'))"\
651 "       and pg_catalog.quote_ident(c1.relname)='%s'"\
652 "       and pg_catalog.pg_table_is_visible(c1.oid)"\
653 "       and not tgisinternal"
654
655 /* the silly-looking length condition is just to eat up the current word */
656 #define Query_for_list_of_tables_for_trigger \
657 "SELECT pg_catalog.quote_ident(relname) "\
658 "  FROM pg_catalog.pg_class"\
659 " WHERE (%d = pg_catalog.length('%s'))"\
660 "   AND oid IN "\
661 "       (SELECT tgrelid FROM pg_catalog.pg_trigger "\
662 "         WHERE pg_catalog.quote_ident(tgname)='%s')"
663
664 #define Query_for_list_of_ts_configurations \
665 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
666 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
667
668 #define Query_for_list_of_ts_dictionaries \
669 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
670 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
671
672 #define Query_for_list_of_ts_parsers \
673 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
674 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
675
676 #define Query_for_list_of_ts_templates \
677 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
678 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
679
680 #define Query_for_list_of_fdws \
681 " SELECT pg_catalog.quote_ident(fdwname) "\
682 "   FROM pg_catalog.pg_foreign_data_wrapper "\
683 "  WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
684
685 #define Query_for_list_of_servers \
686 " SELECT pg_catalog.quote_ident(srvname) "\
687 "   FROM pg_catalog.pg_foreign_server "\
688 "  WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
689
690 #define Query_for_list_of_user_mappings \
691 " SELECT pg_catalog.quote_ident(usename) "\
692 "   FROM pg_catalog.pg_user_mappings "\
693 "  WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
694
695 #define Query_for_list_of_access_methods \
696 " SELECT pg_catalog.quote_ident(amname) "\
697 "   FROM pg_catalog.pg_am "\
698 "  WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
699
700 /* the silly-looking length condition is just to eat up the current word */
701 #define Query_for_list_of_arguments \
702 "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
703 "  FROM pg_catalog.pg_proc "\
704 " WHERE (%d = pg_catalog.length('%s'))"\
705 "   AND (pg_catalog.quote_ident(proname)='%s'"\
706 "        OR '\"' || proname || '\"'='%s') "\
707 "   AND (pg_catalog.pg_function_is_visible(pg_proc.oid))"
708
709 /* the silly-looking length condition is just to eat up the current word */
710 #define Query_for_list_of_arguments_with_schema \
711 "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
712 "  FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
713 " WHERE (%d = pg_catalog.length('%s'))"\
714 "   AND n.oid = p.pronamespace "\
715 "   AND (pg_catalog.quote_ident(proname)='%s' "\
716 "        OR '\"' || proname || '\"' ='%s') "\
717 "   AND (pg_catalog.quote_ident(nspname)='%s' "\
718 "        OR '\"' || nspname || '\"' ='%s') "
719
720 #define Query_for_list_of_extensions \
721 " SELECT pg_catalog.quote_ident(extname) "\
722 "   FROM pg_catalog.pg_extension "\
723 "  WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
724
725 #define Query_for_list_of_available_extensions \
726 " SELECT pg_catalog.quote_ident(name) "\
727 "   FROM pg_catalog.pg_available_extensions "\
728 "  WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
729
730 #define Query_for_list_of_prepared_statements \
731 " SELECT pg_catalog.quote_ident(name) "\
732 "   FROM pg_catalog.pg_prepared_statements "\
733 "  WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'"
734
735 #define Query_for_list_of_event_triggers \
736 " SELECT pg_catalog.quote_ident(evtname) "\
737 "   FROM pg_catalog.pg_event_trigger "\
738 "  WHERE substring(pg_catalog.quote_ident(evtname),1,%d)='%s'"
739
740 /*
741  * This is a list of all "things" in Pgsql, which can show up after CREATE or
742  * DROP; and there is also a query to get a list of them.
743  */
744
745 typedef struct
746 {
747         const char *name;
748         const char *query;                      /* simple query, or NULL */
749         const SchemaQuery *squery;      /* schema query, or NULL */
750         const bits32 flags;                     /* visibility flags, see below */
751 } pgsql_thing_t;
752
753 #define THING_NO_CREATE         (1 << 0)        /* should not show up after CREATE */
754 #define THING_NO_DROP           (1 << 1)        /* should not show up after DROP */
755 #define THING_NO_SHOW           (THING_NO_CREATE | THING_NO_DROP)
756
757 static const pgsql_thing_t words_after_create[] = {
758         {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
759         {"CAST", NULL, NULL},           /* Casts have complex structures for names, so
760                                                                  * skip it */
761         {"COLLATION", "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s'"},
762
763         /*
764          * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
765          * to be used only by pg_dump.
766          */
767         {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
768         {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
769         {"DATABASE", Query_for_list_of_databases},
770         {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
771         {"DOMAIN", NULL, &Query_for_list_of_domains},
772         {"EVENT TRIGGER", NULL, NULL},
773         {"EXTENSION", Query_for_list_of_extensions},
774         {"FOREIGN DATA WRAPPER", NULL, NULL},
775         {"FOREIGN TABLE", NULL, NULL},
776         {"FUNCTION", NULL, &Query_for_list_of_functions},
777         {"GROUP", Query_for_list_of_roles},
778         {"LANGUAGE", Query_for_list_of_languages},
779         {"INDEX", NULL, &Query_for_list_of_indexes},
780         {"MATERIALIZED VIEW", NULL, NULL},
781         {"OPERATOR", NULL, NULL},       /* Querying for this is probably not such a
782                                                                  * good idea. */
783         {"OWNED", NULL, NULL, THING_NO_CREATE},         /* for DROP OWNED BY ... */
784         {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
785         {"POLICY", NULL, NULL},
786         {"ROLE", Query_for_list_of_roles},
787         {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
788         {"SCHEMA", Query_for_list_of_schemas},
789         {"SEQUENCE", NULL, &Query_for_list_of_sequences},
790         {"SERVER", Query_for_list_of_servers},
791         {"TABLE", NULL, &Query_for_list_of_tables},
792         {"TABLESPACE", Query_for_list_of_tablespaces},
793         {"TEMP", NULL, NULL, THING_NO_DROP},            /* for CREATE TEMP TABLE ... */
794         {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
795         {"TEXT SEARCH", NULL, NULL},
796         {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s' AND NOT tgisinternal"},
797         {"TYPE", NULL, &Query_for_list_of_datatypes},
798         {"UNIQUE", NULL, NULL, THING_NO_DROP},          /* for CREATE UNIQUE INDEX ... */
799         {"UNLOGGED", NULL, NULL, THING_NO_DROP},        /* for CREATE UNLOGGED TABLE
800                                                                                                  * ... */
801         {"USER", Query_for_list_of_roles},
802         {"USER MAPPING FOR", NULL, NULL},
803         {"VIEW", NULL, &Query_for_list_of_views},
804         {NULL}                                          /* end of list */
805 };
806
807
808 /* Forward declaration of functions */
809 static char **psql_completion(const char *text, int start, int end);
810 static char *create_command_generator(const char *text, int state);
811 static char *drop_command_generator(const char *text, int state);
812 static char *complete_from_query(const char *text, int state);
813 static char *complete_from_schema_query(const char *text, int state);
814 static char *_complete_from_query(int is_schema_query,
815                                          const char *text, int state);
816 static char *complete_from_list(const char *text, int state);
817 static char *complete_from_const(const char *text, int state);
818 static void append_variable_names(char ***varnames, int *nvars,
819                                           int *maxvars, const char *varname,
820                                           const char *prefix, const char *suffix);
821 static char **complete_from_variables(const char *text,
822                                         const char *prefix, const char *suffix, bool need_value);
823 static char *complete_from_files(const char *text, int state);
824
825 static char *pg_strdup_keyword_case(const char *s, const char *ref);
826 static PGresult *exec_query(const char *query);
827
828 static void get_previous_words(int point, char **previous_words, int nwords);
829
830 #ifdef NOT_USED
831 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
832 static char *dequote_file_name(char *text, char quote_char);
833 #endif
834
835
836 /*
837  * Initialize the readline library for our purposes.
838  */
839 void
840 initialize_readline(void)
841 {
842         rl_readline_name = (char *) pset.progname;
843         rl_attempted_completion_function = psql_completion;
844
845         rl_basic_word_break_characters = WORD_BREAKS;
846
847         completion_max_records = 1000;
848
849         /*
850          * There is a variable rl_completion_query_items for this but apparently
851          * it's not defined everywhere.
852          */
853 }
854
855
856 /*
857  * The completion function.
858  *
859  * According to readline spec this gets passed the text entered so far and its
860  * start and end positions in the readline buffer. The return value is some
861  * partially obscure list format that can be generated by readline's
862  * completion_matches() function, so we don't have to worry about it.
863  */
864 static char **
865 psql_completion(const char *text, int start, int end)
866 {
867         /* This is the variable we'll return. */
868         char      **matches = NULL;
869
870         /* This array will contain some scannage of the input line. */
871         char       *previous_words[6];
872
873         /* For compactness, we use these macros to reference previous_words[]. */
874 #define prev_wd   (previous_words[0])
875 #define prev2_wd  (previous_words[1])
876 #define prev3_wd  (previous_words[2])
877 #define prev4_wd  (previous_words[3])
878 #define prev5_wd  (previous_words[4])
879 #define prev6_wd  (previous_words[5])
880
881         static const char *const sql_commands[] = {
882                 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
883                 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
884                 "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN",
885                 "FETCH", "GRANT", "IMPORT", "INSERT", "LISTEN", "LOAD", "LOCK",
886                 "MOVE", "NOTIFY", "PREPARE",
887                 "REASSIGN", "REFRESH", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
888                 "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
889                 "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
890                 NULL
891         };
892
893         static const char *const backslash_commands[] = {
894                 "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
895                 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df",
896                 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
897                 "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du", "\\dx",
898                 "\\e", "\\echo", "\\ef", "\\encoding",
899                 "\\f", "\\g", "\\gset", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
900                 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
901                 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
902                 "\\set", "\\sf", "\\t", "\\T",
903                 "\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!", NULL
904         };
905
906         (void) end;                                     /* not used */
907
908 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
909         rl_completion_append_character = ' ';
910 #endif
911
912         /* Clear a few things. */
913         completion_charp = NULL;
914         completion_charpp = NULL;
915         completion_info_charp = NULL;
916         completion_info_charp2 = NULL;
917
918         /*
919          * Scan the input line before our current position for the last few words.
920          * According to those we'll make some smart decisions on what the user is
921          * probably intending to type.
922          */
923         get_previous_words(start, previous_words, lengthof(previous_words));
924
925         /* If a backslash command was started, continue */
926         if (text[0] == '\\')
927                 COMPLETE_WITH_LIST_CS(backslash_commands);
928
929         /* Variable interpolation */
930         else if (text[0] == ':' && text[1] != ':')
931         {
932                 if (text[1] == '\'')
933                         matches = complete_from_variables(text, ":'", "'", true);
934                 else if (text[1] == '"')
935                         matches = complete_from_variables(text, ":\"", "\"", true);
936                 else
937                         matches = complete_from_variables(text, ":", "", true);
938         }
939
940         /* If no previous word, suggest one of the basic sql commands */
941         else if (prev_wd[0] == '\0')
942                 COMPLETE_WITH_LIST(sql_commands);
943
944 /* CREATE */
945         /* complete with something you can create */
946         else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
947                 matches = completion_matches(text, create_command_generator);
948
949 /* DROP, but not DROP embedded in other commands */
950         /* complete with something you can drop */
951         else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
952                          prev2_wd[0] == '\0')
953                 matches = completion_matches(text, drop_command_generator);
954
955 /* ALTER */
956
957         /* ALTER TABLE */
958         else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
959                          pg_strcasecmp(prev_wd, "TABLE") == 0)
960         {
961                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
962                                                                    "UNION SELECT 'ALL IN TABLESPACE'");
963         }
964
965         /*
966          * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
967          * in ALTER TABLE sth ALTER
968          */
969         else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
970                          pg_strcasecmp(prev3_wd, "TABLE") != 0)
971         {
972                 static const char *const list_ALTER[] =
973                 {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
974                         "EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
975                         "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR",
976                         "POLICY", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "SYSTEM", "TABLE",
977                         "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
978                 "USER", "USER MAPPING FOR", "VIEW", NULL};
979
980                 COMPLETE_WITH_LIST(list_ALTER);
981         }
982         /* ALTER TABLE,INDEX,MATERIALIZED VIEW xxx ALL IN TABLESPACE xxx */
983         else if (pg_strcasecmp(prev4_wd, "ALL") == 0 &&
984                          pg_strcasecmp(prev3_wd, "IN") == 0 &&
985                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
986         {
987                 static const char *const list_ALTERALLINTSPC[] =
988                 {"SET TABLESPACE", "OWNED BY", NULL};
989
990                 COMPLETE_WITH_LIST(list_ALTERALLINTSPC);
991         }
992         /* ALTER TABLE,INDEX,MATERIALIZED VIEW xxx ALL IN TABLESPACE xxx OWNED BY */
993         else if (pg_strcasecmp(prev6_wd, "ALL") == 0 &&
994                          pg_strcasecmp(prev5_wd, "IN") == 0 &&
995                          pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
996                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
997                          pg_strcasecmp(prev4_wd, "BY") == 0)
998         {
999                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1000         }
1001         /* ALTER AGGREGATE,FUNCTION <name> */
1002         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1003                          (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
1004                           pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
1005                 COMPLETE_WITH_CONST("(");
1006         /* ALTER AGGREGATE,FUNCTION <name> (...) */
1007         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1008                          (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
1009                           pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
1010         {
1011                 if (prev_wd[strlen(prev_wd) - 1] == ')')
1012                 {
1013                         static const char *const list_ALTERAGG[] =
1014                         {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1015
1016                         COMPLETE_WITH_LIST(list_ALTERAGG);
1017                 }
1018                 else
1019                         COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
1020         }
1021
1022         /* ALTER SCHEMA <name> */
1023         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1024                          pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
1025         {
1026                 static const char *const list_ALTERGEN[] =
1027                 {"OWNER TO", "RENAME TO", NULL};
1028
1029                 COMPLETE_WITH_LIST(list_ALTERGEN);
1030         }
1031
1032         /* ALTER COLLATION <name> */
1033         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1034                          pg_strcasecmp(prev2_wd, "COLLATION") == 0)
1035         {
1036                 static const char *const list_ALTERGEN[] =
1037                 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1038
1039                 COMPLETE_WITH_LIST(list_ALTERGEN);
1040         }
1041
1042         /* ALTER CONVERSION <name> */
1043         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1044                          pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
1045         {
1046                 static const char *const list_ALTERGEN[] =
1047                 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1048
1049                 COMPLETE_WITH_LIST(list_ALTERGEN);
1050         }
1051
1052         /* ALTER DATABASE <name> */
1053         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1054                          pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1055         {
1056                 static const char *const list_ALTERDATABASE[] =
1057                 {"RESET", "SET", "OWNER TO", "RENAME TO", "IS_TEMPLATE",
1058                 "ALLOW_CONNECTIONS", "CONNECTION LIMIT", NULL};
1059
1060                 COMPLETE_WITH_LIST(list_ALTERDATABASE);
1061         }
1062
1063         /* ALTER EVENT TRIGGER */
1064         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1065                          pg_strcasecmp(prev2_wd, "EVENT") == 0 &&
1066                          pg_strcasecmp(prev_wd, "TRIGGER") == 0)
1067         {
1068                 COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
1069         }
1070
1071         /* ALTER EVENT TRIGGER <name> */
1072         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1073                          pg_strcasecmp(prev3_wd, "EVENT") == 0 &&
1074                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1075         {
1076                 static const char *const list_ALTER_EVENT_TRIGGER[] =
1077                 {"DISABLE", "ENABLE", "OWNER TO", "RENAME TO", NULL};
1078
1079                 COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER);
1080         }
1081
1082         /* ALTER EVENT TRIGGER <name> ENABLE */
1083         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1084                          pg_strcasecmp(prev4_wd, "EVENT") == 0 &&
1085                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1086                          pg_strcasecmp(prev_wd, "ENABLE") == 0)
1087         {
1088                 static const char *const list_ALTER_EVENT_TRIGGER_ENABLE[] =
1089                 {"REPLICA", "ALWAYS", NULL};
1090
1091                 COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER_ENABLE);
1092         }
1093
1094         /* ALTER EXTENSION <name> */
1095         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1096                          pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
1097         {
1098                 static const char *const list_ALTEREXTENSION[] =
1099                 {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
1100
1101                 COMPLETE_WITH_LIST(list_ALTEREXTENSION);
1102         }
1103
1104         /* ALTER FOREIGN */
1105         else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
1106                          pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1107         {
1108                 static const char *const list_ALTER_FOREIGN[] =
1109                 {"DATA WRAPPER", "TABLE", NULL};
1110
1111                 COMPLETE_WITH_LIST(list_ALTER_FOREIGN);
1112         }
1113
1114         /* ALTER FOREIGN DATA WRAPPER <name> */
1115         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1116                          pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1117                          pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1118                          pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1119         {
1120                 static const char *const list_ALTER_FDW[] =
1121                 {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
1122
1123                 COMPLETE_WITH_LIST(list_ALTER_FDW);
1124         }
1125
1126         /* ALTER FOREIGN TABLE <name> */
1127         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1128                          pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
1129                          pg_strcasecmp(prev2_wd, "TABLE") == 0)
1130         {
1131                 static const char *const list_ALTER_FOREIGN_TABLE[] =
1132                 {"ADD", "ALTER", "DISABLE TRIGGER", "DROP", "ENABLE", "INHERIT",
1133                         "NO INHERIT", "OPTIONS", "OWNER TO", "RENAME", "SET",
1134                 "VALIDATE CONSTRAINT", NULL};
1135
1136                 COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
1137         }
1138
1139         /* ALTER INDEX */
1140         else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
1141                          pg_strcasecmp(prev_wd, "INDEX") == 0)
1142         {
1143                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1144                                                                    "UNION SELECT 'ALL IN TABLESPACE'");
1145         }
1146         /* ALTER INDEX <name> */
1147         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1148                          pg_strcasecmp(prev2_wd, "INDEX") == 0)
1149         {
1150                 static const char *const list_ALTERINDEX[] =
1151                 {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
1152
1153                 COMPLETE_WITH_LIST(list_ALTERINDEX);
1154         }
1155         /* ALTER INDEX <name> SET */
1156         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1157                          pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1158                          pg_strcasecmp(prev_wd, "SET") == 0)
1159         {
1160                 static const char *const list_ALTERINDEXSET[] =
1161                 {"(", "TABLESPACE", NULL};
1162
1163                 COMPLETE_WITH_LIST(list_ALTERINDEXSET);
1164         }
1165         /* ALTER INDEX <name> RESET */
1166         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1167                          pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1168                          pg_strcasecmp(prev_wd, "RESET") == 0)
1169                 COMPLETE_WITH_CONST("(");
1170         /* ALTER INDEX <foo> SET|RESET ( */
1171         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1172                          pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1173                          (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1174                           pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1175                          pg_strcasecmp(prev_wd, "(") == 0)
1176         {
1177                 static const char *const list_INDEXOPTIONS[] =
1178                 {"fillfactor", "fastupdate", "gin_pending_list_limit", NULL};
1179
1180                 COMPLETE_WITH_LIST(list_INDEXOPTIONS);
1181         }
1182
1183         /* ALTER LANGUAGE <name> */
1184         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1185                          pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
1186         {
1187                 static const char *const list_ALTERLANGUAGE[] =
1188                 {"OWNER TO", "RENAME TO", NULL};
1189
1190                 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
1191         }
1192
1193         /* ALTER LARGE OBJECT <oid> */
1194         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1195                          pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
1196                          pg_strcasecmp(prev2_wd, "OBJECT") == 0)
1197         {
1198                 static const char *const list_ALTERLARGEOBJECT[] =
1199                 {"OWNER TO", NULL};
1200
1201                 COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
1202         }
1203
1204         /* ALTER MATERIALIZED VIEW */
1205         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1206                          pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
1207                          pg_strcasecmp(prev_wd, "VIEW") == 0)
1208         {
1209                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
1210                                                                    "UNION SELECT 'ALL IN TABLESPACE'");
1211         }
1212
1213         /* ALTER USER,ROLE <name> */
1214         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1215                          !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1216                          (pg_strcasecmp(prev2_wd, "USER") == 0 ||
1217                           pg_strcasecmp(prev2_wd, "ROLE") == 0))
1218         {
1219                 static const char *const list_ALTERUSER[] =
1220                 {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
1221                         "CREATEUSER", "ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS",
1222                         "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT",
1223                         "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
1224                         "REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED",
1225                 "VALID UNTIL", "WITH", NULL};
1226
1227                 COMPLETE_WITH_LIST(list_ALTERUSER);
1228         }
1229
1230         /* ALTER USER,ROLE <name> WITH */
1231         else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1232                           (pg_strcasecmp(prev3_wd, "USER") == 0 ||
1233                            pg_strcasecmp(prev3_wd, "ROLE") == 0) &&
1234                           pg_strcasecmp(prev_wd, "WITH") == 0))
1235         {
1236                 /* Similar to the above, but don't complete "WITH" again. */
1237                 static const char *const list_ALTERUSER_WITH[] =
1238                 {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
1239                         "CREATEUSER", "ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS",
1240                         "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT",
1241                         "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
1242                         "REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED",
1243                 "VALID UNTIL", NULL};
1244
1245                 COMPLETE_WITH_LIST(list_ALTERUSER_WITH);
1246         }
1247
1248         /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
1249         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1250                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1251                          (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1252         {
1253                 COMPLETE_WITH_CONST("PASSWORD");
1254         }
1255         /* ALTER DEFAULT PRIVILEGES */
1256         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1257                          pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
1258                          pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
1259         {
1260                 static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
1261                 {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
1262
1263                 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
1264         }
1265         /* ALTER DEFAULT PRIVILEGES FOR */
1266         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1267                          pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
1268                          pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
1269                          pg_strcasecmp(prev_wd, "FOR") == 0)
1270         {
1271                 static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
1272                 {"ROLE", "USER", NULL};
1273
1274                 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
1275         }
1276         /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
1277         else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
1278                          pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
1279                          (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
1280                           pg_strcasecmp(prev3_wd, "IN") == 0))
1281         {
1282                 static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
1283                 {"GRANT", "REVOKE", NULL};
1284
1285                 COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
1286         }
1287         /* ALTER DOMAIN <name> */
1288         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1289                          pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
1290         {
1291                 static const char *const list_ALTERDOMAIN[] =
1292                 {"ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT", NULL};
1293
1294                 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1295         }
1296         /* ALTER DOMAIN <sth> DROP */
1297         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1298                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1299                          pg_strcasecmp(prev_wd, "DROP") == 0)
1300         {
1301                 static const char *const list_ALTERDOMAIN2[] =
1302                 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
1303
1304                 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
1305         }
1306         /* ALTER DOMAIN <sth> DROP|RENAME|VALIDATE CONSTRAINT */
1307         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1308                          pg_strcasecmp(prev4_wd, "DOMAIN") == 0 &&
1309                          (pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1310                           pg_strcasecmp(prev2_wd, "RENAME") == 0 ||
1311                           pg_strcasecmp(prev2_wd, "VALIDATE") == 0) &&
1312                          pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
1313         {
1314                 completion_info_charp = prev3_wd;
1315                 COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
1316         }
1317         /* ALTER DOMAIN <sth> RENAME */
1318         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1319                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1320                          pg_strcasecmp(prev_wd, "RENAME") == 0)
1321         {
1322                 static const char *const list_ALTERDOMAIN[] =
1323                 {"CONSTRAINT", "TO", NULL};
1324
1325                 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1326         }
1327         /* ALTER DOMAIN <sth> RENAME CONSTRAINT <sth> */
1328         else if (pg_strcasecmp(prev5_wd, "DOMAIN") == 0 &&
1329                          pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1330                          pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0)
1331                 COMPLETE_WITH_CONST("TO");
1332
1333         /* ALTER DOMAIN <sth> SET */
1334         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1335                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1336                          pg_strcasecmp(prev_wd, "SET") == 0)
1337         {
1338                 static const char *const list_ALTERDOMAIN3[] =
1339                 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
1340
1341                 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
1342         }
1343         /* ALTER SEQUENCE <name> */
1344         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1345                          pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
1346         {
1347                 static const char *const list_ALTERSEQUENCE[] =
1348                 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
1349                 "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
1350
1351                 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
1352         }
1353         /* ALTER SEQUENCE <name> NO */
1354         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1355                          pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
1356                          pg_strcasecmp(prev_wd, "NO") == 0)
1357         {
1358                 static const char *const list_ALTERSEQUENCE2[] =
1359                 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
1360
1361                 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
1362         }
1363         /* ALTER SERVER <name> */
1364         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1365                          pg_strcasecmp(prev2_wd, "SERVER") == 0)
1366         {
1367                 static const char *const list_ALTER_SERVER[] =
1368                 {"VERSION", "OPTIONS", "OWNER TO", NULL};
1369
1370                 COMPLETE_WITH_LIST(list_ALTER_SERVER);
1371         }
1372         /* ALTER SYSTEM SET, RESET, RESET ALL */
1373         else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
1374                          pg_strcasecmp(prev_wd, "SYSTEM") == 0)
1375         {
1376                 static const char *const list_ALTERSYSTEM[] =
1377                 {"SET", "RESET", NULL};
1378
1379                 COMPLETE_WITH_LIST(list_ALTERSYSTEM);
1380         }
1381         /* ALTER SYSTEM SET|RESET <name> */
1382         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1383                          pg_strcasecmp(prev2_wd, "SYSTEM") == 0 &&
1384                          (pg_strcasecmp(prev_wd, "SET") == 0 ||
1385                           pg_strcasecmp(prev_wd, "RESET") == 0))
1386                 COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
1387         /* ALTER VIEW <name> */
1388         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1389                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
1390         {
1391                 static const char *const list_ALTERVIEW[] =
1392                 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1393
1394                 COMPLETE_WITH_LIST(list_ALTERVIEW);
1395         }
1396         /* ALTER MATERIALIZED VIEW <name> */
1397         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1398                          pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
1399                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
1400         {
1401                 static const char *const list_ALTERMATVIEW[] =
1402                 {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1403
1404                 COMPLETE_WITH_LIST(list_ALTERMATVIEW);
1405         }
1406
1407         /* ALTER POLICY <name> ON */
1408         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1409                          pg_strcasecmp(prev2_wd, "POLICY") == 0)
1410                 COMPLETE_WITH_CONST("ON");
1411         /* ALTER POLICY <name> ON <table> */
1412         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1413                          pg_strcasecmp(prev3_wd, "POLICY") == 0 &&
1414                          pg_strcasecmp(prev_wd, "ON") == 0)
1415                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1416         /* ALTER POLICY <name> ON <table> - show options */
1417         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1418                          pg_strcasecmp(prev4_wd, "POLICY") == 0 &&
1419                          pg_strcasecmp(prev2_wd, "ON") == 0)
1420         {
1421                 static const char *const list_ALTERPOLICY[] =
1422                 {"RENAME TO", "TO", "USING", "WITH CHECK", NULL};
1423
1424                 COMPLETE_WITH_LIST(list_ALTERPOLICY);
1425         }
1426         /* ALTER POLICY <name> ON <table> TO <role> */
1427         else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
1428                          pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
1429                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1430                          pg_strcasecmp(prev_wd, "TO") == 0)
1431                 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1432         /* ALTER POLICY <name> ON <table> USING ( */
1433         else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
1434                          pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
1435                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1436                          pg_strcasecmp(prev_wd, "USING") == 0)
1437                 COMPLETE_WITH_CONST("(");
1438         /* ALTER POLICY <name> ON <table> WITH CHECK ( */
1439         else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 &&
1440                          pg_strcasecmp(prev4_wd, "ON") == 0 &&
1441                          pg_strcasecmp(prev2_wd, "WITH") == 0 &&
1442                          pg_strcasecmp(prev_wd, "CHECK") == 0)
1443                 COMPLETE_WITH_CONST("(");
1444
1445         /* ALTER RULE <name>, add ON */
1446         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1447                          pg_strcasecmp(prev2_wd, "RULE") == 0)
1448                 COMPLETE_WITH_CONST("ON");
1449
1450         /* If we have ALTER RULE <name> ON, then add the correct tablename */
1451         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1452                          pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1453                          pg_strcasecmp(prev_wd, "ON") == 0)
1454         {
1455                 completion_info_charp = prev2_wd;
1456                 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
1457         }
1458
1459         /* ALTER RULE <name> ON <name> */
1460         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1461                          pg_strcasecmp(prev4_wd, "RULE") == 0)
1462                 COMPLETE_WITH_CONST("RENAME TO");
1463
1464         /* ALTER TRIGGER <name>, add ON */
1465         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1466                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1467                 COMPLETE_WITH_CONST("ON");
1468
1469         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1470                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
1471         {
1472                 completion_info_charp = prev2_wd;
1473                 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1474         }
1475
1476         /*
1477          * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1478          */
1479         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1480                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1481                          pg_strcasecmp(prev_wd, "ON") == 0)
1482                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1483
1484         /* ALTER TRIGGER <name> ON <name> */
1485         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1486                          pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1487                          pg_strcasecmp(prev2_wd, "ON") == 0)
1488                 COMPLETE_WITH_CONST("RENAME TO");
1489
1490         /*
1491          * If we detect ALTER TABLE <name>, suggest sub commands
1492          */
1493         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1494                          pg_strcasecmp(prev2_wd, "TABLE") == 0)
1495         {
1496                 static const char *const list_ALTER2[] =
1497                 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1498                         "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
1499                 "VALIDATE CONSTRAINT", "REPLICA IDENTITY", NULL};
1500
1501                 COMPLETE_WITH_LIST(list_ALTER2);
1502         }
1503         /* ALTER TABLE xxx ENABLE */
1504         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1505                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1506                          pg_strcasecmp(prev_wd, "ENABLE") == 0)
1507         {
1508                 static const char *const list_ALTERENABLE[] =
1509                 {"ALWAYS", "REPLICA", "ROW LEVEL SECURITY", "RULE", "TRIGGER", NULL};
1510
1511                 COMPLETE_WITH_LIST(list_ALTERENABLE);
1512         }
1513         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1514                          pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1515                          (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
1516                           pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1517         {
1518                 static const char *const list_ALTERENABLE2[] =
1519                 {"RULE", "TRIGGER", NULL};
1520
1521                 COMPLETE_WITH_LIST(list_ALTERENABLE2);
1522         }
1523         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1524                          pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1525                          pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1526                          pg_strcasecmp(prev_wd, "RULE") == 0)
1527         {
1528                 completion_info_charp = prev3_wd;
1529                 COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1530         }
1531         else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
1532                          pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1533                          pg_strcasecmp(prev3_wd, "ENABLE") == 0 &&
1534                          pg_strcasecmp(prev_wd, "RULE") == 0)
1535         {
1536                 completion_info_charp = prev4_wd;
1537                 COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1538         }
1539         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1540                          pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1541                          pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1542                          pg_strcasecmp(prev_wd, "TRIGGER") == 0)
1543         {
1544                 completion_info_charp = prev3_wd;
1545                 COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1546         }
1547         else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
1548                          pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1549                          pg_strcasecmp(prev3_wd, "ENABLE") == 0 &&
1550                          pg_strcasecmp(prev_wd, "TRIGGER") == 0)
1551         {
1552                 completion_info_charp = prev4_wd;
1553                 COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1554         }
1555         /* ALTER TABLE xxx INHERIT */
1556         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1557                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1558                          pg_strcasecmp(prev_wd, "INHERIT") == 0)
1559         {
1560                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1561         }
1562         /* ALTER TABLE xxx NO INHERIT */
1563         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1564                          pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1565                          pg_strcasecmp(prev2_wd, "NO") == 0 &&
1566                          pg_strcasecmp(prev_wd, "INHERIT") == 0)
1567         {
1568                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1569         }
1570         /* ALTER TABLE xxx DISABLE */
1571         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1572                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1573                          pg_strcasecmp(prev_wd, "DISABLE") == 0)
1574         {
1575                 static const char *const list_ALTERDISABLE[] =
1576                 {"ROW LEVEL SECURITY", "RULE", "TRIGGER", NULL};
1577
1578                 COMPLETE_WITH_LIST(list_ALTERDISABLE);
1579         }
1580         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1581                          pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1582                          pg_strcasecmp(prev2_wd, "DISABLE") == 0 &&
1583                          pg_strcasecmp(prev_wd, "RULE") == 0)
1584         {
1585                 completion_info_charp = prev3_wd;
1586                 COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1587         }
1588         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1589                          pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1590                          pg_strcasecmp(prev2_wd, "DISABLE") == 0 &&
1591                          pg_strcasecmp(prev_wd, "TRIGGER") == 0)
1592         {
1593                 completion_info_charp = prev3_wd;
1594                 COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1595         }
1596         else if (pg_strcasecmp(prev4_wd, "DISABLE") == 0 &&
1597                          pg_strcasecmp(prev3_wd, "ROW") == 0 &&
1598                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1599                          pg_strcasecmp(prev_wd, "SECURITY") == 0)
1600         {
1601                 static const char *const list_DISABLERLS[] =
1602                 {"CASCADE", NULL};
1603
1604                 COMPLETE_WITH_LIST(list_DISABLERLS);
1605         }
1606
1607         /* ALTER TABLE xxx ALTER */
1608         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1609                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1610                          pg_strcasecmp(prev_wd, "ALTER") == 0)
1611                 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT'");
1612
1613         /* ALTER TABLE xxx RENAME */
1614         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1615                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1616                          pg_strcasecmp(prev_wd, "RENAME") == 0)
1617                 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'");
1618
1619         /*
1620          * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1621          * columns
1622          */
1623         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1624                          (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1625                           pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1626                          pg_strcasecmp(prev_wd, "COLUMN") == 0)
1627                 COMPLETE_WITH_ATTR(prev3_wd, "");
1628
1629         /* ALTER TABLE xxx RENAME yyy */
1630         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1631                          pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1632                          pg_strcasecmp(prev_wd, "CONSTRAINT") != 0 &&
1633                          pg_strcasecmp(prev_wd, "TO") != 0)
1634                 COMPLETE_WITH_CONST("TO");
1635
1636         /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */
1637         else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1638                          pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1639                          (pg_strcasecmp(prev2_wd, "COLUMN") == 0 ||
1640                           pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0) &&
1641                          pg_strcasecmp(prev_wd, "TO") != 0)
1642                 COMPLETE_WITH_CONST("TO");
1643
1644         /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1645         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1646                          pg_strcasecmp(prev_wd, "DROP") == 0)
1647         {
1648                 static const char *const list_TABLEDROP[] =
1649                 {"COLUMN", "CONSTRAINT", NULL};
1650
1651                 COMPLETE_WITH_LIST(list_TABLEDROP);
1652         }
1653         /* If we have ALTER TABLE <sth> DROP COLUMN, provide list of columns */
1654         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1655                          pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1656                          pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1657                          pg_strcasecmp(prev_wd, "COLUMN") == 0)
1658                 COMPLETE_WITH_ATTR(prev3_wd, "");
1659
1660         /*
1661          * If we have ALTER TABLE <sth> ALTER|DROP|RENAME|VALIDATE CONSTRAINT,
1662          * provide list of constraints
1663          */
1664         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1665                          pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1666                          (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1667                           pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1668                           pg_strcasecmp(prev2_wd, "RENAME") == 0 ||
1669                           pg_strcasecmp(prev2_wd, "VALIDATE") == 0) &&
1670                          pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
1671         {
1672                 completion_info_charp = prev3_wd;
1673                 COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
1674         }
1675         /* ALTER TABLE ALTER [COLUMN] <foo> */
1676         else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1677                           pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1678                          (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1679                           pg_strcasecmp(prev2_wd, "ALTER") == 0))
1680         {
1681                 static const char *const list_COLUMNALTER[] =
1682                 {"TYPE", "SET", "RESET", "DROP", NULL};
1683
1684                 COMPLETE_WITH_LIST(list_COLUMNALTER);
1685         }
1686         /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1687         else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1688                            pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1689                           (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1690                            pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1691                          pg_strcasecmp(prev_wd, "SET") == 0)
1692         {
1693                 static const char *const list_COLUMNSET[] =
1694                 {"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1695
1696                 COMPLETE_WITH_LIST(list_COLUMNSET);
1697         }
1698         /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1699         else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1700                            pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1701                           pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1702                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
1703                          pg_strcasecmp(prev_wd, "(") == 0)
1704         {
1705                 static const char *const list_COLUMNOPTIONS[] =
1706                 {"n_distinct", "n_distinct_inherited", NULL};
1707
1708                 COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1709         }
1710         /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1711         else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1712                            pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1713                           pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1714                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
1715                          pg_strcasecmp(prev_wd, "STORAGE") == 0)
1716         {
1717                 static const char *const list_COLUMNSTORAGE[] =
1718                 {"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1719
1720                 COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1721         }
1722         /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1723         else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1724                            pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1725                           (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1726                            pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1727                          pg_strcasecmp(prev_wd, "DROP") == 0)
1728         {
1729                 static const char *const list_COLUMNDROP[] =
1730                 {"DEFAULT", "NOT NULL", NULL};
1731
1732                 COMPLETE_WITH_LIST(list_COLUMNDROP);
1733         }
1734         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1735                          pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1736                 COMPLETE_WITH_CONST("ON");
1737         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1738                          pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1739                          pg_strcasecmp(prev_wd, "ON") == 0)
1740         {
1741                 completion_info_charp = prev3_wd;
1742                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1743         }
1744         /* If we have TABLE <sth> SET, provide list of attributes and '(' */
1745         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1746                          pg_strcasecmp(prev_wd, "SET") == 0)
1747         {
1748                 static const char *const list_TABLESET[] =
1749                 {"(", "LOGGED", "SCHEMA", "TABLESPACE", "UNLOGGED", "WITH", "WITHOUT", NULL};
1750
1751                 COMPLETE_WITH_LIST(list_TABLESET);
1752         }
1753         /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1754         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1755                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
1756                          pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1757                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1758         /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1759         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1760                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
1761                          pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1762         {
1763                 static const char *const list_TABLESET2[] =
1764                 {"CLUSTER", "OIDS", NULL};
1765
1766                 COMPLETE_WITH_LIST(list_TABLESET2);
1767         }
1768         /* ALTER TABLE <foo> RESET */
1769         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1770                          pg_strcasecmp(prev_wd, "RESET") == 0)
1771                 COMPLETE_WITH_CONST("(");
1772         /* ALTER TABLE <foo> SET|RESET ( */
1773         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1774                          (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1775                           pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1776                          pg_strcasecmp(prev_wd, "(") == 0)
1777         {
1778                 static const char *const list_TABLEOPTIONS[] =
1779                 {
1780                         "autovacuum_analyze_scale_factor",
1781                         "autovacuum_analyze_threshold",
1782                         "autovacuum_enabled",
1783                         "autovacuum_freeze_max_age",
1784                         "autovacuum_freeze_min_age",
1785                         "autovacuum_freeze_table_age",
1786                         "autovacuum_multixact_freeze_max_age",
1787                         "autovacuum_multixact_freeze_min_age",
1788                         "autovacuum_multixact_freeze_table_age",
1789                         "autovacuum_vacuum_cost_delay",
1790                         "autovacuum_vacuum_cost_limit",
1791                         "autovacuum_vacuum_scale_factor",
1792                         "autovacuum_vacuum_threshold",
1793                         "fillfactor",
1794                         "log_autovacuum_min_duration",
1795                         "toast.autovacuum_enabled",
1796                         "toast.autovacuum_freeze_max_age",
1797                         "toast.autovacuum_freeze_min_age",
1798                         "toast.autovacuum_freeze_table_age",
1799                         "toast.autovacuum_multixact_freeze_max_age",
1800                         "toast.autovacuum_multixact_freeze_min_age",
1801                         "toast.autovacuum_multixact_freeze_table_age",
1802                         "toast.autovacuum_vacuum_cost_delay",
1803                         "toast.autovacuum_vacuum_cost_limit",
1804                         "toast.autovacuum_vacuum_scale_factor",
1805                         "toast.autovacuum_vacuum_threshold",
1806                         "toast.log_autovacuum_min_duration",
1807                         "user_catalog_table",
1808                         NULL
1809                 };
1810
1811                 COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1812         }
1813         else if (pg_strcasecmp(prev4_wd, "REPLICA") == 0 &&
1814                          pg_strcasecmp(prev3_wd, "IDENTITY") == 0 &&
1815                          pg_strcasecmp(prev2_wd, "USING") == 0 &&
1816                          pg_strcasecmp(prev_wd, "INDEX") == 0)
1817         {
1818                 completion_info_charp = prev5_wd;
1819                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1820         }
1821         else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1822                          pg_strcasecmp(prev3_wd, "REPLICA") == 0 &&
1823                          pg_strcasecmp(prev2_wd, "IDENTITY") == 0 &&
1824                          pg_strcasecmp(prev_wd, "USING") == 0)
1825         {
1826                 COMPLETE_WITH_CONST("INDEX");
1827         }
1828         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1829                          pg_strcasecmp(prev2_wd, "REPLICA") == 0 &&
1830                          pg_strcasecmp(prev_wd, "IDENTITY") == 0)
1831         {
1832                 static const char *const list_REPLICAID[] =
1833                 {"FULL", "NOTHING", "DEFAULT", "USING", NULL};
1834
1835                 COMPLETE_WITH_LIST(list_REPLICAID);
1836         }
1837         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1838                          pg_strcasecmp(prev_wd, "REPLICA") == 0)
1839         {
1840                 COMPLETE_WITH_CONST("IDENTITY");
1841         }
1842
1843         /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1844         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1845                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1846         {
1847                 static const char *const list_ALTERTSPC[] =
1848                 {"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1849
1850                 COMPLETE_WITH_LIST(list_ALTERTSPC);
1851         }
1852         /* ALTER TABLESPACE <foo> SET|RESET */
1853         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1854                          pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1855                          (pg_strcasecmp(prev_wd, "SET") == 0 ||
1856                           pg_strcasecmp(prev_wd, "RESET") == 0))
1857                 COMPLETE_WITH_CONST("(");
1858         /* ALTER TABLESPACE <foo> SET|RESET ( */
1859         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1860                          pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1861                          (pg_strcasecmp(prev2_wd, "SET") == 0 ||
1862                           pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1863                          pg_strcasecmp(prev_wd, "(") == 0)
1864         {
1865                 static const char *const list_TABLESPACEOPTIONS[] =
1866                 {"seq_page_cost", "random_page_cost", NULL};
1867
1868                 COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1869         }
1870
1871         /* ALTER TEXT SEARCH */
1872         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1873                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1874                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
1875         {
1876                 static const char *const list_ALTERTEXTSEARCH[] =
1877                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1878
1879                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1880         }
1881         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1882                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1883                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1884                          (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1885                           pg_strcasecmp(prev2_wd, "PARSER") == 0))
1886         {
1887                 static const char *const list_ALTERTEXTSEARCH2[] =
1888                 {"RENAME TO", "SET SCHEMA", NULL};
1889
1890                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1891         }
1892
1893         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1894                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1895                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1896                          pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1897         {
1898                 static const char *const list_ALTERTEXTSEARCH3[] =
1899                 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1900
1901                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1902         }
1903
1904         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1905                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1906                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1907                          pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1908         {
1909                 static const char *const list_ALTERTEXTSEARCH4[] =
1910                 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1911
1912                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
1913         }
1914
1915         /* complete ALTER TYPE <foo> with actions */
1916         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1917                          pg_strcasecmp(prev2_wd, "TYPE") == 0)
1918         {
1919                 static const char *const list_ALTERTYPE[] =
1920                 {"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
1921                 "OWNER TO", "RENAME", "SET SCHEMA", NULL};
1922
1923                 COMPLETE_WITH_LIST(list_ALTERTYPE);
1924         }
1925         /* complete ALTER TYPE <foo> ADD with actions */
1926         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1927                          pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1928                          pg_strcasecmp(prev_wd, "ADD") == 0)
1929         {
1930                 static const char *const list_ALTERTYPE[] =
1931                 {"ATTRIBUTE", "VALUE", NULL};
1932
1933                 COMPLETE_WITH_LIST(list_ALTERTYPE);
1934         }
1935         /* ALTER TYPE <foo> RENAME      */
1936         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1937                          pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1938                          pg_strcasecmp(prev_wd, "RENAME") == 0)
1939         {
1940                 static const char *const list_ALTERTYPE[] =
1941                 {"ATTRIBUTE", "TO", NULL};
1942
1943                 COMPLETE_WITH_LIST(list_ALTERTYPE);
1944         }
1945         /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */
1946         else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 &&
1947                          pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1948                          pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)
1949                 COMPLETE_WITH_CONST("TO");
1950
1951         /*
1952          * If we have TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list of
1953          * attributes
1954          */
1955         else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 &&
1956                          (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1957                           pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1958                           pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1959                          pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0)
1960                 COMPLETE_WITH_ATTR(prev3_wd, "");
1961         /* ALTER TYPE ALTER ATTRIBUTE <foo> */
1962         else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1963                           pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0))
1964         {
1965                 COMPLETE_WITH_CONST("TYPE");
1966         }
1967         /* complete ALTER GROUP <foo> */
1968         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1969                          pg_strcasecmp(prev2_wd, "GROUP") == 0)
1970         {
1971                 static const char *const list_ALTERGROUP[] =
1972                 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1973
1974                 COMPLETE_WITH_LIST(list_ALTERGROUP);
1975         }
1976         /* complete ALTER GROUP <foo> ADD|DROP with USER */
1977         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1978                          pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1979                          (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1980                           pg_strcasecmp(prev_wd, "DROP") == 0))
1981                 COMPLETE_WITH_CONST("USER");
1982         /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1983         else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1984                          (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1985                           pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1986                          pg_strcasecmp(prev_wd, "USER") == 0)
1987                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1988
1989 /* BEGIN, END, ABORT */
1990         else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1991                          pg_strcasecmp(prev_wd, "END") == 0 ||
1992                          pg_strcasecmp(prev_wd, "ABORT") == 0)
1993         {
1994                 static const char *const list_TRANS[] =
1995                 {"WORK", "TRANSACTION", NULL};
1996
1997                 COMPLETE_WITH_LIST(list_TRANS);
1998         }
1999 /* COMMIT */
2000         else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
2001         {
2002                 static const char *const list_COMMIT[] =
2003                 {"WORK", "TRANSACTION", "PREPARED", NULL};
2004
2005                 COMPLETE_WITH_LIST(list_COMMIT);
2006         }
2007 /* RELEASE SAVEPOINT */
2008         else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
2009                 COMPLETE_WITH_CONST("SAVEPOINT");
2010 /* ROLLBACK*/
2011         else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
2012         {
2013                 static const char *const list_TRANS[] =
2014                 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
2015
2016                 COMPLETE_WITH_LIST(list_TRANS);
2017         }
2018 /* CLUSTER */
2019
2020         /*
2021          * If the previous word is CLUSTER and not WITHOUT produce list of tables
2022          */
2023         else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
2024                          pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
2025                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "UNION SELECT 'VERBOSE'");
2026
2027         /*
2028          * If the previous words are CLUSTER VERBOSE produce list of tables
2029          */
2030         else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2031                          pg_strcasecmp(prev2_wd, "CLUSTER") == 0)
2032                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
2033
2034         /* If we have CLUSTER <sth>, then add "USING" */
2035         else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
2036                          pg_strcasecmp(prev_wd, "ON") != 0 &&
2037                          pg_strcasecmp(prev_wd, "VERBOSE") != 0)
2038         {
2039                 COMPLETE_WITH_CONST("USING");
2040         }
2041         /* If we have CLUSTER VERBOSE <sth>, then add "USING" */
2042         else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
2043                          pg_strcasecmp(prev2_wd, "VERBOSE") == 0)
2044         {
2045                 COMPLETE_WITH_CONST("USING");
2046         }
2047
2048         /*
2049          * If we have CLUSTER <sth> USING, then add the index as well.
2050          */
2051         else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
2052                          pg_strcasecmp(prev_wd, "USING") == 0)
2053         {
2054                 completion_info_charp = prev2_wd;
2055                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
2056         }
2057
2058         /*
2059          * If we have CLUSTER VERBOSE <sth> USING, then add the index as well.
2060          */
2061         else if (pg_strcasecmp(prev4_wd, "CLUSTER") == 0 &&
2062                          pg_strcasecmp(prev3_wd, "VERBOSE") == 0 &&
2063                          pg_strcasecmp(prev_wd, "USING") == 0)
2064         {
2065                 completion_info_charp = prev2_wd;
2066                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
2067         }
2068
2069 /* COMMENT */
2070         else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
2071                 COMPLETE_WITH_CONST("ON");
2072         else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
2073                          pg_strcasecmp(prev_wd, "ON") == 0)
2074         {
2075                 static const char *const list_COMMENT[] =
2076                 {"CAST", "COLLATION", "CONVERSION", "DATABASE", "EVENT TRIGGER", "EXTENSION",
2077                         "FOREIGN DATA WRAPPER", "FOREIGN TABLE",
2078                         "SERVER", "INDEX", "LANGUAGE", "POLICY", "RULE", "SCHEMA", "SEQUENCE",
2079                         "TABLE", "TYPE", "VIEW", "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
2080                         "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
2081                 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
2082
2083                 COMPLETE_WITH_LIST(list_COMMENT);
2084         }
2085         else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
2086                          pg_strcasecmp(prev2_wd, "ON") == 0 &&
2087                          pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2088         {
2089                 static const char *const list_TRANS2[] =
2090                 {"DATA WRAPPER", "TABLE", NULL};
2091
2092                 COMPLETE_WITH_LIST(list_TRANS2);
2093         }
2094         else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2095                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2096                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2097                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
2098         {
2099                 static const char *const list_TRANS2[] =
2100                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2101
2102                 COMPLETE_WITH_LIST(list_TRANS2);
2103         }
2104         else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
2105                          pg_strcasecmp(prev2_wd, "ON") == 0 &&
2106                          pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
2107         {
2108                 COMPLETE_WITH_QUERY(Query_for_all_table_constraints);
2109         }
2110         else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2111                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2112                          pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0)
2113         {
2114                 COMPLETE_WITH_CONST("ON");
2115         }
2116         else if (pg_strcasecmp(prev5_wd, "COMMENT") == 0 &&
2117                          pg_strcasecmp(prev4_wd, "ON") == 0 &&
2118                          pg_strcasecmp(prev3_wd, "CONSTRAINT") == 0 &&
2119                          pg_strcasecmp(prev_wd, "ON") == 0)
2120         {
2121                 completion_info_charp = prev2_wd;
2122                 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint);
2123         }
2124         else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2125                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2126                          pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
2127                          pg_strcasecmp(prev_wd, "VIEW") == 0)
2128         {
2129                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
2130         }
2131         else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2132                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2133                          pg_strcasecmp(prev2_wd, "EVENT") == 0 &&
2134                          pg_strcasecmp(prev_wd, "TRIGGER") == 0)
2135         {
2136                 COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
2137         }
2138         else if (((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
2139                            pg_strcasecmp(prev3_wd, "ON") == 0) ||
2140                           (pg_strcasecmp(prev5_wd, "COMMENT") == 0 &&
2141                            pg_strcasecmp(prev4_wd, "ON") == 0) ||
2142                           (pg_strcasecmp(prev6_wd, "COMMENT") == 0 &&
2143                            pg_strcasecmp(prev5_wd, "ON") == 0)) &&
2144                          pg_strcasecmp(prev_wd, "IS") != 0)
2145                 COMPLETE_WITH_CONST("IS");
2146
2147 /* COPY */
2148
2149         /*
2150          * If we have COPY [BINARY] (which you'd have to type yourself), offer
2151          * list of tables (Also cover the analogous backslash command)
2152          */
2153         else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
2154                          pg_strcasecmp(prev_wd, "\\copy") == 0 ||
2155                          (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
2156                           pg_strcasecmp(prev_wd, "BINARY") == 0))
2157                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2158         /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
2159         else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
2160                          pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
2161                          pg_strcasecmp(prev2_wd, "BINARY") == 0)
2162         {
2163                 static const char *const list_FROMTO[] =
2164                 {"FROM", "TO", NULL};
2165
2166                 COMPLETE_WITH_LIST(list_FROMTO);
2167         }
2168         /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
2169         else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
2170                           pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
2171                           pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
2172                          (pg_strcasecmp(prev_wd, "FROM") == 0 ||
2173                           pg_strcasecmp(prev_wd, "TO") == 0))
2174         {
2175                 completion_charp = "";
2176                 matches = completion_matches(text, complete_from_files);
2177         }
2178
2179         /* Handle COPY|BINARY <sth> FROM|TO filename */
2180         else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
2181                           pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
2182                           pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
2183                          (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
2184                           pg_strcasecmp(prev2_wd, "TO") == 0))
2185         {
2186                 static const char *const list_COPY[] =
2187                 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL};
2188
2189                 COMPLETE_WITH_LIST(list_COPY);
2190         }
2191
2192         /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
2193         else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
2194                          (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
2195                           pg_strcasecmp(prev3_wd, "TO") == 0))
2196         {
2197                 static const char *const list_CSV[] =
2198                 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL};
2199
2200                 COMPLETE_WITH_LIST(list_CSV);
2201         }
2202
2203         /* CREATE DATABASE */
2204         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2205                          pg_strcasecmp(prev2_wd, "DATABASE") == 0)
2206         {
2207                 static const char *const list_DATABASE[] =
2208                 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "IS_TEMPLATE",
2209                         "ALLOW_CONNECTIONS", "CONNECTION LIMIT", "LC_COLLATE", "LC_CTYPE",
2210                 NULL};
2211
2212                 COMPLETE_WITH_LIST(list_DATABASE);
2213         }
2214
2215         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2216                          pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
2217                          pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
2218                 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
2219
2220         /* CREATE EXTENSION */
2221         /* Complete with available extensions rather than installed ones. */
2222         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2223                          pg_strcasecmp(prev_wd, "EXTENSION") == 0)
2224                 COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
2225         /* CREATE EXTENSION <name> */
2226         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2227                          pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
2228                 COMPLETE_WITH_CONST("WITH SCHEMA");
2229
2230         /* CREATE FOREIGN */
2231         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2232                          pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2233         {
2234                 static const char *const list_CREATE_FOREIGN[] =
2235                 {"DATA WRAPPER", "TABLE", NULL};
2236
2237                 COMPLETE_WITH_LIST(list_CREATE_FOREIGN);
2238         }
2239
2240         /* CREATE FOREIGN DATA WRAPPER */
2241         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2242                          pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2243                          pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2244                          pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
2245         {
2246                 static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] =
2247                 {"HANDLER", "VALIDATOR", NULL};
2248
2249                 COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER);
2250         }
2251
2252         /* CREATE INDEX */
2253         /* First off we complete CREATE UNIQUE with "INDEX" */
2254         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2255                          pg_strcasecmp(prev_wd, "UNIQUE") == 0)
2256                 COMPLETE_WITH_CONST("INDEX");
2257         /* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
2258         else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
2259                          (pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
2260                           pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
2261                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
2262                                                                    " UNION SELECT 'ON'"
2263                                                                    " UNION SELECT 'CONCURRENTLY'");
2264         /* Complete ... INDEX [<name>] ON with a list of tables  */
2265         else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2266                           pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2267                           pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
2268                          pg_strcasecmp(prev_wd, "ON") == 0)
2269                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
2270         /* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
2271         else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2272                           pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
2273                          pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
2274                 COMPLETE_WITH_CONST("ON");
2275         /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
2276         else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2277                           pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
2278                          pg_strcasecmp(prev2_wd, "INDEX") == 0)
2279         {
2280                 static const char *const list_CREATE_INDEX[] =
2281                 {"CONCURRENTLY", "ON", NULL};
2282
2283                 COMPLETE_WITH_LIST(list_CREATE_INDEX);
2284         }
2285
2286         /*
2287          * Complete INDEX <name> ON <table> with a list of table columns (which
2288          * should really be in parens)
2289          */
2290         else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
2291                           pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
2292                           pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
2293                          pg_strcasecmp(prev2_wd, "ON") == 0)
2294         {
2295                 static const char *const list_CREATE_INDEX2[] =
2296                 {"(", "USING", NULL};
2297
2298                 COMPLETE_WITH_LIST(list_CREATE_INDEX2);
2299         }
2300         else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
2301                           pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
2302                           pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
2303                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2304                          pg_strcasecmp(prev_wd, "(") == 0)
2305                 COMPLETE_WITH_ATTR(prev2_wd, "");
2306         /* same if you put in USING */
2307         else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
2308                          pg_strcasecmp(prev3_wd, "USING") == 0 &&
2309                          pg_strcasecmp(prev_wd, "(") == 0)
2310                 COMPLETE_WITH_ATTR(prev4_wd, "");
2311         /* Complete USING with an index method */
2312         else if ((pg_strcasecmp(prev6_wd, "INDEX") == 0 ||
2313                           pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
2314                           pg_strcasecmp(prev4_wd, "INDEX") == 0) &&
2315                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2316                          pg_strcasecmp(prev_wd, "USING") == 0)
2317                 COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
2318         else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
2319                          (!(pg_strcasecmp(prev6_wd, "POLICY") == 0) &&
2320                           !(pg_strcasecmp(prev4_wd, "FOR") == 0)) &&
2321                          pg_strcasecmp(prev2_wd, "USING") == 0)
2322                 COMPLETE_WITH_CONST("(");
2323
2324         /* CREATE POLICY */
2325         /* Complete "CREATE POLICY <name> ON" */
2326         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2327                          pg_strcasecmp(prev2_wd, "POLICY") == 0)
2328                 COMPLETE_WITH_CONST("ON");
2329         /* Complete "CREATE POLICY <name> ON <table>" */
2330         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2331                          pg_strcasecmp(prev3_wd, "POLICY") == 0 &&
2332                          pg_strcasecmp(prev_wd, "ON") == 0)
2333                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2334         /* Complete "CREATE POLICY <name> ON <table> FOR|TO|USING|WITH CHECK" */
2335         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2336                          pg_strcasecmp(prev4_wd, "POLICY") == 0 &&
2337                          pg_strcasecmp(prev2_wd, "ON") == 0)
2338         {
2339                 static const char *const list_POLICYOPTIONS[] =
2340                 {"FOR", "TO", "USING", "WITH CHECK", NULL};
2341
2342                 COMPLETE_WITH_LIST(list_POLICYOPTIONS);
2343         }
2344
2345         /*
2346          * Complete "CREATE POLICY <name> ON <table> FOR
2347          * ALL|SELECT|INSERT|UPDATE|DELETE"
2348          */
2349         else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 &&
2350                          pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
2351                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2352                          pg_strcasecmp(prev_wd, "FOR") == 0)
2353         {
2354                 static const char *const list_POLICYCMDS[] =
2355                 {"ALL", "SELECT", "INSERT", "UPDATE", "DELETE", NULL};
2356
2357                 COMPLETE_WITH_LIST(list_POLICYCMDS);
2358         }
2359         /* Complete "CREATE POLICY <name> ON <table> FOR INSERT TO|WITH CHECK" */
2360         else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 &&
2361                          pg_strcasecmp(prev4_wd, "ON") == 0 &&
2362                          pg_strcasecmp(prev2_wd, "FOR") == 0 &&
2363                          pg_strcasecmp(prev_wd, "INSERT") == 0)
2364         {
2365                 static const char *const list_POLICYOPTIONS[] =
2366                 {"TO", "WITH CHECK", NULL};
2367
2368                 COMPLETE_WITH_LIST(list_POLICYOPTIONS);
2369         }
2370
2371         /*
2372          * Complete "CREATE POLICY <name> ON <table> FOR SELECT TO|USING" Complete
2373          * "CREATE POLICY <name> ON <table> FOR DELETE TO|USING"
2374          */
2375         else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 &&
2376                          pg_strcasecmp(prev4_wd, "ON") == 0 &&
2377                          pg_strcasecmp(prev2_wd, "FOR") == 0 &&
2378                          (pg_strcasecmp(prev_wd, "SELECT") == 0 ||
2379                           pg_strcasecmp(prev_wd, "DELETE") == 0))
2380         {
2381                 static const char *const list_POLICYOPTIONS[] =
2382                 {"TO", "USING", NULL};
2383
2384                 COMPLETE_WITH_LIST(list_POLICYOPTIONS);
2385         }
2386
2387         /*
2388          * Complete "CREATE POLICY <name> ON <table> FOR ALL TO|USING|WITH CHECK"
2389          * Complete "CREATE POLICY <name> ON <table> FOR UPDATE TO|USING|WITH
2390          * CHECK"
2391          */
2392         else if (pg_strcasecmp(prev6_wd, "POLICY") == 0 &&
2393                          pg_strcasecmp(prev4_wd, "ON") == 0 &&
2394                          pg_strcasecmp(prev2_wd, "FOR") == 0 &&
2395                          (pg_strcasecmp(prev_wd, "ALL") == 0 ||
2396                           pg_strcasecmp(prev_wd, "UPDATE") == 0))
2397         {
2398                 static const char *const list_POLICYOPTIONS[] =
2399                 {"TO", "USING", "WITH CHECK", NULL};
2400
2401                 COMPLETE_WITH_LIST(list_POLICYOPTIONS);
2402         }
2403         /* Complete "CREATE POLICY <name> ON <table> TO <role>" */
2404         else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 &&
2405                          pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
2406                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2407                          pg_strcasecmp(prev_wd, "TO") == 0)
2408                 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2409         /* Complete "CREATE POLICY <name> ON <table> USING (" */
2410         else if (pg_strcasecmp(prev6_wd, "CREATE") == 0 &&
2411                          pg_strcasecmp(prev5_wd, "POLICY") == 0 &&
2412                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2413                          pg_strcasecmp(prev_wd, "USING") == 0)
2414                 COMPLETE_WITH_CONST("(");
2415
2416 /* CREATE RULE */
2417         /* Complete "CREATE RULE <sth>" with "AS" */
2418         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2419                          pg_strcasecmp(prev2_wd, "RULE") == 0)
2420                 COMPLETE_WITH_CONST("AS");
2421         /* Complete "CREATE RULE <sth> AS with "ON" */
2422         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2423                          pg_strcasecmp(prev3_wd, "RULE") == 0 &&
2424                          pg_strcasecmp(prev_wd, "AS") == 0)
2425                 COMPLETE_WITH_CONST("ON");
2426         /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
2427         else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
2428                          pg_strcasecmp(prev2_wd, "AS") == 0 &&
2429                          pg_strcasecmp(prev_wd, "ON") == 0)
2430         {
2431                 static const char *const rule_events[] =
2432                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2433
2434                 COMPLETE_WITH_LIST(rule_events);
2435         }
2436         /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
2437         else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
2438                          pg_strcasecmp(prev2_wd, "ON") == 0 &&
2439                          (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
2440                           pg_toupper((unsigned char) prev_wd[5]) == 'T'))
2441                 COMPLETE_WITH_CONST("TO");
2442         /* Complete "AS ON <sth> TO" with a table name */
2443         else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
2444                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
2445                          pg_strcasecmp(prev_wd, "TO") == 0)
2446                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2447
2448 /* CREATE SERVER <name> */
2449         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2450                          pg_strcasecmp(prev2_wd, "SERVER") == 0)
2451         {
2452                 static const char *const list_CREATE_SERVER[] =
2453                 {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
2454
2455                 COMPLETE_WITH_LIST(list_CREATE_SERVER);
2456         }
2457
2458 /* CREATE TABLE */
2459         /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
2460         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2461                          (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
2462                           pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
2463         {
2464                 static const char *const list_TEMP[] =
2465                 {"SEQUENCE", "TABLE", "VIEW", NULL};
2466
2467                 COMPLETE_WITH_LIST(list_TEMP);
2468         }
2469         /* Complete "CREATE UNLOGGED" with TABLE */
2470         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2471                          pg_strcasecmp(prev_wd, "UNLOGGED") == 0)
2472         {
2473                 static const char *const list_UNLOGGED[] =
2474                 {"TABLE", "MATERIALIZED VIEW", NULL};
2475
2476                 COMPLETE_WITH_LIST(list_UNLOGGED);
2477         }
2478
2479 /* CREATE TABLESPACE */
2480         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2481                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
2482         {
2483                 static const char *const list_CREATETABLESPACE[] =
2484                 {"OWNER", "LOCATION", NULL};
2485
2486                 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
2487         }
2488         /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
2489         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2490                          pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
2491                          pg_strcasecmp(prev2_wd, "OWNER") == 0)
2492         {
2493                 COMPLETE_WITH_CONST("LOCATION");
2494         }
2495
2496 /* CREATE TEXT SEARCH */
2497         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2498                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2499                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
2500         {
2501                 static const char *const list_CREATETEXTSEARCH[] =
2502                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2503
2504                 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
2505         }
2506         else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2507                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2508                          pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
2509                 COMPLETE_WITH_CONST("(");
2510
2511 /* CREATE TRIGGER */
2512         /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
2513         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2514                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
2515         {
2516                 static const char *const list_CREATETRIGGER[] =
2517                 {"BEFORE", "AFTER", "INSTEAD OF", NULL};
2518
2519                 COMPLETE_WITH_LIST(list_CREATETRIGGER);
2520         }
2521         /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
2522         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2523                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
2524                          (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
2525                           pg_strcasecmp(prev_wd, "AFTER") == 0))
2526         {
2527                 static const char *const list_CREATETRIGGER_EVENTS[] =
2528                 {"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
2529
2530                 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
2531         }
2532         /* complete CREATE TRIGGER <name> INSTEAD OF with an event */
2533         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2534                          pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2535                          pg_strcasecmp(prev2_wd, "INSTEAD") == 0 &&
2536                          pg_strcasecmp(prev_wd, "OF") == 0)
2537         {
2538                 static const char *const list_CREATETRIGGER_EVENTS[] =
2539                 {"INSERT", "DELETE", "UPDATE", NULL};
2540
2541                 COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
2542         }
2543         /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
2544         else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2545                           pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2546                           (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2547                            pg_strcasecmp(prev2_wd, "AFTER") == 0)) ||
2548                          (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
2549                           pg_strcasecmp(prev3_wd, "INSTEAD") == 0 &&
2550                           pg_strcasecmp(prev2_wd, "OF") == 0))
2551         {
2552                 static const char *const list_CREATETRIGGER2[] =
2553                 {"ON", "OR", NULL};
2554
2555                 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
2556         }
2557
2558         /*
2559          * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
2560          * tables
2561          */
2562         else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
2563                          (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
2564                           pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
2565                          pg_strcasecmp(prev_wd, "ON") == 0)
2566                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2567         /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
2568         else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 &&
2569                          pg_strcasecmp(prev3_wd, "OF") == 0 &&
2570                          pg_strcasecmp(prev_wd, "ON") == 0)
2571                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2572         /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
2573         else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2574                          prev2_wd[0] != '\0')
2575                 COMPLETE_WITH_CONST("PROCEDURE");
2576
2577 /* CREATE ROLE,USER,GROUP <name> */
2578         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2579                          !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
2580                          (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
2581                           pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
2582         {
2583                 static const char *const list_CREATEROLE[] =
2584                 {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
2585                         "CREATEUSER", "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
2586                         "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT",
2587                         "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
2588                         "REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED",
2589                         "VALID UNTIL", "WITH", NULL};
2590
2591                 COMPLETE_WITH_LIST(list_CREATEROLE);
2592         }
2593
2594 /* CREATE ROLE,USER,GROUP <name> WITH */
2595         else if ((pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2596                           (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2597                            pg_strcasecmp(prev3_wd, "GROUP") == 0 ||
2598                            pg_strcasecmp(prev3_wd, "USER") == 0) &&
2599                           pg_strcasecmp(prev_wd, "WITH") == 0))
2600         {
2601                 /* Similar to the above, but don't complete "WITH" again. */
2602                 static const char *const list_CREATEROLE_WITH[] =
2603                 {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
2604                         "CREATEUSER", "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
2605                         "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT",
2606                         "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
2607                         "REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED",
2608                         "VALID UNTIL", NULL};
2609
2610                 COMPLETE_WITH_LIST(list_CREATEROLE_WITH);
2611         }
2612
2613         /*
2614          * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
2615          * PASSWORD
2616          */
2617         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2618                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2619                           pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
2620                          (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
2621         {
2622                 COMPLETE_WITH_CONST("PASSWORD");
2623         }
2624         /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
2625         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2626                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
2627                           pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
2628                          pg_strcasecmp(prev_wd, "IN") == 0)
2629         {
2630                 static const char *const list_CREATEROLE3[] =
2631                 {"GROUP", "ROLE", NULL};
2632
2633                 COMPLETE_WITH_LIST(list_CREATEROLE3);
2634         }
2635
2636 /* CREATE VIEW */
2637         /* Complete CREATE VIEW <name> with AS */
2638         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
2639                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
2640                 COMPLETE_WITH_CONST("AS");
2641         /* Complete "CREATE VIEW <sth> AS with "SELECT" */
2642         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2643                          pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2644                          pg_strcasecmp(prev_wd, "AS") == 0)
2645                 COMPLETE_WITH_CONST("SELECT");
2646
2647 /* CREATE MATERIALIZED VIEW */
2648         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2649                          pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
2650                 COMPLETE_WITH_CONST("VIEW");
2651         /* Complete CREATE MATERIALIZED VIEW <name> with AS */
2652         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2653                          pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
2654                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
2655                 COMPLETE_WITH_CONST("AS");
2656         /* Complete "CREATE MATERIALIZED VIEW <sth> AS with "SELECT" */
2657         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2658                          pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
2659                          pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
2660                          pg_strcasecmp(prev_wd, "AS") == 0)
2661                 COMPLETE_WITH_CONST("SELECT");
2662
2663 /* CREATE EVENT TRIGGER */
2664         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
2665                          pg_strcasecmp(prev_wd, "EVENT") == 0)
2666                 COMPLETE_WITH_CONST("TRIGGER");
2667         /* Complete CREATE EVENT TRIGGER <name> with ON */
2668         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2669                          pg_strcasecmp(prev3_wd, "EVENT") == 0 &&
2670                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
2671                 COMPLETE_WITH_CONST("ON");
2672         /* Complete CREATE EVENT TRIGGER <name> ON with event_type */
2673         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
2674                          pg_strcasecmp(prev4_wd, "EVENT") == 0 &&
2675                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
2676                          pg_strcasecmp(prev_wd, "ON") == 0)
2677         {
2678                 static const char *const list_CREATE_EVENT_TRIGGER_ON[] =
2679                 {"ddl_command_start", "ddl_command_end", "sql_drop", NULL};
2680
2681                 COMPLETE_WITH_LIST(list_CREATE_EVENT_TRIGGER_ON);
2682         }
2683
2684 /* DECLARE */
2685         else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
2686         {
2687                 static const char *const list_DECLARE[] =
2688                 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
2689
2690                 COMPLETE_WITH_LIST(list_DECLARE);
2691         }
2692
2693 /* CURSOR */
2694         else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
2695         {
2696                 static const char *const list_DECLARECURSOR[] =
2697                 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
2698
2699                 COMPLETE_WITH_LIST(list_DECLARECURSOR);
2700         }
2701
2702
2703 /* DELETE */
2704
2705         /*
2706          * Complete DELETE with FROM (only if the word before that is not "ON"
2707          * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
2708          */
2709         else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
2710                          !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
2711                            pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2712                            pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
2713                            pg_strcasecmp(prev2_wd, "AFTER") == 0))
2714                 COMPLETE_WITH_CONST("FROM");
2715         /* Complete DELETE FROM with a list of tables */
2716         else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
2717                          pg_strcasecmp(prev_wd, "FROM") == 0)
2718                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
2719         /* Complete DELETE FROM <table> */
2720         else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
2721                          pg_strcasecmp(prev2_wd, "FROM") == 0)
2722         {
2723                 static const char *const list_DELETE[] =
2724                 {"USING", "WHERE", "SET", NULL};
2725
2726                 COMPLETE_WITH_LIST(list_DELETE);
2727         }
2728         /* XXX: implement tab completion for DELETE ... USING */
2729
2730 /* DISCARD */
2731         else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
2732         {
2733                 static const char *const list_DISCARD[] =
2734                 {"ALL", "PLANS", "SEQUENCES", "TEMP", NULL};
2735
2736                 COMPLETE_WITH_LIST(list_DISCARD);
2737         }
2738
2739 /* DO */
2740
2741         /*
2742          * Complete DO with LANGUAGE.
2743          */
2744         else if (pg_strcasecmp(prev_wd, "DO") == 0)
2745         {
2746                 static const char *const list_DO[] =
2747                 {"LANGUAGE", NULL};
2748
2749                 COMPLETE_WITH_LIST(list_DO);
2750         }
2751
2752 /* DROP (when not the previous word) */
2753         /* DROP AGGREGATE */
2754         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2755                          pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
2756                 COMPLETE_WITH_CONST("(");
2757
2758         /* DROP object with CASCADE / RESTRICT */
2759         else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2760                           (pg_strcasecmp(prev2_wd, "COLLATION") == 0 ||
2761                            pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
2762                            pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
2763                            pg_strcasecmp(prev2_wd, "EXTENSION") == 0 ||
2764                            pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
2765                            pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2766                            pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
2767                            pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
2768                            pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
2769                            pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
2770                            pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
2771                            pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
2772                            pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
2773                          (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2774                           pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
2775                           prev_wd[strlen(prev_wd) - 1] == ')') ||
2776                          (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2777                           pg_strcasecmp(prev3_wd, "EVENT") == 0 &&
2778                           pg_strcasecmp(prev2_wd, "TRIGGER") == 0) ||
2779                          (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2780                           pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2781                           pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2782                           pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
2783                          (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2784                           pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2785                           pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2786                           (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
2787                            pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
2788                            pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
2789                            pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
2790                 )
2791         {
2792                 if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2793                         pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
2794                 {
2795                         COMPLETE_WITH_CONST("(");
2796                 }
2797                 else
2798                 {
2799                         static const char *const list_DROPCR[] =
2800                         {"CASCADE", "RESTRICT", NULL};
2801
2802                         COMPLETE_WITH_LIST(list_DROPCR);
2803                 }
2804         }
2805         else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2806                          pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2807         {
2808                 static const char *const drop_CREATE_FOREIGN[] =
2809                 {"DATA WRAPPER", "TABLE", NULL};
2810
2811                 COMPLETE_WITH_LIST(drop_CREATE_FOREIGN);
2812         }
2813
2814         /* DROP MATERIALIZED VIEW */
2815         else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2816                          pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
2817         {
2818                 COMPLETE_WITH_CONST("VIEW");
2819         }
2820         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2821                          pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
2822                          pg_strcasecmp(prev_wd, "VIEW") == 0)
2823         {
2824                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
2825         }
2826
2827         else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2828                          (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
2829                           pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
2830                          pg_strcasecmp(prev_wd, "(") == 0)
2831                 COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
2832         /* DROP OWNED BY */
2833         else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2834                          pg_strcasecmp(prev_wd, "OWNED") == 0)
2835                 COMPLETE_WITH_CONST("BY");
2836         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2837                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2838                          pg_strcasecmp(prev_wd, "BY") == 0)
2839                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2840         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2841                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2842                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
2843         {
2844
2845                 static const char *const list_ALTERTEXTSEARCH[] =
2846                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2847
2848                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
2849         }
2850
2851         /* DROP TRIGGER */
2852         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2853                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
2854         {
2855                 COMPLETE_WITH_CONST("ON");
2856         }
2857         else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2858                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
2859                          pg_strcasecmp(prev_wd, "ON") == 0)
2860         {
2861                 completion_info_charp = prev2_wd;
2862                 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
2863         }
2864         else if (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2865                          pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
2866                          pg_strcasecmp(prev2_wd, "ON") == 0)
2867         {
2868                 static const char *const list_DROPCR[] =
2869                 {"CASCADE", "RESTRICT", NULL};
2870
2871                 COMPLETE_WITH_LIST(list_DROPCR);
2872         }
2873
2874         /* DROP EVENT TRIGGER */
2875         else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2876                          pg_strcasecmp(prev_wd, "EVENT") == 0)
2877         {
2878                 COMPLETE_WITH_CONST("TRIGGER");
2879         }
2880         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2881                          pg_strcasecmp(prev2_wd, "EVENT") == 0 &&
2882                          pg_strcasecmp(prev_wd, "TRIGGER") == 0)
2883         {
2884                 COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
2885         }
2886
2887         /* DROP POLICY <name> ON */
2888         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2889                          pg_strcasecmp(prev2_wd, "POLICY") == 0)
2890                 COMPLETE_WITH_CONST("ON");
2891         /* DROP POLICY <name> ON <table> */
2892         else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2893                          pg_strcasecmp(prev3_wd, "POLICY") == 0 &&
2894                          pg_strcasecmp(prev_wd, "ON") == 0)
2895                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2896
2897         /* DROP RULE */
2898         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2899                          pg_strcasecmp(prev2_wd, "RULE") == 0)
2900         {
2901                 COMPLETE_WITH_CONST("ON");
2902         }
2903         else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2904                          pg_strcasecmp(prev3_wd, "RULE") == 0 &&
2905                          pg_strcasecmp(prev_wd, "ON") == 0)
2906         {
2907                 completion_info_charp = prev2_wd;
2908                 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
2909         }
2910         else if (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2911                          pg_strcasecmp(prev4_wd, "RULE") == 0 &&
2912                          pg_strcasecmp(prev2_wd, "ON") == 0)
2913         {
2914                 static const char *const list_DROPCR[] =
2915                 {"CASCADE", "RESTRICT", NULL};
2916
2917                 COMPLETE_WITH_LIST(list_DROPCR);
2918         }
2919
2920 /* EXECUTE, but not EXECUTE embedded in other commands */
2921         else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0 &&
2922                          prev2_wd[0] == '\0')
2923                 COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
2924
2925 /* EXPLAIN */
2926
2927         /*
2928          * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2929          */
2930         else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
2931         {
2932                 static const char *const list_EXPLAIN[] =
2933                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
2934
2935                 COMPLETE_WITH_LIST(list_EXPLAIN);
2936         }
2937         else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2938                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2939         {
2940                 static const char *const list_EXPLAIN[] =
2941                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
2942
2943                 COMPLETE_WITH_LIST(list_EXPLAIN);
2944         }
2945         else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2946                           pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
2947                          (pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
2948                           pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
2949                           pg_strcasecmp(prev_wd, "VERBOSE") == 0))
2950         {
2951                 static const char *const list_EXPLAIN[] =
2952                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
2953
2954                 COMPLETE_WITH_LIST(list_EXPLAIN);
2955         }
2956
2957 /* FETCH && MOVE */
2958         /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
2959         else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
2960                          pg_strcasecmp(prev_wd, "MOVE") == 0)
2961         {
2962                 static const char *const list_FETCH1[] =
2963                 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
2964
2965                 COMPLETE_WITH_LIST(list_FETCH1);
2966         }
2967         /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
2968         else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
2969                          pg_strcasecmp(prev2_wd, "MOVE") == 0)
2970         {
2971                 static const char *const list_FETCH2[] =
2972                 {"ALL", "NEXT", "PRIOR", NULL};
2973
2974                 COMPLETE_WITH_LIST(list_FETCH2);
2975         }
2976
2977         /*
2978          * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
2979          * but we may as well tab-complete both: perhaps some users prefer one
2980          * variant or the other.
2981          */
2982         else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
2983                          pg_strcasecmp(prev3_wd, "MOVE") == 0)
2984         {
2985                 static const char *const list_FROMIN[] =
2986                 {"FROM", "IN", NULL};
2987
2988                 COMPLETE_WITH_LIST(list_FROMIN);
2989         }
2990
2991 /* FOREIGN DATA WRAPPER */
2992         /* applies in ALTER/DROP FDW and in CREATE SERVER */
2993         else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
2994                          pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
2995                          pg_strcasecmp(prev2_wd, "DATA") == 0 &&
2996                          pg_strcasecmp(prev_wd, "WRAPPER") == 0)
2997                 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2998
2999 /* FOREIGN TABLE */
3000         else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 &&
3001                          pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
3002                          pg_strcasecmp(prev_wd, "TABLE") == 0)
3003                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
3004
3005 /* GRANT && REVOKE */
3006         /* Complete GRANT/REVOKE with a list of roles and privileges */
3007         else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
3008                          pg_strcasecmp(prev_wd, "REVOKE") == 0)
3009         {
3010                 COMPLETE_WITH_QUERY(Query_for_list_of_roles
3011                                                         " UNION SELECT 'SELECT'"
3012                                                         " UNION SELECT 'INSERT'"
3013                                                         " UNION SELECT 'UPDATE'"
3014                                                         " UNION SELECT 'DELETE'"
3015                                                         " UNION SELECT 'TRUNCATE'"
3016                                                         " UNION SELECT 'REFERENCES'"
3017                                                         " UNION SELECT 'TRIGGER'"
3018                                                         " UNION SELECT 'CREATE'"
3019                                                         " UNION SELECT 'CONNECT'"
3020                                                         " UNION SELECT 'TEMPORARY'"
3021                                                         " UNION SELECT 'EXECUTE'"
3022                                                         " UNION SELECT 'USAGE'"
3023                                                         " UNION SELECT 'ALL'");
3024         }
3025
3026         /*
3027          * Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
3028          * TO/FROM
3029          */
3030         else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
3031                          pg_strcasecmp(prev2_wd, "REVOKE") == 0)
3032         {
3033                 if (pg_strcasecmp(prev_wd, "SELECT") == 0
3034                         || pg_strcasecmp(prev_wd, "INSERT") == 0
3035                         || pg_strcasecmp(prev_wd, "UPDATE") == 0
3036                         || pg_strcasecmp(prev_wd, "DELETE") == 0
3037                         || pg_strcasecmp(prev_wd, "TRUNCATE") == 0
3038                         || pg_strcasecmp(prev_wd, "REFERENCES") == 0
3039                         || pg_strcasecmp(prev_wd, "TRIGGER") == 0
3040                         || pg_strcasecmp(prev_wd, "CREATE") == 0
3041                         || pg_strcasecmp(prev_wd, "CONNECT") == 0
3042                         || pg_strcasecmp(prev_wd, "TEMPORARY") == 0
3043                         || pg_strcasecmp(prev_wd, "TEMP") == 0
3044                         || pg_strcasecmp(prev_wd, "EXECUTE") == 0
3045                         || pg_strcasecmp(prev_wd, "USAGE") == 0
3046                         || pg_strcasecmp(prev_wd, "ALL") == 0)
3047                         COMPLETE_WITH_CONST("ON");
3048                 else
3049                 {
3050                         if (pg_strcasecmp(prev2_wd, "GRANT") == 0)
3051                                 COMPLETE_WITH_CONST("TO");
3052                         else
3053                                 COMPLETE_WITH_CONST("FROM");
3054                 }
3055         }
3056
3057         /*
3058          * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
3059          * and indexes
3060          *
3061          * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
3062          * UNION; seems to work intuitively
3063          *
3064          * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
3065          * here will only work if the privilege list contains exactly one
3066          * privilege
3067          */
3068         else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
3069                           pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
3070                          pg_strcasecmp(prev_wd, "ON") == 0)
3071                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
3072                                                                    " UNION SELECT 'DATABASE'"
3073                                                                    " UNION SELECT 'DOMAIN'"
3074                                                                    " UNION SELECT 'FOREIGN DATA WRAPPER'"
3075                                                                    " UNION SELECT 'FOREIGN SERVER'"
3076                                                                    " UNION SELECT 'FUNCTION'"
3077                                                                    " UNION SELECT 'LANGUAGE'"
3078                                                                    " UNION SELECT 'LARGE OBJECT'"
3079                                                                    " UNION SELECT 'SCHEMA'"
3080                                                                    " UNION SELECT 'TABLESPACE'"
3081                                                                    " UNION SELECT 'TYPE'");
3082         else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
3083                           pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
3084                          pg_strcasecmp(prev2_wd, "ON") == 0 &&
3085                          pg_strcasecmp(prev_wd, "FOREIGN") == 0)
3086         {
3087                 static const char *const list_privilege_foreign[] =
3088                 {"DATA WRAPPER", "SERVER", NULL};
3089
3090                 COMPLETE_WITH_LIST(list_privilege_foreign);
3091         }
3092
3093         /* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
3094         else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
3095                           pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
3096                          pg_strcasecmp(prev2_wd, "ON") == 0)
3097         {
3098                 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
3099                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3100                 else if (pg_strcasecmp(prev_wd, "DOMAIN") == 0)
3101                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
3102                 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
3103                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3104                 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
3105                         COMPLETE_WITH_QUERY(Query_for_list_of_languages);
3106                 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
3107                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3108                 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
3109                         COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
3110                 else if (pg_strcasecmp(prev_wd, "TYPE") == 0)
3111                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
3112                 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
3113                         COMPLETE_WITH_CONST("TO");
3114                 else
3115                         COMPLETE_WITH_CONST("FROM");
3116         }
3117
3118         /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
3119         else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
3120                          pg_strcasecmp(prev3_wd, "ON") == 0)
3121         {
3122                 if (pg_strcasecmp(prev_wd, "TO") == 0)
3123                         COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
3124                 else
3125                         COMPLETE_WITH_CONST("TO");
3126         }
3127         else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
3128                          pg_strcasecmp(prev3_wd, "ON") == 0)
3129         {
3130                 if (pg_strcasecmp(prev_wd, "FROM") == 0)
3131                         COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
3132                 else
3133                         COMPLETE_WITH_CONST("FROM");
3134         }
3135
3136         /* Complete "GRANT/REVOKE * TO/FROM" with username, GROUP, or PUBLIC */
3137         else if (pg_strcasecmp(prev3_wd, "GRANT") == 0 &&
3138                          pg_strcasecmp(prev_wd, "TO") == 0)
3139         {
3140                 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
3141         }
3142         else if (pg_strcasecmp(prev3_wd, "REVOKE") == 0 &&
3143                          pg_strcasecmp(prev_wd, "FROM") == 0)
3144         {
3145                 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
3146         }
3147
3148 /* GROUP BY */
3149         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
3150                          pg_strcasecmp(prev_wd, "GROUP") == 0)
3151                 COMPLETE_WITH_CONST("BY");
3152
3153 /* IMPORT FOREIGN SCHEMA */
3154         else if (pg_strcasecmp(prev_wd, "IMPORT") == 0)
3155                 COMPLETE_WITH_CONST("FOREIGN SCHEMA");
3156         else if (pg_strcasecmp(prev2_wd, "IMPORT") == 0 &&
3157                          pg_strcasecmp(prev_wd, "FOREIGN") == 0)
3158                 COMPLETE_WITH_CONST("SCHEMA");
3159
3160 /* INSERT */
3161         /* Complete INSERT with "INTO" */
3162         else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
3163                 COMPLETE_WITH_CONST("INTO");
3164         /* Complete INSERT INTO with table names */
3165         else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
3166                          pg_strcasecmp(prev_wd, "INTO") == 0)
3167                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
3168         /* Complete "INSERT INTO <table> (" with attribute names */
3169         else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
3170                          pg_strcasecmp(prev3_wd, "INTO") == 0 &&
3171                          pg_strcasecmp(prev_wd, "(") == 0)
3172                 COMPLETE_WITH_ATTR(prev2_wd, "");
3173
3174         /*
3175          * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
3176          * "TABLE" or "DEFAULT VALUES"
3177          */
3178         else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
3179                          pg_strcasecmp(prev2_wd, "INTO") == 0)
3180         {
3181                 static const char *const list_INSERT[] =
3182                 {"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
3183
3184                 COMPLETE_WITH_LIST(list_INSERT);
3185         }
3186
3187         /*
3188          * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
3189          * "TABLE"
3190          */
3191         else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
3192                          pg_strcasecmp(prev3_wd, "INTO") == 0 &&
3193                          prev_wd[strlen(prev_wd) - 1] == ')')
3194         {
3195                 static const char *const list_INSERT[] =
3196                 {"SELECT", "TABLE", "VALUES", NULL};
3197
3198                 COMPLETE_WITH_LIST(list_INSERT);
3199         }
3200
3201         /* Insert an open parenthesis after "VALUES" */
3202         else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
3203                          pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
3204                 COMPLETE_WITH_CONST("(");
3205
3206 /* LOCK */
3207         /* Complete LOCK [TABLE] with a list of tables */
3208         else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
3209                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
3210                                                                    " UNION SELECT 'TABLE'");
3211         else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
3212                          pg_strcasecmp(prev2_wd, "LOCK") == 0)
3213                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
3214
3215         /* For the following, handle the case of a single table only for now */
3216
3217         /* Complete LOCK [TABLE] <table> with "IN" */
3218         else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
3219                           pg_strcasecmp(prev_wd, "TABLE") != 0) ||
3220                          (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
3221                           pg_strcasecmp(prev3_wd, "LOCK") == 0))
3222                 COMPLETE_WITH_CONST("IN");
3223
3224         /* Complete LOCK [TABLE] <table> IN with a lock mode */
3225         else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
3226                          (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
3227                           (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
3228                            pg_strcasecmp(prev4_wd, "LOCK") == 0)))
3229         {
3230                 static const char *const lock_modes[] =
3231                 {"ACCESS SHARE MODE",
3232                         "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
3233                         "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
3234                         "SHARE ROW EXCLUSIVE MODE",
3235                 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
3236
3237                 COMPLETE_WITH_LIST(lock_modes);
3238         }
3239
3240 /* NOTIFY */
3241         else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
3242                 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'");
3243
3244 /* OPTIONS */
3245         else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
3246                 COMPLETE_WITH_CONST("(");
3247
3248 /* OWNER TO  - complete with available roles */
3249         else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
3250                          pg_strcasecmp(prev_wd, "TO") == 0)
3251                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3252
3253 /* ORDER BY */
3254         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
3255                          pg_strcasecmp(prev_wd, "ORDER") == 0)
3256                 COMPLETE_WITH_CONST("BY");
3257         else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
3258                          pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
3259                          pg_strcasecmp(prev_wd, "BY") == 0)
3260                 COMPLETE_WITH_ATTR(prev3_wd, "");
3261
3262 /* PREPARE xx AS */
3263         else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
3264                          pg_strcasecmp(prev3_wd, "PREPARE") == 0)
3265         {
3266                 static const char *const list_PREPARE[] =
3267                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
3268
3269                 COMPLETE_WITH_LIST(list_PREPARE);
3270         }
3271
3272 /*
3273  * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
3274  * managers, not for manual use in interactive sessions.
3275  */
3276
3277 /* REASSIGN OWNED BY xxx TO yyy */
3278         else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
3279                 COMPLETE_WITH_CONST("OWNED");
3280         else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
3281                          pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
3282                 COMPLETE_WITH_CONST("BY");
3283         else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
3284                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
3285                          pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
3286                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3287         else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
3288                          pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
3289                          pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
3290                 COMPLETE_WITH_CONST("TO");
3291         else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
3292                          pg_strcasecmp(prev3_wd, "BY") == 0 &&
3293                          pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
3294                          pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
3295                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3296
3297 /* REFRESH MATERIALIZED VIEW */
3298         else if (pg_strcasecmp(prev_wd, "REFRESH") == 0)
3299                 COMPLETE_WITH_CONST("MATERIALIZED VIEW");
3300         else if (pg_strcasecmp(prev2_wd, "REFRESH") == 0 &&
3301                          pg_strcasecmp(prev_wd, "MATERIALIZED") == 0)
3302                 COMPLETE_WITH_CONST("VIEW");
3303         else if (pg_strcasecmp(prev3_wd, "REFRESH") == 0 &&
3304                          pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
3305                          pg_strcasecmp(prev_wd, "VIEW") == 0)
3306                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
3307                                                                    " UNION SELECT 'CONCURRENTLY'");
3308         else if (pg_strcasecmp(prev4_wd, "REFRESH") == 0 &&
3309                          pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
3310                          pg_strcasecmp(prev2_wd, "VIEW") == 0 &&
3311                          pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
3312                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
3313         else if (pg_strcasecmp(prev4_wd, "REFRESH") == 0 &&
3314                          pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
3315                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
3316                 COMPLETE_WITH_CONST("WITH");
3317         else if (pg_strcasecmp(prev5_wd, "REFRESH") == 0 &&
3318                          pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
3319                          pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
3320                          pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0)
3321                 COMPLETE_WITH_CONST("WITH DATA");
3322         else if (pg_strcasecmp(prev5_wd, "REFRESH") == 0 &&
3323                          pg_strcasecmp(prev4_wd, "MATERIALIZED") == 0 &&
3324                          pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
3325                          pg_strcasecmp(prev_wd, "WITH") == 0)
3326         {
3327                 static const char *const list_WITH_DATA[] =
3328                 {"NO DATA", "DATA", NULL};
3329
3330                 COMPLETE_WITH_LIST(list_WITH_DATA);
3331         }
3332         else if (pg_strcasecmp(prev6_wd, "REFRESH") == 0 &&
3333                          pg_strcasecmp(prev5_wd, "MATERIALIZED") == 0 &&
3334                          pg_strcasecmp(prev4_wd, "VIEW") == 0 &&
3335                          pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0 &&
3336                          pg_strcasecmp(prev_wd, "WITH") == 0)
3337                 COMPLETE_WITH_CONST("DATA");
3338         else if (pg_strcasecmp(prev6_wd, "REFRESH") == 0 &&
3339                          pg_strcasecmp(prev5_wd, "MATERIALIZED") == 0 &&
3340                          pg_strcasecmp(prev4_wd, "VIEW") == 0 &&
3341                          pg_strcasecmp(prev2_wd, "WITH") == 0 &&
3342                          pg_strcasecmp(prev_wd, "NO") == 0)
3343                 COMPLETE_WITH_CONST("DATA");
3344
3345 /* REINDEX */
3346         else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
3347         {
3348                 static const char *const list_REINDEX[] =
3349                 {"TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE", NULL};
3350
3351                 COMPLETE_WITH_LIST(list_REINDEX);
3352         }
3353         else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
3354         {
3355                 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
3356                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
3357                 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
3358                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
3359                 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
3360                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3361                 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
3362                                  pg_strcasecmp(prev_wd, "DATABASE") == 0)
3363                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3364         }
3365
3366 /* SECURITY LABEL */
3367         else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
3368                 COMPLETE_WITH_CONST("LABEL");
3369         else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
3370                          pg_strcasecmp(prev_wd, "LABEL") == 0)
3371         {
3372                 static const char *const list_SECURITY_LABEL_preposition[] =
3373                 {"ON", "FOR"};
3374
3375                 COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
3376         }
3377         else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
3378                          pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
3379                          pg_strcasecmp(prev2_wd, "FOR") == 0)
3380                 COMPLETE_WITH_CONST("ON");
3381         else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
3382                           pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
3383                           pg_strcasecmp(prev_wd, "ON") == 0) ||
3384                          (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
3385                           pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
3386                           pg_strcasecmp(prev3_wd, "FOR") == 0 &&
3387                           pg_strcasecmp(prev_wd, "ON") == 0))
3388         {
3389                 static const char *const list_SECURITY_LABEL[] =
3390                 {"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW",
3391                         "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "DOMAIN",
3392                 "LARGE OBJECT", NULL};
3393
3394                 COMPLETE_WITH_LIST(list_SECURITY_LABEL);
3395         }
3396         else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
3397                          pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
3398                          pg_strcasecmp(prev3_wd, "ON") == 0)
3399                 COMPLETE_WITH_CONST("IS");
3400
3401 /* SELECT */
3402         /* naah . . . */
3403
3404 /* SET, RESET, SHOW */
3405         /* Complete with a variable name */
3406         else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
3407                           pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
3408                          pg_strcasecmp(prev_wd, "RESET") == 0)
3409                 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
3410         else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
3411                 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
3412         /* Complete "SET TRANSACTION" */
3413         else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
3414                           pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
3415                          || (pg_strcasecmp(prev2_wd, "START") == 0
3416                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
3417                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
3418                                  && pg_strcasecmp(prev_wd, "WORK") == 0)
3419                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
3420                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
3421                          || (pg_strcasecmp(prev4_wd, "SESSION") == 0
3422                                  && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
3423                                  && pg_strcasecmp(prev2_wd, "AS") == 0
3424                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
3425         {
3426                 static const char *const my_list[] =
3427                 {"ISOLATION LEVEL", "READ", NULL};
3428
3429                 COMPLETE_WITH_LIST(my_list);
3430         }
3431         else if ((pg_strcasecmp(prev3_wd, "SET") == 0
3432                           || pg_strcasecmp(prev3_wd, "BEGIN") == 0
3433                           || pg_strcasecmp(prev3_wd, "START") == 0
3434                           || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
3435                                   && pg_strcasecmp(prev3_wd, "AS") == 0))
3436                          && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
3437                                  || pg_strcasecmp(prev2_wd, "WORK") == 0)
3438                          && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
3439                 COMPLETE_WITH_CONST("LEVEL");
3440         else if ((pg_strcasecmp(prev4_wd, "SET") == 0
3441                           || pg_strcasecmp(prev4_wd, "BEGIN") == 0
3442                           || pg_strcasecmp(prev4_wd, "START") == 0
3443                           || pg_strcasecmp(prev4_wd, "AS") == 0)
3444                          && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
3445                                  || pg_strcasecmp(prev3_wd, "WORK") == 0)
3446                          && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
3447                          && pg_strcasecmp(prev_wd, "LEVEL") == 0)
3448         {
3449                 static const char *const my_list[] =
3450                 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
3451
3452                 COMPLETE_WITH_LIST(my_list);
3453         }
3454         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
3455                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
3456                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
3457                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
3458                          pg_strcasecmp(prev_wd, "READ") == 0)
3459         {
3460                 static const char *const my_list[] =
3461                 {"UNCOMMITTED", "COMMITTED", NULL};
3462
3463                 COMPLETE_WITH_LIST(my_list);
3464         }
3465         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
3466                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
3467                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
3468                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
3469                          pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
3470                 COMPLETE_WITH_CONST("READ");
3471         else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
3472                           pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
3473                           pg_strcasecmp(prev3_wd, "START") == 0 ||
3474                           pg_strcasecmp(prev3_wd, "AS") == 0) &&
3475                          (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
3476                           pg_strcasecmp(prev2_wd, "WORK") == 0) &&
3477                          pg_strcasecmp(prev_wd, "READ") == 0)
3478         {
3479                 static const char *const my_list[] =
3480                 {"ONLY", "WRITE", NULL};
3481
3482                 COMPLETE_WITH_LIST(my_list);
3483         }
3484         /* SET CONSTRAINTS */
3485         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3486                          pg_strcasecmp(prev_wd, "CONSTRAINTS") == 0)
3487         {
3488                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, "UNION SELECT 'ALL'");
3489         }
3490         /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
3491         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
3492                          pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
3493         {
3494                 static const char *const constraint_list[] =
3495                 {"DEFERRED", "IMMEDIATE", NULL};
3496
3497                 COMPLETE_WITH_LIST(constraint_list);
3498         }
3499         /* Complete SET ROLE */
3500         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3501                          pg_strcasecmp(prev_wd, "ROLE") == 0)
3502                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3503         /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
3504         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3505                          pg_strcasecmp(prev_wd, "SESSION") == 0)
3506         {
3507                 static const char *const my_list[] =
3508                 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
3509
3510                 COMPLETE_WITH_LIST(my_list);
3511         }
3512         /* Complete SET SESSION AUTHORIZATION with username */
3513         else if (pg_strcasecmp(prev3_wd, "SET") == 0
3514                          && pg_strcasecmp(prev2_wd, "SESSION") == 0
3515                          && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
3516                 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
3517         /* Complete RESET SESSION with AUTHORIZATION */
3518         else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
3519                          pg_strcasecmp(prev_wd, "SESSION") == 0)
3520                 COMPLETE_WITH_CONST("AUTHORIZATION");
3521         /* Complete SET <var> with "TO" */
3522         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3523                          pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
3524                          pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
3525                          pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
3526                          prev_wd[strlen(prev_wd) - 1] != ')' &&
3527                          prev_wd[strlen(prev_wd) - 1] != '=' &&
3528                          pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
3529                 COMPLETE_WITH_CONST("TO");
3530         /* Suggest possible variable values */
3531         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
3532                          (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
3533         {
3534                 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
3535                 {
3536                         static const char *const my_list[] =
3537                         {"ISO", "SQL", "Postgres", "German",
3538                                 "YMD", "DMY", "MDY",
3539                                 "US", "European", "NonEuropean",
3540                         "DEFAULT", NULL};
3541
3542                         COMPLETE_WITH_LIST(my_list);
3543                 }
3544                 else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
3545                 {
3546                         static const char *const my_list[] =
3547                         {"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
3548
3549                         COMPLETE_WITH_LIST(my_list);
3550                 }
3551                 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
3552                 {
3553                         static const char *const my_list[] =
3554                         {"ON", "OFF", "DEFAULT", NULL};
3555
3556                         COMPLETE_WITH_LIST(my_list);
3557                 }
3558                 else if (pg_strcasecmp(prev2_wd, "search_path") == 0)
3559                 {
3560                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas
3561                                                                 " AND nspname not like 'pg\\_toast%%' "
3562                                                                 " AND nspname not like 'pg\\_temp%%' "
3563                                                                 " UNION SELECT 'DEFAULT' ");
3564                 }
3565                 else
3566                 {
3567                         static const char *const my_list[] =
3568                         {"DEFAULT", NULL};
3569
3570                         COMPLETE_WITH_LIST(my_list);
3571                 }
3572         }
3573
3574 /* START TRANSACTION */
3575         else if (pg_strcasecmp(prev_wd, "START") == 0)
3576                 COMPLETE_WITH_CONST("TRANSACTION");
3577
3578 /* TABLE, but not TABLE embedded in other commands */
3579         else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
3580                          prev2_wd[0] == '\0')
3581                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3582
3583 /* TRUNCATE */
3584         else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
3585                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3586
3587 /* UNLISTEN */
3588         else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
3589                 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 '*'");
3590
3591 /* UPDATE */
3592         /* If prev. word is UPDATE suggest a list of tables */
3593         else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
3594                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
3595         /* Complete UPDATE <table> with "SET" */
3596         else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
3597                 COMPLETE_WITH_CONST("SET");
3598
3599         /*
3600          * If the previous word is SET (and it wasn't caught above as the _first_
3601          * word) the word before it was (hopefully) a table name and we'll now
3602          * make a list of attributes.
3603          */
3604         else if (pg_strcasecmp(prev_wd, "SET") == 0)
3605                 COMPLETE_WITH_ATTR(prev2_wd, "");
3606
3607 /* UPDATE xx SET yy = */
3608         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
3609                          pg_strcasecmp(prev4_wd, "UPDATE") == 0)
3610                 COMPLETE_WITH_CONST("=");
3611
3612 /* USER MAPPING */
3613         else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
3614                           pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
3615                           pg_strcasecmp(prev3_wd, "DROP") == 0) &&
3616                          pg_strcasecmp(prev2_wd, "USER") == 0 &&
3617                          pg_strcasecmp(prev_wd, "MAPPING") == 0)
3618                 COMPLETE_WITH_CONST("FOR");
3619         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
3620                          pg_strcasecmp(prev3_wd, "USER") == 0 &&
3621                          pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
3622                          pg_strcasecmp(prev_wd, "FOR") == 0)
3623                 COMPLETE_WITH_QUERY(Query_for_list_of_roles
3624                                                         " UNION SELECT 'CURRENT_USER'"
3625                                                         " UNION SELECT 'PUBLIC'"
3626                                                         " UNION SELECT 'USER'");
3627         else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
3628                           pg_strcasecmp(prev4_wd, "DROP") == 0) &&
3629                          pg_strcasecmp(prev3_wd, "USER") == 0 &&
3630                          pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
3631                          pg_strcasecmp(prev_wd, "FOR") == 0)
3632                 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3633         else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
3634                           pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
3635                           pg_strcasecmp(prev5_wd, "DROP") == 0) &&
3636                          pg_strcasecmp(prev4_wd, "USER") == 0 &&
3637                          pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
3638                          pg_strcasecmp(prev2_wd, "FOR") == 0)
3639                 COMPLETE_WITH_CONST("SERVER");
3640
3641 /*
3642  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
3643  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
3644  */
3645         else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
3646                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3647                                                                    " UNION SELECT 'FULL'"
3648                                                                    " UNION SELECT 'FREEZE'"
3649                                                                    " UNION SELECT 'ANALYZE'"
3650                                                                    " UNION SELECT 'VERBOSE'");
3651         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3652                          (pg_strcasecmp(prev_wd, "FULL") == 0 ||
3653                           pg_strcasecmp(prev_wd, "FREEZE") == 0))
3654                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3655                                                                    " UNION SELECT 'ANALYZE'"
3656                                                                    " UNION SELECT 'VERBOSE'");
3657         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
3658                          pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
3659                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
3660                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
3661                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3662                                                                    " UNION SELECT 'VERBOSE'");
3663         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
3664                          pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
3665                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
3666                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
3667                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3668                                                                    " UNION SELECT 'ANALYZE'");
3669         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3670                          pg_strcasecmp(prev_wd, "VERBOSE") == 0)
3671                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3672                                                                    " UNION SELECT 'ANALYZE'");
3673         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
3674                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
3675                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3676                                                                    " UNION SELECT 'VERBOSE'");
3677         else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
3678                           pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
3679                          (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
3680                           pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
3681                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
3682
3683 /* WITH [RECURSIVE] */
3684
3685         /*
3686          * Only match when WITH is the first word, as WITH may appear in many
3687          * other contexts.
3688          */
3689         else if (pg_strcasecmp(prev_wd, "WITH") == 0 &&
3690                          prev2_wd[0] == '\0')
3691                 COMPLETE_WITH_CONST("RECURSIVE");
3692
3693 /* ANALYZE */
3694         /* If the previous word is ANALYZE, produce list of tables */
3695         else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
3696                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, NULL);
3697
3698 /* WHERE */
3699         /* Simple case of the word before the where being the table name */
3700         else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
3701                 COMPLETE_WITH_ATTR(prev2_wd, "");
3702
3703 /* ... FROM ... */
3704 /* TODO: also include SRF ? */
3705         else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
3706                          pg_strcasecmp(prev3_wd, "COPY") != 0 &&
3707                          pg_strcasecmp(prev3_wd, "\\copy") != 0)
3708                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3709
3710 /* ... JOIN ... */
3711         else if (pg_strcasecmp(prev_wd, "JOIN") == 0)
3712                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3713
3714 /* Backslash commands */
3715 /* TODO:  \dc \dd \dl */
3716         else if (strcmp(prev_wd, "\\?") == 0)
3717         {
3718                 static const char *const my_list[] =
3719                 {"commands", "options", "variables", NULL};
3720
3721                 COMPLETE_WITH_LIST_CS(my_list);
3722         }
3723         else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
3724         {
3725                 if (!recognized_connection_string(text))
3726                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3727         }
3728         else if (strcmp(prev2_wd, "\\connect") == 0 || strcmp(prev2_wd, "\\c") == 0)
3729         {
3730                 if (!recognized_connection_string(prev_wd))
3731                         COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3732         }
3733         else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
3734                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
3735         else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
3736                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
3737         else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
3738                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
3739         else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
3740                 COMPLETE_WITH_QUERY(Query_for_list_of_servers);
3741         else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
3742                 COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3743         else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
3744                 COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
3745
3746         else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
3747                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3748         else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
3749                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
3750         else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
3751                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
3752         else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
3753                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
3754         /* must be at end of \dF */
3755         else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
3756                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
3757
3758         else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
3759                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
3760         else if (strncmp(prev_wd, "\\dL", strlen("\\dL")) == 0)
3761                 COMPLETE_WITH_QUERY(Query_for_list_of_languages);
3762         else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
3763                 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3764         else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0
3765                          || strncmp(prev_wd, "\\z", strlen("\\z")) == 0)
3766                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3767         else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
3768                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
3769         else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
3770                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3771         else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
3772                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
3773         else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0
3774                          || (strncmp(prev_wd, "\\dg", strlen("\\dg")) == 0))
3775                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3776         else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
3777                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
3778         else if (strncmp(prev_wd, "\\dx", strlen("\\dx")) == 0)
3779                 COMPLETE_WITH_QUERY(Query_for_list_of_extensions);
3780         else if (strncmp(prev_wd, "\\dm", strlen("\\dm")) == 0)
3781                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
3782
3783         /* must be at end of \d list */
3784         else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
3785                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3786
3787         else if (strcmp(prev_wd, "\\ef") == 0)
3788                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3789
3790         else if (strcmp(prev_wd, "\\encoding") == 0)
3791                 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
3792         else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
3793                 COMPLETE_WITH_LIST(sql_commands);
3794         else if (strcmp(prev_wd, "\\password") == 0)
3795                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3796         else if (strcmp(prev_wd, "\\pset") == 0)
3797         {
3798                 static const char *const my_list[] =
3799                 {"border", "columns", "expanded", "fieldsep", "fieldsep_zero",
3800                         "footer", "format", "linestyle", "null", "numericlocale",
3801                         "pager", "recordsep", "recordsep_zero", "tableattr", "title",
3802                         "tuples_only", "unicode_border_linestyle",
3803                 "unicode_column_linestyle", "unicode_header_linestyle", NULL};
3804
3805                 COMPLETE_WITH_LIST_CS(my_list);
3806         }
3807         else if (strcmp(prev2_wd, "\\pset") == 0)
3808         {
3809                 if (strcmp(prev_wd, "format") == 0)
3810                 {
3811                         static const char *const my_list[] =
3812                         {"unaligned", "aligned", "wrapped", "html", "asciidoc",
3813                         "latex", "latex-longtable", "troff-ms", NULL};
3814
3815                         COMPLETE_WITH_LIST_CS(my_list);
3816                 }
3817                 else if (strcmp(prev_wd, "linestyle") == 0)
3818                 {
3819                         static const char *const my_list[] =
3820                         {"ascii", "old-ascii", "unicode", NULL};
3821
3822                         COMPLETE_WITH_LIST_CS(my_list);
3823                 }
3824                 else if (strcmp(prev_wd, "unicode_border_linestyle") == 0 ||
3825                                  strcmp(prev_wd, "unicode_column_linestyle") == 0 ||
3826                                  strcmp(prev_wd, "unicode_header_linestyle") == 0)
3827                 {
3828                         static const char *const my_list[] =
3829                         {"single", "double", NULL};
3830
3831                         COMPLETE_WITH_LIST_CS(my_list);
3832
3833                 }
3834         }
3835         else if (strcmp(prev_wd, "\\unset") == 0)
3836         {
3837                 matches = complete_from_variables(text, "", "", true);
3838         }
3839         else if (strcmp(prev_wd, "\\set") == 0)
3840         {
3841                 matches = complete_from_variables(text, "", "", false);
3842         }
3843         else if (strcmp(prev2_wd, "\\set") == 0)
3844         {
3845                 static const char *const boolean_value_list[] =
3846                 {"on", "off", NULL};
3847
3848                 if (strcmp(prev_wd, "AUTOCOMMIT") == 0)
3849                         COMPLETE_WITH_LIST_CS(boolean_value_list);
3850                 else if (strcmp(prev_wd, "COMP_KEYWORD_CASE") == 0)
3851                 {
3852                         static const char *const my_list[] =
3853                         {"lower", "upper", "preserve-lower", "preserve-upper", NULL};
3854
3855                         COMPLETE_WITH_LIST_CS(my_list);
3856                 }
3857                 else if (strcmp(prev_wd, "ECHO") == 0)
3858                 {
3859                         static const char *const my_list[] =
3860                         {"errors", "queries", "all", "none", NULL};
3861
3862                         COMPLETE_WITH_LIST_CS(my_list);
3863                 }
3864                 else if (strcmp(prev_wd, "ECHO_HIDDEN") == 0)
3865                 {
3866                         static const char *const my_list[] =
3867                         {"noexec", "off", "on", NULL};
3868
3869                         COMPLETE_WITH_LIST_CS(my_list);
3870                 }
3871                 else if (strcmp(prev_wd, "HISTCONTROL") == 0)
3872                 {
3873                         static const char *const my_list[] =
3874                         {"ignorespace", "ignoredups", "ignoreboth", "none", NULL};
3875
3876                         COMPLETE_WITH_LIST_CS(my_list);
3877                 }
3878                 else if (strcmp(prev_wd, "ON_ERROR_ROLLBACK") == 0)
3879                 {
3880                         static const char *const my_list[] =
3881                         {"on", "off", "interactive", NULL};
3882
3883                         COMPLETE_WITH_LIST_CS(my_list);
3884                 }
3885                 else if (strcmp(prev_wd, "ON_ERROR_STOP") == 0)
3886                         COMPLETE_WITH_LIST_CS(boolean_value_list);
3887                 else if (strcmp(prev_wd, "QUIET") == 0)
3888                         COMPLETE_WITH_LIST_CS(boolean_value_list);
3889                 else if (strcmp(prev_wd, "SINGLELINE") == 0)
3890                         COMPLETE_WITH_LIST_CS(boolean_value_list);
3891                 else if (strcmp(prev_wd, "SINGLESTEP") == 0)
3892                         COMPLETE_WITH_LIST_CS(boolean_value_list);
3893                 else if (strcmp(prev_wd, "VERBOSITY") == 0)
3894                 {
3895                         static const char *const my_list[] =
3896                         {"default", "verbose", "terse", NULL};
3897
3898                         COMPLETE_WITH_LIST_CS(my_list);
3899                 }
3900         }
3901         else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
3902                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3903         else if (strcmp(prev_wd, "\\cd") == 0 ||
3904                          strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
3905                          strcmp(prev_wd, "\\g") == 0 ||
3906                   strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
3907                          strcmp(prev_wd, "\\ir") == 0 || strcmp(prev_wd, "\\include_relative") == 0 ||
3908                          strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
3909                          strcmp(prev_wd, "\\s") == 0 ||
3910                          strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0 ||
3911                          strcmp(prev_wd, "\\lo_import") == 0
3912                 )
3913         {
3914                 completion_charp = "\\";
3915                 matches = completion_matches(text, complete_from_files);
3916         }
3917
3918         /*
3919          * Finally, we look through the list of "things", such as TABLE, INDEX and
3920          * check if that was the previous word. If so, execute the query to get a
3921          * list of them.
3922          */
3923         else
3924         {
3925                 int                     i;
3926
3927                 for (i = 0; words_after_create[i].name; i++)
3928                 {
3929                         if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
3930                         {
3931                                 if (words_after_create[i].query)
3932                                         COMPLETE_WITH_QUERY(words_after_create[i].query);
3933                                 else if (words_after_create[i].squery)
3934                                         COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
3935                                                                                            NULL);
3936                                 break;
3937                         }
3938                 }
3939         }
3940
3941         /*
3942          * If we still don't have anything to match we have to fabricate some sort
3943          * of default list. If we were to just return NULL, readline automatically
3944          * attempts filename completion, and that's usually no good.
3945          */
3946         if (matches == NULL)
3947         {
3948                 COMPLETE_WITH_CONST("");
3949 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
3950                 rl_completion_append_character = '\0';
3951 #endif
3952         }
3953
3954         /* free storage */
3955         {
3956                 int                     i;
3957
3958                 for (i = 0; i < lengthof(previous_words); i++)
3959                         free(previous_words[i]);
3960         }
3961
3962         /* Return our Grand List O' Matches */
3963         return matches;
3964 }
3965
3966
3967 /*
3968  * GENERATOR FUNCTIONS
3969  *
3970  * These functions do all the actual work of completing the input. They get
3971  * passed the text so far and the count how many times they have been called
3972  * so far with the same text.
3973  * If you read the above carefully, you'll see that these don't get called
3974  * directly but through the readline interface.
3975  * The return value is expected to be the full completion of the text, going
3976  * through a list each time, or NULL if there are no more matches. The string
3977  * will be free()'d by readline, so you must run it through strdup() or
3978  * something of that sort.
3979  */
3980
3981 /*
3982  * Common routine for create_command_generator and drop_command_generator.
3983  * Entries that have 'excluded' flags are not returned.
3984  */
3985 static char *
3986 create_or_drop_command_generator(const char *text, int state, bits32 excluded)
3987 {
3988         static int      list_index,
3989                                 string_length;
3990         const char *name;
3991
3992         /* If this is the first time for this completion, init some values */
3993         if (state == 0)
3994         {
3995                 list_index = 0;
3996                 string_length = strlen(text);
3997         }
3998
3999         /* find something that matches */
4000         while ((name = words_after_create[list_index++].name))
4001         {
4002                 if ((pg_strncasecmp(name, text, string_length) == 0) &&
4003                         !(words_after_create[list_index - 1].flags & excluded))
4004                         return pg_strdup_keyword_case(name, text);
4005         }
4006         /* if nothing matches, return NULL */
4007         return NULL;
4008 }
4009
4010 /*
4011  * This one gives you one from a list of things you can put after CREATE
4012  * as defined above.
4013  */
4014 static char *
4015 create_command_generator(const char *text, int state)
4016 {
4017         return create_or_drop_command_generator(text, state, THING_NO_CREATE);
4018 }
4019
4020 /*
4021  * This function gives you a list of things you can put after a DROP command.
4022  */
4023 static char *
4024 drop_command_generator(const char *text, int state)
4025 {
4026         return create_or_drop_command_generator(text, state, THING_NO_DROP);
4027 }
4028
4029 /* The following two functions are wrappers for _complete_from_query */
4030
4031 static char *
4032 complete_from_query(const char *text, int state)
4033 {
4034         return _complete_from_query(0, text, state);
4035 }
4036
4037 static char *
4038 complete_from_schema_query(const char *text, int state)
4039 {
4040         return _complete_from_query(1, text, state);
4041 }
4042
4043
4044 /*
4045  * This creates a list of matching things, according to a query pointed to
4046  * by completion_charp.
4047  * The query can be one of two kinds:
4048  *
4049  * 1. A simple query which must contain a %d and a %s, which will be replaced
4050  * by the string length of the text and the text itself. The query may also
4051  * have up to four more %s in it; the first two such will be replaced by the
4052  * value of completion_info_charp, the next two by the value of
4053  * completion_info_charp2.
4054  *
4055  * 2. A schema query used for completion of both schema and relation names.
4056  * These are more complex and must contain in the following order:
4057  * %d %s %d %s %d %s %s %d %s
4058  * where %d is the string length of the text and %s the text itself.
4059  *
4060  * It is assumed that strings should be escaped to become SQL literals
4061  * (that is, what is in the query is actually ... '%s' ...)
4062  *
4063  * See top of file for examples of both kinds of query.
4064  */
4065 static char *
4066 _complete_from_query(int is_schema_query, const char *text, int state)
4067 {
4068         static int      list_index,
4069                                 string_length;
4070         static PGresult *result = NULL;
4071
4072         /*
4073          * If this is the first time for this completion, we fetch a list of our
4074          * "things" from the backend.
4075          */
4076         if (state == 0)
4077         {
4078                 PQExpBufferData query_buffer;
4079                 char       *e_text;
4080                 char       *e_info_charp;
4081                 char       *e_info_charp2;
4082
4083                 list_index = 0;
4084                 string_length = strlen(text);
4085
4086                 /* Free any prior result */
4087                 PQclear(result);
4088                 result = NULL;
4089
4090                 /* Set up suitably-escaped copies of textual inputs */
4091                 e_text = pg_malloc(string_length * 2 + 1);
4092                 PQescapeString(e_text, text, string_length);
4093
4094                 if (completion_info_charp)
4095                 {
4096                         size_t          charp_len;
4097
4098                         charp_len = strlen(completion_info_charp);
4099                         e_info_charp = pg_malloc(charp_len * 2 + 1);
4100                         PQescapeString(e_info_charp, completion_info_charp,
4101                                                    charp_len);
4102                 }
4103                 else
4104                         e_info_charp = NULL;
4105
4106                 if (completion_info_charp2)
4107                 {
4108                         size_t          charp_len;
4109
4110                         charp_len = strlen(completion_info_charp2);
4111                         e_info_charp2 = pg_malloc(charp_len * 2 + 1);
4112                         PQescapeString(e_info_charp2, completion_info_charp2,
4113                                                    charp_len);
4114                 }
4115                 else
4116                         e_info_charp2 = NULL;
4117
4118                 initPQExpBuffer(&query_buffer);
4119
4120                 if (is_schema_query)
4121                 {
4122                         /* completion_squery gives us the pieces to assemble */
4123                         const char *qualresult = completion_squery->qualresult;
4124
4125                         if (qualresult == NULL)
4126                                 qualresult = completion_squery->result;
4127
4128                         /* Get unqualified names matching the input-so-far */
4129                         appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
4130                                                           completion_squery->result,
4131                                                           completion_squery->catname);
4132                         if (completion_squery->selcondition)
4133                                 appendPQExpBuffer(&query_buffer, "%s AND ",
4134                                                                   completion_squery->selcondition);
4135                         appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
4136                                                           completion_squery->result,
4137                                                           string_length, e_text);
4138                         appendPQExpBuffer(&query_buffer, " AND %s",
4139                                                           completion_squery->viscondition);
4140
4141                         /*
4142                          * When fetching relation names, suppress system catalogs unless
4143                          * the input-so-far begins with "pg_".  This is a compromise
4144                          * between not offering system catalogs for completion at all, and
4145                          * having them swamp the result when the input is just "p".
4146                          */
4147                         if (strcmp(completion_squery->catname,
4148                                            "pg_catalog.pg_class c") == 0 &&
4149                                 strncmp(text, "pg_", 3) !=0)
4150                         {
4151                                 appendPQExpBufferStr(&query_buffer,
4152                                                                          " AND c.relnamespace <> (SELECT oid FROM"
4153                                    " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
4154                         }
4155
4156                         /*
4157                          * Add in matching schema names, but only if there is more than
4158                          * one potential match among schema names.
4159                          */
4160                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
4161                                                    "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
4162                                                           "FROM pg_catalog.pg_namespace n "
4163                                                           "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
4164                                                           string_length, e_text);
4165                         appendPQExpBuffer(&query_buffer,
4166                                                           " AND (SELECT pg_catalog.count(*)"
4167                                                           " FROM pg_catalog.pg_namespace"
4168                         " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
4169                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
4170                                                           string_length, e_text);
4171
4172                         /*
4173                          * Add in matching qualified names, but only if there is exactly
4174                          * one schema matching the input-so-far.
4175                          */
4176                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
4177                                          "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
4178                                                           "FROM %s, pg_catalog.pg_namespace n "
4179                                                           "WHERE %s = n.oid AND ",
4180                                                           qualresult,
4181                                                           completion_squery->catname,
4182                                                           completion_squery->namespace);
4183                         if (completion_squery->selcondition)
4184                                 appendPQExpBuffer(&query_buffer, "%s AND ",
4185                                                                   completion_squery->selcondition);
4186                         appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
4187                                                           qualresult,
4188                                                           string_length, e_text);
4189
4190                         /*
4191                          * This condition exploits the single-matching-schema rule to
4192                          * speed up the query
4193                          */
4194                         appendPQExpBuffer(&query_buffer,
4195                         " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
4196                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
4197                                                           string_length, e_text);
4198                         appendPQExpBuffer(&query_buffer,
4199                                                           " AND (SELECT pg_catalog.count(*)"
4200                                                           " FROM pg_catalog.pg_namespace"
4201                         " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
4202                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
4203                                                           string_length, e_text);
4204
4205                         /* If an addon query was provided, use it */
4206                         if (completion_charp)
4207                                 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
4208                 }
4209                 else
4210                 {
4211                         /* completion_charp is an sprintf-style format string */
4212                         appendPQExpBuffer(&query_buffer, completion_charp,
4213                                                           string_length, e_text,
4214                                                           e_info_charp, e_info_charp,
4215                                                           e_info_charp2, e_info_charp2);
4216                 }
4217
4218                 /* Limit the number of records in the result */
4219                 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
4220                                                   completion_max_records);
4221
4222                 result = exec_query(query_buffer.data);
4223
4224                 termPQExpBuffer(&query_buffer);
4225                 free(e_text);
4226                 if (e_info_charp)
4227                         free(e_info_charp);
4228                 if (e_info_charp2)
4229                         free(e_info_charp2);
4230         }
4231
4232         /* Find something that matches */
4233         if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
4234         {
4235                 const char *item;
4236
4237                 while (list_index < PQntuples(result) &&
4238                            (item = PQgetvalue(result, list_index++, 0)))
4239                         if (pg_strncasecmp(text, item, string_length) == 0)
4240                                 return pg_strdup(item);
4241         }
4242
4243         /* If nothing matches, free the db structure and return null */
4244         PQclear(result);
4245         result = NULL;
4246         return NULL;
4247 }
4248
4249
4250 /*
4251  * This function returns in order one of a fixed, NULL pointer terminated list
4252  * of strings (if matching). This can be used if there are only a fixed number
4253  * SQL words that can appear at certain spot.
4254  */
4255 static char *
4256 complete_from_list(const char *text, int state)
4257 {
4258         static int      string_length,
4259                                 list_index,
4260                                 matches;
4261         static bool casesensitive;
4262         const char *item;
4263
4264         /* need to have a list */
4265         Assert(completion_charpp != NULL);
4266
4267         /* Initialization */
4268         if (state == 0)
4269         {
4270                 list_index = 0;
4271                 string_length = strlen(text);
4272                 casesensitive = completion_case_sensitive;
4273                 matches = 0;
4274         }
4275
4276         while ((item = completion_charpp[list_index++]))
4277         {
4278                 /* First pass is case sensitive */
4279                 if (casesensitive && strncmp(text, item, string_length) == 0)
4280                 {
4281                         matches++;
4282                         return pg_strdup(item);
4283                 }
4284
4285                 /* Second pass is case insensitive, don't bother counting matches */
4286                 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
4287                 {
4288                         if (completion_case_sensitive)
4289                                 return pg_strdup(item);
4290                         else
4291
4292                                 /*
4293                                  * If case insensitive matching was requested initially,
4294                                  * adjust the case according to setting.
4295                                  */
4296                                 return pg_strdup_keyword_case(item, text);
4297                 }
4298         }
4299
4300         /*
4301          * No matches found. If we're not case insensitive already, lets switch to
4302          * being case insensitive and try again
4303          */
4304         if (casesensitive && matches == 0)
4305         {
4306                 casesensitive = false;
4307                 list_index = 0;
4308                 state++;
4309                 return complete_from_list(text, state);
4310         }
4311
4312         /* If no more matches, return null. */
4313         return NULL;
4314 }
4315
4316
4317 /*
4318  * This function returns one fixed string the first time even if it doesn't
4319  * match what's there, and nothing the second time. This should be used if
4320  * there is only one possibility that can appear at a certain spot, so
4321  * misspellings will be overwritten.  The string to be passed must be in
4322  * completion_charp.
4323  */
4324 static char *
4325 complete_from_const(const char *text, int state)
4326 {
4327         Assert(completion_charp != NULL);
4328         if (state == 0)
4329         {
4330                 if (completion_case_sensitive)
4331                         return pg_strdup(completion_charp);
4332                 else
4333
4334                         /*
4335                          * If case insensitive matching was requested initially, adjust
4336                          * the case according to setting.
4337                          */
4338                         return pg_strdup_keyword_case(completion_charp, text);
4339         }
4340         else
4341                 return NULL;
4342 }
4343
4344
4345 /*
4346  * This function appends the variable name with prefix and suffix to
4347  * the variable names array.
4348  */
4349 static void
4350 append_variable_names(char ***varnames, int *nvars,
4351                                           int *maxvars, const char *varname,
4352                                           const char *prefix, const char *suffix)
4353 {
4354         if (*nvars >= *maxvars)
4355         {
4356                 *maxvars *= 2;
4357                 *varnames = (char **) pg_realloc(*varnames,
4358                                                                                  ((*maxvars) + 1) * sizeof(char *));
4359         }
4360
4361         (*varnames)[(*nvars)++] = psprintf("%s%s%s", prefix, varname, suffix);
4362 }
4363
4364
4365 /*
4366  * This function supports completion with the name of a psql variable.
4367  * The variable names can be prefixed and suffixed with additional text
4368  * to support quoting usages. If need_value is true, only the variables
4369  * that have the set values are picked up.
4370  */
4371 static char **
4372 complete_from_variables(const char *text, const char *prefix, const char *suffix,
4373                                                 bool need_value)
4374 {
4375         char      **matches;
4376         char      **varnames;
4377         int                     nvars = 0;
4378         int                     maxvars = 100;
4379         int                     i;
4380         struct _variable *ptr;
4381
4382         static const char *const known_varnames[] = {
4383                 "AUTOCOMMIT", "COMP_KEYWORD_CASE", "DBNAME", "ECHO", "ECHO_HIDDEN",
4384                 "ENCODING", "FETCH_COUNT", "HISTCONTROL", "HISTFILE", "HISTSIZE",
4385                 "HOST", "IGNOREEOF", "LASTOID", "ON_ERROR_ROLLBACK", "ON_ERROR_STOP",
4386                 "PORT", "PROMPT1", "PROMPT2", "PROMPT3", "QUIET", "SINGLELINE",
4387                 "SINGLESTEP", "USER", "VERBOSITY", NULL
4388         };
4389
4390         varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *));
4391
4392         if (!need_value)
4393         {
4394                 for (i = 0; known_varnames[i] && nvars < maxvars; i++)
4395                         append_variable_names(&varnames, &nvars, &maxvars,
4396                                                                   known_varnames[i], prefix, suffix);
4397         }
4398
4399         for (ptr = pset.vars->next; ptr; ptr = ptr->next)
4400         {
4401                 if (need_value && !(ptr->value))
4402                         continue;
4403                 for (i = 0; known_varnames[i]; i++)             /* remove duplicate entry */
4404                 {
4405                         if (strcmp(ptr->name, known_varnames[i]) == 0)
4406                                 continue;
4407                 }
4408                 append_variable_names(&varnames, &nvars, &maxvars, ptr->name,
4409                                                           prefix, suffix);
4410         }
4411
4412         varnames[nvars] = NULL;
4413         COMPLETE_WITH_LIST_CS((const char *const *) varnames);
4414
4415         for (i = 0; i < nvars; i++)
4416                 free(varnames[i]);
4417         free(varnames);
4418
4419         return matches;
4420 }
4421
4422
4423 /*
4424  * This function wraps rl_filename_completion_function() to strip quotes from
4425  * the input before searching for matches and to quote any matches for which
4426  * the consuming command will require it.
4427  */
4428 static char *
4429 complete_from_files(const char *text, int state)
4430 {
4431         static const char *unquoted_text;
4432         char       *unquoted_match;
4433         char       *ret = NULL;
4434
4435         if (state == 0)
4436         {
4437                 /* Initialization: stash the unquoted input. */
4438                 unquoted_text = strtokx(text, "", NULL, "'", *completion_charp,
4439                                                                 false, true, pset.encoding);
4440                 /* expect a NULL return for the empty string only */
4441                 if (!unquoted_text)
4442                 {
4443                         Assert(*text == '\0');
4444                         unquoted_text = text;
4445                 }
4446         }
4447
4448         unquoted_match = filename_completion_function(unquoted_text, state);
4449         if (unquoted_match)
4450         {
4451                 /*
4452                  * Caller sets completion_charp to a zero- or one-character string
4453                  * containing the escape character.  This is necessary since \copy has
4454                  * no escape character, but every other backslash command recognizes
4455                  * "\" as an escape character.  Since we have only two callers, don't
4456                  * bother providing a macro to simplify this.
4457                  */
4458                 ret = quote_if_needed(unquoted_match, " \t\r\n\"`",
4459                                                           '\'', *completion_charp, pset.encoding);
4460                 if (ret)
4461                         free(unquoted_match);
4462                 else
4463                         ret = unquoted_match;
4464         }
4465
4466         return ret;
4467 }
4468
4469
4470 /* HELPER FUNCTIONS */
4471
4472
4473 /*
4474  * Make a pg_strdup copy of s and convert the case according to
4475  * COMP_KEYWORD_CASE setting, using ref as the text that was already entered.
4476  */
4477 static char *
4478 pg_strdup_keyword_case(const char *s, const char *ref)
4479 {
4480         char       *ret,
4481                            *p;
4482         unsigned char first = ref[0];
4483
4484         ret = pg_strdup(s);
4485
4486         if (pset.comp_case == PSQL_COMP_CASE_LOWER ||
4487                 ((pset.comp_case == PSQL_COMP_CASE_PRESERVE_LOWER ||
4488            pset.comp_case == PSQL_COMP_CASE_PRESERVE_UPPER) && islower(first)) ||
4489                 (pset.comp_case == PSQL_COMP_CASE_PRESERVE_LOWER && !isalpha(first)))
4490         {
4491                 for (p = ret; *p; p++)
4492                         *p = pg_tolower((unsigned char) *p);
4493         }
4494         else
4495         {
4496                 for (p = ret; *p; p++)
4497                         *p = pg_toupper((unsigned char) *p);
4498         }
4499
4500         return ret;
4501 }
4502
4503
4504 /*
4505  * Execute a query and report any errors. This should be the preferred way of
4506  * talking to the database in this file.
4507  */
4508 static PGresult *
4509 exec_query(const char *query)
4510 {
4511         PGresult   *result;
4512
4513         if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
4514                 return NULL;
4515
4516         result = PQexec(pset.db, query);
4517
4518         if (PQresultStatus(result) != PGRES_TUPLES_OK)
4519         {
4520 #ifdef NOT_USED
4521                 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
4522                                    PQerrorMessage(pset.db), query);
4523 #endif
4524                 PQclear(result);
4525                 result = NULL;
4526         }
4527
4528         return result;
4529 }
4530
4531
4532 /*
4533  * Return the nwords word(s) before point.  Words are returned right to left,
4534  * that is, previous_words[0] gets the last word before point.
4535  * If we run out of words, remaining array elements are set to empty strings.
4536  * Each array element is filled with a malloc'd string.
4537  */
4538 static void
4539 get_previous_words(int point, char **previous_words, int nwords)
4540 {
4541         const char *buf = rl_line_buffer;       /* alias */
4542         int                     i;
4543
4544         /* first we look for a non-word char before the current point */
4545         for (i = point - 1; i >= 0; i--)
4546                 if (strchr(WORD_BREAKS, buf[i]))
4547                         break;
4548         point = i;
4549
4550         while (nwords-- > 0)
4551         {
4552                 int                     start,
4553                                         end;
4554                 char       *s;
4555
4556                 /* now find the first non-space which then constitutes the end */
4557                 end = -1;
4558                 for (i = point; i >= 0; i--)
4559                 {
4560                         if (!isspace((unsigned char) buf[i]))
4561                         {
4562                                 end = i;
4563                                 break;
4564                         }
4565                 }
4566
4567                 /*
4568                  * If no end found we return an empty string, because there is no word
4569                  * before the point
4570                  */
4571                 if (end < 0)
4572                 {
4573                         point = end;
4574                         s = pg_strdup("");
4575                 }
4576                 else
4577                 {
4578                         /*
4579                          * Otherwise we now look for the start. The start is either the
4580                          * last character before any word-break character going backwards
4581                          * from the end, or it's simply character 0. We also handle open
4582                          * quotes and parentheses.
4583                          */
4584                         bool            inquotes = false;
4585                         int                     parentheses = 0;
4586
4587                         for (start = end; start > 0; start--)
4588                         {
4589                                 if (buf[start] == '"')
4590                                         inquotes = !inquotes;
4591                                 if (!inquotes)
4592                                 {
4593                                         if (buf[start] == ')')
4594                                                 parentheses++;
4595                                         else if (buf[start] == '(')
4596                                         {
4597                                                 if (--parentheses <= 0)
4598                                                         break;
4599                                         }
4600                                         else if (parentheses == 0 &&
4601                                                          strchr(WORD_BREAKS, buf[start - 1]))
4602                                                 break;
4603                                 }
4604                         }
4605
4606                         point = start - 1;
4607
4608                         /* make a copy of chars from start to end inclusive */
4609                         s = pg_malloc(end - start + 2);
4610                         strlcpy(s, &buf[start], end - start + 2);
4611                 }
4612
4613                 *previous_words++ = s;
4614         }
4615 }
4616
4617 #ifdef NOT_USED
4618
4619 /*
4620  * Surround a string with single quotes. This works for both SQL and
4621  * psql internal. Currently disabled because it is reported not to
4622  * cooperate with certain versions of readline.
4623  */
4624 static char *
4625 quote_file_name(char *text, int match_type, char *quote_pointer)
4626 {
4627         char       *s;
4628         size_t          length;
4629
4630         (void) quote_pointer;           /* not used */
4631
4632         length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
4633         s = pg_malloc(length);
4634         s[0] = '\'';
4635         strcpy(s + 1, text);
4636         if (match_type == SINGLE_MATCH)
4637                 s[length - 2] = '\'';
4638         s[length - 1] = '\0';
4639         return s;
4640 }
4641
4642 static char *
4643 dequote_file_name(char *text, char quote_char)
4644 {
4645         char       *s;
4646         size_t          length;
4647
4648         if (!quote_char)
4649                 return pg_strdup(text);
4650
4651         length = strlen(text);
4652         s = pg_malloc(length - 2 + 1);
4653         strlcpy(s, text +1, length - 2 + 1);
4654
4655         return s;
4656 }
4657 #endif   /* NOT_USED */
4658
4659 #endif   /* USE_READLINE */