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