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