]> granicus.if.org Git - postgresql/blob - src/bin/psql/tab-complete.c
Fix a couple of places where psql might fail to report a suitable error
[postgresql] / src / bin / psql / tab-complete.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.171 2008/08/16 01:36:35 tgl Exp $
7  */
8
9 /*----------------------------------------------------------------------
10  * This file implements a somewhat more sophisticated readline "TAB
11  * completion" in psql. It is not intended to be AI, to replace
12  * learning SQL, or to relieve you from thinking about what you're
13  * doing. Also it does not always give you all the syntactically legal
14  * completions, only those that are the most common or the ones that
15  * the programmer felt most like implementing.
16  *
17  * CAVEAT: Tab completion causes queries to be sent to the backend.
18  * The number of tuples returned gets limited, in most default
19  * installations to 1000, but if you still don't like this prospect,
20  * you can turn off tab completion in your ~/.inputrc (or else
21  * ${INPUTRC}) file so:
22  *
23  *       $if psql
24  *       set disable-completion on
25  *       $endif
26  *
27  * See `man 3 readline' or `info readline' for the full details. Also,
28  * hence the
29  *
30  * BUGS:
31  *
32  * - If you split your queries across lines, this whole thing gets
33  *       confused. (To fix this, one would have to read psql's query
34  *       buffer rather than readline's line buffer, which would require
35  *       some major revisions of things.)
36  *
37  * - Table or attribute names with spaces in it may confuse it.
38  *
39  * - Quotes, parenthesis, and other funny characters are not handled
40  *       all that gracefully.
41  *----------------------------------------------------------------------
42  */
43
44 #include "postgres_fe.h"
45 #include "tab-complete.h"
46 #include "input.h"
47
48 /* If we don't have this, we might as well forget about the whole thing: */
49 #ifdef USE_READLINE
50
51 #include <ctype.h>
52 #include "libpq-fe.h"
53 #include "pqexpbuffer.h"
54 #include "common.h"
55 #include "settings.h"
56 #include "stringutils.h"
57
58 #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
59 #define filename_completion_function rl_filename_completion_function
60 #else
61 /* missing in some header files */
62 extern char *filename_completion_function();
63 #endif
64
65 #ifdef HAVE_RL_COMPLETION_MATCHES
66 #define completion_matches rl_completion_matches
67 #endif
68
69
70 /*
71  * This struct is used to define "schema queries", which are custom-built
72  * to obtain possibly-schema-qualified names of database objects.  There is
73  * enough similarity in the structure that we don't want to repeat it each
74  * time.  So we put the components of each query into this struct and
75  * assemble them with the common boilerplate in _complete_from_query().
76  */
77 typedef struct SchemaQuery
78 {
79         /*
80          * Name of catalog or catalogs to be queried, with alias, eg.
81          * "pg_catalog.pg_class c".  Note that "pg_namespace n" will be added.
82          */
83         const char *catname;
84
85         /*
86          * Selection condition --- only rows meeting this condition are candidates
87          * to display.  If catname mentions multiple tables, include the necessary
88          * join condition here.  For example, "c.relkind = 'r'". Write NULL (not
89          * an empty string) if not needed.
90          */
91         const char *selcondition;
92
93         /*
94          * Visibility condition --- which rows are visible without schema
95          * qualification?  For example, "pg_catalog.pg_table_is_visible(c.oid)".
96          */
97         const char *viscondition;
98
99         /*
100          * Namespace --- name of field to join to pg_namespace.oid. For example,
101          * "c.relnamespace".
102          */
103         const char *namespace;
104
105         /*
106          * Result --- the appropriately-quoted name to return, in the case of an
107          * unqualified name.  For example, "pg_catalog.quote_ident(c.relname)".
108          */
109         const char *result;
110
111         /*
112          * In some cases a different result must be used for qualified names.
113          * Enter that here, or write NULL if result can be used.
114          */
115         const char *qualresult;
116 } SchemaQuery;
117
118
119 /* Store maximum number of records we want from database queries
120  * (implemented via SELECT ... LIMIT xx).
121  */
122 static int      completion_max_records;
123
124 /*
125  * Communication variables set by COMPLETE_WITH_FOO macros and then used by
126  * the completion callback functions.  Ugly but there is no better way.
127  */
128 static const char *completion_charp;                    /* to pass a string */
129 static const char *const * completion_charpp;   /* to pass a list of strings */
130 static const char *completion_info_charp;               /* to pass a second string */
131 static const char *completion_info_charp2;              /* to pass a third string */
132 static const SchemaQuery *completion_squery;    /* to pass a SchemaQuery */
133
134 /*
135  * A few macros to ease typing. You can use these to complete the given
136  * string with
137  * 1) The results from a query you pass it. (Perhaps one of those below?)
138  * 2) The results from a schema query you pass it.
139  * 3) The items from a null-pointer-terminated list.
140  * 4) A string constant.
141  * 5) The list of attributes of the given table (possibly schema-qualified).
142  */
143 #define COMPLETE_WITH_QUERY(query) \
144 do { \
145         completion_charp = query; \
146         matches = completion_matches(text, complete_from_query); \
147 } while (0)
148
149 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
150 do { \
151         completion_squery = &(query); \
152         completion_charp = addon; \
153         matches = completion_matches(text, complete_from_schema_query); \
154 } while (0)
155
156 #define COMPLETE_WITH_LIST(list) \
157 do { \
158         completion_charpp = list; \
159         matches = completion_matches(text, complete_from_list); \
160 } while (0)
161
162 #define COMPLETE_WITH_CONST(string) \
163 do { \
164         completion_charp = string; \
165         matches = completion_matches(text, complete_from_const); \
166 } while (0)
167
168 #define COMPLETE_WITH_ATTR(relation, addon) \
169 do { \
170         char   *_completion_schema; \
171         char   *_completion_table; \
172 \
173         _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
174                                                                  false, false, pset.encoding); \
175         (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
176                                    false, false, pset.encoding); \
177         _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
178                                                                 false, false, pset.encoding); \
179         if (_completion_table == NULL) \
180         { \
181                 completion_charp = Query_for_list_of_attributes  addon; \
182                 completion_info_charp = relation; \
183         } \
184         else \
185         { \
186                 completion_charp = Query_for_list_of_attributes_with_schema  addon; \
187                 completion_info_charp = _completion_table; \
188                 completion_info_charp2 = _completion_schema; \
189         } \
190         matches = completion_matches(text, complete_from_query); \
191 } while (0)
192
193 /*
194  * Assembly instructions for schema queries
195  */
196
197 static const SchemaQuery Query_for_list_of_aggregates = {
198         /* catname */
199         "pg_catalog.pg_proc p",
200         /* selcondition */
201         "p.proisagg",
202         /* viscondition */
203         "pg_catalog.pg_function_is_visible(p.oid)",
204         /* namespace */
205         "p.pronamespace",
206         /* result */
207         "pg_catalog.quote_ident(p.proname)",
208         /* qualresult */
209         NULL
210 };
211
212 static const SchemaQuery Query_for_list_of_datatypes = {
213         /* catname */
214         "pg_catalog.pg_type t",
215         /* selcondition --- ignore table rowtypes and array types */
216         "(t.typrelid = 0 "
217         " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
218         "AND t.typname !~ '^_'",
219         /* viscondition */
220         "pg_catalog.pg_type_is_visible(t.oid)",
221         /* namespace */
222         "t.typnamespace",
223         /* result */
224         "pg_catalog.format_type(t.oid, NULL)",
225         /* qualresult */
226         "pg_catalog.quote_ident(t.typname)"
227 };
228
229 static const SchemaQuery Query_for_list_of_domains = {
230         /* catname */
231         "pg_catalog.pg_type t",
232         /* selcondition */
233         "t.typtype = 'd'",
234         /* viscondition */
235         "pg_catalog.pg_type_is_visible(t.oid)",
236         /* namespace */
237         "t.typnamespace",
238         /* result */
239         "pg_catalog.quote_ident(t.typname)",
240         /* qualresult */
241         NULL
242 };
243
244 static const SchemaQuery Query_for_list_of_functions = {
245         /* catname */
246         "pg_catalog.pg_proc p",
247         /* selcondition */
248         NULL,
249         /* viscondition */
250         "pg_catalog.pg_function_is_visible(p.oid)",
251         /* namespace */
252         "p.pronamespace",
253         /* result */
254         "pg_catalog.quote_ident(p.proname)",
255         /* qualresult */
256         NULL
257 };
258
259 static const SchemaQuery Query_for_list_of_indexes = {
260         /* catname */
261         "pg_catalog.pg_class c",
262         /* selcondition */
263         "c.relkind IN ('i')",
264         /* viscondition */
265         "pg_catalog.pg_table_is_visible(c.oid)",
266         /* namespace */
267         "c.relnamespace",
268         /* result */
269         "pg_catalog.quote_ident(c.relname)",
270         /* qualresult */
271         NULL
272 };
273
274 static const SchemaQuery Query_for_list_of_sequences = {
275         /* catname */
276         "pg_catalog.pg_class c",
277         /* selcondition */
278         "c.relkind IN ('S')",
279         /* viscondition */
280         "pg_catalog.pg_table_is_visible(c.oid)",
281         /* namespace */
282         "c.relnamespace",
283         /* result */
284         "pg_catalog.quote_ident(c.relname)",
285         /* qualresult */
286         NULL
287 };
288
289 static const SchemaQuery Query_for_list_of_tables = {
290         /* catname */
291         "pg_catalog.pg_class c",
292         /* selcondition */
293         "c.relkind IN ('r')",
294         /* viscondition */
295         "pg_catalog.pg_table_is_visible(c.oid)",
296         /* namespace */
297         "c.relnamespace",
298         /* result */
299         "pg_catalog.quote_ident(c.relname)",
300         /* qualresult */
301         NULL
302 };
303
304 static const SchemaQuery Query_for_list_of_tisv = {
305         /* catname */
306         "pg_catalog.pg_class c",
307         /* selcondition */
308         "c.relkind IN ('r', 'i', 'S', 'v')",
309         /* viscondition */
310         "pg_catalog.pg_table_is_visible(c.oid)",
311         /* namespace */
312         "c.relnamespace",
313         /* result */
314         "pg_catalog.quote_ident(c.relname)",
315         /* qualresult */
316         NULL
317 };
318
319 static const SchemaQuery Query_for_list_of_tsv = {
320         /* catname */
321         "pg_catalog.pg_class c",
322         /* selcondition */
323         "c.relkind IN ('r', 'S', 'v')",
324         /* viscondition */
325         "pg_catalog.pg_table_is_visible(c.oid)",
326         /* namespace */
327         "c.relnamespace",
328         /* result */
329         "pg_catalog.quote_ident(c.relname)",
330         /* qualresult */
331         NULL
332 };
333
334 static const SchemaQuery Query_for_list_of_views = {
335         /* catname */
336         "pg_catalog.pg_class c",
337         /* selcondition */
338         "c.relkind IN ('v')",
339         /* viscondition */
340         "pg_catalog.pg_table_is_visible(c.oid)",
341         /* namespace */
342         "c.relnamespace",
343         /* result */
344         "pg_catalog.quote_ident(c.relname)",
345         /* qualresult */
346         NULL
347 };
348
349
350 /*
351  * Queries to get lists of names of various kinds of things, possibly
352  * restricted to names matching a partially entered name.  In these queries,
353  * the first %s will be replaced by the text entered so far (suitably escaped
354  * to become a SQL literal string).  %d will be replaced by the length of the
355  * string (in unescaped form).  A second and third %s, if present, will be
356  * replaced by a suitably-escaped version of the string provided in
357  * completion_info_charp.  A fourth and fifth %s are similarly replaced by
358  * completion_info_charp2.
359  *
360  * Beware that the allowed sequences of %s and %d are determined by
361  * _complete_from_query().
362  */
363
364 #define Query_for_list_of_attributes \
365 "SELECT pg_catalog.quote_ident(attname) "\
366 "  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
367 " WHERE c.oid = a.attrelid "\
368 "   AND a.attnum > 0 "\
369 "   AND NOT a.attisdropped "\
370 "   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
371 "   AND (pg_catalog.quote_ident(relname)='%s' "\
372 "        OR '\"' || relname || '\"'='%s') "\
373 "   AND pg_catalog.pg_table_is_visible(c.oid)"
374
375 #define Query_for_list_of_attributes_with_schema \
376 "SELECT pg_catalog.quote_ident(attname) "\
377 "  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
378 " WHERE c.oid = a.attrelid "\
379 "   AND n.oid = c.relnamespace "\
380 "   AND a.attnum > 0 "\
381 "   AND NOT a.attisdropped "\
382 "   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
383 "   AND (pg_catalog.quote_ident(relname)='%s' "\
384 "        OR '\"' || relname || '\"' ='%s') "\
385 "   AND (pg_catalog.quote_ident(nspname)='%s' "\
386 "        OR '\"' || nspname || '\"' ='%s') "
387
388 #define Query_for_list_of_template_databases \
389 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
390 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' and datistemplate IS TRUE"
391
392 #define Query_for_list_of_databases \
393 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
394 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
395
396 #define Query_for_list_of_tablespaces \
397 "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
398 " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
399
400 #define Query_for_list_of_encodings \
401 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
402 "   FROM pg_catalog.pg_conversion "\
403 "  WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
404
405 #define Query_for_list_of_languages \
406 "SELECT pg_catalog.quote_ident(lanname) "\
407 "  FROM pg_language "\
408 " WHERE lanname != 'internal' "\
409 "   AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
410
411 #define Query_for_list_of_schemas \
412 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
413 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
414
415 #define Query_for_list_of_set_vars \
416 "SELECT name FROM "\
417 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
418 "  WHERE context IN ('user', 'superuser') "\
419 "  UNION ALL SELECT 'constraints' "\
420 "  UNION ALL SELECT 'transaction' "\
421 "  UNION ALL SELECT 'session' "\
422 "  UNION ALL SELECT 'role' "\
423 "  UNION ALL SELECT 'all') ss "\
424 " WHERE substring(name,1,%d)='%s'"
425
426 #define Query_for_list_of_show_vars \
427 "SELECT name FROM "\
428 " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
429 "  UNION ALL SELECT 'session authorization' "\
430 "  UNION ALL SELECT 'all') ss "\
431 " WHERE substring(name,1,%d)='%s'"
432
433 /*
434  * Note: As of Pg 8.2, we no longer use relkind 's', but we keep it here
435  * for compatibility with older servers
436  */
437 #define Query_for_list_of_system_relations \
438 "SELECT pg_catalog.quote_ident(relname) "\
439 "  FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
440 " WHERE c.relkind IN ('r', 'v', 's', 'S') "\
441 "   AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
442 "   AND c.relnamespace = n.oid "\
443 "   AND n.nspname = 'pg_catalog'"
444
445 #define Query_for_list_of_roles \
446 " SELECT pg_catalog.quote_ident(rolname) "\
447 "   FROM pg_catalog.pg_roles "\
448 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
449
450 #define Query_for_list_of_grant_roles \
451 " SELECT pg_catalog.quote_ident(rolname) "\
452 "   FROM pg_catalog.pg_roles "\
453 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
454 " UNION ALL SELECT 'PUBLIC'"
455
456 /* the silly-looking length condition is just to eat up the current word */
457 #define Query_for_table_owning_index \
458 "SELECT pg_catalog.quote_ident(c1.relname) "\
459 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
460 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
461 "       and (%d = pg_catalog.length('%s'))"\
462 "       and pg_catalog.quote_ident(c2.relname)='%s'"\
463 "       and pg_catalog.pg_table_is_visible(c2.oid)"
464
465 /* the silly-looking length condition is just to eat up the current word */
466 #define Query_for_index_of_table \
467 "SELECT pg_catalog.quote_ident(c2.relname) "\
468 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
469 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
470 "       and (%d = pg_catalog.length('%s'))"\
471 "       and pg_catalog.quote_ident(c1.relname)='%s'"\
472 "       and pg_catalog.pg_table_is_visible(c2.oid)"
473
474 /* the silly-looking length condition is just to eat up the current word */
475 #define Query_for_list_of_tables_for_trigger \
476 "SELECT pg_catalog.quote_ident(relname) "\
477 "  FROM pg_catalog.pg_class"\
478 " WHERE (%d = pg_catalog.length('%s'))"\
479 "   AND oid IN "\
480 "       (SELECT tgrelid FROM pg_catalog.pg_trigger "\
481 "         WHERE pg_catalog.quote_ident(tgname)='%s')"
482
483 #define Query_for_list_of_ts_configurations \
484 "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
485 " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
486
487 #define Query_for_list_of_ts_dictionaries \
488 "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
489 " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
490
491 #define Query_for_list_of_ts_parsers \
492 "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
493 " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
494
495 #define Query_for_list_of_ts_templates \
496 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
497 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
498
499 /*
500  * This is a list of all "things" in Pgsql, which can show up after CREATE or
501  * DROP; and there is also a query to get a list of them.
502  */
503
504 typedef struct
505 {
506         const char *name;
507         const char *query;                      /* simple query, or NULL */
508         const SchemaQuery *squery;      /* schema query, or NULL */
509         const bool      noshow;                 /* NULL or true if this word should not show
510                                                                  * up after CREATE or DROP */
511 } pgsql_thing_t;
512
513 static const pgsql_thing_t words_after_create[] = {
514         {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
515         {"CAST", NULL, NULL},           /* Casts have complex structures for names, so
516                                                                  * skip it */
517
518         /*
519          * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
520          * to be used only by pg_dump.
521          */
522         {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, true},
523         {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
524         {"DATABASE", Query_for_list_of_databases},
525         {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, true},
526         {"DOMAIN", NULL, &Query_for_list_of_domains},
527         {"FUNCTION", NULL, &Query_for_list_of_functions},
528         {"GROUP", Query_for_list_of_roles},
529         {"LANGUAGE", Query_for_list_of_languages},
530         {"INDEX", NULL, &Query_for_list_of_indexes},
531         {"OPERATOR", NULL, NULL},       /* Querying for this is probably not such a
532                                                                  * good idea. */
533         {"PARSER", Query_for_list_of_ts_parsers, NULL, true},
534         {"ROLE", Query_for_list_of_roles},
535         {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
536         {"SCHEMA", Query_for_list_of_schemas},
537         {"SEQUENCE", NULL, &Query_for_list_of_sequences},
538         {"TABLE", NULL, &Query_for_list_of_tables},
539         {"TABLESPACE", Query_for_list_of_tablespaces},
540         {"TEMP", NULL, NULL},           /* for CREATE TEMP TABLE ... */
541         {"TEMPLATE", Query_for_list_of_ts_templates, NULL, true},
542         {"TEXT SEARCH", NULL, NULL},
543         {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
544         {"TYPE", NULL, &Query_for_list_of_datatypes},
545         {"UNIQUE", NULL, NULL},         /* for CREATE UNIQUE INDEX ... */
546         {"USER", Query_for_list_of_roles},
547         {"VIEW", NULL, &Query_for_list_of_views},
548         {NULL, NULL, NULL, false}       /* end of list */
549 };
550
551
552 /* Forward declaration of functions */
553 static char **psql_completion(char *text, int start, int end);
554 static char *create_command_generator(const char *text, int state);
555 static char *drop_command_generator(const char *text, int state);
556 static char *complete_from_query(const char *text, int state);
557 static char *complete_from_schema_query(const char *text, int state);
558 static char *_complete_from_query(int is_schema_query,
559                                          const char *text, int state);
560 static char *complete_from_const(const char *text, int state);
561 static char *complete_from_list(const char *text, int state);
562
563 static PGresult *exec_query(const char *query);
564
565 static char *previous_word(int point, int skip);
566
567 static int      find_open_parenthesis(int end);
568
569 #if 0
570 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
571 static char *dequote_file_name(char *text, char quote_char);
572 #endif
573
574
575 /* Initialize the readline library for our purposes. */
576 void
577 initialize_readline(void)
578 {
579         rl_readline_name = (char *) pset.progname;
580         rl_attempted_completion_function = (void *) psql_completion;
581
582         rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
583
584         completion_max_records = 1000;
585
586         /*
587          * There is a variable rl_completion_query_items for this but apparently
588          * it's not defined everywhere.
589          */
590 }
591
592
593 /* The completion function. Acc. to readline spec this gets passed the text
594    entered to far and its start and end in the readline buffer. The return value
595    is some partially obscure list format that can be generated by the readline
596    libraries completion_matches() function, so we don't have to worry about it.
597 */
598 static char **
599 psql_completion(char *text, int start, int end)
600 {
601         /* This is the variable we'll return. */
602         char      **matches = NULL;
603
604         /* These are going to contain some scannage of the input line. */
605         char       *prev_wd,
606                            *prev2_wd,
607                            *prev3_wd,
608                            *prev4_wd,
609                            *prev5_wd;
610
611         static const char *const sql_commands[] = {
612                 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
613                 "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
614                 "DELETE FROM", "DISCARD", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
615                 "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
616                 "REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
617                 "SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN",
618                 "UPDATE", "VACUUM", "VALUES", NULL
619         };
620
621         static const char *const backslash_commands[] = {
622                 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
623                 "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
624                 "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl",
625                 "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
626                 "\\e", "\\echo", "\\encoding",
627                 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
628                 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
629                 "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
630                 "\\set", "\\t", "\\T",
631                 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
632         };
633
634         (void) end;                                     /* not used */
635
636 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
637         rl_completion_append_character = ' ';
638 #endif
639
640         /* Clear a few things. */
641         completion_charp = NULL;
642         completion_charpp = NULL;
643         completion_info_charp = NULL;
644         completion_info_charp2 = NULL;
645
646         /*
647          * Scan the input line before our current position for the last five
648          * words. According to those we'll make some smart decisions on what the
649          * user is probably intending to type. TODO: Use strtokx() to do this.
650          */
651         prev_wd = previous_word(start, 0);
652         prev2_wd = previous_word(start, 1);
653         prev3_wd = previous_word(start, 2);
654         prev4_wd = previous_word(start, 3);
655         prev5_wd = previous_word(start, 4);
656
657         /* If a backslash command was started, continue */
658         if (text[0] == '\\')
659                 COMPLETE_WITH_LIST(backslash_commands);
660
661         /* If no previous word, suggest one of the basic sql commands */
662         else if (!prev_wd)
663                 COMPLETE_WITH_LIST(sql_commands);
664
665 /* CREATE */
666         /* complete with something you can create */
667         else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
668                 matches = completion_matches(text, create_command_generator);
669
670 /* DROP, except ALTER (TABLE|DOMAIN|GROUP) sth DROP */
671         /* complete with something you can drop */
672         else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
673                          pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
674                          pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
675                          pg_strcasecmp(prev3_wd, "GROUP") != 0)
676                 matches = completion_matches(text, drop_command_generator);
677
678 /* ALTER */
679
680         /*
681          * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
682          * in ALTER TABLE sth ALTER
683          */
684         else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
685                          pg_strcasecmp(prev3_wd, "TABLE") != 0)
686         {
687                 static const char *const list_ALTER[] =
688                 {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
689                         "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SEQUENCE", "TABLE",
690                 "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "VIEW", NULL};
691
692                 COMPLETE_WITH_LIST(list_ALTER);
693         }
694         /* ALTER AGGREGATE,FUNCTION <name> */
695         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
696                          (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
697                           pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
698         {
699                 static const char *const list_ALTERAGG[] =
700                 {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
701
702                 COMPLETE_WITH_LIST(list_ALTERAGG);
703         }
704
705         /* ALTER CONVERSION,SCHEMA <name> */
706         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
707                          (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
708                           pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
709         {
710                 static const char *const list_ALTERGEN[] =
711                 {"OWNER TO", "RENAME TO", NULL};
712
713                 COMPLETE_WITH_LIST(list_ALTERGEN);
714         }
715
716         /* ALTER DATABASE <name> */
717         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
718                          pg_strcasecmp(prev2_wd, "DATABASE") == 0)
719         {
720                 static const char *const list_ALTERDATABASE[] =
721                 {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
722
723                 COMPLETE_WITH_LIST(list_ALTERDATABASE);
724         }
725
726         /* ALTER INDEX <name> */
727         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
728                          pg_strcasecmp(prev2_wd, "INDEX") == 0)
729         {
730                 static const char *const list_ALTERINDEX[] =
731                 {"SET TABLESPACE", "OWNER TO", "RENAME TO", "SET", "RESET", NULL};
732
733                 COMPLETE_WITH_LIST(list_ALTERINDEX);
734         }
735
736         /* ALTER LANGUAGE <name> */
737         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
738                          pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
739         {
740                 static const char *const list_ALTERLANGUAGE[] =
741                 {"OWNER TO", "RENAME TO", NULL};
742
743                 COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
744         }
745
746         /* ALTER USER,ROLE <name> */
747         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
748                          (pg_strcasecmp(prev2_wd, "USER") == 0 ||
749                           pg_strcasecmp(prev2_wd, "ROLE") == 0))
750         {
751                 static const char *const list_ALTERUSER[] =
752                 {"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
753                         "NOCREATEUSER", "CREATEROLE", "NOCREATEROLE", "INHERIT", "NOINHERIT",
754                         "LOGIN", "NOLOGIN", "CONNECTION LIMIT", "VALID UNTIL", "RENAME TO",
755                 "SUPERUSER", "NOSUPERUSER", "SET", "RESET", NULL};
756
757                 COMPLETE_WITH_LIST(list_ALTERUSER);
758         }
759
760         /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
761         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
762                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
763                          (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
764         {
765                 COMPLETE_WITH_CONST("PASSWORD");
766         }
767         /* ALTER DOMAIN <name> */
768         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
769                          pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
770         {
771                 static const char *const list_ALTERDOMAIN[] =
772                 {"ADD", "DROP", "OWNER TO", "SET", NULL};
773
774                 COMPLETE_WITH_LIST(list_ALTERDOMAIN);
775         }
776         /* ALTER DOMAIN <sth> DROP */
777         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
778                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
779                          pg_strcasecmp(prev_wd, "DROP") == 0)
780         {
781                 static const char *const list_ALTERDOMAIN2[] =
782                 {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
783
784                 COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
785         }
786         /* ALTER DOMAIN <sth> SET */
787         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
788                          pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
789                          pg_strcasecmp(prev_wd, "SET") == 0)
790         {
791                 static const char *const list_ALTERDOMAIN3[] =
792                 {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
793
794                 COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
795         }
796         /* ALTER SEQUENCE <name> */
797         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
798                          pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
799         {
800                 static const char *const list_ALTERSEQUENCE[] =
801                 {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
802                 "SET SCHEMA", "OWNED BY", "RENAME TO", NULL};
803
804                 COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
805         }
806         /* ALTER SEQUENCE <name> NO */
807         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
808                          pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
809                          pg_strcasecmp(prev_wd, "NO") == 0)
810         {
811                 static const char *const list_ALTERSEQUENCE2[] =
812                 {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
813
814                 COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
815         }
816         /* ALTER VIEW <name> */
817         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
818                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
819         {
820                 static const char *const list_ALTERVIEW[] = {"RENAME TO", NULL};
821
822                 COMPLETE_WITH_LIST(list_ALTERVIEW);
823         }
824         /* ALTER TRIGGER <name>, add ON */
825         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
826                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
827                 COMPLETE_WITH_CONST("ON");
828
829         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
830                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
831         {
832                 completion_info_charp = prev2_wd;
833                 COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
834         }
835
836         /*
837          * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
838          */
839         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
840                          pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
841                          pg_strcasecmp(prev_wd, "ON") == 0)
842                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
843
844         /* ALTER TRIGGER <name> ON <name> */
845         else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
846                          pg_strcasecmp(prev2_wd, "ON") == 0)
847                 COMPLETE_WITH_CONST("RENAME TO");
848
849         /*
850          * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
851          * RENAME, CLUSTER ON or OWNER
852          */
853         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
854                          pg_strcasecmp(prev2_wd, "TABLE") == 0)
855         {
856                 static const char *const list_ALTER2[] =
857                 {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
858                 "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET", NULL};
859
860                 COMPLETE_WITH_LIST(list_ALTER2);
861         }
862         /* ALTER TABLE xxx ENABLE */
863         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
864                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
865                          pg_strcasecmp(prev_wd, "ENABLE") == 0)
866         {
867                 static const char *const list_ALTERENABLE[] =
868                 {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
869
870                 COMPLETE_WITH_LIST(list_ALTERENABLE);
871         }
872         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
873                          pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
874                          (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
875                           pg_strcasecmp(prev_wd, "ALWAYS") == 0))
876         {
877                 static const char *const list_ALTERENABLE2[] =
878                 {"RULE", "TRIGGER", NULL};
879
880                 COMPLETE_WITH_LIST(list_ALTERENABLE2);
881         }
882         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
883                          pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
884                          pg_strcasecmp(prev_wd, "DISABLE") == 0)
885         {
886                 static const char *const list_ALTERDISABLE[] =
887                 {"RULE", "TRIGGER", NULL};
888
889                 COMPLETE_WITH_LIST(list_ALTERDISABLE);
890         }
891
892         /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
893         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
894                          (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
895                           pg_strcasecmp(prev_wd, "RENAME") == 0))
896                 COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
897
898         /*
899          * If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
900          * columns
901          */
902         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
903                          (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
904                           pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
905                          pg_strcasecmp(prev_wd, "COLUMN") == 0)
906                 COMPLETE_WITH_ATTR(prev3_wd, "");
907
908         /* ALTER TABLE xxx RENAME yyy */
909         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
910                          pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
911                          pg_strcasecmp(prev_wd, "TO") != 0)
912                 COMPLETE_WITH_CONST("TO");
913
914         /* ALTER TABLE xxx RENAME COLUMN yyy */
915         else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
916                          pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
917                          pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
918                          pg_strcasecmp(prev_wd, "TO") != 0)
919                 COMPLETE_WITH_CONST("TO");
920
921         /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
922         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
923                          pg_strcasecmp(prev_wd, "DROP") == 0)
924         {
925                 static const char *const list_TABLEDROP[] =
926                 {"COLUMN", "CONSTRAINT", NULL};
927
928                 COMPLETE_WITH_LIST(list_TABLEDROP);
929         }
930         /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
931         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
932                          pg_strcasecmp(prev2_wd, "DROP") == 0 &&
933                          pg_strcasecmp(prev_wd, "COLUMN") == 0)
934                 COMPLETE_WITH_ATTR(prev3_wd, "");
935         /* ALTER TABLE ALTER [COLUMN] <foo> */
936         else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
937                           pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
938                          (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
939                           pg_strcasecmp(prev2_wd, "ALTER") == 0))
940         {
941                 /* DROP ... does not work well yet */
942                 static const char *const list_COLUMNALTER[] =
943                 {"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
944                 "DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
945
946                 COMPLETE_WITH_LIST(list_COLUMNALTER);
947         }
948         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0)
949                 COMPLETE_WITH_CONST("ON");
950         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
951                          pg_strcasecmp(prev_wd, "ON") == 0)
952         {
953                 completion_info_charp = prev3_wd;
954                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
955         }
956         /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
957         else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
958                          pg_strcasecmp(prev_wd, "SET") == 0)
959         {
960                 static const char *const list_TABLESET[] =
961                 {"WITHOUT", "TABLESPACE", "SCHEMA", NULL};
962
963                 COMPLETE_WITH_LIST(list_TABLESET);
964         }
965         /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
966         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
967                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
968                          pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
969                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
970         /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
971         else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
972                          pg_strcasecmp(prev2_wd, "SET") == 0 &&
973                          pg_strcasecmp(prev_wd, "WITHOUT") == 0)
974         {
975                 static const char *const list_TABLESET2[] =
976                 {"CLUSTER", "OIDS", NULL};
977
978                 COMPLETE_WITH_LIST(list_TABLESET2);
979         }
980         /* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */
981         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
982                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
983         {
984                 static const char *const list_ALTERTSPC[] =
985                 {"RENAME TO", "OWNER TO", NULL};
986
987                 COMPLETE_WITH_LIST(list_ALTERTSPC);
988         }
989         /* ALTER TEXT SEARCH */
990         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
991                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
992                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
993         {
994                 static const char *const list_ALTERTEXTSEARCH[] =
995                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
996
997                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
998         }
999         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1000                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1001                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1002                          (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1003                           pg_strcasecmp(prev2_wd, "PARSER") == 0))
1004                 COMPLETE_WITH_CONST("RENAME TO");
1005
1006         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1007                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1008                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1009                          pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1010         {
1011                 static const char *const list_ALTERTEXTSEARCH2[] =
1012                 {"OWNER TO", "RENAME TO", NULL};
1013
1014                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1015         }
1016
1017         else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1018                          pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1019                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1020                          pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1021         {
1022                 static const char *const list_ALTERTEXTSEARCH3[] =
1023                 {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", NULL};
1024
1025                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1026         }
1027
1028         /* complete ALTER TYPE <foo> with OWNER TO, SET SCHEMA */
1029         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1030                          pg_strcasecmp(prev2_wd, "TYPE") == 0)
1031         {
1032                 static const char *const list_ALTERTYPE[] =
1033                 {"OWNER TO", "SET SCHEMA", NULL};
1034
1035                 COMPLETE_WITH_LIST(list_ALTERTYPE);
1036         }
1037         /* complete ALTER GROUP <foo> */
1038         else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1039                          pg_strcasecmp(prev2_wd, "GROUP") == 0)
1040         {
1041                 static const char *const list_ALTERGROUP[] =
1042                 {"ADD USER", "DROP USER", "RENAME TO", NULL};
1043
1044                 COMPLETE_WITH_LIST(list_ALTERGROUP);
1045         }
1046         /* complete ALTER GROUP <foo> ADD|DROP with USER */
1047         else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1048                          pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1049                          (pg_strcasecmp(prev_wd, "ADD") == 0 ||
1050                           pg_strcasecmp(prev_wd, "DROP") == 0))
1051                 COMPLETE_WITH_CONST("USER");
1052         /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1053         else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1054                          (pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1055                           pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1056                          pg_strcasecmp(prev_wd, "USER") == 0)
1057                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1058
1059 /* BEGIN, END, ABORT */
1060         else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1061                          pg_strcasecmp(prev_wd, "END") == 0 ||
1062                          pg_strcasecmp(prev_wd, "ABORT") == 0)
1063         {
1064                 static const char *const list_TRANS[] =
1065                 {"WORK", "TRANSACTION", NULL};
1066
1067                 COMPLETE_WITH_LIST(list_TRANS);
1068         }
1069 /* COMMIT */
1070         else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1071         {
1072                 static const char *const list_COMMIT[] =
1073                 {"WORK", "TRANSACTION", "PREPARED", NULL};
1074
1075                 COMPLETE_WITH_LIST(list_COMMIT);
1076         }
1077 /* RELEASE SAVEPOINT */
1078         else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1079                 COMPLETE_WITH_CONST("SAVEPOINT");
1080 /* ROLLBACK*/
1081         else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1082         {
1083                 static const char *const list_TRANS[] =
1084                 {"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1085
1086                 COMPLETE_WITH_LIST(list_TRANS);
1087         }
1088 /* CLUSTER */
1089
1090         /*
1091          * If the previous word is CLUSTER and not without produce list of tables
1092          */
1093         else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1094                          pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1095                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1096         /* If we have CLUSTER <sth>, then add "USING" */
1097         else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1098                          pg_strcasecmp(prev_wd, "ON") != 0)
1099         {
1100                 COMPLETE_WITH_CONST("USING");
1101         }
1102
1103         /*
1104          * If we have CLUSTER <sth> USING, then add the index as well.
1105          */
1106         else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1107                          pg_strcasecmp(prev_wd, "USING") == 0)
1108         {
1109                 completion_info_charp = prev2_wd;
1110                 COMPLETE_WITH_QUERY(Query_for_index_of_table);
1111         }
1112
1113 /* COMMENT */
1114         else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1115                 COMPLETE_WITH_CONST("ON");
1116         else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1117                          pg_strcasecmp(prev_wd, "ON") == 0)
1118         {
1119                 static const char *const list_COMMENT[] =
1120                 {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
1121                         "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1122                         "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1123                 "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1124
1125                 COMPLETE_WITH_LIST(list_COMMENT);
1126         }
1127         else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1128                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1129                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1130                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
1131         {
1132                 static const char *const list_TRANS2[] =
1133                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1134
1135                 COMPLETE_WITH_LIST(list_TRANS2);
1136         }
1137         else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1138                           pg_strcasecmp(prev3_wd, "ON") == 0) ||
1139                          (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1140                           pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1141                           pg_strcasecmp(prev3_wd, "SEARCH") == 0))
1142                 COMPLETE_WITH_CONST("IS");
1143
1144 /* COPY */
1145
1146         /*
1147          * If we have COPY [BINARY] (which you'd have to type yourself), offer
1148          * list of tables (Also cover the analogous backslash command)
1149          */
1150         else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1151                          pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1152                          (pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1153                           pg_strcasecmp(prev_wd, "BINARY") == 0))
1154                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1155         /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1156         else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1157                          pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1158                          pg_strcasecmp(prev2_wd, "BINARY") == 0)
1159         {
1160                 static const char *const list_FROMTO[] =
1161                 {"FROM", "TO", NULL};
1162
1163                 COMPLETE_WITH_LIST(list_FROMTO);
1164         }
1165         /* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1166         else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1167                           pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1168                           pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1169                          (pg_strcasecmp(prev_wd, "FROM") == 0 ||
1170                           pg_strcasecmp(prev_wd, "TO") == 0))
1171                 matches = completion_matches(text, filename_completion_function);
1172
1173         /* Handle COPY|BINARY <sth> FROM|TO filename */
1174         else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1175                           pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1176                           pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1177                          (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1178                           pg_strcasecmp(prev2_wd, "TO") == 0))
1179         {
1180                 static const char *const list_COPY[] =
1181                 {"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", NULL};
1182
1183                 COMPLETE_WITH_LIST(list_COPY);
1184         }
1185
1186         /* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1187         else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1188                          (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1189                           pg_strcasecmp(prev3_wd, "TO") == 0))
1190         {
1191                 static const char *const list_CSV[] =
1192                 {"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
1193
1194                 COMPLETE_WITH_LIST(list_CSV);
1195         }
1196
1197         /* CREATE DATABASE */
1198         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1199                          pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1200         {
1201                 static const char *const list_DATABASE[] =
1202                 {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1203                 NULL};
1204
1205                 COMPLETE_WITH_LIST(list_DATABASE);
1206         }
1207
1208         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1209                          pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1210                          pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1211                 COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1212
1213         /* CREATE INDEX */
1214         /* First off we complete CREATE UNIQUE with "INDEX" */
1215         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1216                          pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1217                 COMPLETE_WITH_CONST("INDEX");
1218         /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
1219         else if (pg_strcasecmp(prev2_wd, "INDEX") == 0 &&
1220                          (pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1221                           pg_strcasecmp(prev3_wd, "UNIQUE") == 0))
1222                 COMPLETE_WITH_CONST("ON");
1223         /* Complete ... INDEX <name> ON with a list of tables  */
1224         else if (pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
1225                          pg_strcasecmp(prev_wd, "ON") == 0)
1226                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1227
1228         /*
1229          * Complete INDEX <name> ON <table> with a list of table columns (which
1230          * should really be in parens)
1231          */
1232         else if (pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
1233                          pg_strcasecmp(prev2_wd, "ON") == 0)
1234         {
1235                 if (find_open_parenthesis(end))
1236                         COMPLETE_WITH_ATTR(prev_wd, "");
1237                 else
1238                         COMPLETE_WITH_CONST("(");
1239         }
1240         else if (pg_strcasecmp(prev5_wd, "INDEX") == 0 &&
1241                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1242                          pg_strcasecmp(prev_wd, "(") == 0)
1243                 COMPLETE_WITH_ATTR(prev2_wd, "");
1244         /* same if you put in USING */
1245         else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1246                          pg_strcasecmp(prev2_wd, "USING") == 0)
1247                 COMPLETE_WITH_ATTR(prev3_wd, "");
1248         /* Complete USING with an index method */
1249         else if (pg_strcasecmp(prev_wd, "USING") == 0)
1250         {
1251                 static const char *const index_mth[] =
1252                 {"BTREE", "HASH", "GIN", "GIST", NULL};
1253
1254                 COMPLETE_WITH_LIST(index_mth);
1255         }
1256
1257 /* CREATE RULE */
1258         /* Complete "CREATE RULE <sth>" with "AS" */
1259         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1260                          pg_strcasecmp(prev2_wd, "RULE") == 0)
1261                 COMPLETE_WITH_CONST("AS");
1262         /* Complete "CREATE RULE <sth> AS with "ON" */
1263         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1264                          pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1265                          pg_strcasecmp(prev_wd, "AS") == 0)
1266                 COMPLETE_WITH_CONST("ON");
1267         /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1268         else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1269                          pg_strcasecmp(prev2_wd, "AS") == 0 &&
1270                          pg_strcasecmp(prev_wd, "ON") == 0)
1271         {
1272                 static const char *const rule_events[] =
1273                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1274
1275                 COMPLETE_WITH_LIST(rule_events);
1276         }
1277         /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1278         else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1279                          pg_strcasecmp(prev2_wd, "ON") == 0 &&
1280                          (pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1281                           pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1282                 COMPLETE_WITH_CONST("TO");
1283         /* Complete "AS ON <sth> TO" with a table name */
1284         else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1285                          pg_strcasecmp(prev3_wd, "ON") == 0 &&
1286                          pg_strcasecmp(prev_wd, "TO") == 0)
1287                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1288
1289 /* CREATE TABLE */
1290         /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
1291         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1292                          (pg_strcasecmp(prev_wd, "TEMP") == 0 ||
1293                           pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
1294         {
1295                 static const char *const list_TEMP[] =
1296                 {"SEQUENCE", "TABLE", "VIEW", NULL};
1297
1298                 COMPLETE_WITH_LIST(list_TEMP);
1299         }
1300
1301 /* CREATE TABLESPACE */
1302         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1303                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1304         {
1305                 static const char *const list_CREATETABLESPACE[] =
1306                 {"OWNER", "LOCATION", NULL};
1307
1308                 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1309         }
1310         /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1311         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1312                          pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1313                          pg_strcasecmp(prev2_wd, "OWNER") == 0)
1314         {
1315                 COMPLETE_WITH_CONST("LOCATION");
1316         }
1317
1318 /* CREATE TEXT SEARCH */
1319         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1320                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1321                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
1322         {
1323                 static const char *const list_CREATETEXTSEARCH[] =
1324                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1325
1326                 COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
1327         }
1328         else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1329                          pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1330                          pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1331                 COMPLETE_WITH_CONST("(");
1332
1333 /* CREATE TRIGGER */
1334         /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1335         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1336                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1337         {
1338                 static const char *const list_CREATETRIGGER[] =
1339                 {"BEFORE", "AFTER", NULL};
1340
1341                 COMPLETE_WITH_LIST(list_CREATETRIGGER);
1342         }
1343         /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1344         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1345                          pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1346                          (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1347                           pg_strcasecmp(prev2_wd, "AFTER") == 0))
1348         {
1349                 static const char *const list_CREATETRIGGER2[] =
1350                 {"ON", "OR", NULL};
1351
1352                 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1353         }
1354
1355 /* CREATE ROLE,USER,GROUP */
1356         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1357                          (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1358                           pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1359         {
1360                 static const char *const list_CREATEROLE[] =
1361                 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1362                         "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOINHERIT", "NOLOGIN", "NOCREATEDB",
1363                         "NOCREATEROLE", "NOCREATEUSER", "NOSUPERUSER", "ROLE", "SUPERUSER", "SYSID",
1364                 "UNENCRYPTED", NULL};
1365
1366                 COMPLETE_WITH_LIST(list_CREATEROLE);
1367         }
1368
1369         /*
1370          * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1371          * PASSWORD
1372          */
1373         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1374                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1375                           pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1376                          (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1377         {
1378                 COMPLETE_WITH_CONST("PASSWORD");
1379         }
1380         /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1381         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1382                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1383                           pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1384                          pg_strcasecmp(prev_wd, "IN") == 0)
1385         {
1386                 static const char *const list_CREATEROLE3[] =
1387                 {"GROUP", "ROLE", NULL};
1388
1389                 COMPLETE_WITH_LIST(list_CREATEROLE3);
1390         }
1391
1392 /* CREATE VIEW */
1393         /* Complete CREATE VIEW <name> with AS */
1394         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1395                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
1396                 COMPLETE_WITH_CONST("AS");
1397         /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1398         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1399                          pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1400                          pg_strcasecmp(prev_wd, "AS") == 0)
1401                 COMPLETE_WITH_CONST("SELECT");
1402
1403 /* DECLARE */
1404         else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1405         {
1406                 static const char *const list_DECLARE[] =
1407                 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1408
1409                 COMPLETE_WITH_LIST(list_DECLARE);
1410         }
1411
1412         else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1413         {
1414                 static const char *const list_DECLARECURSOR[] =
1415                 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1416
1417                 COMPLETE_WITH_LIST(list_DECLARECURSOR);
1418         }
1419
1420
1421 /* DELETE */
1422
1423         /*
1424          * Complete DELETE with FROM (only if the word before that is not "ON"
1425          * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1426          */
1427         else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1428                          !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1429                            pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1430                            pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1431                            pg_strcasecmp(prev2_wd, "AFTER") == 0))
1432                 COMPLETE_WITH_CONST("FROM");
1433         /* Complete DELETE FROM with a list of tables */
1434         else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1435                          pg_strcasecmp(prev_wd, "FROM") == 0)
1436                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1437         /* Complete DELETE FROM <table> */
1438         else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1439                          pg_strcasecmp(prev2_wd, "FROM") == 0)
1440         {
1441                 static const char *const list_DELETE[] =
1442                 {"USING", "WHERE", "SET", NULL};
1443
1444                 COMPLETE_WITH_LIST(list_DELETE);
1445         }
1446         /* XXX: implement tab completion for DELETE ... USING */
1447
1448 /* DISCARD */
1449         else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
1450         {
1451                 static const char *const list_DISCARD[] =
1452                 {"ALL", "PLANS", "TEMP", NULL};
1453
1454                 COMPLETE_WITH_LIST(list_DISCARD);
1455         }
1456
1457 /* DROP (when not the previous word) */
1458         /* DROP AGGREGATE */
1459         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1460                          pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1461                 COMPLETE_WITH_CONST("(");
1462
1463         /* DROP object with CASCADE / RESTRICT */
1464         else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1465                           (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1466                            pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1467                            pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1468                            pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1469                            pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1470                            pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1471                            pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1472                            pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1473                            pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1474                            pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1475                          (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1476                           pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1477                           prev_wd[strlen(prev_wd) - 1] == ')') ||
1478                          (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
1479                           pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1480                           pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1481                           (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
1482                            pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
1483                            pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
1484                            pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
1485                 )
1486         {
1487                 if ((pg_strcasecmp(prev3_wd, "DROP") == 0) && (pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
1488                 {
1489                         if (find_open_parenthesis(end))
1490                         {
1491                                 static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1492                                 char       *tmp_buf = malloc(strlen(func_args_query) + strlen(prev_wd));
1493
1494                                 sprintf(tmp_buf, func_args_query, prev_wd);
1495                                 COMPLETE_WITH_QUERY(tmp_buf);
1496                                 free(tmp_buf);
1497                         }
1498                         else
1499                         {
1500                                 COMPLETE_WITH_CONST("(");
1501                         }
1502                 }
1503                 else
1504                 {
1505                         static const char *const list_DROPCR[] =
1506                         {"CASCADE", "RESTRICT", NULL};
1507
1508                         COMPLETE_WITH_LIST(list_DROPCR);
1509                 }
1510         }
1511         else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1512                          pg_strcasecmp(prev3_wd, "FUNCTION") == 0 &&
1513                          pg_strcasecmp(prev_wd, "(") == 0)
1514         {
1515                 static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1516                 char       *tmp_buf = malloc(strlen(func_args_query) + strlen(prev2_wd));
1517
1518                 sprintf(tmp_buf, func_args_query, prev2_wd);
1519                 COMPLETE_WITH_QUERY(tmp_buf);
1520                 free(tmp_buf);
1521         }
1522         /* DROP OWNED BY */
1523         else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1524                          pg_strcasecmp(prev_wd, "OWNED") == 0)
1525                 COMPLETE_WITH_CONST("BY");
1526         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1527                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1528                          pg_strcasecmp(prev_wd, "BY") == 0)
1529                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1530         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1531                          pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1532                          pg_strcasecmp(prev_wd, "SEARCH") == 0)
1533         {
1534
1535                 static const char *const list_ALTERTEXTSEARCH[] =
1536                 {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1537
1538                 COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1539         }
1540
1541 /* EXPLAIN */
1542
1543         /*
1544          * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1545          */
1546         else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1547         {
1548                 static const char *const list_EXPLAIN[] =
1549                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
1550
1551                 COMPLETE_WITH_LIST(list_EXPLAIN);
1552         }
1553         else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1554                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1555         {
1556                 static const char *const list_EXPLAIN[] =
1557                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
1558
1559                 COMPLETE_WITH_LIST(list_EXPLAIN);
1560         }
1561         else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1562                          pg_strcasecmp(prev3_wd, "VACUUM") != 0 &&
1563                          pg_strcasecmp(prev4_wd, "VACUUM") != 0 &&
1564                          (pg_strcasecmp(prev2_wd, "ANALYZE") == 0 ||
1565                           pg_strcasecmp(prev2_wd, "EXPLAIN") == 0))
1566         {
1567                 static const char *const list_EXPLAIN[] =
1568                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
1569
1570                 COMPLETE_WITH_LIST(list_EXPLAIN);
1571         }
1572
1573 /* FETCH && MOVE */
1574         /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1575         else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1576                          pg_strcasecmp(prev_wd, "MOVE") == 0)
1577         {
1578                 static const char *const list_FETCH1[] =
1579                 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1580
1581                 COMPLETE_WITH_LIST(list_FETCH1);
1582         }
1583         /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1584         else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1585                          pg_strcasecmp(prev2_wd, "MOVE") == 0)
1586         {
1587                 static const char *const list_FETCH2[] =
1588                 {"ALL", "NEXT", "PRIOR", NULL};
1589
1590                 COMPLETE_WITH_LIST(list_FETCH2);
1591         }
1592
1593         /*
1594          * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
1595          * but we may as well tab-complete both: perhaps some users prefer one
1596          * variant or the other.
1597          */
1598         else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
1599                          pg_strcasecmp(prev3_wd, "MOVE") == 0)
1600         {
1601                 static const char *const list_FROMIN[] =
1602                 {"FROM", "IN", NULL};
1603
1604                 COMPLETE_WITH_LIST(list_FROMIN);
1605         }
1606
1607 /* GRANT && REVOKE*/
1608         /* Complete GRANT/REVOKE with a list of privileges */
1609         else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
1610                          pg_strcasecmp(prev_wd, "REVOKE") == 0)
1611         {
1612                 static const char *const list_privileg[] =
1613                 {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
1614                         "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
1615                 "ALL", NULL};
1616
1617                 COMPLETE_WITH_LIST(list_privileg);
1618         }
1619         /* Complete GRANT/REVOKE <sth> with "ON" */
1620         else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1621                          pg_strcasecmp(prev2_wd, "REVOKE") == 0)
1622                 COMPLETE_WITH_CONST("ON");
1623
1624         /*
1625          * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
1626          * and indexes
1627          *
1628          * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
1629          * UNION; seems to work intuitively
1630          *
1631          * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
1632          * here will only work if the privilege list contains exactly one
1633          * privilege
1634          */
1635         else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
1636                           pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
1637                          pg_strcasecmp(prev_wd, "ON") == 0)
1638                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
1639                                                                    " UNION SELECT 'DATABASE'"
1640                                                                    " UNION SELECT 'FUNCTION'"
1641                                                                    " UNION SELECT 'LANGUAGE'"
1642                                                                    " UNION SELECT 'SCHEMA'"
1643                                                                    " UNION SELECT 'TABLESPACE'");
1644
1645         /* Complete "GRANT/REVOKE * ON * " with "TO" */
1646         else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1647                           pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1648                          pg_strcasecmp(prev2_wd, "ON") == 0)
1649         {
1650                 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1651                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1652                 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
1653                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1654                 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
1655                         COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1656                 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
1657                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1658                 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1659                         COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1660                 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
1661                         COMPLETE_WITH_CONST("TO");
1662                 else
1663                         COMPLETE_WITH_CONST("FROM");
1664         }
1665
1666         /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1667         else if (pg_strcasecmp(prev3_wd, "ON") == 0 &&
1668                          ((pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
1669                            pg_strcasecmp(prev_wd, "TO") == 0) ||
1670                           (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
1671                            pg_strcasecmp(prev_wd, "FROM") == 0)))
1672                 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1673
1674 /* GROUP BY */
1675         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1676                          pg_strcasecmp(prev_wd, "GROUP") == 0)
1677                 COMPLETE_WITH_CONST("BY");
1678
1679 /* INSERT */
1680         /* Complete INSERT with "INTO" */
1681         else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
1682                 COMPLETE_WITH_CONST("INTO");
1683         /* Complete INSERT INTO with table names */
1684         else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
1685                          pg_strcasecmp(prev_wd, "INTO") == 0)
1686                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1687         /* Complete "INSERT INTO <table> (" with attribute names */
1688         else if (rl_line_buffer[start - 1] == '(' &&
1689                          pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1690                          pg_strcasecmp(prev2_wd, "INTO") == 0)
1691                 COMPLETE_WITH_ATTR(prev_wd, "");
1692
1693         /*
1694          * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1695          * VALUES"
1696          */
1697         else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1698                          pg_strcasecmp(prev2_wd, "INTO") == 0)
1699         {
1700                 static const char *const list_INSERT[] =
1701                 {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1702
1703                 COMPLETE_WITH_LIST(list_INSERT);
1704         }
1705         /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1706         else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
1707                          pg_strcasecmp(prev3_wd, "INTO") == 0 &&
1708                          prev_wd[strlen(prev_wd) - 1] == ')')
1709         {
1710                 static const char *const list_INSERT[] =
1711                 {"SELECT", "VALUES", NULL};
1712
1713                 COMPLETE_WITH_LIST(list_INSERT);
1714         }
1715
1716         /* Insert an open parenthesis after "VALUES" */
1717         else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
1718                          pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
1719                 COMPLETE_WITH_CONST("(");
1720
1721 /* LOCK */
1722         /* Complete LOCK [TABLE] with a list of tables */
1723         else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
1724                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1725                                                                    " UNION SELECT 'TABLE'");
1726         else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
1727                          pg_strcasecmp(prev2_wd, "LOCK") == 0)
1728                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1729
1730         /* For the following, handle the case of a single table only for now */
1731
1732         /* Complete LOCK [TABLE] <table> with "IN" */
1733         else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
1734                           pg_strcasecmp(prev_wd, "TABLE")) ||
1735                          (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
1736                           pg_strcasecmp(prev3_wd, "LOCK") == 0))
1737                 COMPLETE_WITH_CONST("IN");
1738
1739         /* Complete LOCK [TABLE] <table> IN with a lock mode */
1740         else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
1741                          (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
1742                           (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1743                            pg_strcasecmp(prev4_wd, "LOCK") == 0)))
1744         {
1745                 static const char *const lock_modes[] =
1746                 {"ACCESS SHARE MODE",
1747                         "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1748                         "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1749                         "SHARE ROW EXCLUSIVE MODE",
1750                 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1751
1752                 COMPLETE_WITH_LIST(lock_modes);
1753         }
1754
1755 /* NOTIFY */
1756         else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
1757                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1758
1759 /* OWNER TO  - complete with available roles */
1760         else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
1761                          pg_strcasecmp(prev_wd, "TO") == 0)
1762                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1763
1764 /* ORDER BY */
1765         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1766                          pg_strcasecmp(prev_wd, "ORDER") == 0)
1767                 COMPLETE_WITH_CONST("BY");
1768         else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
1769                          pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
1770                          pg_strcasecmp(prev_wd, "BY") == 0)
1771                 COMPLETE_WITH_ATTR(prev3_wd, "");
1772
1773 /* PREPARE xx AS */
1774         else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
1775                          pg_strcasecmp(prev3_wd, "PREPARE") == 0)
1776         {
1777                 static const char *const list_PREPARE[] =
1778                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1779
1780                 COMPLETE_WITH_LIST(list_PREPARE);
1781         }
1782
1783 /* REASSIGN OWNED BY xxx TO yyy */
1784         else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
1785                 COMPLETE_WITH_CONST("OWNED");
1786         else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
1787                          pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
1788                 COMPLETE_WITH_CONST("BY");
1789         else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
1790                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1791                          pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
1792                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1793         else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
1794                          pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
1795                          pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
1796                 COMPLETE_WITH_CONST("TO");
1797         else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
1798                          pg_strcasecmp(prev3_wd, "BY") == 0 &&
1799                          pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
1800                          pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
1801                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1802
1803 /* REINDEX */
1804         else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
1805         {
1806                 static const char *const list_REINDEX[] =
1807                 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
1808
1809                 COMPLETE_WITH_LIST(list_REINDEX);
1810         }
1811         else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
1812         {
1813                 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
1814                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1815                 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
1816                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1817                 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
1818                                  pg_strcasecmp(prev_wd, "DATABASE") == 0)
1819                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1820         }
1821
1822 /* SELECT */
1823         /* naah . . . */
1824
1825 /* SET, RESET, SHOW */
1826         /* Complete with a variable name */
1827         else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
1828                           pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
1829                          pg_strcasecmp(prev_wd, "RESET") == 0)
1830                 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
1831         else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
1832                 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
1833         /* Complete "SET TRANSACTION" */
1834         else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
1835                           pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1836                          || (pg_strcasecmp(prev2_wd, "START") == 0
1837                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1838                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1839                                  && pg_strcasecmp(prev_wd, "WORK") == 0)
1840                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1841                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1842                          || (pg_strcasecmp(prev4_wd, "SESSION") == 0
1843                                  && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
1844                                  && pg_strcasecmp(prev2_wd, "AS") == 0
1845                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
1846         {
1847                 static const char *const my_list[] =
1848                 {"ISOLATION LEVEL", "READ", NULL};
1849
1850                 COMPLETE_WITH_LIST(my_list);
1851         }
1852         else if ((pg_strcasecmp(prev3_wd, "SET") == 0
1853                           || pg_strcasecmp(prev3_wd, "BEGIN") == 0
1854                           || pg_strcasecmp(prev3_wd, "START") == 0
1855                           || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
1856                                   && pg_strcasecmp(prev3_wd, "AS") == 0))
1857                          && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
1858                                  || pg_strcasecmp(prev2_wd, "WORK") == 0)
1859                          && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
1860                 COMPLETE_WITH_CONST("LEVEL");
1861         else if ((pg_strcasecmp(prev4_wd, "SET") == 0
1862                           || pg_strcasecmp(prev4_wd, "BEGIN") == 0
1863                           || pg_strcasecmp(prev4_wd, "START") == 0
1864                           || pg_strcasecmp(prev4_wd, "AS") == 0)
1865                          && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
1866                                  || pg_strcasecmp(prev3_wd, "WORK") == 0)
1867                          && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
1868                          && pg_strcasecmp(prev_wd, "LEVEL") == 0)
1869         {
1870                 static const char *const my_list[] =
1871                 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
1872
1873                 COMPLETE_WITH_LIST(my_list);
1874         }
1875         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1876                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1877                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1878                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1879                          pg_strcasecmp(prev_wd, "READ") == 0)
1880         {
1881                 static const char *const my_list[] =
1882                 {"UNCOMMITTED", "COMMITTED", NULL};
1883
1884                 COMPLETE_WITH_LIST(my_list);
1885         }
1886         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1887                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1888                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1889                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1890                          pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
1891                 COMPLETE_WITH_CONST("READ");
1892         else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
1893                           pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
1894                           pg_strcasecmp(prev3_wd, "START") == 0 ||
1895                           pg_strcasecmp(prev3_wd, "AS") == 0) &&
1896                          (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
1897                           pg_strcasecmp(prev2_wd, "WORK") == 0) &&
1898                          pg_strcasecmp(prev_wd, "READ") == 0)
1899         {
1900                 static const char *const my_list[] =
1901                 {"ONLY", "WRITE", NULL};
1902
1903                 COMPLETE_WITH_LIST(my_list);
1904         }
1905         /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1906         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1907                          pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1908         {
1909                 static const char *const constraint_list[] =
1910                 {"DEFERRED", "IMMEDIATE", NULL};
1911
1912                 COMPLETE_WITH_LIST(constraint_list);
1913         }
1914         /* Complete SET ROLE */
1915         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1916                          pg_strcasecmp(prev_wd, "ROLE") == 0)
1917                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1918         /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1919         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1920                          pg_strcasecmp(prev_wd, "SESSION") == 0)
1921         {
1922                 static const char *const my_list[] =
1923                 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
1924
1925                 COMPLETE_WITH_LIST(my_list);
1926         }
1927         /* Complete SET SESSION AUTHORIZATION with username */
1928         else if (pg_strcasecmp(prev3_wd, "SET") == 0
1929                          && pg_strcasecmp(prev2_wd, "SESSION") == 0
1930                          && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1931                 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
1932         /* Complete RESET SESSION with AUTHORIZATION */
1933         else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
1934                          pg_strcasecmp(prev_wd, "SESSION") == 0)
1935                 COMPLETE_WITH_CONST("AUTHORIZATION");
1936         /* Complete SET <var> with "TO" */
1937         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1938                          pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
1939                          pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
1940                          pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
1941                 COMPLETE_WITH_CONST("TO");
1942         /* Suggest possible variable values */
1943         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1944                          (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1945         {
1946                 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
1947                 {
1948                         static const char *const my_list[] =
1949                         {"ISO", "SQL", "Postgres", "German",
1950                                 "YMD", "DMY", "MDY",
1951                                 "US", "European", "NonEuropean",
1952                         "DEFAULT", NULL};
1953
1954                         COMPLETE_WITH_LIST(my_list);
1955                 }
1956                 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
1957                 {
1958                         static const char *const my_list[] =
1959                         {"ON", "OFF", "DEFAULT", NULL};
1960
1961                         COMPLETE_WITH_LIST(my_list);
1962                 }
1963                 else
1964                 {
1965                         static const char *const my_list[] =
1966                         {"DEFAULT", NULL};
1967
1968                         COMPLETE_WITH_LIST(my_list);
1969                 }
1970         }
1971
1972 /* START TRANSACTION */
1973         else if (pg_strcasecmp(prev_wd, "START") == 0)
1974                 COMPLETE_WITH_CONST("TRANSACTION");
1975
1976 /* TRUNCATE */
1977         else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
1978                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1979
1980 /* UNLISTEN */
1981         else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
1982                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s' UNION SELECT '*'");
1983
1984 /* UPDATE */
1985         /* If prev. word is UPDATE suggest a list of tables */
1986         else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
1987                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1988         /* Complete UPDATE <table> with "SET" */
1989         else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
1990                 COMPLETE_WITH_CONST("SET");
1991
1992         /*
1993          * If the previous word is SET (and it wasn't caught above as the _first_
1994          * word) the word before it was (hopefully) a table name and we'll now
1995          * make a list of attributes.
1996          */
1997         else if (pg_strcasecmp(prev_wd, "SET") == 0)
1998                 COMPLETE_WITH_ATTR(prev2_wd, "");
1999
2000 /* UPDATE xx SET yy = */
2001         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2002                          pg_strcasecmp(prev4_wd, "UPDATE") == 0)
2003                 COMPLETE_WITH_CONST("=");
2004
2005 /*
2006  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
2007  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
2008  */
2009         else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
2010                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2011                                                                    " UNION SELECT 'FULL'"
2012                                                                    " UNION SELECT 'FREEZE'"
2013                                                                    " UNION SELECT 'ANALYZE'"
2014                                                                    " UNION SELECT 'VERBOSE'");
2015         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2016                          (pg_strcasecmp(prev_wd, "FULL") == 0 ||
2017                           pg_strcasecmp(prev_wd, "FREEZE") == 0))
2018                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2019                                                                    " UNION SELECT 'ANALYZE'"
2020                                                                    " UNION SELECT 'VERBOSE'");
2021         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2022                          pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2023                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2024                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2025                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2026                                                                    " UNION SELECT 'VERBOSE'");
2027         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2028                          pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2029                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2030                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2031                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2032                                                                    " UNION SELECT 'ANALYZE'");
2033         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2034                          pg_strcasecmp(prev_wd, "VERBOSE") == 0)
2035                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2036                                                                    " UNION SELECT 'ANALYZE'");
2037         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2038                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2039                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2040                                                                    " UNION SELECT 'VERBOSE'");
2041         else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2042                           pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
2043                          (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2044                           pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
2045                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2046
2047 /* ANALYZE */
2048         /* If the previous word is ANALYZE, produce list of tables */
2049         else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2050                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2051
2052 /* WHERE */
2053         /* Simple case of the word before the where being the table name */
2054         else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
2055                 COMPLETE_WITH_ATTR(prev2_wd, "");
2056
2057 /* ... FROM ... */
2058 /* TODO: also include SRF ? */
2059         else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
2060                          pg_strcasecmp(prev3_wd, "COPY") != 0 &&
2061                          pg_strcasecmp(prev3_wd, "\\copy") != 0)
2062                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
2063
2064
2065 /* Backslash commands */
2066 /* TODO:  \dc \dd \dl */
2067         else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
2068                 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2069         else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
2070                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
2071         else if (strcmp(prev_wd, "\\da") == 0)
2072                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
2073         else if (strcmp(prev_wd, "\\db") == 0)
2074                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2075         else if (strcmp(prev_wd, "\\dD") == 0)
2076                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2077         else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
2078                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2079         else if (strcmp(prev_wd, "\\dF") == 0 || strcmp(prev_wd, "\\dF+") == 0)
2080                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
2081         else if (strcmp(prev_wd, "\\dFd") == 0 || strcmp(prev_wd, "\\dFd+") == 0)
2082                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
2083         else if (strcmp(prev_wd, "\\dFp") == 0 || strcmp(prev_wd, "\\dFp+") == 0)
2084                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
2085         else if (strcmp(prev_wd, "\\dFt") == 0 || strcmp(prev_wd, "\\dFt+") == 0)
2086                 COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
2087         else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
2088                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2089         else if (strcmp(prev_wd, "\\dn") == 0)
2090                 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2091         else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
2092                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
2093         else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
2094                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
2095         else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
2096                 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
2097         else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
2098                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2099         else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
2100                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2101         else if (strcmp(prev_wd, "\\du") == 0)
2102                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2103         else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
2104                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2105         else if (strcmp(prev_wd, "\\encoding") == 0)
2106                 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
2107         else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
2108                 COMPLETE_WITH_LIST(sql_commands);
2109         else if (strcmp(prev_wd, "\\password") == 0)
2110                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2111         else if (strcmp(prev_wd, "\\pset") == 0)
2112         {
2113                 static const char *const my_list[] =
2114                 {"format", "border", "expanded",
2115                         "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
2116                 "recordsep", NULL};
2117
2118                 COMPLETE_WITH_LIST(my_list);
2119         }
2120         else if (strcmp(prev_wd, "\\cd") == 0 ||
2121                          strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
2122                          strcmp(prev_wd, "\\g") == 0 ||
2123                   strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
2124                          strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
2125                          strcmp(prev_wd, "\\s") == 0 ||
2126                          strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
2127                 )
2128                 matches = completion_matches(text, filename_completion_function);
2129
2130
2131         /*
2132          * Finally, we look through the list of "things", such as TABLE, INDEX and
2133          * check if that was the previous word. If so, execute the query to get a
2134          * list of them.
2135          */
2136         else
2137         {
2138                 int                     i;
2139
2140                 for (i = 0; words_after_create[i].name; i++)
2141                 {
2142                         if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
2143                         {
2144                                 if (words_after_create[i].query)
2145                                         COMPLETE_WITH_QUERY(words_after_create[i].query);
2146                                 else if (words_after_create[i].squery)
2147                                         COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
2148                                                                                            NULL);
2149                                 break;
2150                         }
2151                 }
2152         }
2153
2154         /*
2155          * If we still don't have anything to match we have to fabricate some sort
2156          * of default list. If we were to just return NULL, readline automatically
2157          * attempts filename completion, and that's usually no good.
2158          */
2159         if (matches == NULL)
2160         {
2161                 COMPLETE_WITH_CONST("");
2162 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
2163                 rl_completion_append_character = '\0';
2164 #endif
2165         }
2166
2167         /* free storage */
2168         free(prev_wd);
2169         free(prev2_wd);
2170         free(prev3_wd);
2171         free(prev4_wd);
2172         free(prev5_wd);
2173
2174         /* Return our Grand List O' Matches */
2175         return matches;
2176 }
2177
2178
2179
2180 /* GENERATOR FUNCTIONS
2181
2182    These functions do all the actual work of completing the input. They get
2183    passed the text so far and the count how many times they have been called so
2184    far with the same text.
2185    If you read the above carefully, you'll see that these don't get called
2186    directly but through the readline interface.
2187    The return value is expected to be the full completion of the text, going
2188    through a list each time, or NULL if there are no more matches. The string
2189    will be free()'d by readline, so you must run it through strdup() or
2190    something of that sort.
2191 */
2192
2193 /* This one gives you one from a list of things you can put after CREATE
2194    as defined above.
2195 */
2196 static char *
2197 create_command_generator(const char *text, int state)
2198 {
2199         static int      list_index,
2200                                 string_length;
2201         const char *name;
2202
2203         /* If this is the first time for this completion, init some values */
2204         if (state == 0)
2205         {
2206                 list_index = 0;
2207                 string_length = strlen(text);
2208         }
2209
2210         /* find something that matches */
2211         while ((name = words_after_create[list_index++].name))
2212         {
2213                 if ((pg_strncasecmp(name, text, string_length) == 0) && !words_after_create[list_index - 1].noshow)
2214                         return pg_strdup(name);
2215         }
2216         /* if nothing matches, return NULL */
2217         return NULL;
2218 }
2219
2220 /*
2221  * This function gives you a list of things you can put after a DROP command.
2222  * Very similar to create_command_generator, but has an additional entry for
2223  * OWNED BY.  (We do it this way in order not to duplicate the
2224  * words_after_create list.)
2225  */
2226 static char *
2227 drop_command_generator(const char *text, int state)
2228 {
2229         static int      list_index,
2230                                 string_length;
2231         const char *name;
2232
2233         if (state == 0)
2234         {
2235                 /* If this is the first time for this completion, init some values */
2236                 list_index = 0;
2237                 string_length = strlen(text);
2238
2239                 /*
2240                  * DROP can be followed by "OWNED BY", which is not found in the list
2241                  * for CREATE matches, so make it the first state. (We do not make it
2242                  * the last state because it would be more difficult to detect when we
2243                  * have to return NULL instead.)
2244                  *
2245                  * Make sure we advance to the next state.
2246                  */
2247                 list_index++;
2248                 if (pg_strncasecmp("OWNED", text, string_length) == 0)
2249                         return pg_strdup("OWNED");
2250         }
2251
2252         /*
2253          * In subsequent attempts, try to complete with the same items we use for
2254          * CREATE
2255          */
2256         while ((name = words_after_create[list_index++ - 1].name))
2257         {
2258                 if ((pg_strncasecmp(name, text, string_length) == 0) && (!words_after_create[list_index - 2].noshow))
2259                         return pg_strdup(name);
2260         }
2261
2262         /* if nothing matches, return NULL */
2263         return NULL;
2264 }
2265
2266 /* The following two functions are wrappers for _complete_from_query */
2267
2268 static char *
2269 complete_from_query(const char *text, int state)
2270 {
2271         return _complete_from_query(0, text, state);
2272 }
2273
2274 static char *
2275 complete_from_schema_query(const char *text, int state)
2276 {
2277         return _complete_from_query(1, text, state);
2278 }
2279
2280
2281 /* This creates a list of matching things, according to a query pointed to
2282    by completion_charp.
2283    The query can be one of two kinds:
2284    - A simple query which must contain a %d and a %s, which will be replaced
2285    by the string length of the text and the text itself. The query may also
2286    have up to four more %s in it; the first two such will be replaced by the
2287    value of completion_info_charp, the next two by the value of
2288    completion_info_charp2.
2289          or:
2290    - A schema query used for completion of both schema and relation names;
2291    these are more complex and must contain in the following order:
2292          %d %s %d %s %d %s %s %d %s
2293    where %d is the string length of the text and %s the text itself.
2294
2295    It is assumed that strings should be escaped to become SQL literals
2296    (that is, what is in the query is actually ... '%s' ...)
2297
2298    See top of file for examples of both kinds of query.
2299 */
2300
2301 static char *
2302 _complete_from_query(int is_schema_query, const char *text, int state)
2303 {
2304         static int      list_index,
2305                                 string_length;
2306         static PGresult *result = NULL;
2307
2308         /*
2309          * If this is the first time for this completion, we fetch a list of our
2310          * "things" from the backend.
2311          */
2312         if (state == 0)
2313         {
2314                 PQExpBufferData query_buffer;
2315                 char       *e_text;
2316                 char       *e_info_charp;
2317                 char       *e_info_charp2;
2318
2319                 list_index = 0;
2320                 string_length = strlen(text);
2321
2322                 /* Free any prior result */
2323                 PQclear(result);
2324                 result = NULL;
2325
2326                 /* Set up suitably-escaped copies of textual inputs */
2327                 e_text = pg_malloc(string_length * 2 + 1);
2328                 PQescapeString(e_text, text, string_length);
2329
2330                 if (completion_info_charp)
2331                 {
2332                         size_t          charp_len;
2333
2334                         charp_len = strlen(completion_info_charp);
2335                         e_info_charp = pg_malloc(charp_len * 2 + 1);
2336                         PQescapeString(e_info_charp, completion_info_charp,
2337                                                    charp_len);
2338                 }
2339                 else
2340                         e_info_charp = NULL;
2341
2342                 if (completion_info_charp2)
2343                 {
2344                         size_t          charp_len;
2345
2346                         charp_len = strlen(completion_info_charp2);
2347                         e_info_charp2 = pg_malloc(charp_len * 2 + 1);
2348                         PQescapeString(e_info_charp2, completion_info_charp2,
2349                                                    charp_len);
2350                 }
2351                 else
2352                         e_info_charp2 = NULL;
2353
2354                 initPQExpBuffer(&query_buffer);
2355
2356                 if (is_schema_query)
2357                 {
2358                         /* completion_squery gives us the pieces to assemble */
2359                         const char *qualresult = completion_squery->qualresult;
2360
2361                         if (qualresult == NULL)
2362                                 qualresult = completion_squery->result;
2363
2364                         /* Get unqualified names matching the input-so-far */
2365                         appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
2366                                                           completion_squery->result,
2367                                                           completion_squery->catname);
2368                         if (completion_squery->selcondition)
2369                                 appendPQExpBuffer(&query_buffer, "%s AND ",
2370                                                                   completion_squery->selcondition);
2371                         appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
2372                                                           completion_squery->result,
2373                                                           string_length, e_text);
2374                         appendPQExpBuffer(&query_buffer, " AND %s",
2375                                                           completion_squery->viscondition);
2376
2377                         /*
2378                          * When fetching relation names, suppress system catalogs unless
2379                          * the input-so-far begins with "pg_".  This is a compromise
2380                          * between not offering system catalogs for completion at all, and
2381                          * having them swamp the result when the input is just "p".
2382                          */
2383                         if (strcmp(completion_squery->catname,
2384                                            "pg_catalog.pg_class c") == 0 &&
2385                                 strncmp(text, "pg_", 3) !=0)
2386                         {
2387                                 appendPQExpBuffer(&query_buffer,
2388                                                                   " AND c.relnamespace <> (SELECT oid FROM"
2389                                    " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
2390                         }
2391
2392                         /*
2393                          * Add in matching schema names, but only if there is more than
2394                          * one potential match among schema names.
2395                          */
2396                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
2397                                                    "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
2398                                                           "FROM pg_catalog.pg_namespace n "
2399                                                           "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
2400                                                           string_length, e_text);
2401                         appendPQExpBuffer(&query_buffer,
2402                                                           " AND (SELECT pg_catalog.count(*)"
2403                                                           " FROM pg_catalog.pg_namespace"
2404                         " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2405                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
2406                                                           string_length, e_text);
2407
2408                         /*
2409                          * Add in matching qualified names, but only if there is exactly
2410                          * one schema matching the input-so-far.
2411                          */
2412                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
2413                                          "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
2414                                                           "FROM %s, pg_catalog.pg_namespace n "
2415                                                           "WHERE %s = n.oid AND ",
2416                                                           qualresult,
2417                                                           completion_squery->catname,
2418                                                           completion_squery->namespace);
2419                         if (completion_squery->selcondition)
2420                                 appendPQExpBuffer(&query_buffer, "%s AND ",
2421                                                                   completion_squery->selcondition);
2422                         appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
2423                                                           qualresult,
2424                                                           string_length, e_text);
2425
2426                         /*
2427                          * This condition exploits the single-matching-schema rule to
2428                          * speed up the query
2429                          */
2430                         appendPQExpBuffer(&query_buffer,
2431                         " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
2432                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
2433                                                           string_length, e_text);
2434                         appendPQExpBuffer(&query_buffer,
2435                                                           " AND (SELECT pg_catalog.count(*)"
2436                                                           " FROM pg_catalog.pg_namespace"
2437                         " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2438                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
2439                                                           string_length, e_text);
2440
2441                         /* If an addon query was provided, use it */
2442                         if (completion_charp)
2443                                 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
2444                 }
2445                 else
2446                 {
2447                         /* completion_charp is an sprintf-style format string */
2448                         appendPQExpBuffer(&query_buffer, completion_charp,
2449                                                           string_length, e_text,
2450                                                           e_info_charp, e_info_charp,
2451                                                           e_info_charp2, e_info_charp2);
2452                 }
2453
2454                 /* Limit the number of records in the result */
2455                 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
2456                                                   completion_max_records);
2457
2458                 result = exec_query(query_buffer.data);
2459
2460                 termPQExpBuffer(&query_buffer);
2461                 free(e_text);
2462                 if (e_info_charp)
2463                         free(e_info_charp);
2464                 if (e_info_charp2)
2465                         free(e_info_charp2);
2466         }
2467
2468         /* Find something that matches */
2469         if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
2470         {
2471                 const char *item;
2472
2473                 while (list_index < PQntuples(result) &&
2474                            (item = PQgetvalue(result, list_index++, 0)))
2475                         if (pg_strncasecmp(text, item, string_length) == 0)
2476                                 return pg_strdup(item);
2477         }
2478
2479         /* If nothing matches, free the db structure and return null */
2480         PQclear(result);
2481         result = NULL;
2482         return NULL;
2483 }
2484
2485
2486 /* This function returns in order one of a fixed, NULL pointer terminated list
2487    of strings (if matching). This can be used if there are only a fixed number
2488    SQL words that can appear at certain spot.
2489 */
2490 static char *
2491 complete_from_list(const char *text, int state)
2492 {
2493         static int      string_length,
2494                                 list_index,
2495                                 matches;
2496         static bool casesensitive;
2497         const char *item;
2498
2499         /* need to have a list */
2500         psql_assert(completion_charpp);
2501
2502         /* Initialization */
2503         if (state == 0)
2504         {
2505                 list_index = 0;
2506                 string_length = strlen(text);
2507                 casesensitive = true;
2508                 matches = 0;
2509         }
2510
2511         while ((item = completion_charpp[list_index++]))
2512         {
2513                 /* First pass is case sensitive */
2514                 if (casesensitive && strncmp(text, item, string_length) == 0)
2515                 {
2516                         matches++;
2517                         return pg_strdup(item);
2518                 }
2519
2520                 /* Second pass is case insensitive, don't bother counting matches */
2521                 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
2522                         return pg_strdup(item);
2523         }
2524
2525         /*
2526          * No matches found. If we're not case insensitive already, lets switch to
2527          * being case insensitive and try again
2528          */
2529         if (casesensitive && matches == 0)
2530         {
2531                 casesensitive = false;
2532                 list_index = 0;
2533                 state++;
2534                 return complete_from_list(text, state);
2535         }
2536
2537         /* If no more matches, return null. */
2538         return NULL;
2539 }
2540
2541
2542 /* This function returns one fixed string the first time even if it doesn't
2543    match what's there, and nothing the second time. This should be used if there
2544    is only one possibility that can appear at a certain spot, so misspellings
2545    will be overwritten.
2546    The string to be passed must be in completion_charp.
2547 */
2548 static char *
2549 complete_from_const(const char *text, int state)
2550 {
2551         (void) text;                            /* We don't care about what was entered
2552                                                                  * already. */
2553
2554         psql_assert(completion_charp);
2555         if (state == 0)
2556                 return pg_strdup(completion_charp);
2557         else
2558                 return NULL;
2559 }
2560
2561
2562
2563 /* HELPER FUNCTIONS */
2564
2565
2566 /*
2567  * Execute a query and report any errors. This should be the preferred way of
2568  * talking to the database in this file.
2569  */
2570 static PGresult *
2571 exec_query(const char *query)
2572 {
2573         PGresult   *result;
2574
2575         if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
2576                 return NULL;
2577
2578         result = PQexec(pset.db, query);
2579
2580         if (PQresultStatus(result) != PGRES_TUPLES_OK)
2581         {
2582 #if 0
2583                 psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
2584                                    PQerrorMessage(pset.db), query);
2585 #endif
2586                 PQclear(result);
2587                 result = NULL;
2588         }
2589
2590         return result;
2591 }
2592
2593
2594
2595 /*
2596  * Return the word (space delimited) before point. Set skip > 0 to
2597  * skip that many words; e.g. skip=1 finds the word before the
2598  * previous one. Return value is NULL or a malloc'ed string.
2599  */
2600 static char *
2601 previous_word(int point, int skip)
2602 {
2603         int                     i,
2604                                 start = 0,
2605                                 end = -1,
2606                                 inquotes = 0;
2607         char       *s;
2608
2609         while (skip-- >= 0)
2610         {
2611                 /* first we look for a space before the current word */
2612                 for (i = point; i >= 0; i--)
2613                         if (rl_line_buffer[i] == ' ')
2614                                 break;
2615
2616                 /* now find the first non-space which then constitutes the end */
2617                 for (; i >= 0; i--)
2618                         if (rl_line_buffer[i] != ' ')
2619                         {
2620                                 end = i;
2621                                 break;
2622                         }
2623
2624                 /*
2625                  * If no end found we return null, because there is no word before the
2626                  * point
2627                  */
2628                 if (end == -1)
2629                         return NULL;
2630
2631                 /*
2632                  * Otherwise we now look for the start. The start is either the last
2633                  * character before any space going backwards from the end, or it's
2634                  * simply character 0
2635                  */
2636                 for (start = end; start > 0; start--)
2637                 {
2638                         if (rl_line_buffer[start] == '"')
2639                                 inquotes = !inquotes;
2640                         if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
2641                                 break;
2642                 }
2643
2644                 point = start;
2645         }
2646
2647         /* make a copy */
2648         s = pg_malloc(end - start + 2);
2649         strlcpy(s, &rl_line_buffer[start], end - start + 2);
2650
2651         return s;
2652 }
2653
2654 /* Find the parenthesis after the last word */
2655
2656
2657 static int
2658 find_open_parenthesis(int end)
2659 {
2660         int                     i = end - 1;
2661
2662         while ((rl_line_buffer[i] != ' ') && (i >= 0))
2663         {
2664                 if (rl_line_buffer[i] == '(')
2665                         return 1;
2666                 i--;
2667         }
2668         while ((rl_line_buffer[i] == ' ') && (i >= 0))
2669         {
2670                 i--;
2671         }
2672         if (rl_line_buffer[i] == '(')
2673         {
2674                 return 1;
2675         }
2676         return 0;
2677
2678 }
2679
2680 #if 0
2681
2682 /*
2683  * Surround a string with single quotes. This works for both SQL and
2684  * psql internal. Currently disabled because it is reported not to
2685  * cooperate with certain versions of readline.
2686  */
2687 static char *
2688 quote_file_name(char *text, int match_type, char *quote_pointer)
2689 {
2690         char       *s;
2691         size_t          length;
2692
2693         (void) quote_pointer;           /* not used */
2694
2695         length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
2696         s = pg_malloc(length);
2697         s[0] = '\'';
2698         strcpy(s + 1, text);
2699         if (match_type == SINGLE_MATCH)
2700                 s[length - 2] = '\'';
2701         s[length - 1] = '\0';
2702         return s;
2703 }
2704
2705
2706
2707 static char *
2708 dequote_file_name(char *text, char quote_char)
2709 {
2710         char       *s;
2711         size_t          length;
2712
2713         if (!quote_char)
2714                 return pg_strdup(text);
2715
2716         length = strlen(text);
2717         s = pg_malloc(length - 2 + 1);
2718         strlcpy(s, text +1, length - 2 + 1);
2719
2720         return s;
2721 }
2722 #endif   /* 0 */
2723
2724 #endif   /* USE_READLINE */