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