]> granicus.if.org Git - postgresql/blob - src/bin/psql/tab-complete.c
Support syntax "CLUSTER table USING index", which is more logical.
[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.161 2007/04/08 00:26:34 momjian 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", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", "GRANT",
531                 "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 with "TABLE" */
1111         else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1112                          pg_strcasecmp(prev_wd, "TEMP") == 0)
1113                 COMPLETE_WITH_CONST("TABLE");
1114
1115 /* CREATE TABLESPACE */
1116         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1117                          pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1118         {
1119                 static const char *const list_CREATETABLESPACE[] =
1120                 {"OWNER", "LOCATION", NULL};
1121
1122                 COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1123         }
1124         /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1125         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1126                          pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1127                          pg_strcasecmp(prev2_wd, "OWNER") == 0)
1128         {
1129                 COMPLETE_WITH_CONST("LOCATION");
1130         }
1131
1132 /* CREATE TRIGGER */
1133         /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1134         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1135                          pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1136         {
1137                 static const char *const list_CREATETRIGGER[] =
1138                 {"BEFORE", "AFTER", NULL};
1139
1140                 COMPLETE_WITH_LIST(list_CREATETRIGGER);
1141         }
1142         /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1143         else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1144                          pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1145                          (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1146                           pg_strcasecmp(prev2_wd, "AFTER") == 0))
1147         {
1148                 static const char *const list_CREATETRIGGER2[] =
1149                 {"ON", "OR", NULL};
1150
1151                 COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1152         }
1153
1154 /* CREATE ROLE,USER,GROUP */
1155         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1156                          (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1157                           pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1158         {
1159                 static const char *const list_CREATEROLE[] =
1160                 {"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1161                         "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOINHERIT", "NOLOGIN", "NOCREATEDB",
1162                         "NOCREATEROLE", "NOCREATEUSER", "NOSUPERUSER", "ROLE", "SUPERUSER", "SYSID",
1163                 "UNENCRYPTED", NULL};
1164
1165                 COMPLETE_WITH_LIST(list_CREATEROLE);
1166         }
1167
1168         /*
1169          * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1170          * PASSWORD
1171          */
1172         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1173                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1174                           pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1175                          (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1176         {
1177                 COMPLETE_WITH_CONST("PASSWORD");
1178         }
1179         /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1180         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1181                          (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1182                           pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1183                          pg_strcasecmp(prev_wd, "IN") == 0)
1184         {
1185                 static const char *const list_CREATEROLE3[] =
1186                 {"GROUP", "ROLE", NULL};
1187
1188                 COMPLETE_WITH_LIST(list_CREATEROLE3);
1189         }
1190
1191 /* CREATE VIEW */
1192         /* Complete CREATE VIEW <name> with AS */
1193         else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1194                          pg_strcasecmp(prev2_wd, "VIEW") == 0)
1195                 COMPLETE_WITH_CONST("AS");
1196         /* Complete "CREATE VIEW <sth> AS with "SELECT" */
1197         else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1198                          pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1199                          pg_strcasecmp(prev_wd, "AS") == 0)
1200                 COMPLETE_WITH_CONST("SELECT");
1201
1202 /* DECLARE */
1203         else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1204         {
1205                 static const char *const list_DECLARE[] =
1206                 {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1207
1208                 COMPLETE_WITH_LIST(list_DECLARE);
1209         }
1210
1211         else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1212         {
1213                 static const char *const list_DECLARECURSOR[] =
1214                 {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1215
1216                 COMPLETE_WITH_LIST(list_DECLARECURSOR);
1217         }
1218
1219
1220 /* DELETE */
1221
1222         /*
1223          * Complete DELETE with FROM (only if the word before that is not "ON"
1224          * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1225          */
1226         else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1227                          !(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1228                            pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1229                            pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1230                            pg_strcasecmp(prev2_wd, "AFTER") == 0))
1231                 COMPLETE_WITH_CONST("FROM");
1232         /* Complete DELETE FROM with a list of tables */
1233         else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1234                          pg_strcasecmp(prev_wd, "FROM") == 0)
1235                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1236         /* Complete DELETE FROM <table> */
1237         else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1238                          pg_strcasecmp(prev2_wd, "FROM") == 0)
1239         {
1240                 static const char *const list_DELETE[] =
1241                 {"USING", "WHERE", "SET", NULL};
1242
1243                 COMPLETE_WITH_LIST(list_DELETE);
1244         }
1245         /* XXX: implement tab completion for DELETE ... USING */
1246
1247 /* DROP (when not the previous word) */
1248         /* DROP AGGREGATE */
1249         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1250                          pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1251                 COMPLETE_WITH_CONST("(");
1252
1253         /* DROP object with CASCADE / RESTRICT */
1254         else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1255                           (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1256                            pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1257                            pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1258                            pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1259                            pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1260                            pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1261                            pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1262                            pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1263                            pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1264                            pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1265                          (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1266                           pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1267                           prev_wd[strlen(prev_wd) - 1] == ')'))
1268         {
1269                 if ((pg_strcasecmp(prev3_wd, "DROP") == 0) && (pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
1270                 {
1271                         if (find_open_parenthesis(end))
1272                         {
1273                                 static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1274                                 char       *tmp_buf = malloc(strlen(func_args_query) + strlen(prev_wd));
1275
1276                                 sprintf(tmp_buf, func_args_query, prev_wd);
1277                                 COMPLETE_WITH_QUERY(tmp_buf);
1278                                 free(tmp_buf);
1279                         }
1280                         else
1281                         {
1282                                 COMPLETE_WITH_CONST("(");
1283                         }
1284                 }
1285                 else
1286                 {
1287                         static const char *const list_DROPCR[] =
1288                         {"CASCADE", "RESTRICT", NULL};
1289
1290                         COMPLETE_WITH_LIST(list_DROPCR);
1291                 }
1292         }
1293         else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1294                          pg_strcasecmp(prev3_wd, "FUNCTION") == 0 &&
1295                          pg_strcasecmp(prev_wd, "(") == 0)
1296         {
1297                 static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1298                 char       *tmp_buf = malloc(strlen(func_args_query) + strlen(prev2_wd));
1299
1300                 sprintf(tmp_buf, func_args_query, prev2_wd);
1301                 COMPLETE_WITH_QUERY(tmp_buf);
1302                 free(tmp_buf);
1303         }
1304         /* DROP OWNED BY */
1305         else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1306                          pg_strcasecmp(prev_wd, "OWNED") == 0)
1307                 COMPLETE_WITH_CONST("BY");
1308         else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1309                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1310                          pg_strcasecmp(prev_wd, "BY") == 0)
1311                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1312
1313
1314
1315 /* EXPLAIN */
1316
1317         /*
1318          * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1319          */
1320         else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1321         {
1322                 static const char *const list_EXPLAIN[] =
1323                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
1324
1325                 COMPLETE_WITH_LIST(list_EXPLAIN);
1326         }
1327         else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1328                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1329         {
1330                 static const char *const list_EXPLAIN[] =
1331                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
1332
1333                 COMPLETE_WITH_LIST(list_EXPLAIN);
1334         }
1335         else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1336                          pg_strcasecmp(prev3_wd, "VACUUM") != 0 &&
1337                          pg_strcasecmp(prev4_wd, "VACUUM") != 0 &&
1338                          (pg_strcasecmp(prev2_wd, "ANALYZE") == 0 ||
1339                           pg_strcasecmp(prev2_wd, "EXPLAIN") == 0))
1340         {
1341                 static const char *const list_EXPLAIN[] =
1342                 {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
1343
1344                 COMPLETE_WITH_LIST(list_EXPLAIN);
1345         }
1346
1347 /* FETCH && MOVE */
1348         /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1349         else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1350                          pg_strcasecmp(prev_wd, "MOVE") == 0)
1351         {
1352                 static const char *const list_FETCH1[] =
1353                 {"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1354
1355                 COMPLETE_WITH_LIST(list_FETCH1);
1356         }
1357         /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1358         else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1359                          pg_strcasecmp(prev2_wd, "MOVE") == 0)
1360         {
1361                 static const char *const list_FETCH2[] =
1362                 {"ALL", "NEXT", "PRIOR", NULL};
1363
1364                 COMPLETE_WITH_LIST(list_FETCH2);
1365         }
1366
1367         /*
1368          * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
1369          * but we may as well tab-complete both: perhaps some users prefer one
1370          * variant or the other.
1371          */
1372         else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
1373                          pg_strcasecmp(prev3_wd, "MOVE") == 0)
1374         {
1375                 static const char *const list_FROMIN[] =
1376                 {"FROM", "IN", NULL};
1377
1378                 COMPLETE_WITH_LIST(list_FROMIN);
1379         }
1380
1381 /* GRANT && REVOKE*/
1382         /* Complete GRANT/REVOKE with a list of privileges */
1383         else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
1384                          pg_strcasecmp(prev_wd, "REVOKE") == 0)
1385         {
1386                 static const char *const list_privileg[] =
1387                 {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
1388                         "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
1389                 "ALL", NULL};
1390
1391                 COMPLETE_WITH_LIST(list_privileg);
1392         }
1393         /* Complete GRANT/REVOKE <sth> with "ON" */
1394         else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1395                          pg_strcasecmp(prev2_wd, "REVOKE") == 0)
1396                 COMPLETE_WITH_CONST("ON");
1397
1398         /*
1399          * Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
1400          * and indexes
1401          *
1402          * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
1403          * UNION; seems to work intuitively
1404          *
1405          * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
1406          * here will only work if the privilege list contains exactly one
1407          * privilege
1408          */
1409         else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
1410                           pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
1411                          pg_strcasecmp(prev_wd, "ON") == 0)
1412                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
1413                                                                    " UNION SELECT 'DATABASE'"
1414                                                                    " UNION SELECT 'FUNCTION'"
1415                                                                    " UNION SELECT 'LANGUAGE'"
1416                                                                    " UNION SELECT 'SCHEMA'"
1417                                                                    " UNION SELECT 'TABLESPACE'");
1418
1419         /* Complete "GRANT/REVOKE * ON * " with "TO" */
1420         else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1421                           pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1422                          pg_strcasecmp(prev2_wd, "ON") == 0)
1423         {
1424                 if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1425                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1426                 else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
1427                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1428                 else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
1429                         COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1430                 else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
1431                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1432                 else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1433                         COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1434                 else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
1435                         COMPLETE_WITH_CONST("TO");
1436                 else
1437                         COMPLETE_WITH_CONST("FROM");
1438         }
1439
1440         /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1441         else if (pg_strcasecmp(prev3_wd, "ON") == 0 &&
1442                          ((pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
1443                            pg_strcasecmp(prev_wd, "TO") == 0) ||
1444                           (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
1445                            pg_strcasecmp(prev_wd, "FROM") == 0)))
1446                 COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1447
1448 /* GROUP BY */
1449         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1450                          pg_strcasecmp(prev_wd, "GROUP") == 0)
1451                 COMPLETE_WITH_CONST("BY");
1452
1453 /* INSERT */
1454         /* Complete INSERT with "INTO" */
1455         else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
1456                 COMPLETE_WITH_CONST("INTO");
1457         /* Complete INSERT INTO with table names */
1458         else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
1459                          pg_strcasecmp(prev_wd, "INTO") == 0)
1460                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1461         /* Complete "INSERT INTO <table> (" with attribute names */
1462         else if (rl_line_buffer[start - 1] == '(' &&
1463                          pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1464                          pg_strcasecmp(prev2_wd, "INTO") == 0)
1465                 COMPLETE_WITH_ATTR(prev_wd, "");
1466
1467         /*
1468          * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1469          * VALUES"
1470          */
1471         else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1472                          pg_strcasecmp(prev2_wd, "INTO") == 0)
1473         {
1474                 static const char *const list_INSERT[] =
1475                 {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1476
1477                 COMPLETE_WITH_LIST(list_INSERT);
1478         }
1479         /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1480         else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
1481                          pg_strcasecmp(prev3_wd, "INTO") == 0 &&
1482                          prev_wd[strlen(prev_wd) - 1] == ')')
1483         {
1484                 static const char *const list_INSERT[] =
1485                 {"SELECT", "VALUES", NULL};
1486
1487                 COMPLETE_WITH_LIST(list_INSERT);
1488         }
1489
1490         /* Insert an open parenthesis after "VALUES" */
1491         else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
1492                          pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
1493                 COMPLETE_WITH_CONST("(");
1494
1495 /* LOCK */
1496         /* Complete LOCK [TABLE] with a list of tables */
1497         else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
1498                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1499                                                                    " UNION SELECT 'TABLE'");
1500         else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
1501                          pg_strcasecmp(prev2_wd, "LOCK") == 0)
1502                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1503
1504         /* For the following, handle the case of a single table only for now */
1505
1506         /* Complete LOCK [TABLE] <table> with "IN" */
1507         else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
1508                           pg_strcasecmp(prev_wd, "TABLE")) ||
1509                          (pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
1510                           pg_strcasecmp(prev3_wd, "LOCK") == 0))
1511                 COMPLETE_WITH_CONST("IN");
1512
1513         /* Complete LOCK [TABLE] <table> IN with a lock mode */
1514         else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
1515                          (pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
1516                           (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1517                            pg_strcasecmp(prev4_wd, "LOCK") == 0)))
1518         {
1519                 static const char *const lock_modes[] =
1520                 {"ACCESS SHARE MODE",
1521                         "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1522                         "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1523                         "SHARE ROW EXCLUSIVE MODE",
1524                 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1525
1526                 COMPLETE_WITH_LIST(lock_modes);
1527         }
1528
1529 /* NOTIFY */
1530         else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
1531                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1532
1533 /* OWNER TO  - complete with available roles */
1534         else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
1535                          pg_strcasecmp(prev_wd, "TO") == 0)
1536                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1537
1538 /* ORDER BY */
1539         else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1540                          pg_strcasecmp(prev_wd, "ORDER") == 0)
1541                 COMPLETE_WITH_CONST("BY");
1542         else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
1543                          pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
1544                          pg_strcasecmp(prev_wd, "BY") == 0)
1545                 COMPLETE_WITH_ATTR(prev3_wd, "");
1546
1547 /* PREPARE xx AS */
1548         else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
1549                          pg_strcasecmp(prev3_wd, "PREPARE") == 0)
1550         {
1551                 static const char *const list_PREPARE[] =
1552                 {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1553
1554                 COMPLETE_WITH_LIST(list_PREPARE);
1555         }
1556
1557 /* REASSIGN OWNED BY xxx TO yyy */
1558         else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
1559                 COMPLETE_WITH_CONST("OWNED");
1560         else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
1561                          pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
1562                 COMPLETE_WITH_CONST("BY");
1563         else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
1564                          pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
1565                          pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
1566                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1567         else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
1568                          pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
1569                          pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
1570                 COMPLETE_WITH_CONST("TO");
1571         else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
1572                          pg_strcasecmp(prev3_wd, "BY") == 0 &&
1573                          pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
1574                          pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
1575                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1576
1577 /* REINDEX */
1578         else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
1579         {
1580                 static const char *const list_REINDEX[] =
1581                 {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
1582
1583                 COMPLETE_WITH_LIST(list_REINDEX);
1584         }
1585         else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
1586         {
1587                 if (pg_strcasecmp(prev_wd, "TABLE") == 0)
1588                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1589                 else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
1590                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1591                 else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
1592                                  pg_strcasecmp(prev_wd, "DATABASE") == 0)
1593                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1594         }
1595
1596 /* SELECT */
1597         /* naah . . . */
1598
1599 /* SET, RESET, SHOW */
1600         /* Complete with a variable name */
1601         else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
1602                           pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
1603                          pg_strcasecmp(prev_wd, "RESET") == 0)
1604                 COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
1605         else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
1606                 COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
1607         /* Complete "SET TRANSACTION" */
1608         else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
1609                           pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1610                          || (pg_strcasecmp(prev2_wd, "START") == 0
1611                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1612                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1613                                  && pg_strcasecmp(prev_wd, "WORK") == 0)
1614                          || (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1615                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1616                          || (pg_strcasecmp(prev4_wd, "SESSION") == 0
1617                                  && pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
1618                                  && pg_strcasecmp(prev2_wd, "AS") == 0
1619                                  && pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
1620         {
1621                 static const char *const my_list[] =
1622                 {"ISOLATION LEVEL", "READ", NULL};
1623
1624                 COMPLETE_WITH_LIST(my_list);
1625         }
1626         else if ((pg_strcasecmp(prev3_wd, "SET") == 0
1627                           || pg_strcasecmp(prev3_wd, "BEGIN") == 0
1628                           || pg_strcasecmp(prev3_wd, "START") == 0
1629                           || (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
1630                                   && pg_strcasecmp(prev3_wd, "AS") == 0))
1631                          && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
1632                                  || pg_strcasecmp(prev2_wd, "WORK") == 0)
1633                          && pg_strcasecmp(prev_wd, "ISOLATION") == 0)
1634                 COMPLETE_WITH_CONST("LEVEL");
1635         else if ((pg_strcasecmp(prev4_wd, "SET") == 0
1636                           || pg_strcasecmp(prev4_wd, "BEGIN") == 0
1637                           || pg_strcasecmp(prev4_wd, "START") == 0
1638                           || pg_strcasecmp(prev4_wd, "AS") == 0)
1639                          && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
1640                                  || pg_strcasecmp(prev3_wd, "WORK") == 0)
1641                          && pg_strcasecmp(prev2_wd, "ISOLATION") == 0
1642                          && pg_strcasecmp(prev_wd, "LEVEL") == 0)
1643         {
1644                 static const char *const my_list[] =
1645                 {"READ", "REPEATABLE", "SERIALIZABLE", NULL};
1646
1647                 COMPLETE_WITH_LIST(my_list);
1648         }
1649         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1650                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1651                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1652                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1653                          pg_strcasecmp(prev_wd, "READ") == 0)
1654         {
1655                 static const char *const my_list[] =
1656                 {"UNCOMMITTED", "COMMITTED", NULL};
1657
1658                 COMPLETE_WITH_LIST(my_list);
1659         }
1660         else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1661                           pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1662                          pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1663                          pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1664                          pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
1665                 COMPLETE_WITH_CONST("READ");
1666         else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
1667                           pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
1668                           pg_strcasecmp(prev3_wd, "START") == 0 ||
1669                           pg_strcasecmp(prev3_wd, "AS") == 0) &&
1670                          (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
1671                           pg_strcasecmp(prev2_wd, "WORK") == 0) &&
1672                          pg_strcasecmp(prev_wd, "READ") == 0)
1673         {
1674                 static const char *const my_list[] =
1675                 {"ONLY", "WRITE", NULL};
1676
1677                 COMPLETE_WITH_LIST(my_list);
1678         }
1679         /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1680         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1681                          pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1682         {
1683                 static const char *const constraint_list[] =
1684                 {"DEFERRED", "IMMEDIATE", NULL};
1685
1686                 COMPLETE_WITH_LIST(constraint_list);
1687         }
1688         /* Complete SET ROLE */
1689         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1690                          pg_strcasecmp(prev_wd, "ROLE") == 0)
1691                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1692         /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1693         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1694                          pg_strcasecmp(prev_wd, "SESSION") == 0)
1695         {
1696                 static const char *const my_list[] =
1697                 {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
1698
1699                 COMPLETE_WITH_LIST(my_list);
1700         }
1701         /* Complete SET SESSION AUTHORIZATION with username */
1702         else if (pg_strcasecmp(prev3_wd, "SET") == 0
1703                          && pg_strcasecmp(prev2_wd, "SESSION") == 0
1704                          && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1705                 COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
1706         /* Complete RESET SESSION with AUTHORIZATION */
1707         else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
1708                          pg_strcasecmp(prev_wd, "SESSION") == 0)
1709                 COMPLETE_WITH_CONST("AUTHORIZATION");
1710         /* Complete SET <var> with "TO" */
1711         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1712                          pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
1713                          pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
1714                          pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
1715                 COMPLETE_WITH_CONST("TO");
1716         /* Suggest possible variable values */
1717         else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1718                          (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1719         {
1720                 if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
1721                 {
1722                         static const char *const my_list[] =
1723                         {"ISO", "SQL", "Postgres", "German",
1724                                 "YMD", "DMY", "MDY",
1725                                 "US", "European", "NonEuropean",
1726                         "DEFAULT", NULL};
1727
1728                         COMPLETE_WITH_LIST(my_list);
1729                 }
1730                 else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
1731                 {
1732                         static const char *const my_list[] =
1733                         {"ON", "OFF", "DEFAULT", NULL};
1734
1735                         COMPLETE_WITH_LIST(my_list);
1736                 }
1737                 else
1738                 {
1739                         static const char *const my_list[] =
1740                         {"DEFAULT", NULL};
1741
1742                         COMPLETE_WITH_LIST(my_list);
1743                 }
1744         }
1745
1746 /* START TRANSACTION */
1747         else if (pg_strcasecmp(prev_wd, "START") == 0)
1748                 COMPLETE_WITH_CONST("TRANSACTION");
1749
1750 /* TRUNCATE */
1751         else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
1752                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1753
1754 /* UNLISTEN */
1755         else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
1756                 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 '*'");
1757
1758 /* UPDATE */
1759         /* If prev. word is UPDATE suggest a list of tables */
1760         else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
1761                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1762         /* Complete UPDATE <table> with "SET" */
1763         else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
1764                 COMPLETE_WITH_CONST("SET");
1765
1766         /*
1767          * If the previous word is SET (and it wasn't caught above as the _first_
1768          * word) the word before it was (hopefully) a table name and we'll now
1769          * make a list of attributes.
1770          */
1771         else if (pg_strcasecmp(prev_wd, "SET") == 0)
1772                 COMPLETE_WITH_ATTR(prev2_wd, "");
1773
1774 /* UPDATE xx SET yy = */
1775         else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1776                          pg_strcasecmp(prev4_wd, "UPDATE") == 0)
1777                 COMPLETE_WITH_CONST("=");
1778
1779 /*
1780  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
1781  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
1782  */
1783         else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
1784                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1785                                                                    " UNION SELECT 'FULL'"
1786                                                                    " UNION SELECT 'FREEZE'"
1787                                                                    " UNION SELECT 'ANALYZE'"
1788                                                                    " UNION SELECT 'VERBOSE'");
1789         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1790                          (pg_strcasecmp(prev_wd, "FULL") == 0 ||
1791                           pg_strcasecmp(prev_wd, "FREEZE") == 0))
1792                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1793                                                                    " UNION SELECT 'ANALYZE'"
1794                                                                    " UNION SELECT 'VERBOSE'");
1795         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1796                          pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1797                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1798                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1799                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1800                                                                    " UNION SELECT 'VERBOSE'");
1801         else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1802                          pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1803                          (pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1804                           pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1805                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1806                                                                    " UNION SELECT 'ANALYZE'");
1807         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1808                          pg_strcasecmp(prev_wd, "VERBOSE") == 0)
1809                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1810                                                                    " UNION SELECT 'ANALYZE'");
1811         else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1812                          pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1813                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1814                                                                    " UNION SELECT 'VERBOSE'");
1815         else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1816                           pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
1817                          (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1818                           pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
1819                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1820
1821 /* ANALYZE */
1822         /* If the previous word is ANALYZE, produce list of tables */
1823         else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1824                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1825
1826 /* WHERE */
1827         /* Simple case of the word before the where being the table name */
1828         else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
1829                 COMPLETE_WITH_ATTR(prev2_wd, "");
1830
1831 /* ... FROM ... */
1832 /* TODO: also include SRF ? */
1833         else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
1834                          pg_strcasecmp(prev3_wd, "COPY") != 0 &&
1835                          pg_strcasecmp(prev3_wd, "\\copy") != 0)
1836                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1837
1838
1839 /* Backslash commands */
1840 /* TODO:  \dc \dd \dl */
1841         else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1842                 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1843         else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1844                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
1845         else if (strcmp(prev_wd, "\\da") == 0)
1846                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
1847         else if (strcmp(prev_wd, "\\db") == 0)
1848                 COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1849         else if (strcmp(prev_wd, "\\dD") == 0)
1850                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
1851         else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1852                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1853         else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1854                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1855         else if (strcmp(prev_wd, "\\dn") == 0)
1856                 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1857         else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1858                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1859         else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1860                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
1861         else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1862                 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1863         else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1864                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1865         else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1866                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
1867         else if (strcmp(prev_wd, "\\du") == 0)
1868                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1869         else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1870                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
1871         else if (strcmp(prev_wd, "\\encoding") == 0)
1872                 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
1873         else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1874                 COMPLETE_WITH_LIST(sql_commands);
1875         else if (strcmp(prev_wd, "\\password") == 0)
1876                 COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1877         else if (strcmp(prev_wd, "\\pset") == 0)
1878         {
1879                 static const char *const my_list[] =
1880                 {"format", "border", "expanded",
1881                         "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1882                 "recordsep", NULL};
1883
1884                 COMPLETE_WITH_LIST(my_list);
1885         }
1886         else if (strcmp(prev_wd, "\\cd") == 0 ||
1887                          strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1888                          strcmp(prev_wd, "\\g") == 0 ||
1889                   strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1890                          strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1891                          strcmp(prev_wd, "\\s") == 0 ||
1892                          strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1893                 )
1894                 matches = completion_matches(text, filename_completion_function);
1895
1896
1897         /*
1898          * Finally, we look through the list of "things", such as TABLE, INDEX and
1899          * check if that was the previous word. If so, execute the query to get a
1900          * list of them.
1901          */
1902         else
1903         {
1904                 int                     i;
1905
1906                 for (i = 0; words_after_create[i].name; i++)
1907                 {
1908                         if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
1909                         {
1910                                 if (words_after_create[i].query)
1911                                         COMPLETE_WITH_QUERY(words_after_create[i].query);
1912                                 else if (words_after_create[i].squery)
1913                                         COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
1914                                                                                            NULL);
1915                                 break;
1916                         }
1917                 }
1918         }
1919
1920         /*
1921          * If we still don't have anything to match we have to fabricate some sort
1922          * of default list. If we were to just return NULL, readline automatically
1923          * attempts filename completion, and that's usually no good.
1924          */
1925         if (matches == NULL)
1926         {
1927                 COMPLETE_WITH_CONST("");
1928 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1929                 rl_completion_append_character = '\0';
1930 #endif
1931         }
1932
1933         /* free storage */
1934         free(prev_wd);
1935         free(prev2_wd);
1936         free(prev3_wd);
1937         free(prev4_wd);
1938         free(prev5_wd);
1939
1940         /* Return our Grand List O' Matches */
1941         return matches;
1942 }
1943
1944
1945
1946 /* GENERATOR FUNCTIONS
1947
1948    These functions do all the actual work of completing the input. They get
1949    passed the text so far and the count how many times they have been called so
1950    far with the same text.
1951    If you read the above carefully, you'll see that these don't get called
1952    directly but through the readline interface.
1953    The return value is expected to be the full completion of the text, going
1954    through a list each time, or NULL if there are no more matches. The string
1955    will be free()'d by readline, so you must run it through strdup() or
1956    something of that sort.
1957 */
1958
1959 /* This one gives you one from a list of things you can put after CREATE
1960    as defined above.
1961 */
1962 static char *
1963 create_command_generator(const char *text, int state)
1964 {
1965         static int      list_index,
1966                                 string_length;
1967         const char *name;
1968
1969         /* If this is the first time for this completion, init some values */
1970         if (state == 0)
1971         {
1972                 list_index = 0;
1973                 string_length = strlen(text);
1974         }
1975
1976         /* find something that matches */
1977         while ((name = words_after_create[list_index++].name))
1978                 if (pg_strncasecmp(name, text, string_length) == 0)
1979                         return pg_strdup(name);
1980
1981         /* if nothing matches, return NULL */
1982         return NULL;
1983 }
1984
1985 /*
1986  * This function gives you a list of things you can put after a DROP command.
1987  * Very similar to create_command_generator, but has an additional entry for
1988  * OWNED BY.  (We do it this way in order not to duplicate the
1989  * words_after_create list.)
1990  */
1991 static char *
1992 drop_command_generator(const char *text, int state)
1993 {
1994         static int      list_index,
1995                                 string_length;
1996         const char *name;
1997
1998         if (state == 0)
1999         {
2000                 /* If this is the first time for this completion, init some values */
2001                 list_index = 0;
2002                 string_length = strlen(text);
2003
2004                 /*
2005                  * DROP can be followed by "OWNED BY", which is not found in the list
2006                  * for CREATE matches, so make it the first state. (We do not make it
2007                  * the last state because it would be more difficult to detect when we
2008                  * have to return NULL instead.)
2009                  *
2010                  * Make sure we advance to the next state.
2011                  */
2012                 list_index++;
2013                 if (pg_strncasecmp("OWNED", text, string_length) == 0)
2014                         return pg_strdup("OWNED");
2015         }
2016
2017         /*
2018          * In subsequent attempts, try to complete with the same items we use for
2019          * CREATE
2020          */
2021         while ((name = words_after_create[list_index++ - 1].name))
2022         {
2023                 if (pg_strncasecmp(name, text, string_length) == 0)
2024                         return pg_strdup(name);
2025         }
2026
2027         /* if nothing matches, return NULL */
2028         return NULL;
2029 }
2030
2031 /* The following two functions are wrappers for _complete_from_query */
2032
2033 static char *
2034 complete_from_query(const char *text, int state)
2035 {
2036         return _complete_from_query(0, text, state);
2037 }
2038
2039 static char *
2040 complete_from_schema_query(const char *text, int state)
2041 {
2042         return _complete_from_query(1, text, state);
2043 }
2044
2045
2046 /* This creates a list of matching things, according to a query pointed to
2047    by completion_charp.
2048    The query can be one of two kinds:
2049    - A simple query which must contain a %d and a %s, which will be replaced
2050    by the string length of the text and the text itself. The query may also
2051    have another %s in it, which will be replaced by the value of
2052    completion_info_charp.
2053          or:
2054    - A schema query used for completion of both schema and relation names;
2055    these are more complex and must contain in the following order:
2056          %d %s %d %s %d %s %s %d %s
2057    where %d is the string length of the text and %s the text itself.
2058
2059    It is assumed that strings should be escaped to become SQL literals
2060    (that is, what is in the query is actually ... '%s' ...)
2061
2062    See top of file for examples of both kinds of query.
2063 */
2064
2065 static char *
2066 _complete_from_query(int is_schema_query, const char *text, int state)
2067 {
2068         static int      list_index,
2069                                 string_length;
2070         static PGresult *result = NULL;
2071
2072         /*
2073          * If this is the first time for this completion, we fetch a list of our
2074          * "things" from the backend.
2075          */
2076         if (state == 0)
2077         {
2078                 PQExpBufferData query_buffer;
2079                 char       *e_text;
2080                 char       *e_info_charp;
2081
2082                 list_index = 0;
2083                 string_length = strlen(text);
2084
2085                 /* Free any prior result */
2086                 PQclear(result);
2087                 result = NULL;
2088
2089                 /* Set up suitably-escaped copies of textual inputs */
2090                 e_text = pg_malloc(string_length * 2 + 1);
2091                 PQescapeString(e_text, text, string_length);
2092
2093                 if (completion_info_charp)
2094                 {
2095                         size_t          charp_len;
2096
2097                         charp_len = strlen(completion_info_charp);
2098                         e_info_charp = pg_malloc(charp_len * 2 + 1);
2099                         PQescapeString(e_info_charp, completion_info_charp,
2100                                                    charp_len);
2101                 }
2102                 else
2103                         e_info_charp = NULL;
2104
2105                 initPQExpBuffer(&query_buffer);
2106
2107                 if (is_schema_query)
2108                 {
2109                         /* completion_squery gives us the pieces to assemble */
2110                         const char *qualresult = completion_squery->qualresult;
2111
2112                         if (qualresult == NULL)
2113                                 qualresult = completion_squery->result;
2114
2115                         /* Get unqualified names matching the input-so-far */
2116                         appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
2117                                                           completion_squery->result,
2118                                                           completion_squery->catname);
2119                         if (completion_squery->selcondition)
2120                                 appendPQExpBuffer(&query_buffer, "%s AND ",
2121                                                                   completion_squery->selcondition);
2122                         appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
2123                                                           completion_squery->result,
2124                                                           string_length, e_text);
2125                         appendPQExpBuffer(&query_buffer, " AND %s",
2126                                                           completion_squery->viscondition);
2127
2128                         /*
2129                          * When fetching relation names, suppress system catalogs unless
2130                          * the input-so-far begins with "pg_".  This is a compromise
2131                          * between not offering system catalogs for completion at all, and
2132                          * having them swamp the result when the input is just "p".
2133                          */
2134                         if (strcmp(completion_squery->catname,
2135                                            "pg_catalog.pg_class c") == 0 &&
2136                                 strncmp(text, "pg_", 3) !=0)
2137                         {
2138                                 appendPQExpBuffer(&query_buffer,
2139                                                                   " AND c.relnamespace <> (SELECT oid FROM"
2140                                    " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
2141                         }
2142
2143                         /*
2144                          * Add in matching schema names, but only if there is more than
2145                          * one potential match among schema names.
2146                          */
2147                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
2148                                                    "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
2149                                                           "FROM pg_catalog.pg_namespace n "
2150                                                           "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
2151                                                           string_length, e_text);
2152                         appendPQExpBuffer(&query_buffer,
2153                                                           " AND (SELECT pg_catalog.count(*)"
2154                                                           " FROM pg_catalog.pg_namespace"
2155                         " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2156                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
2157                                                           string_length, e_text);
2158
2159                         /*
2160                          * Add in matching qualified names, but only if there is exactly
2161                          * one schema matching the input-so-far.
2162                          */
2163                         appendPQExpBuffer(&query_buffer, "\nUNION\n"
2164                                          "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
2165                                                           "FROM %s, pg_catalog.pg_namespace n "
2166                                                           "WHERE %s = n.oid AND ",
2167                                                           qualresult,
2168                                                           completion_squery->catname,
2169                                                           completion_squery->namespace);
2170                         if (completion_squery->selcondition)
2171                                 appendPQExpBuffer(&query_buffer, "%s AND ",
2172                                                                   completion_squery->selcondition);
2173                         appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
2174                                                           qualresult,
2175                                                           string_length, e_text);
2176
2177                         /*
2178                          * This condition exploits the single-matching-schema rule to
2179                          * speed up the query
2180                          */
2181                         appendPQExpBuffer(&query_buffer,
2182                         " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
2183                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
2184                                                           string_length, e_text);
2185                         appendPQExpBuffer(&query_buffer,
2186                                                           " AND (SELECT pg_catalog.count(*)"
2187                                                           " FROM pg_catalog.pg_namespace"
2188                         " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
2189                                                           " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
2190                                                           string_length, e_text);
2191
2192                         /* If an addon query was provided, use it */
2193                         if (completion_charp)
2194                                 appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
2195                 }
2196                 else
2197                 {
2198                         /* completion_charp is an sprintf-style format string */
2199                         appendPQExpBuffer(&query_buffer, completion_charp,
2200                                                           string_length, e_text, e_info_charp);
2201                 }
2202
2203                 /* Limit the number of records in the result */
2204                 appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
2205                                                   completion_max_records);
2206
2207                 result = exec_query(query_buffer.data);
2208
2209                 termPQExpBuffer(&query_buffer);
2210                 free(e_text);
2211                 if (e_info_charp)
2212                         free(e_info_charp);
2213         }
2214
2215         /* Find something that matches */
2216         if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
2217         {
2218                 const char *item;
2219
2220                 while (list_index < PQntuples(result) &&
2221                            (item = PQgetvalue(result, list_index++, 0)))
2222                         if (pg_strncasecmp(text, item, string_length) == 0)
2223                                 return pg_strdup(item);
2224         }
2225
2226         /* If nothing matches, free the db structure and return null */
2227         PQclear(result);
2228         result = NULL;
2229         return NULL;
2230 }
2231
2232
2233 /* This function returns in order one of a fixed, NULL pointer terminated list
2234    of strings (if matching). This can be used if there are only a fixed number
2235    SQL words that can appear at certain spot.
2236 */
2237 static char *
2238 complete_from_list(const char *text, int state)
2239 {
2240         static int      string_length,
2241                                 list_index,
2242                                 matches;
2243         static bool casesensitive;
2244         const char *item;
2245
2246         /* need to have a list */
2247         psql_assert(completion_charpp);
2248
2249         /* Initialization */
2250         if (state == 0)
2251         {
2252                 list_index = 0;
2253                 string_length = strlen(text);
2254                 casesensitive = true;
2255                 matches = 0;
2256         }
2257
2258         while ((item = completion_charpp[list_index++]))
2259         {
2260                 /* First pass is case sensitive */
2261                 if (casesensitive && strncmp(text, item, string_length) == 0)
2262                 {
2263                         matches++;
2264                         return pg_strdup(item);
2265                 }
2266
2267                 /* Second pass is case insensitive, don't bother counting matches */
2268                 if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
2269                         return pg_strdup(item);
2270         }
2271
2272         /*
2273          * No matches found. If we're not case insensitive already, lets switch to
2274          * being case insensitive and try again
2275          */
2276         if (casesensitive && matches == 0)
2277         {
2278                 casesensitive = false;
2279                 list_index = 0;
2280                 state++;
2281                 return complete_from_list(text, state);
2282         }
2283
2284         /* If no more matches, return null. */
2285         return NULL;
2286 }
2287
2288
2289 /* This function returns one fixed string the first time even if it doesn't
2290    match what's there, and nothing the second time. This should be used if there
2291    is only one possibility that can appear at a certain spot, so misspellings
2292    will be overwritten.
2293    The string to be passed must be in completion_charp.
2294 */
2295 static char *
2296 complete_from_const(const char *text, int state)
2297 {
2298         (void) text;                            /* We don't care about what was entered
2299                                                                  * already. */
2300
2301         psql_assert(completion_charp);
2302         if (state == 0)
2303                 return pg_strdup(completion_charp);
2304         else
2305                 return NULL;
2306 }
2307
2308
2309
2310 /* HELPER FUNCTIONS */
2311
2312
2313 /*
2314  * Execute a query and report any errors. This should be the preferred way of
2315  * talking to the database in this file.
2316  */
2317 static PGresult *
2318 exec_query(const char *query)
2319 {
2320         PGresult   *result;
2321
2322         if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
2323                 return NULL;
2324
2325         result = PQexec(pset.db, query);
2326
2327         if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
2328         {
2329 #if 0
2330                 psql_error("tab completion: %s failed - %s\n",
2331                                    query, PQresStatus(PQresultStatus(result)));
2332 #endif
2333                 PQclear(result);
2334                 result = NULL;
2335         }
2336
2337         return result;
2338 }
2339
2340
2341
2342 /*
2343  * Return the word (space delimited) before point. Set skip > 0 to
2344  * skip that many words; e.g. skip=1 finds the word before the
2345  * previous one. Return value is NULL or a malloc'ed string.
2346  */
2347 static char *
2348 previous_word(int point, int skip)
2349 {
2350         int                     i,
2351                                 start = 0,
2352                                 end = -1,
2353                                 inquotes = 0;
2354         char       *s;
2355
2356         while (skip-- >= 0)
2357         {
2358                 /* first we look for a space before the current word */
2359                 for (i = point; i >= 0; i--)
2360                         if (rl_line_buffer[i] == ' ')
2361                                 break;
2362
2363                 /* now find the first non-space which then constitutes the end */
2364                 for (; i >= 0; i--)
2365                         if (rl_line_buffer[i] != ' ')
2366                         {
2367                                 end = i;
2368                                 break;
2369                         }
2370
2371                 /*
2372                  * If no end found we return null, because there is no word before the
2373                  * point
2374                  */
2375                 if (end == -1)
2376                         return NULL;
2377
2378                 /*
2379                  * Otherwise we now look for the start. The start is either the last
2380                  * character before any space going backwards from the end, or it's
2381                  * simply character 0
2382                  */
2383                 for (start = end; start > 0; start--)
2384                 {
2385                         if (rl_line_buffer[start] == '"')
2386                                 inquotes = !inquotes;
2387                         if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
2388                                 break;
2389                 }
2390
2391                 point = start;
2392         }
2393
2394         /* make a copy */
2395         s = pg_malloc(end - start + 2);
2396         strlcpy(s, &rl_line_buffer[start], end - start + 2);
2397
2398         return s;
2399 }
2400
2401 /* Find the parenthesis after the last word */
2402
2403
2404 static int
2405 find_open_parenthesis(int end)
2406 {
2407         int                     i = end - 1;
2408
2409         while ((rl_line_buffer[i] != ' ') && (i >= 0))
2410         {
2411                 if (rl_line_buffer[i] == '(')
2412                         return 1;
2413                 i--;
2414         }
2415         while ((rl_line_buffer[i] == ' ') && (i >= 0))
2416         {
2417                 i--;
2418         }
2419         if (rl_line_buffer[i] == '(')
2420         {
2421                 return 1;
2422         }
2423         return 0;
2424
2425 }
2426
2427 #if 0
2428
2429 /*
2430  * Surround a string with single quotes. This works for both SQL and
2431  * psql internal. Currently disabled because it is reported not to
2432  * cooperate with certain versions of readline.
2433  */
2434 static char *
2435 quote_file_name(char *text, int match_type, char *quote_pointer)
2436 {
2437         char       *s;
2438         size_t          length;
2439
2440         (void) quote_pointer;           /* not used */
2441
2442         length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
2443         s = pg_malloc(length);
2444         s[0] = '\'';
2445         strcpy(s + 1, text);
2446         if (match_type == SINGLE_MATCH)
2447                 s[length - 2] = '\'';
2448         s[length - 1] = '\0';
2449         return s;
2450 }
2451
2452
2453
2454 static char *
2455 dequote_file_name(char *text, char quote_char)
2456 {
2457         char       *s;
2458         size_t          length;
2459
2460         if (!quote_char)
2461                 return pg_strdup(text);
2462
2463         length = strlen(text);
2464         s = pg_malloc(length - 2 + 1);
2465         strlcpy(s, text +1, length - 2 + 1);
2466
2467         return s;
2468 }
2469 #endif   /* 0 */
2470
2471 #endif   /* USE_READLINE */