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