1
typedef struct SchemaQuery
4
* Name of catalog or catalogs to be queried, with alias, eg.
5
* "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
10
* Selection condition --- only rows meeting this condition are candidates
11
* to display. If catname mentions multiple tables, include the necessary
12
* join condition here. For example, "c.relkind = 'r'". Write NULL (not
13
* an empty string) if not needed.
15
const char *selcondition;
18
* Visibility condition --- which rows are visible without schema
19
* qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
21
const char *viscondition;
24
* Namespace --- name of field to join to pg_namespace.oid. For example,
27
const char *namespace;
30
* Result --- the appropriately-quoted name to return, in the case of an
31
* unqualified name. For example, "pg_catalog.quote_ident(c.relname)".
36
* In some cases a different result must be used for qualified names.
37
* Enter that here, or write NULL if result can be used.
39
const char *qualresult;
44
* Communication variables set by COMPLETE_WITH_FOO macros and then used by
45
* the completion callback functions. Ugly but there is no better way.
47
static const char *completion_charp; /* to pass a string */
48
static const char *const * completion_charpp; /* to pass a list of strings */
49
static const char *completion_info_charp; /* to pass a second string */
52
* Assembly instructions for schema queries
55
static const SchemaQuery Query_for_list_of_aggregates = {
57
"pg_catalog.pg_proc p",
61
"pg_catalog.pg_function_is_visible(p.oid)",
65
"pg_catalog.quote_ident(p.proname)",
70
static const SchemaQuery Query_for_list_of_datatypes = {
72
"pg_catalog.pg_type t",
73
/* selcondition --- ignore table rowtypes and array types */
75
" OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
76
"AND t.typname !~ '^_'",
78
"pg_catalog.pg_type_is_visible(t.oid)",
82
"pg_catalog.format_type(t.oid, NULL)",
84
"pg_catalog.quote_ident(t.typname)"
87
static const SchemaQuery Query_for_list_of_domains = {
89
"pg_catalog.pg_type t",
93
"pg_catalog.pg_type_is_visible(t.oid)",
97
"pg_catalog.quote_ident(t.typname)",
102
static const SchemaQuery Query_for_list_of_functions = {
104
"pg_catalog.pg_proc p",
108
"pg_catalog.pg_function_is_visible(p.oid)",
112
"pg_catalog.quote_ident(p.proname)",
117
static const SchemaQuery Query_for_list_of_indexes = {
119
"pg_catalog.pg_class c",
121
"c.relkind IN ('i')",
123
"pg_catalog.pg_table_is_visible(c.oid)",
127
"pg_catalog.quote_ident(c.relname)",
132
static const SchemaQuery Query_for_list_of_sequences = {
134
"pg_catalog.pg_class c",
136
"c.relkind IN ('S')",
138
"pg_catalog.pg_table_is_visible(c.oid)",
142
"pg_catalog.quote_ident(c.relname)",
147
static const SchemaQuery Query_for_list_of_tables = {
149
"pg_catalog.pg_class c",
151
"c.relkind IN ('r')",
153
"pg_catalog.pg_table_is_visible(c.oid)",
157
"pg_catalog.quote_ident(c.relname)",
162
static const SchemaQuery Query_for_list_of_tisv = {
164
"pg_catalog.pg_class c",
166
"c.relkind IN ('r', 'i', 'S', 'v')",
168
"pg_catalog.pg_table_is_visible(c.oid)",
172
"pg_catalog.quote_ident(c.relname)",
177
static const SchemaQuery Query_for_list_of_tsv = {
179
"pg_catalog.pg_class c",
181
"c.relkind IN ('r', 'S', 'v')",
183
"pg_catalog.pg_table_is_visible(c.oid)",
187
"pg_catalog.quote_ident(c.relname)",
192
static const SchemaQuery Query_for_list_of_views = {
194
"pg_catalog.pg_class c",
196
"c.relkind IN ('v')",
198
"pg_catalog.pg_table_is_visible(c.oid)",
202
"pg_catalog.quote_ident(c.relname)",
209
* Queries to get lists of names of various kinds of things, possibly
210
* restricted to names matching a partially entered name. In these queries,
211
* %s will be replaced by the text entered so far (suitably escaped to
212
* become a SQL literal string). %d will be replaced by the length of the
213
* string (in unescaped form). A second %s, if present, will be replaced
214
* by a suitably-escaped version of the string provided in
215
* completion_info_charp.
217
* Beware that the allowed sequences of %s and %d are determined by
218
* _complete_from_query().
221
#define Query_for_list_of_attributes \
222
"SELECT pg_catalog.quote_ident(attname) "\
223
" FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
224
" WHERE c.oid = a.attrelid "\
225
" AND a.attnum > 0 "\
226
" AND NOT a.attisdropped "\
227
" AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
228
" AND pg_catalog.quote_ident(relname)='%s' "\
229
" AND pg_catalog.pg_table_is_visible(c.oid)"
231
#define Query_for_list_of_databases \
232
"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
233
" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
235
#define Query_for_list_of_tablespaces \
236
"SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
237
" WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
239
#define Query_for_list_of_encodings \
240
" SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
241
" FROM pg_catalog.pg_conversion "\
242
" WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
244
#define Query_for_list_of_languages \
245
"SELECT pg_catalog.quote_ident(lanname) "\
246
" FROM pg_language "\
247
" WHERE lanname != 'internal' "\
248
" AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
250
#define Query_for_list_of_schemas \
251
"SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
252
" WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
254
#define Query_for_list_of_set_vars \
256
" (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
257
" WHERE context IN ('user', 'superuser') "\
258
" UNION ALL SELECT 'constraints' "\
259
" UNION ALL SELECT 'transaction' "\
260
" UNION ALL SELECT 'session' "\
261
" UNION ALL SELECT 'role' "\
262
" UNION ALL SELECT 'all') ss "\
263
" WHERE substring(name,1,%d)='%s'"
265
#define Query_for_list_of_show_vars \
267
" (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
268
" UNION ALL SELECT 'session authorization' "\
269
" UNION ALL SELECT 'all') ss "\
270
" WHERE substring(name,1,%d)='%s'"
272
#define Query_for_list_of_system_relations \
273
"SELECT pg_catalog.quote_ident(relname) "\
274
" FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
275
" WHERE c.relkind IN ('r', 'v', 's', 'S') "\
276
" AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
277
" AND c.relnamespace = n.oid "\
278
" AND n.nspname = 'pg_catalog'"
280
#define Query_for_list_of_roles \
281
" SELECT pg_catalog.quote_ident(rolname) "\
282
" FROM pg_catalog.pg_roles "\
283
" WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
285
#define Query_for_list_of_grant_roles \
286
" SELECT pg_catalog.quote_ident(rolname) "\
287
" FROM pg_catalog.pg_roles "\
288
" WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
289
" UNION ALL SELECT 'PUBLIC'"
291
/* the silly-looking length condition is just to eat up the current word */
292
#define Query_for_table_owning_index \
293
"SELECT pg_catalog.quote_ident(c1.relname) "\
294
" FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
295
" WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
296
" and (%d = length('%s'))"\
297
" and pg_catalog.quote_ident(c2.relname)='%s'"\
298
" and pg_catalog.pg_table_is_visible(c2.oid)"
300
/* the silly-looking length condition is just to eat up the current word */
301
#define Query_for_index_of_table \
302
"SELECT pg_catalog.quote_ident(c2.relname) "\
303
" FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
304
" WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
305
" and (%d = length('%s'))"\
306
" and pg_catalog.quote_ident(c1.relname)='%s'"\
307
" and pg_catalog.pg_table_is_visible(c2.oid)"
309
/* the silly-looking length condition is just to eat up the current word */
310
#define Query_for_list_of_tables_for_trigger \
311
"SELECT pg_catalog.quote_ident(relname) "\
312
" FROM pg_catalog.pg_class"\
313
" WHERE (%d = length('%s'))"\
315
" (SELECT tgrelid FROM pg_catalog.pg_trigger "\
316
" WHERE pg_catalog.quote_ident(tgname)='%s')"
319
* This is a list of all "things" in Pgsql, which can show up after CREATE or
320
* DROP; and there is also a query to get a list of them.
326
const char *query; /* simple query, or NULL */
327
const SchemaQuery *squery; /* schema query, or NULL */
330
static const pgsql_thing_t words_after_create[] = {
331
{"AGGREGATE", NULL, &Query_for_list_of_aggregates},
332
{"CAST", NULL, NULL}, /* Casts have complex structures for names, so
336
* CREATE CONSTRAINT TRIGGER is not supported here because it is designed
337
* to be used only by pg_dump.
339
{"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
340
{"DATABASE", Query_for_list_of_databases},
341
{"DOMAIN", NULL, &Query_for_list_of_domains},
342
{"FUNCTION", NULL, &Query_for_list_of_functions},
343
{"GROUP", Query_for_list_of_roles},
344
{"LANGUAGE", Query_for_list_of_languages},
345
{"INDEX", NULL, &Query_for_list_of_indexes},
346
{"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
348
{"ROLE", Query_for_list_of_roles},
349
{"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
350
{"SCHEMA", Query_for_list_of_schemas},
351
{"SEQUENCE", NULL, &Query_for_list_of_sequences},
352
{"TABLE", NULL, &Query_for_list_of_tables},
353
{"TABLESPACE", Query_for_list_of_tablespaces},
354
{"TEMP", NULL, NULL}, /* for CREATE TEMP TABLE ... */
355
{"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
356
{"TYPE", NULL, &Query_for_list_of_datatypes},
357
{"UNIQUE", NULL, NULL}, /* for CREATE UNIQUE INDEX ... */
358
{"USER", Query_for_list_of_roles},
359
{"VIEW", NULL, &Query_for_list_of_views},
360
{NULL, NULL, NULL} /* end of list */
364
/* The completion function. Acc. to readline spec this gets passed the text
365
entered to far and its start and end in the readline buffer. The return value
366
is some partially obscure list format that can be generated by the readline
367
libraries completion_matches() function, so we don't have to worry about it.
369
static char * psql_completion(char *text, int start, int end, void *dbptr)
371
/* This is the variable we'll return. */
372
char *matches = NULL;
374
/* These are going to contain some scannage of the input line. */
381
static const char *const sql_commands[] = {
382
"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
383
"COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE FROM", "DROP", "END", "EXECUTE",
384
"EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
385
"PREPARE", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", "SAVEPOINT",
386
"SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
389
static const char *const backslash_commands[] = {
390
"\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
391
"\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
392
"\\dg", "\\di", "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS",
393
"\\dt", "\\dT", "\\dv", "\\du",
394
"\\e", "\\echo", "\\encoding",
395
"\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
396
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
397
"\\o", "\\p", "\\password", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
398
"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
401
(void) end; /* not used */
403
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
404
rl_completion_append_character = ' ';
407
/* Clear a few things. */
408
completion_charp = NULL;
409
completion_charpp = NULL;
410
completion_info_charp = NULL;
413
* Scan the input line before our current position for the last four
414
* words. According to those we'll make some smart decisions on what the
415
* user is probably intending to type. TODO: Use strtokx() to do this.
417
prev_wd = previous_word(start, 0);
418
prev2_wd = previous_word(start, 1);
419
prev3_wd = previous_word(start, 2);
420
prev4_wd = previous_word(start, 3);
421
prev5_wd = previous_word(start, 4);
423
/* If a backslash command was started, continue */
425
COMPLETE_WITH_LIST(backslash_commands);
427
/* If no previous word, suggest one of the basic sql commands */
429
COMPLETE_WITH_LIST(sql_commands);
431
/* CREATE or DROP but not ALTER (TABLE|DOMAIN|GROUP) sth DROP */
432
/* complete with something you can create or drop */
433
else if (pg_strcasecmp(prev_wd, "CREATE") == 0 ||
434
(pg_strcasecmp(prev_wd, "DROP") == 0 &&
435
pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
436
pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
437
pg_strcasecmp(prev3_wd, "GROUP") != 0))
438
matches = complete_create_command(text);
443
* complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
444
* in ALTER TABLE sth ALTER
446
else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
447
pg_strcasecmp(prev3_wd, "TABLE") != 0)
449
static const char *const list_ALTER[] =
450
{"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
451
"GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SEQUENCE", "TABLE",
452
"TABLESPACE", "TRIGGER", "TYPE", "USER", NULL};
454
COMPLETE_WITH_LIST(list_ALTER);
456
/* ALTER AGGREGATE,FUNCTION <name> */
457
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
458
(pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
459
pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
461
static const char *const list_ALTERAGG[] =
462
{"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
464
COMPLETE_WITH_LIST(list_ALTERAGG);
467
/* ALTER CONVERSION,SCHEMA <name> */
468
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
469
(pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
470
pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
472
static const char *const list_ALTERGEN[] =
473
{"OWNER TO", "RENAME TO", NULL};
475
COMPLETE_WITH_LIST(list_ALTERGEN);
478
/* ALTER DATABASE <name> */
479
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
480
pg_strcasecmp(prev2_wd, "DATABASE") == 0)
482
static const char *const list_ALTERDATABASE[] =
483
{"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
485
COMPLETE_WITH_LIST(list_ALTERDATABASE);
488
/* ALTER INDEX <name> */
489
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
490
pg_strcasecmp(prev2_wd, "INDEX") == 0)
492
static const char *const list_ALTERINDEX[] =
493
{"SET TABLESPACE", "OWNER TO", "RENAME TO", NULL};
495
COMPLETE_WITH_LIST(list_ALTERINDEX);
498
/* ALTER LANGUAGE <name> */
499
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
500
pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
501
COMPLETE_WITH_CONST("RENAME TO");
503
/* ALTER USER,ROLE <name> */
504
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
505
(pg_strcasecmp(prev2_wd, "USER") == 0 ||
506
pg_strcasecmp(prev2_wd, "ROLE") == 0))
508
static const char *const list_ALTERUSER[] =
509
{"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
510
"NOCREATEUSER", "CREATEROLE", "NOCREATEROLE", "INHERIT", "NOINHERIT",
511
"LOGIN", "NOLOGIN", "CONNECTION LIMIT", "VALID UNTIL", "RENAME TO",
512
"SUPERUSER", "NOSUPERUSER", "SET", "RESET", NULL};
514
COMPLETE_WITH_LIST(list_ALTERUSER);
517
/* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
518
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
519
(pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
520
(pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
522
COMPLETE_WITH_CONST("PASSWORD");
524
/* ALTER DOMAIN <name> */
525
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
526
pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
528
static const char *const list_ALTERDOMAIN[] =
529
{"ADD", "DROP", "OWNER TO", "SET", NULL};
531
COMPLETE_WITH_LIST(list_ALTERDOMAIN);
533
/* ALTER DOMAIN <sth> DROP */
534
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
535
pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
536
pg_strcasecmp(prev_wd, "DROP") == 0)
538
static const char *const list_ALTERDOMAIN2[] =
539
{"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
541
COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
543
/* ALTER DOMAIN <sth> SET */
544
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
545
pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
546
pg_strcasecmp(prev_wd, "SET") == 0)
548
static const char *const list_ALTERDOMAIN3[] =
549
{"DEFAULT", "NOT NULL", "SCHEMA", NULL};
551
COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
553
/* ALTER SEQUENCE <name> */
554
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
555
pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
557
static const char *const list_ALTERSEQUENCE[] =
558
{"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
561
COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
563
/* ALTER SEQUENCE <name> NO */
564
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
565
pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
566
pg_strcasecmp(prev_wd, "NO") == 0)
568
static const char *const list_ALTERSEQUENCE2[] =
569
{"MINVALUE", "MAXVALUE", "CYCLE", NULL};
571
COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
573
/* ALTER TRIGGER <name>, add ON */
574
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
575
pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
576
COMPLETE_WITH_CONST("ON");
578
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
579
pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
581
completion_info_charp = prev2_wd;
582
COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
586
* If we have ALTER TRIGGER <sth> ON, then add the correct tablename
588
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
589
pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
590
pg_strcasecmp(prev_wd, "ON") == 0)
591
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
593
/* ALTER TRIGGER <name> ON <name> */
594
else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
595
pg_strcasecmp(prev2_wd, "ON") == 0)
596
COMPLETE_WITH_CONST("RENAME TO");
599
* If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
600
* RENAME, CLUSTER ON or OWNER
602
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
603
pg_strcasecmp(prev2_wd, "TABLE") == 0)
605
static const char *const list_ALTER2[] =
606
{"ADD", "ALTER", "CLUSTER ON", "DROP", "RENAME", "OWNER TO",
609
COMPLETE_WITH_LIST(list_ALTER2);
611
/* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
612
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
613
(pg_strcasecmp(prev_wd, "ALTER") == 0 ||
614
pg_strcasecmp(prev_wd, "RENAME") == 0))
615
COMPLETE_WITH_ATTR(prev2_wd);
617
/* ALTER TABLE xxx RENAME yyy */
618
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
619
pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
620
pg_strcasecmp(prev_wd, "TO") != 0)
621
COMPLETE_WITH_CONST("TO");
623
/* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
624
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
625
pg_strcasecmp(prev_wd, "DROP") == 0)
627
static const char *const list_TABLEDROP[] =
628
{"COLUMN", "CONSTRAINT", NULL};
630
COMPLETE_WITH_LIST(list_TABLEDROP);
632
/* If we have TABLE <sth> DROP COLUMN, provide list of columns */
633
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
634
pg_strcasecmp(prev2_wd, "DROP") == 0 &&
635
pg_strcasecmp(prev_wd, "COLUMN") == 0)
636
COMPLETE_WITH_ATTR(prev3_wd);
637
/* ALTER TABLE ALTER [COLUMN] <foo> */
638
else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
639
pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
640
(pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
641
pg_strcasecmp(prev2_wd, "ALTER") == 0))
643
/* DROP ... does not work well yet */
644
static const char *const list_COLUMNALTER[] =
645
{"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL",
646
"DROP NOT NULL", "SET STATISTICS", "SET STORAGE", NULL};
648
COMPLETE_WITH_LIST(list_COLUMNALTER);
650
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
651
pg_strcasecmp(prev_wd, "CLUSTER") == 0)
652
COMPLETE_WITH_CONST("ON");
653
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
654
pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
655
pg_strcasecmp(prev_wd, "ON") == 0)
657
completion_info_charp = prev3_wd;
658
COMPLETE_WITH_QUERY(Query_for_index_of_table);
660
/* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
661
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
662
pg_strcasecmp(prev_wd, "SET") == 0)
664
static const char *const list_TABLESET[] =
665
{"WITHOUT", "TABLESPACE", "SCHEMA", NULL};
667
COMPLETE_WITH_LIST(list_TABLESET);
669
/* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
670
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
671
pg_strcasecmp(prev2_wd, "SET") == 0 &&
672
pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
673
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
674
/* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
675
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
676
pg_strcasecmp(prev2_wd, "SET") == 0 &&
677
pg_strcasecmp(prev_wd, "WITHOUT") == 0)
679
static const char *const list_TABLESET2[] =
680
{"CLUSTER", "OIDS", NULL};
682
COMPLETE_WITH_LIST(list_TABLESET2);
684
/* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */
685
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
686
pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
688
static const char *const list_ALTERTSPC[] =
689
{"RENAME TO", "OWNER TO", NULL};
691
COMPLETE_WITH_LIST(list_ALTERTSPC);
693
/* complete ALTER TYPE <foo> with OWNER TO, SET SCHEMA */
694
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
695
pg_strcasecmp(prev2_wd, "TYPE") == 0)
697
static const char *const list_ALTERTYPE[] =
698
{"OWNER TO", "SET SCHEMA", NULL};
700
COMPLETE_WITH_LIST(list_ALTERTYPE);
702
/* complete ALTER GROUP <foo> */
703
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
704
pg_strcasecmp(prev2_wd, "GROUP") == 0)
706
static const char *const list_ALTERGROUP[] =
707
{"ADD USER", "DROP USER", "RENAME TO", NULL};
709
COMPLETE_WITH_LIST(list_ALTERGROUP);
711
/* complete ALTER GROUP <foo> ADD|DROP with USER */
712
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
713
pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
714
(pg_strcasecmp(prev_wd, "ADD") == 0 ||
715
pg_strcasecmp(prev_wd, "DROP") == 0))
716
COMPLETE_WITH_CONST("USER");
717
/* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
718
else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
719
(pg_strcasecmp(prev2_wd, "ADD") == 0 ||
720
pg_strcasecmp(prev2_wd, "DROP") == 0) &&
721
pg_strcasecmp(prev_wd, "USER") == 0)
722
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
724
/* BEGIN, END, ABORT */
725
else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
726
pg_strcasecmp(prev_wd, "END") == 0 ||
727
pg_strcasecmp(prev_wd, "ABORT") == 0)
729
static const char *const list_TRANS[] =
730
{"WORK", "TRANSACTION", NULL};
732
COMPLETE_WITH_LIST(list_TRANS);
735
else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
737
static const char *const list_COMMIT[] =
738
{"WORK", "TRANSACTION", "PREPARED", NULL};
740
COMPLETE_WITH_LIST(list_COMMIT);
742
/* RELEASE SAVEPOINT */
743
else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
744
COMPLETE_WITH_CONST("SAVEPOINT");
746
else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
748
static const char *const list_TRANS[] =
749
{"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
751
COMPLETE_WITH_LIST(list_TRANS);
756
* If the previous word is CLUSTER and not without produce list of
759
else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
760
pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
761
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
762
/* If we have CLUSTER <sth>, then add "ON" */
763
else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
764
pg_strcasecmp(prev_wd, "ON") != 0)
765
COMPLETE_WITH_CONST("ON");
768
* If we have CLUSTER <sth> ON, then add the correct tablename as well.
770
else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
771
pg_strcasecmp(prev_wd, "ON") == 0)
773
completion_info_charp = prev2_wd;
774
COMPLETE_WITH_QUERY(Query_for_table_owning_index);
778
else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
779
COMPLETE_WITH_CONST("ON");
780
else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
781
pg_strcasecmp(prev_wd, "ON") == 0)
783
static const char *const list_COMMENT[] =
784
{"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
785
"SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
786
"OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT", NULL};
788
COMPLETE_WITH_LIST(list_COMMENT);
790
else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
791
pg_strcasecmp(prev3_wd, "ON") == 0)
792
COMPLETE_WITH_CONST("IS");
797
* If we have COPY [BINARY] (which you'd have to type yourself), offer
798
* list of tables (Also cover the analogous backslash command)
800
else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
801
pg_strcasecmp(prev_wd, "\\copy") == 0 ||
802
(pg_strcasecmp(prev2_wd, "COPY") == 0 &&
803
pg_strcasecmp(prev_wd, "BINARY") == 0))
804
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
805
/* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
806
else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
807
pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
808
pg_strcasecmp(prev2_wd, "BINARY") == 0)
810
static const char *const list_FROMTO[] =
811
{"FROM", "TO", NULL};
813
COMPLETE_WITH_LIST(list_FROMTO);
815
/* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
816
else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
817
pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
818
pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
819
(pg_strcasecmp(prev_wd, "FROM") == 0 ||
820
pg_strcasecmp(prev_wd, "TO") == 0))
821
matches = complete_filename();
823
/* Handle COPY|BINARY <sth> FROM|TO filename */
824
else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
825
pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
826
pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
827
(pg_strcasecmp(prev2_wd, "FROM") == 0 ||
828
pg_strcasecmp(prev2_wd, "TO") == 0))
830
static const char *const list_COPY[] =
831
{"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", NULL};
833
COMPLETE_WITH_LIST(list_COPY);
836
/* Handle COPY|BINARY <sth> FROM|TO filename CSV */
837
else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
838
(pg_strcasecmp(prev3_wd, "FROM") == 0 ||
839
pg_strcasecmp(prev3_wd, "TO") == 0))
841
static const char *const list_CSV[] =
842
{"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
844
COMPLETE_WITH_LIST(list_CSV);
847
/* CREATE DATABASE */
848
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
849
pg_strcasecmp(prev2_wd, "DATABASE") == 0)
851
static const char *const list_DATABASE[] =
852
{"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
855
COMPLETE_WITH_LIST(list_DATABASE);
859
/* First off we complete CREATE UNIQUE with "INDEX" */
860
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
861
pg_strcasecmp(prev_wd, "UNIQUE") == 0)
862
COMPLETE_WITH_CONST("INDEX");
863
/* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
864
else if (pg_strcasecmp(prev2_wd, "INDEX") == 0 &&
865
(pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
866
pg_strcasecmp(prev3_wd, "UNIQUE") == 0))
867
COMPLETE_WITH_CONST("ON");
868
/* Complete ... INDEX <name> ON with a list of tables */
869
else if (pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
870
pg_strcasecmp(prev_wd, "ON") == 0)
871
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
874
* Complete INDEX <name> ON <table> with a list of table columns (which
875
* should really be in parens)
877
else if (pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
878
pg_strcasecmp(prev2_wd, "ON") == 0)
880
if (find_open_parenthesis(end))
881
COMPLETE_WITH_ATTR(prev_wd);
883
COMPLETE_WITH_CONST("(");
885
else if (pg_strcasecmp(prev5_wd, "INDEX") == 0 &&
886
pg_strcasecmp(prev3_wd, "ON") == 0 &&
887
pg_strcasecmp(prev_wd, "(") == 0)
888
COMPLETE_WITH_ATTR(prev2_wd);
889
/* same if you put in USING */
890
else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
891
pg_strcasecmp(prev2_wd, "USING") == 0)
892
COMPLETE_WITH_ATTR(prev3_wd);
893
/* Complete USING with an index method */
894
else if (pg_strcasecmp(prev_wd, "USING") == 0)
896
static const char *const index_mth[] =
897
{"BTREE", "HASH", "GIST", NULL};
899
COMPLETE_WITH_LIST(index_mth);
903
/* Complete "CREATE RULE <sth>" with "AS" */
904
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
905
pg_strcasecmp(prev2_wd, "RULE") == 0)
906
COMPLETE_WITH_CONST("AS");
907
/* Complete "CREATE RULE <sth> AS with "ON" */
908
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
909
pg_strcasecmp(prev3_wd, "RULE") == 0 &&
910
pg_strcasecmp(prev_wd, "AS") == 0)
911
COMPLETE_WITH_CONST("ON");
912
/* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
913
else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
914
pg_strcasecmp(prev2_wd, "AS") == 0 &&
915
pg_strcasecmp(prev_wd, "ON") == 0)
917
static const char *const rule_events[] =
918
{"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
920
COMPLETE_WITH_LIST(rule_events);
922
/* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
923
else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
924
pg_strcasecmp(prev2_wd, "ON") == 0 &&
925
(toupper((unsigned char) prev_wd[4]) == 'T' ||
926
toupper((unsigned char) prev_wd[5]) == 'T'))
927
COMPLETE_WITH_CONST("TO");
928
/* Complete "AS ON <sth> TO" with a table name */
929
else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
930
pg_strcasecmp(prev3_wd, "ON") == 0 &&
931
pg_strcasecmp(prev_wd, "TO") == 0)
932
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
935
/* Complete CREATE TEMP with "TABLE" */
936
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
937
pg_strcasecmp(prev_wd, "TEMP") == 0)
938
COMPLETE_WITH_CONST("TABLE");
940
/* CREATE TABLESPACE */
941
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
942
pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
944
static const char *const list_CREATETABLESPACE[] =
945
{"OWNER", "LOCATION", NULL};
947
COMPLETE_WITH_LIST(list_CREATETABLESPACE);
949
/* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
950
else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
951
pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
952
pg_strcasecmp(prev2_wd, "OWNER") == 0)
954
COMPLETE_WITH_CONST("LOCATION");
958
/* complete CREATE TRIGGER <name> with BEFORE,AFTER */
959
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
960
pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
962
static const char *const list_CREATETRIGGER[] =
963
{"BEFORE", "AFTER", NULL};
965
COMPLETE_WITH_LIST(list_CREATETRIGGER);
967
/* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
968
else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
969
pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
970
(pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
971
pg_strcasecmp(prev2_wd, "AFTER") == 0))
973
static const char *const list_CREATETRIGGER2[] =
976
COMPLETE_WITH_LIST(list_CREATETRIGGER2);
979
/* CREATE ROLE,USER,GROUP */
980
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
981
(pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
982
pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
984
static const char *const list_CREATEROLE[] =
985
{"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
986
"ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOINHERIT", "NOLOGIN", "NOCREATEDB",
987
"NOCREATEROLE", "NOCREATEUSER", "NOSUPERUSER", "ROLE", "SUPERUSER", "SYSID",
988
"UNENCRYPTED", NULL};
990
COMPLETE_WITH_LIST(list_CREATEROLE);
994
* complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
997
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
998
(pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
999
pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1000
(pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1002
COMPLETE_WITH_CONST("PASSWORD");
1004
/* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1005
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1006
(pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1007
pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1008
pg_strcasecmp(prev_wd, "IN") == 0)
1010
static const char *const list_CREATEROLE3[] =
1011
{"GROUP", "ROLE", NULL};
1013
COMPLETE_WITH_LIST(list_CREATEROLE3);
1017
/* Complete CREATE VIEW <name> with AS */
1018
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1019
pg_strcasecmp(prev2_wd, "VIEW") == 0)
1020
COMPLETE_WITH_CONST("AS");
1021
/* Complete "CREATE VIEW <sth> AS with "SELECT" */
1022
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1023
pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1024
pg_strcasecmp(prev_wd, "AS") == 0)
1025
COMPLETE_WITH_CONST("SELECT");
1028
else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1030
static const char *const list_DECLARE[] =
1031
{"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1033
COMPLETE_WITH_LIST(list_DECLARE);
1036
else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1038
static const char *const list_DECLARECURSOR[] =
1039
{"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1041
COMPLETE_WITH_LIST(list_DECLARECURSOR);
1048
* Complete DELETE with FROM (only if the word before that is not "ON"
1049
* (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1051
else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1052
!(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1053
pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1054
pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1055
pg_strcasecmp(prev2_wd, "AFTER") == 0))
1056
COMPLETE_WITH_CONST("FROM");
1057
/* Complete DELETE FROM with a list of tables */
1058
else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1059
pg_strcasecmp(prev_wd, "FROM") == 0)
1060
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1061
/* Complete DELETE FROM <table> */
1062
else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
1063
pg_strcasecmp(prev2_wd, "FROM") == 0)
1065
static const char *const list_DELETE[] =
1066
{"USING", "WHERE", "SET", NULL};
1068
COMPLETE_WITH_LIST(list_DELETE);
1070
/* XXX: implement tab completion for DELETE ... USING */
1072
/* DROP (when not the previous word) */
1073
/* DROP AGGREGATE */
1074
else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1075
pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
1076
COMPLETE_WITH_CONST("(");
1078
/* DROP object with CASCADE / RESTRICT */
1079
else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
1080
(pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
1081
pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
1082
pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
1083
pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1084
pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
1085
pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
1086
pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
1087
pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
1088
pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
1089
pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
1090
(pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1091
pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
1092
prev_wd[strlen(prev_wd) - 1] == ')'))
1095
if ((pg_strcasecmp(prev3_wd, "DROP") == 0) && (pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
1097
if (find_open_parenthesis(end))
1099
static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1100
char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev_wd));
1101
sprintf(tmp_buf, func_args_query, prev_wd);
1102
COMPLETE_WITH_QUERY(tmp_buf);
1107
COMPLETE_WITH_CONST("(");
1112
static const char *const list_DROPCR[] =
1113
{"CASCADE", "RESTRICT", NULL};
1115
COMPLETE_WITH_LIST(list_DROPCR);
1118
else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
1119
pg_strcasecmp(prev3_wd, "FUNCTION") == 0 &&
1120
pg_strcasecmp(prev_wd, "(") == 0 )
1122
static const char func_args_query[] = "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'";
1123
char *tmp_buf = malloc(strlen(func_args_query) + strlen(prev2_wd));
1124
sprintf(tmp_buf, func_args_query, prev2_wd);
1125
COMPLETE_WITH_QUERY(tmp_buf);
1134
* Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
1136
else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
1138
static const char *const list_EXPLAIN[] =
1139
{"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
1141
COMPLETE_WITH_LIST(list_EXPLAIN);
1143
else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
1144
pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1146
static const char *const list_EXPLAIN[] =
1147
{"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
1149
COMPLETE_WITH_LIST(list_EXPLAIN);
1151
else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1152
pg_strcasecmp(prev3_wd, "VACUUM") != 0 &&
1153
pg_strcasecmp(prev4_wd, "VACUUM") != 0 &&
1154
(pg_strcasecmp(prev2_wd, "ANALYZE") == 0 ||
1155
pg_strcasecmp(prev2_wd, "EXPLAIN") == 0))
1157
static const char *const list_EXPLAIN[] =
1158
{"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
1160
COMPLETE_WITH_LIST(list_EXPLAIN);
1164
/* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
1165
else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
1166
pg_strcasecmp(prev_wd, "MOVE") == 0)
1168
static const char *const list_FETCH1[] =
1169
{"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
1171
COMPLETE_WITH_LIST(list_FETCH1);
1173
/* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
1174
else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
1175
pg_strcasecmp(prev2_wd, "MOVE") == 0)
1177
static const char *const list_FETCH2[] =
1178
{"ALL", "NEXT", "PRIOR", NULL};
1180
COMPLETE_WITH_LIST(list_FETCH2);
1184
* Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
1185
* but we may as well tab-complete both: perhaps some users prefer one
1186
* variant or the other.
1188
else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
1189
pg_strcasecmp(prev3_wd, "MOVE") == 0)
1191
static const char *const list_FROMIN[] =
1192
{"FROM", "IN", NULL};
1194
COMPLETE_WITH_LIST(list_FROMIN);
1197
/* GRANT && REVOKE*/
1198
/* Complete GRANT/REVOKE with a list of privileges */
1199
else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
1200
pg_strcasecmp(prev_wd, "REVOKE") == 0)
1202
static const char *const list_privileg[] =
1203
{"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
1204
"TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
1206
COMPLETE_WITH_LIST(list_privileg);
1208
/* Complete GRANT/REVOKE <sth> with "ON" */
1209
else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1210
pg_strcasecmp(prev2_wd, "REVOKE") == 0)
1211
COMPLETE_WITH_CONST("ON");
1214
* Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
1217
* keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
1218
* UNION; seems to work intuitively
1220
* Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
1221
* here will only work if the privilege list contains exactly one
1224
else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
1225
pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
1226
pg_strcasecmp(prev_wd, "ON") == 0)
1227
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
1228
" UNION SELECT 'DATABASE'"
1229
" UNION SELECT 'FUNCTION'"
1230
" UNION SELECT 'LANGUAGE'"
1231
" UNION SELECT 'SCHEMA'"
1232
" UNION SELECT 'TABLESPACE'");
1234
/* Complete "GRANT/REVOKE * ON * " with "TO" */
1235
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
1236
pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
1237
pg_strcasecmp(prev2_wd, "ON") == 0)
1239
if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
1240
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1241
else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
1242
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1243
else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
1244
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1245
else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
1246
COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1247
else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1248
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1249
else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
1250
COMPLETE_WITH_CONST("TO");
1252
COMPLETE_WITH_CONST("FROM");
1255
/* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1256
else if (pg_strcasecmp(prev3_wd, "ON") == 0 &&
1257
((pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
1258
pg_strcasecmp(prev_wd, "TO") == 0) ||
1259
(pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
1260
pg_strcasecmp(prev_wd, "FROM") == 0)))
1261
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1264
else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1265
pg_strcasecmp(prev_wd, "GROUP") == 0)
1266
COMPLETE_WITH_CONST("BY");
1269
/* Complete INSERT with "INTO" */
1270
else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
1271
COMPLETE_WITH_CONST("INTO");
1272
/* Complete INSERT INTO with table names */
1273
else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
1274
pg_strcasecmp(prev_wd, "INTO") == 0)
1275
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1276
/* Complete "INSERT INTO <table> (" with attribute names */
1277
else if (rl_line_buffer[start - 1] == '(' &&
1278
pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1279
pg_strcasecmp(prev2_wd, "INTO") == 0)
1280
COMPLETE_WITH_ATTR(prev_wd);
1283
* Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1286
else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
1287
pg_strcasecmp(prev2_wd, "INTO") == 0)
1289
static const char *const list_INSERT[] =
1290
{"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1292
COMPLETE_WITH_LIST(list_INSERT);
1294
/* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1295
else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
1296
pg_strcasecmp(prev3_wd, "INTO") == 0 &&
1297
prev_wd[strlen(prev_wd) - 1] == ')')
1299
static const char *const list_INSERT[] =
1300
{"SELECT", "VALUES", NULL};
1302
COMPLETE_WITH_LIST(list_INSERT);
1305
/* Insert an open parenthesis after "VALUES" */
1306
else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
1307
pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
1308
COMPLETE_WITH_CONST("(");
1311
/* Complete LOCK [TABLE] with a list of tables */
1312
else if (pg_strcasecmp(prev_wd, "LOCK") == 0 ||
1313
(pg_strcasecmp(prev_wd, "TABLE") == 0 &&
1314
pg_strcasecmp(prev2_wd, "LOCK") == 0))
1315
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1317
/* For the following, handle the case of a single table only for now */
1319
/* Complete LOCK [TABLE] <table> with "IN" */
1320
else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
1321
pg_strcasecmp(prev_wd, "TABLE")) ||
1322
(pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
1323
pg_strcasecmp(prev3_wd, "LOCK") == 0))
1324
COMPLETE_WITH_CONST("IN");
1326
/* Complete LOCK [TABLE] <table> IN with a lock mode */
1327
else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
1328
(pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
1329
(pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1330
pg_strcasecmp(prev4_wd, "LOCK") == 0)))
1332
static const char *const lock_modes[] =
1333
{"ACCESS SHARE MODE",
1334
"ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1335
"SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1336
"SHARE ROW EXCLUSIVE MODE",
1337
"EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1339
COMPLETE_WITH_LIST(lock_modes);
1343
else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
1344
COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1346
/* OWNER TO - complete with available roles*/
1347
else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
1348
pg_strcasecmp(prev_wd, "TO") == 0)
1349
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1352
else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
1353
pg_strcasecmp(prev_wd, "ORDER") == 0)
1354
COMPLETE_WITH_CONST("BY");
1355
else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
1356
pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
1357
pg_strcasecmp(prev_wd, "BY") == 0)
1358
COMPLETE_WITH_ATTR(prev3_wd);
1361
else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
1362
pg_strcasecmp(prev3_wd, "PREPARE") == 0)
1364
static const char *const list_PREPARE[] =
1365
{"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1367
COMPLETE_WITH_LIST(list_PREPARE);
1372
else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
1374
static const char *const list_REINDEX[] =
1375
{"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
1377
COMPLETE_WITH_LIST(list_REINDEX);
1379
else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
1381
if (pg_strcasecmp(prev_wd, "TABLE") == 0)
1382
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1383
else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
1384
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1385
else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
1386
pg_strcasecmp(prev_wd, "DATABASE") == 0)
1387
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1393
/* SET, RESET, SHOW */
1394
/* Complete with a variable name */
1395
else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
1396
pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
1397
pg_strcasecmp(prev_wd, "RESET") == 0)
1398
COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
1399
else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
1400
COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
1401
/* Complete "SET TRANSACTION" */
1402
else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
1403
pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1404
|| (pg_strcasecmp(prev2_wd, "START") == 0
1405
&& pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1406
|| (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1407
&& pg_strcasecmp(prev_wd, "WORK") == 0)
1408
|| (pg_strcasecmp(prev2_wd, "BEGIN") == 0
1409
&& pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
1410
|| (pg_strcasecmp(prev4_wd, "SESSION") == 0
1411
&& pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
1412
&& pg_strcasecmp(prev2_wd, "AS") == 0
1413
&& pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
1415
static const char *const my_list[] =
1416
{"ISOLATION LEVEL", "READ", NULL};
1418
COMPLETE_WITH_LIST(my_list);
1420
else if ((pg_strcasecmp(prev3_wd, "SET") == 0
1421
|| pg_strcasecmp(prev3_wd, "BEGIN") == 0
1422
|| pg_strcasecmp(prev3_wd, "START") == 0
1423
|| (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
1424
&& pg_strcasecmp(prev3_wd, "AS") == 0))
1425
&& (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
1426
|| pg_strcasecmp(prev2_wd, "WORK") == 0)
1427
&& pg_strcasecmp(prev_wd, "ISOLATION") == 0)
1428
COMPLETE_WITH_CONST("LEVEL");
1429
else if ((pg_strcasecmp(prev4_wd, "SET") == 0
1430
|| pg_strcasecmp(prev4_wd, "BEGIN") == 0
1431
|| pg_strcasecmp(prev4_wd, "START") == 0
1432
|| pg_strcasecmp(prev4_wd, "AS") == 0)
1433
&& (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
1434
|| pg_strcasecmp(prev3_wd, "WORK") == 0)
1435
&& pg_strcasecmp(prev2_wd, "ISOLATION") == 0
1436
&& pg_strcasecmp(prev_wd, "LEVEL") == 0)
1438
static const char *const my_list[] =
1439
{"READ", "REPEATABLE", "SERIALIZABLE", NULL};
1441
COMPLETE_WITH_LIST(my_list);
1443
else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1444
pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1445
pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1446
pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1447
pg_strcasecmp(prev_wd, "READ") == 0)
1449
static const char *const my_list[] =
1450
{"UNCOMMITTED", "COMMITTED", NULL};
1452
COMPLETE_WITH_LIST(my_list);
1454
else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
1455
pg_strcasecmp(prev4_wd, "WORK") == 0) &&
1456
pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1457
pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
1458
pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
1459
COMPLETE_WITH_CONST("READ");
1460
else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
1461
pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
1462
pg_strcasecmp(prev3_wd, "START") == 0 ||
1463
pg_strcasecmp(prev3_wd, "AS") == 0) &&
1464
(pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
1465
pg_strcasecmp(prev2_wd, "WORK") == 0) &&
1466
pg_strcasecmp(prev_wd, "READ") == 0)
1468
static const char *const my_list[] =
1469
{"ONLY", "WRITE", NULL};
1471
COMPLETE_WITH_LIST(my_list);
1473
/* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1474
else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1475
pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1477
static const char *const constraint_list[] =
1478
{"DEFERRED", "IMMEDIATE", NULL};
1480
COMPLETE_WITH_LIST(constraint_list);
1482
/* Complete SET ROLE */
1483
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1484
pg_strcasecmp(prev_wd, "ROLE") == 0)
1485
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1486
/* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1487
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1488
pg_strcasecmp(prev_wd, "SESSION") == 0)
1490
static const char *const my_list[] =
1491
{"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
1493
COMPLETE_WITH_LIST(my_list);
1495
/* Complete SET SESSION AUTHORIZATION with username */
1496
else if (pg_strcasecmp(prev3_wd, "SET") == 0
1497
&& pg_strcasecmp(prev2_wd, "SESSION") == 0
1498
&& pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1499
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1500
/* Complete RESET SESSION with AUTHORIZATION */
1501
else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
1502
pg_strcasecmp(prev_wd, "SESSION") == 0)
1503
COMPLETE_WITH_CONST("AUTHORIZATION");
1504
/* Complete SET <var> with "TO" */
1505
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1506
pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
1507
pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
1508
pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
1509
COMPLETE_WITH_CONST("TO");
1510
/* Suggest possible variable values */
1511
else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
1512
(pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1514
if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
1516
static const char *const my_list[] =
1517
{"ISO", "SQL", "Postgres", "German",
1518
"YMD", "DMY", "MDY",
1519
"US", "European", "NonEuropean",
1522
COMPLETE_WITH_LIST(my_list);
1524
else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
1526
static const char *const my_list[] =
1527
{"ON", "OFF", "DEFAULT", NULL};
1529
COMPLETE_WITH_LIST(my_list);
1533
static const char *const my_list[] =
1536
COMPLETE_WITH_LIST(my_list);
1540
/* START TRANSACTION */
1541
else if (pg_strcasecmp(prev_wd, "START") == 0)
1542
COMPLETE_WITH_CONST("TRANSACTION");
1545
else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
1546
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1549
else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
1550
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 '*'");
1553
/* If prev. word is UPDATE suggest a list of tables */
1554
else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
1555
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1556
/* Complete UPDATE <table> with "SET" */
1557
else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
1558
COMPLETE_WITH_CONST("SET");
1561
* If the previous word is SET (and it wasn't caught above as the _first_
1562
* word) the word before it was (hopefully) a table name and we'll now
1563
* make a list of attributes.
1565
else if (pg_strcasecmp(prev_wd, "SET") == 0)
1566
COMPLETE_WITH_ATTR(prev2_wd);
1568
/* UPDATE xx SET yy = */
1569
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
1570
pg_strcasecmp(prev4_wd, "UPDATE") == 0)
1571
COMPLETE_WITH_CONST("=");
1574
* VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
1575
* VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
1577
else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
1578
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1579
" UNION SELECT 'FULL'"
1580
" UNION SELECT 'FREEZE'"
1581
" UNION SELECT 'ANALYZE'"
1582
" UNION SELECT 'VERBOSE'");
1583
else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1584
(pg_strcasecmp(prev_wd, "FULL") == 0 ||
1585
pg_strcasecmp(prev_wd, "FREEZE") == 0))
1586
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1587
" UNION SELECT 'ANALYZE'"
1588
" UNION SELECT 'VERBOSE'");
1589
else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1590
pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1591
(pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1592
pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1593
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1594
" UNION SELECT 'VERBOSE'");
1595
else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
1596
pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1597
(pg_strcasecmp(prev2_wd, "FULL") == 0 ||
1598
pg_strcasecmp(prev2_wd, "FREEZE") == 0))
1599
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1600
" UNION SELECT 'ANALYZE'");
1601
else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1602
pg_strcasecmp(prev_wd, "VERBOSE") == 0)
1603
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1604
" UNION SELECT 'ANALYZE'");
1605
else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
1606
pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1607
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1608
" UNION SELECT 'VERBOSE'");
1609
else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
1610
pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
1611
(pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
1612
pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
1613
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1616
/* If the previous word is ANALYZE, produce list of tables */
1617
else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
1618
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1621
/* Simple case of the word before the where being the table name */
1622
else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
1623
COMPLETE_WITH_ATTR(prev2_wd);
1626
/* TODO: also include SRF ? */
1627
else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
1628
pg_strcasecmp(prev3_wd, "COPY") != 0 &&
1629
pg_strcasecmp(prev3_wd, "\\copy") != 0)
1630
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1633
/* Backslash commands */
1634
/* TODO: \dc \dd \dl */
1635
else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1636
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1637
else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1638
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL);
1639
else if (strcmp(prev_wd, "\\da") == 0)
1640
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
1641
else if (strcmp(prev_wd, "\\db") == 0)
1642
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1643
else if (strcmp(prev_wd, "\\dD") == 0)
1644
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
1645
else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1646
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
1647
else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1648
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
1649
else if (strcmp(prev_wd, "\\dn") == 0)
1650
COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1651
else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1652
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
1653
else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1654
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
1655
else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1656
COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1657
else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1658
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1659
else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1660
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
1661
else if (strcmp(prev_wd, "\\du") == 0)
1662
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1663
else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1664
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
1665
else if (strcmp(prev_wd, "\\encoding") == 0)
1666
COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
1667
else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1668
COMPLETE_WITH_LIST(sql_commands);
1669
else if (strcmp(prev_wd, "\\password") == 0)
1670
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1671
else if (strcmp(prev_wd, "\\pset") == 0)
1673
static const char *const my_list[] =
1674
{"format", "border", "expanded",
1675
"null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1678
COMPLETE_WITH_LIST(my_list);
1680
else if (strcmp(prev_wd, "\\cd") == 0 ||
1681
strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1682
strcmp(prev_wd, "\\g") == 0 ||
1683
strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1684
strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1685
strcmp(prev_wd, "\\s") == 0 ||
1686
strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1688
matches = complete_filename();
1692
* Finally, we look through the list of "things", such as TABLE, INDEX and
1693
* check if that was the previous word. If so, execute the query to get a
1700
for (i = 0; words_after_create[i].name; i++)
1702
if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
1704
if (words_after_create[i].query)
1705
COMPLETE_WITH_QUERY(words_after_create[i].query);
1706
else if (words_after_create[i].squery)
1707
COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
1715
* If we still don't have anything to match we have to fabricate some sort
1716
* of default list. If we were to just return NULL, readline automatically
1717
* attempts filename completion, and that's usually no good.
1719
if (matches == NULL)
1721
COMPLETE_WITH_CONST("");
1722
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1723
rl_completion_append_character = '\0';
1734
/* Return our Grand List O' Matches */