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