2
* psql - the PostgreSQL interactive terminal
4
* Copyright (c) 2000-2011, PostgreSQL Global Development Group
6
* src/bin/psql/tab-complete.c
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.
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:
24
* set disable-completion on
27
* See `man 3 readline' or `info readline' for the full details. Also,
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.)
37
* - Table or attribute names with spaces in it may confuse it.
39
* - Quotes, parenthesis, and other funny characters are not handled
40
* all that gracefully.
41
*----------------------------------------------------------------------
44
#include "postgres_fe.h"
45
#include "tab-complete.h"
48
/* If we don't have this, we might as well forget about the whole thing: */
53
#include "pqexpbuffer.h"
56
#include "stringutils.h"
58
#ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
59
#define filename_completion_function rl_filename_completion_function
61
/* missing in some header files */
62
extern char *filename_completion_function();
65
#ifdef HAVE_RL_COMPLETION_MATCHES
66
#define completion_matches rl_completion_matches
69
/* word break characters */
70
#define WORD_BREAKS "\t\n@$><=;|&{() "
73
* This struct is used to define "schema queries", which are custom-built
74
* to obtain possibly-schema-qualified names of database objects. There is
75
* enough similarity in the structure that we don't want to repeat it each
76
* time. So we put the components of each query into this struct and
77
* assemble them with the common boilerplate in _complete_from_query().
79
typedef struct SchemaQuery
82
* Name of catalog or catalogs to be queried, with alias, eg.
83
* "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
88
* Selection condition --- only rows meeting this condition are candidates
89
* to display. If catname mentions multiple tables, include the necessary
90
* join condition here. For example, "c.relkind = 'r'". Write NULL (not
91
* an empty string) if not needed.
93
const char *selcondition;
96
* Visibility condition --- which rows are visible without schema
97
* qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
99
const char *viscondition;
102
* Namespace --- name of field to join to pg_namespace.oid. For example,
105
const char *namespace;
108
* Result --- the appropriately-quoted name to return, in the case of an
109
* unqualified name. For example, "pg_catalog.quote_ident(c.relname)".
114
* In some cases a different result must be used for qualified names.
115
* Enter that here, or write NULL if result can be used.
117
const char *qualresult;
121
/* Store maximum number of records we want from database queries
122
* (implemented via SELECT ... LIMIT xx).
124
static int completion_max_records;
127
* Communication variables set by COMPLETE_WITH_FOO macros and then used by
128
* the completion callback functions. Ugly but there is no better way.
130
static const char *completion_charp; /* to pass a string */
131
static const char *const * completion_charpp; /* to pass a list of strings */
132
static const char *completion_info_charp; /* to pass a second string */
133
static const char *completion_info_charp2; /* to pass a third string */
134
static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
137
* A few macros to ease typing. You can use these to complete the given
139
* 1) The results from a query you pass it. (Perhaps one of those below?)
140
* 2) The results from a schema query you pass it.
141
* 3) The items from a null-pointer-terminated list.
142
* 4) A string constant.
143
* 5) The list of attributes of the given table (possibly schema-qualified).
145
#define COMPLETE_WITH_QUERY(query) \
147
completion_charp = query; \
148
matches = completion_matches(text, complete_from_query); \
151
#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
153
completion_squery = &(query); \
154
completion_charp = addon; \
155
matches = completion_matches(text, complete_from_schema_query); \
158
#define COMPLETE_WITH_LIST(list) \
160
completion_charpp = list; \
161
matches = completion_matches(text, complete_from_list); \
164
#define COMPLETE_WITH_CONST(string) \
166
completion_charp = string; \
167
matches = completion_matches(text, complete_from_const); \
170
#define COMPLETE_WITH_ATTR(relation, addon) \
172
char *_completion_schema; \
173
char *_completion_table; \
175
_completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
176
false, false, pset.encoding); \
177
(void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
178
false, false, pset.encoding); \
179
_completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
180
false, false, pset.encoding); \
181
if (_completion_table == NULL) \
183
completion_charp = Query_for_list_of_attributes addon; \
184
completion_info_charp = relation; \
188
completion_charp = Query_for_list_of_attributes_with_schema addon; \
189
completion_info_charp = _completion_table; \
190
completion_info_charp2 = _completion_schema; \
192
matches = completion_matches(text, complete_from_query); \
196
* Assembly instructions for schema queries
199
static const SchemaQuery Query_for_list_of_aggregates = {
201
"pg_catalog.pg_proc p",
205
"pg_catalog.pg_function_is_visible(p.oid)",
209
"pg_catalog.quote_ident(p.proname)",
214
static const SchemaQuery Query_for_list_of_datatypes = {
216
"pg_catalog.pg_type t",
217
/* selcondition --- ignore table rowtypes and array types */
219
" OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
220
"AND t.typname !~ '^_'",
222
"pg_catalog.pg_type_is_visible(t.oid)",
226
"pg_catalog.format_type(t.oid, NULL)",
228
"pg_catalog.quote_ident(t.typname)"
231
static const SchemaQuery Query_for_list_of_domains = {
233
"pg_catalog.pg_type t",
237
"pg_catalog.pg_type_is_visible(t.oid)",
241
"pg_catalog.quote_ident(t.typname)",
246
static const SchemaQuery Query_for_list_of_functions = {
248
"pg_catalog.pg_proc p",
252
"pg_catalog.pg_function_is_visible(p.oid)",
256
"pg_catalog.quote_ident(p.proname)",
261
static const SchemaQuery Query_for_list_of_indexes = {
263
"pg_catalog.pg_class c",
265
"c.relkind IN ('i')",
267
"pg_catalog.pg_table_is_visible(c.oid)",
271
"pg_catalog.quote_ident(c.relname)",
276
static const SchemaQuery Query_for_list_of_sequences = {
278
"pg_catalog.pg_class c",
280
"c.relkind IN ('S')",
282
"pg_catalog.pg_table_is_visible(c.oid)",
286
"pg_catalog.quote_ident(c.relname)",
291
static const SchemaQuery Query_for_list_of_foreign_tables = {
293
"pg_catalog.pg_class c",
295
"c.relkind IN ('f')",
297
"pg_catalog.pg_table_is_visible(c.oid)",
301
"pg_catalog.quote_ident(c.relname)",
306
static const SchemaQuery Query_for_list_of_tables = {
308
"pg_catalog.pg_class c",
310
"c.relkind IN ('r')",
312
"pg_catalog.pg_table_is_visible(c.oid)",
316
"pg_catalog.quote_ident(c.relname)",
321
/* The bit masks for the following three functions come from
322
* src/include/catalog/pg_trigger.h.
324
static const SchemaQuery Query_for_list_of_insertables = {
326
"pg_catalog.pg_class c",
328
"(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
329
"(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))",
331
"pg_catalog.pg_table_is_visible(c.oid)",
335
"pg_catalog.quote_ident(c.relname)",
340
static const SchemaQuery Query_for_list_of_deletables = {
342
"pg_catalog.pg_class c",
344
"(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
345
"(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))",
347
"pg_catalog.pg_table_is_visible(c.oid)",
351
"pg_catalog.quote_ident(c.relname)",
356
static const SchemaQuery Query_for_list_of_updatables = {
358
"pg_catalog.pg_class c",
360
"(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
361
"(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))",
363
"pg_catalog.pg_table_is_visible(c.oid)",
367
"pg_catalog.quote_ident(c.relname)",
372
static const SchemaQuery Query_for_list_of_tisvf = {
374
"pg_catalog.pg_class c",
376
"c.relkind IN ('r', 'i', 'S', 'v', 'f')",
378
"pg_catalog.pg_table_is_visible(c.oid)",
382
"pg_catalog.quote_ident(c.relname)",
387
static const SchemaQuery Query_for_list_of_tsvf = {
389
"pg_catalog.pg_class c",
391
"c.relkind IN ('r', 'S', 'v', 'f')",
393
"pg_catalog.pg_table_is_visible(c.oid)",
397
"pg_catalog.quote_ident(c.relname)",
402
static const SchemaQuery Query_for_list_of_views = {
404
"pg_catalog.pg_class c",
406
"c.relkind IN ('v')",
408
"pg_catalog.pg_table_is_visible(c.oid)",
412
"pg_catalog.quote_ident(c.relname)",
419
* Queries to get lists of names of various kinds of things, possibly
420
* restricted to names matching a partially entered name. In these queries,
421
* the first %s will be replaced by the text entered so far (suitably escaped
422
* to become a SQL literal string). %d will be replaced by the length of the
423
* string (in unescaped form). A second and third %s, if present, will be
424
* replaced by a suitably-escaped version of the string provided in
425
* completion_info_charp. A fourth and fifth %s are similarly replaced by
426
* completion_info_charp2.
428
* Beware that the allowed sequences of %s and %d are determined by
429
* _complete_from_query().
432
#define Query_for_list_of_attributes \
433
"SELECT pg_catalog.quote_ident(attname) "\
434
" FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
435
" WHERE c.oid = a.attrelid "\
436
" AND a.attnum > 0 "\
437
" AND NOT a.attisdropped "\
438
" AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
439
" AND (pg_catalog.quote_ident(relname)='%s' "\
440
" OR '\"' || relname || '\"'='%s') "\
441
" AND pg_catalog.pg_table_is_visible(c.oid)"
443
#define Query_for_list_of_attributes_with_schema \
444
"SELECT pg_catalog.quote_ident(attname) "\
445
" FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
446
" WHERE c.oid = a.attrelid "\
447
" AND n.oid = c.relnamespace "\
448
" AND a.attnum > 0 "\
449
" AND NOT a.attisdropped "\
450
" AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
451
" AND (pg_catalog.quote_ident(relname)='%s' "\
452
" OR '\"' || relname || '\"' ='%s') "\
453
" AND (pg_catalog.quote_ident(nspname)='%s' "\
454
" OR '\"' || nspname || '\"' ='%s') "
456
#define Query_for_list_of_template_databases \
457
"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
458
" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
460
#define Query_for_list_of_databases \
461
"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
462
" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
464
#define Query_for_list_of_tablespaces \
465
"SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
466
" WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
468
#define Query_for_list_of_encodings \
469
" SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
470
" FROM pg_catalog.pg_conversion "\
471
" WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
473
#define Query_for_list_of_languages \
474
"SELECT pg_catalog.quote_ident(lanname) "\
475
" FROM pg_catalog.pg_language "\
476
" WHERE lanname != 'internal' "\
477
" AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
479
#define Query_for_list_of_schemas \
480
"SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
481
" WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
483
#define Query_for_list_of_set_vars \
485
" (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
486
" WHERE context IN ('user', 'superuser') "\
487
" UNION ALL SELECT 'constraints' "\
488
" UNION ALL SELECT 'transaction' "\
489
" UNION ALL SELECT 'session' "\
490
" UNION ALL SELECT 'role' "\
491
" UNION ALL SELECT 'tablespace' "\
492
" UNION ALL SELECT 'all') ss "\
493
" WHERE substring(name,1,%d)='%s'"
495
#define Query_for_list_of_show_vars \
497
" (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
498
" UNION ALL SELECT 'session authorization' "\
499
" UNION ALL SELECT 'all') ss "\
500
" WHERE substring(name,1,%d)='%s'"
502
#define Query_for_list_of_roles \
503
" SELECT pg_catalog.quote_ident(rolname) "\
504
" FROM pg_catalog.pg_roles "\
505
" WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
507
#define Query_for_list_of_grant_roles \
508
" SELECT pg_catalog.quote_ident(rolname) "\
509
" FROM pg_catalog.pg_roles "\
510
" WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
511
" UNION ALL SELECT 'PUBLIC'"
513
/* the silly-looking length condition is just to eat up the current word */
514
#define Query_for_table_owning_index \
515
"SELECT pg_catalog.quote_ident(c1.relname) "\
516
" FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
517
" WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
518
" and (%d = pg_catalog.length('%s'))"\
519
" and pg_catalog.quote_ident(c2.relname)='%s'"\
520
" and pg_catalog.pg_table_is_visible(c2.oid)"
522
/* the silly-looking length condition is just to eat up the current word */
523
#define Query_for_index_of_table \
524
"SELECT pg_catalog.quote_ident(c2.relname) "\
525
" FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
526
" WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
527
" and (%d = pg_catalog.length('%s'))"\
528
" and pg_catalog.quote_ident(c1.relname)='%s'"\
529
" and pg_catalog.pg_table_is_visible(c2.oid)"
531
/* the silly-looking length condition is just to eat up the current word */
532
#define Query_for_list_of_tables_for_trigger \
533
"SELECT pg_catalog.quote_ident(relname) "\
534
" FROM pg_catalog.pg_class"\
535
" WHERE (%d = pg_catalog.length('%s'))"\
537
" (SELECT tgrelid FROM pg_catalog.pg_trigger "\
538
" WHERE pg_catalog.quote_ident(tgname)='%s')"
540
#define Query_for_list_of_ts_configurations \
541
"SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
542
" WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
544
#define Query_for_list_of_ts_dictionaries \
545
"SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
546
" WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
548
#define Query_for_list_of_ts_parsers \
549
"SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
550
" WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
552
#define Query_for_list_of_ts_templates \
553
"SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
554
" WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
556
#define Query_for_list_of_fdws \
557
" SELECT pg_catalog.quote_ident(fdwname) "\
558
" FROM pg_catalog.pg_foreign_data_wrapper "\
559
" WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
561
#define Query_for_list_of_servers \
562
" SELECT pg_catalog.quote_ident(srvname) "\
563
" FROM pg_catalog.pg_foreign_server "\
564
" WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
566
#define Query_for_list_of_user_mappings \
567
" SELECT pg_catalog.quote_ident(usename) "\
568
" FROM pg_catalog.pg_user_mappings "\
569
" WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
571
#define Query_for_list_of_access_methods \
572
" SELECT pg_catalog.quote_ident(amname) "\
573
" FROM pg_catalog.pg_am "\
574
" WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
576
#define Query_for_list_of_arguments \
577
" SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
578
" FROM pg_catalog.pg_proc "\
579
" WHERE proname='%s'"
581
#define Query_for_list_of_extensions \
582
" SELECT pg_catalog.quote_ident(extname) "\
583
" FROM pg_catalog.pg_extension "\
584
" WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
586
#define Query_for_list_of_available_extensions \
587
" SELECT pg_catalog.quote_ident(name) "\
588
" FROM pg_catalog.pg_available_extensions "\
589
" WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
592
* This is a list of all "things" in Pgsql, which can show up after CREATE or
593
* DROP; and there is also a query to get a list of them.
599
const char *query; /* simple query, or NULL */
600
const SchemaQuery *squery; /* schema query, or NULL */
601
const bits32 flags; /* visibility flags, see below */
604
#define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
605
#define THING_NO_DROP (1 << 1) /* should not show up after DROP */
606
#define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
608
static const pgsql_thing_t words_after_create[] = {
609
{"AGGREGATE", NULL, &Query_for_list_of_aggregates},
610
{"CAST", NULL, NULL}, /* Casts have complex structures for names, so
612
{"COLLATION", "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s'"},
615
* CREATE CONSTRAINT TRIGGER is not supported here because it is designed
616
* to be used only by pg_dump.
618
{"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
619
{"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
620
{"DATABASE", Query_for_list_of_databases},
621
{"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
622
{"DOMAIN", NULL, &Query_for_list_of_domains},
623
{"EXTENSION", Query_for_list_of_extensions},
624
{"FOREIGN DATA WRAPPER", NULL, NULL},
625
{"FOREIGN TABLE", NULL, NULL},
626
{"FUNCTION", NULL, &Query_for_list_of_functions},
627
{"GROUP", Query_for_list_of_roles},
628
{"LANGUAGE", Query_for_list_of_languages},
629
{"INDEX", NULL, &Query_for_list_of_indexes},
630
{"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
632
{"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */
633
{"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
634
{"ROLE", Query_for_list_of_roles},
635
{"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
636
{"SCHEMA", Query_for_list_of_schemas},
637
{"SEQUENCE", NULL, &Query_for_list_of_sequences},
638
{"SERVER", Query_for_list_of_servers},
639
{"TABLE", NULL, &Query_for_list_of_tables},
640
{"TABLESPACE", Query_for_list_of_tablespaces},
641
{"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
642
{"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
643
{"TEXT SEARCH", NULL, NULL},
644
{"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
645
{"TYPE", NULL, &Query_for_list_of_datatypes},
646
{"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
647
{"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE
649
{"USER", Query_for_list_of_roles},
650
{"USER MAPPING FOR", NULL, NULL},
651
{"VIEW", NULL, &Query_for_list_of_views},
652
{NULL} /* end of list */
656
/* Forward declaration of functions */
657
static char **psql_completion(char *text, int start, int end);
658
static char *create_command_generator(const char *text, int state);
659
static char *drop_command_generator(const char *text, int state);
660
static char *complete_from_query(const char *text, int state);
661
static char *complete_from_schema_query(const char *text, int state);
662
static char *_complete_from_query(int is_schema_query,
663
const char *text, int state);
664
static char *complete_from_list(const char *text, int state);
665
static char *complete_from_const(const char *text, int state);
666
static char **complete_from_variables(char *text,
667
const char *prefix, const char *suffix);
669
static PGresult *exec_query(const char *query);
671
static char *previous_word(int point, int skip);
674
static char *quote_file_name(char *text, int match_type, char *quote_pointer);
675
static char *dequote_file_name(char *text, char quote_char);
680
* Initialize the readline library for our purposes.
683
initialize_readline(void)
685
rl_readline_name = (char *) pset.progname;
686
rl_attempted_completion_function = (void *) psql_completion;
688
rl_basic_word_break_characters = WORD_BREAKS;
690
completion_max_records = 1000;
693
* There is a variable rl_completion_query_items for this but apparently
694
* it's not defined everywhere.
700
* The completion function.
702
* According to readline spec this gets passed the text entered so far and its
703
* start and end positions in the readline buffer. The return value is some
704
* partially obscure list format that can be generated by readline's
705
* completion_matches() function, so we don't have to worry about it.
708
psql_completion(char *text, int start, int end)
710
/* This is the variable we'll return. */
711
char **matches = NULL;
713
/* These are going to contain some scannage of the input line. */
721
static const char *const sql_commands[] = {
722
"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
723
"COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
724
"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
725
"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
726
"REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
727
"SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
728
"TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
732
static const char *const backslash_commands[] = {
733
"\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
734
"\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df",
735
"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
736
"\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
737
"\\e", "\\echo", "\\ef", "\\encoding",
738
"\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
739
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
740
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
741
"\\set", "\\sf", "\\t", "\\T",
742
"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
745
(void) end; /* not used */
747
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
748
rl_completion_append_character = ' ';
751
/* Clear a few things. */
752
completion_charp = NULL;
753
completion_charpp = NULL;
754
completion_info_charp = NULL;
755
completion_info_charp2 = NULL;
758
* Scan the input line before our current position for the last five
759
* words. According to those we'll make some smart decisions on what the
760
* user is probably intending to type. TODO: Use strtokx() to do this.
762
prev_wd = previous_word(start, 0);
763
prev2_wd = previous_word(start, 1);
764
prev3_wd = previous_word(start, 2);
765
prev4_wd = previous_word(start, 3);
766
prev5_wd = previous_word(start, 4);
767
prev6_wd = previous_word(start, 5);
769
/* If a backslash command was started, continue */
771
COMPLETE_WITH_LIST(backslash_commands);
773
/* Variable interpolation */
774
else if (text[0] == ':' && text[1] != ':')
777
matches = complete_from_variables(text, ":'", "'");
778
else if (text[1] == '"')
779
matches = complete_from_variables(text, ":\"", "\"");
781
matches = complete_from_variables(text, ":", "");
784
/* If no previous word, suggest one of the basic sql commands */
786
COMPLETE_WITH_LIST(sql_commands);
789
/* complete with something you can create */
790
else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
791
matches = completion_matches(text, create_command_generator);
793
/* DROP, but watch out for DROP embedded in other commands */
794
/* complete with something you can drop */
795
else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
796
pg_strcasecmp(prev2_wd, "DROP") == 0)
797
matches = completion_matches(text, drop_command_generator);
802
* complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
803
* in ALTER TABLE sth ALTER
805
else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
806
pg_strcasecmp(prev3_wd, "TABLE") != 0)
808
static const char *const list_ALTER[] =
809
{"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
810
"EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
811
"GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR",
812
"ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
813
"TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
814
"USER", "USER MAPPING FOR", "VIEW", NULL};
816
COMPLETE_WITH_LIST(list_ALTER);
818
/* ALTER AGGREGATE,FUNCTION <name> */
819
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
820
(pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
821
pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
822
COMPLETE_WITH_CONST("(");
823
/* ALTER AGGREGATE,FUNCTION <name> (...) */
824
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
825
(pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
826
pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
828
if (prev_wd[strlen(prev_wd) - 1] == ')')
830
static const char *const list_ALTERAGG[] =
831
{"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
833
COMPLETE_WITH_LIST(list_ALTERAGG);
837
char *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
839
sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
840
COMPLETE_WITH_QUERY(tmp_buf);
845
/* ALTER SCHEMA <name> */
846
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
847
pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
849
static const char *const list_ALTERGEN[] =
850
{"OWNER TO", "RENAME TO", NULL};
852
COMPLETE_WITH_LIST(list_ALTERGEN);
855
/* ALTER COLLATION <name> */
856
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
857
pg_strcasecmp(prev2_wd, "COLLATION") == 0)
859
static const char *const list_ALTERGEN[] =
860
{"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
862
COMPLETE_WITH_LIST(list_ALTERGEN);
865
/* ALTER CONVERSION <name> */
866
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
867
pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
869
static const char *const list_ALTERGEN[] =
870
{"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
872
COMPLETE_WITH_LIST(list_ALTERGEN);
875
/* ALTER DATABASE <name> */
876
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
877
pg_strcasecmp(prev2_wd, "DATABASE") == 0)
879
static const char *const list_ALTERDATABASE[] =
880
{"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};
882
COMPLETE_WITH_LIST(list_ALTERDATABASE);
885
/* ALTER EXTENSION <name> */
886
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
887
pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
889
static const char *const list_ALTEREXTENSION[] =
890
{"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
892
COMPLETE_WITH_LIST(list_ALTEREXTENSION);
896
else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
897
pg_strcasecmp(prev_wd, "FOREIGN") == 0)
899
static const char *const list_ALTER_FOREIGN[] =
900
{"DATA WRAPPER", "TABLE", NULL};
902
COMPLETE_WITH_LIST(list_ALTER_FOREIGN);
905
/* ALTER FOREIGN DATA WRAPPER <name> */
906
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
907
pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
908
pg_strcasecmp(prev3_wd, "DATA") == 0 &&
909
pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
911
static const char *const list_ALTER_FDW[] =
912
{"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
914
COMPLETE_WITH_LIST(list_ALTER_FDW);
917
/* ALTER FOREIGN TABLE <name> */
918
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
919
pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
920
pg_strcasecmp(prev2_wd, "TABLE") == 0)
922
static const char *const list_ALTER_FOREIGN_TABLE[] =
923
{"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL};
925
COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
928
/* ALTER INDEX <name> */
929
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
930
pg_strcasecmp(prev2_wd, "INDEX") == 0)
932
static const char *const list_ALTERINDEX[] =
933
{"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
935
COMPLETE_WITH_LIST(list_ALTERINDEX);
937
/* ALTER INDEX <name> SET */
938
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
939
pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
940
pg_strcasecmp(prev_wd, "SET") == 0)
942
static const char *const list_ALTERINDEXSET[] =
943
{"(", "TABLESPACE", NULL};
945
COMPLETE_WITH_LIST(list_ALTERINDEXSET);
947
/* ALTER INDEX <name> RESET */
948
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
949
pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
950
pg_strcasecmp(prev_wd, "RESET") == 0)
951
COMPLETE_WITH_CONST("(");
952
/* ALTER INDEX <foo> SET|RESET ( */
953
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
954
pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
955
(pg_strcasecmp(prev2_wd, "SET") == 0 ||
956
pg_strcasecmp(prev2_wd, "RESET") == 0) &&
957
pg_strcasecmp(prev_wd, "(") == 0)
959
static const char *const list_INDEXOPTIONS[] =
960
{"fillfactor", "fastupdate", NULL};
962
COMPLETE_WITH_LIST(list_INDEXOPTIONS);
965
/* ALTER LANGUAGE <name> */
966
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
967
pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
969
static const char *const list_ALTERLANGUAGE[] =
970
{"OWNER TO", "RENAME TO", NULL};
972
COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
975
/* ALTER LARGE OBJECT <oid> */
976
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
977
pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
978
pg_strcasecmp(prev2_wd, "OBJECT") == 0)
980
static const char *const list_ALTERLARGEOBJECT[] =
983
COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
986
/* ALTER USER,ROLE <name> */
987
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
988
!(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
989
(pg_strcasecmp(prev2_wd, "USER") == 0 ||
990
pg_strcasecmp(prev2_wd, "ROLE") == 0))
992
static const char *const list_ALTERUSER[] =
993
{"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
994
"ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
995
"NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
996
"NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
997
"SUPERUSER", "UNENCRYPTED", "VALID UNTIL", NULL};
999
COMPLETE_WITH_LIST(list_ALTERUSER);
1002
/* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
1003
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1004
(pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1005
(pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1007
COMPLETE_WITH_CONST("PASSWORD");
1009
/* ALTER DEFAULT PRIVILEGES */
1010
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1011
pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
1012
pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
1014
static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
1015
{"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
1017
COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
1019
/* ALTER DEFAULT PRIVILEGES FOR */
1020
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1021
pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
1022
pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
1023
pg_strcasecmp(prev_wd, "FOR") == 0)
1025
static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
1026
{"ROLE", "USER", NULL};
1028
COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
1030
/* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
1031
else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
1032
pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
1033
(pg_strcasecmp(prev3_wd, "FOR") == 0 ||
1034
pg_strcasecmp(prev3_wd, "IN") == 0))
1036
static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
1037
{"GRANT", "REVOKE", NULL};
1039
COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
1041
/* ALTER DOMAIN <name> */
1042
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1043
pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
1045
static const char *const list_ALTERDOMAIN[] =
1046
{"ADD", "DROP", "OWNER TO", "SET", NULL};
1048
COMPLETE_WITH_LIST(list_ALTERDOMAIN);
1050
/* ALTER DOMAIN <sth> DROP */
1051
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1052
pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1053
pg_strcasecmp(prev_wd, "DROP") == 0)
1055
static const char *const list_ALTERDOMAIN2[] =
1056
{"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
1058
COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
1060
/* ALTER DOMAIN <sth> SET */
1061
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1062
pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
1063
pg_strcasecmp(prev_wd, "SET") == 0)
1065
static const char *const list_ALTERDOMAIN3[] =
1066
{"DEFAULT", "NOT NULL", "SCHEMA", NULL};
1068
COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
1070
/* ALTER SEQUENCE <name> */
1071
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1072
pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
1074
static const char *const list_ALTERSEQUENCE[] =
1075
{"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
1076
"SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
1078
COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
1080
/* ALTER SEQUENCE <name> NO */
1081
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1082
pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
1083
pg_strcasecmp(prev_wd, "NO") == 0)
1085
static const char *const list_ALTERSEQUENCE2[] =
1086
{"MINVALUE", "MAXVALUE", "CYCLE", NULL};
1088
COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
1090
/* ALTER SERVER <name> */
1091
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1092
pg_strcasecmp(prev2_wd, "SERVER") == 0)
1094
static const char *const list_ALTER_SERVER[] =
1095
{"VERSION", "OPTIONS", "OWNER TO", NULL};
1097
COMPLETE_WITH_LIST(list_ALTER_SERVER);
1099
/* ALTER VIEW <name> */
1100
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1101
pg_strcasecmp(prev2_wd, "VIEW") == 0)
1103
static const char *const list_ALTERVIEW[] =
1104
{"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1106
COMPLETE_WITH_LIST(list_ALTERVIEW);
1108
/* ALTER TRIGGER <name>, add ON */
1109
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1110
pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1111
COMPLETE_WITH_CONST("ON");
1113
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1114
pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
1116
completion_info_charp = prev2_wd;
1117
COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1121
* If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1123
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1124
pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1125
pg_strcasecmp(prev_wd, "ON") == 0)
1126
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1128
/* ALTER TRIGGER <name> ON <name> */
1129
else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1130
pg_strcasecmp(prev2_wd, "ON") == 0)
1131
COMPLETE_WITH_CONST("RENAME TO");
1134
* If we detect ALTER TABLE <name>, suggest sub commands
1136
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1137
pg_strcasecmp(prev2_wd, "TABLE") == 0)
1139
static const char *const list_ALTER2[] =
1140
{"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1141
"NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
1142
"VALIDATE CONSTRAINT", NULL};
1144
COMPLETE_WITH_LIST(list_ALTER2);
1146
/* ALTER TABLE xxx ENABLE */
1147
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1148
pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1149
pg_strcasecmp(prev_wd, "ENABLE") == 0)
1151
static const char *const list_ALTERENABLE[] =
1152
{"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
1154
COMPLETE_WITH_LIST(list_ALTERENABLE);
1156
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1157
pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
1158
(pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
1159
pg_strcasecmp(prev_wd, "ALWAYS") == 0))
1161
static const char *const list_ALTERENABLE2[] =
1162
{"RULE", "TRIGGER", NULL};
1164
COMPLETE_WITH_LIST(list_ALTERENABLE2);
1166
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1167
pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1168
pg_strcasecmp(prev_wd, "DISABLE") == 0)
1170
static const char *const list_ALTERDISABLE[] =
1171
{"RULE", "TRIGGER", NULL};
1173
COMPLETE_WITH_LIST(list_ALTERDISABLE);
1176
/* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
1177
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1178
(pg_strcasecmp(prev_wd, "ALTER") == 0 ||
1179
pg_strcasecmp(prev_wd, "RENAME") == 0))
1180
COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");
1183
* If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of
1186
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1187
(pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1188
pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1189
pg_strcasecmp(prev_wd, "COLUMN") == 0)
1190
COMPLETE_WITH_ATTR(prev3_wd, "");
1192
/* ALTER TABLE xxx RENAME yyy */
1193
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1194
pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
1195
pg_strcasecmp(prev_wd, "TO") != 0)
1196
COMPLETE_WITH_CONST("TO");
1198
/* ALTER TABLE xxx RENAME COLUMN yyy */
1199
else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1200
pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1201
pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
1202
pg_strcasecmp(prev_wd, "TO") != 0)
1203
COMPLETE_WITH_CONST("TO");
1205
/* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1206
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1207
pg_strcasecmp(prev_wd, "DROP") == 0)
1209
static const char *const list_TABLEDROP[] =
1210
{"COLUMN", "CONSTRAINT", NULL};
1212
COMPLETE_WITH_LIST(list_TABLEDROP);
1214
/* If we have TABLE <sth> DROP COLUMN, provide list of columns */
1215
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1216
pg_strcasecmp(prev2_wd, "DROP") == 0 &&
1217
pg_strcasecmp(prev_wd, "COLUMN") == 0)
1218
COMPLETE_WITH_ATTR(prev3_wd, "");
1219
/* ALTER TABLE ALTER [COLUMN] <foo> */
1220
else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1221
pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
1222
(pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1223
pg_strcasecmp(prev2_wd, "ALTER") == 0))
1225
static const char *const list_COLUMNALTER[] =
1226
{"TYPE", "SET", "RESET", "DROP", NULL};
1228
COMPLETE_WITH_LIST(list_COLUMNALTER);
1230
/* ALTER TABLE ALTER [COLUMN] <foo> SET */
1231
else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1232
pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1233
(pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1234
pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1235
pg_strcasecmp(prev_wd, "SET") == 0)
1237
static const char *const list_COLUMNSET[] =
1238
{"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
1240
COMPLETE_WITH_LIST(list_COLUMNSET);
1242
/* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1243
else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1244
pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1245
pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1246
pg_strcasecmp(prev2_wd, "SET") == 0 &&
1247
pg_strcasecmp(prev_wd, "(") == 0)
1249
static const char *const list_COLUMNOPTIONS[] =
1250
{"n_distinct", "n_distinct_inherited", NULL};
1252
COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
1254
/* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1255
else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1256
pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
1257
pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
1258
pg_strcasecmp(prev2_wd, "SET") == 0 &&
1259
pg_strcasecmp(prev_wd, "STORAGE") == 0)
1261
static const char *const list_COLUMNSTORAGE[] =
1262
{"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
1264
COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
1266
/* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1267
else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1268
pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
1269
(pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
1270
pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
1271
pg_strcasecmp(prev_wd, "DROP") == 0)
1273
static const char *const list_COLUMNDROP[] =
1274
{"DEFAULT", "NOT NULL", NULL};
1276
COMPLETE_WITH_LIST(list_COLUMNDROP);
1278
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1279
pg_strcasecmp(prev_wd, "CLUSTER") == 0)
1280
COMPLETE_WITH_CONST("ON");
1281
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1282
pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1283
pg_strcasecmp(prev_wd, "ON") == 0)
1285
completion_info_charp = prev3_wd;
1286
COMPLETE_WITH_QUERY(Query_for_index_of_table);
1288
/* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
1289
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1290
pg_strcasecmp(prev_wd, "SET") == 0)
1292
static const char *const list_TABLESET[] =
1293
{"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
1295
COMPLETE_WITH_LIST(list_TABLESET);
1297
/* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces */
1298
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1299
pg_strcasecmp(prev2_wd, "SET") == 0 &&
1300
pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
1301
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1302
/* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1303
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1304
pg_strcasecmp(prev2_wd, "SET") == 0 &&
1305
pg_strcasecmp(prev_wd, "WITHOUT") == 0)
1307
static const char *const list_TABLESET2[] =
1308
{"CLUSTER", "OIDS", NULL};
1310
COMPLETE_WITH_LIST(list_TABLESET2);
1312
/* ALTER TABLE <foo> RESET */
1313
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
1314
pg_strcasecmp(prev_wd, "RESET") == 0)
1315
COMPLETE_WITH_CONST("(");
1316
/* ALTER TABLE <foo> SET|RESET ( */
1317
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
1318
(pg_strcasecmp(prev2_wd, "SET") == 0 ||
1319
pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1320
pg_strcasecmp(prev_wd, "(") == 0)
1322
static const char *const list_TABLEOPTIONS[] =
1324
"autovacuum_analyze_scale_factor",
1325
"autovacuum_analyze_threshold",
1326
"autovacuum_enabled",
1327
"autovacuum_freeze_max_age",
1328
"autovacuum_freeze_min_age",
1329
"autovacuum_freeze_table_age",
1330
"autovacuum_vacuum_cost_delay",
1331
"autovacuum_vacuum_cost_limit",
1332
"autovacuum_vacuum_scale_factor",
1333
"autovacuum_vacuum_threshold",
1335
"toast.autovacuum_enabled",
1336
"toast.autovacuum_freeze_max_age",
1337
"toast.autovacuum_freeze_min_age",
1338
"toast.autovacuum_freeze_table_age",
1339
"toast.autovacuum_vacuum_cost_delay",
1340
"toast.autovacuum_vacuum_cost_limit",
1341
"toast.autovacuum_vacuum_scale_factor",
1342
"toast.autovacuum_vacuum_threshold",
1346
COMPLETE_WITH_LIST(list_TABLEOPTIONS);
1349
/* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
1350
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1351
pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1353
static const char *const list_ALTERTSPC[] =
1354
{"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
1356
COMPLETE_WITH_LIST(list_ALTERTSPC);
1358
/* ALTER TABLESPACE <foo> SET|RESET */
1359
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1360
pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
1361
(pg_strcasecmp(prev_wd, "SET") == 0 ||
1362
pg_strcasecmp(prev_wd, "RESET") == 0))
1363
COMPLETE_WITH_CONST("(");
1364
/* ALTER TABLESPACE <foo> SET|RESET ( */
1365
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1366
pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1367
(pg_strcasecmp(prev2_wd, "SET") == 0 ||
1368
pg_strcasecmp(prev2_wd, "RESET") == 0) &&
1369
pg_strcasecmp(prev_wd, "(") == 0)
1371
static const char *const list_TABLESPACEOPTIONS[] =
1372
{"seq_page_cost", "random_page_cost", NULL};
1374
COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
1377
/* ALTER TEXT SEARCH */
1378
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1379
pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1380
pg_strcasecmp(prev_wd, "SEARCH") == 0)
1382
static const char *const list_ALTERTEXTSEARCH[] =
1383
{"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1385
COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
1387
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1388
pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1389
pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1390
(pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
1391
pg_strcasecmp(prev2_wd, "PARSER") == 0))
1393
static const char *const list_ALTERTEXTSEARCH2[] =
1394
{"RENAME TO", "SET SCHEMA", NULL};
1396
COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
1399
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1400
pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1401
pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1402
pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
1404
static const char *const list_ALTERTEXTSEARCH3[] =
1405
{"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1407
COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
1410
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1411
pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1412
pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1413
pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1415
static const char *const list_ALTERTEXTSEARCH4[] =
1416
{"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
1418
COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
1421
/* complete ALTER TYPE <foo> with actions */
1422
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1423
pg_strcasecmp(prev2_wd, "TYPE") == 0)
1425
static const char *const list_ALTERTYPE[] =
1426
{"ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE",
1427
"OWNER TO", "RENAME", "SET SCHEMA", NULL};
1429
COMPLETE_WITH_LIST(list_ALTERTYPE);
1431
/* complete ALTER TYPE <foo> ADD with actions */
1432
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1433
pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1434
pg_strcasecmp(prev_wd, "ADD") == 0)
1436
static const char *const list_ALTERTYPE[] =
1437
{"ATTRIBUTE", "VALUE", NULL};
1439
COMPLETE_WITH_LIST(list_ALTERTYPE);
1441
/* ALTER TYPE <foo> RENAME */
1442
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1443
pg_strcasecmp(prev3_wd, "TYPE") == 0 &&
1444
pg_strcasecmp(prev_wd, "RENAME") == 0)
1446
static const char *const list_ALTERTYPE[] =
1447
{"ATTRIBUTE", "TO", NULL};
1449
COMPLETE_WITH_LIST(list_ALTERTYPE);
1451
/* ALTER TYPE xxx RENAME ATTRIBUTE yyy */
1452
else if (pg_strcasecmp(prev5_wd, "TYPE") == 0 &&
1453
pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
1454
pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0)
1455
COMPLETE_WITH_CONST("TO");
1458
* If we have TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list of
1461
else if (pg_strcasecmp(prev4_wd, "TYPE") == 0 &&
1462
(pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
1463
pg_strcasecmp(prev2_wd, "DROP") == 0 ||
1464
pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
1465
pg_strcasecmp(prev_wd, "ATTRIBUTE") == 0)
1466
COMPLETE_WITH_ATTR(prev3_wd, "");
1467
/* ALTER TYPE ALTER ATTRIBUTE <foo> */
1468
else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1469
pg_strcasecmp(prev2_wd, "ATTRIBUTE") == 0))
1471
COMPLETE_WITH_CONST("TYPE");
1473
/* complete ALTER GROUP <foo> */
1474
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1475
pg_strcasecmp(prev2_wd, "GROUP") == 0)
1477
static const char *const list_ALTERGROUP[] =
1478
{"ADD USER", "DROP USER", "RENAME TO", NULL};
1480
COMPLETE_WITH_LIST(list_ALTERGROUP);
1482
/* complete ALTER GROUP <foo> ADD|DROP with USER */
1483
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1484
pg_strcasecmp(prev3_wd, "GROUP") == 0 &&
1485
(pg_strcasecmp(prev_wd, "ADD") == 0 ||
1486
pg_strcasecmp(prev_wd, "DROP") == 0))
1487
COMPLETE_WITH_CONST("USER");
1488
/* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
1489
else if (pg_strcasecmp(prev4_wd, "GROUP") == 0 &&
1490
(pg_strcasecmp(prev2_wd, "ADD") == 0 ||
1491
pg_strcasecmp(prev2_wd, "DROP") == 0) &&
1492
pg_strcasecmp(prev_wd, "USER") == 0)
1493
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1495
/* BEGIN, END, ABORT */
1496
else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 ||
1497
pg_strcasecmp(prev_wd, "END") == 0 ||
1498
pg_strcasecmp(prev_wd, "ABORT") == 0)
1500
static const char *const list_TRANS[] =
1501
{"WORK", "TRANSACTION", NULL};
1503
COMPLETE_WITH_LIST(list_TRANS);
1506
else if (pg_strcasecmp(prev_wd, "COMMIT") == 0)
1508
static const char *const list_COMMIT[] =
1509
{"WORK", "TRANSACTION", "PREPARED", NULL};
1511
COMPLETE_WITH_LIST(list_COMMIT);
1513
/* RELEASE SAVEPOINT */
1514
else if (pg_strcasecmp(prev_wd, "RELEASE") == 0)
1515
COMPLETE_WITH_CONST("SAVEPOINT");
1517
else if (pg_strcasecmp(prev_wd, "ROLLBACK") == 0)
1519
static const char *const list_TRANS[] =
1520
{"WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED", NULL};
1522
COMPLETE_WITH_LIST(list_TRANS);
1527
* If the previous word is CLUSTER and not without produce list of tables
1529
else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
1530
pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
1531
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1532
/* If we have CLUSTER <sth>, then add "USING" */
1533
else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
1534
pg_strcasecmp(prev_wd, "ON") != 0)
1536
COMPLETE_WITH_CONST("USING");
1540
* If we have CLUSTER <sth> USING, then add the index as well.
1542
else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
1543
pg_strcasecmp(prev_wd, "USING") == 0)
1545
completion_info_charp = prev2_wd;
1546
COMPLETE_WITH_QUERY(Query_for_index_of_table);
1550
else if (pg_strcasecmp(prev_wd, "COMMENT") == 0)
1551
COMPLETE_WITH_CONST("ON");
1552
else if (pg_strcasecmp(prev2_wd, "COMMENT") == 0 &&
1553
pg_strcasecmp(prev_wd, "ON") == 0)
1555
static const char *const list_COMMENT[] =
1556
{"CAST", "COLLATION", "CONVERSION", "DATABASE", "FOREIGN DATA WRAPPER",
1557
"SERVER", "FOREIGN TABLE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
1558
"SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
1559
"OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
1560
"TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
1562
COMPLETE_WITH_LIST(list_COMMENT);
1564
else if (pg_strcasecmp(prev3_wd, "COMMENT") == 0 &&
1565
pg_strcasecmp(prev2_wd, "ON") == 0 &&
1566
pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1568
static const char *const list_TRANS2[] =
1569
{"DATA WRAPPER", "TABLE", NULL};
1571
COMPLETE_WITH_LIST(list_TRANS2);
1573
else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1574
pg_strcasecmp(prev3_wd, "ON") == 0 &&
1575
pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1576
pg_strcasecmp(prev_wd, "SEARCH") == 0)
1578
static const char *const list_TRANS2[] =
1579
{"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1581
COMPLETE_WITH_LIST(list_TRANS2);
1583
else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
1584
pg_strcasecmp(prev3_wd, "ON") == 0) ||
1585
(pg_strcasecmp(prev6_wd, "COMMENT") == 0 &&
1586
pg_strcasecmp(prev5_wd, "ON") == 0) ||
1587
(pg_strcasecmp(prev5_wd, "ON") == 0 &&
1588
pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1589
pg_strcasecmp(prev3_wd, "SEARCH") == 0))
1590
COMPLETE_WITH_CONST("IS");
1595
* If we have COPY [BINARY] (which you'd have to type yourself), offer
1596
* list of tables (Also cover the analogous backslash command)
1598
else if (pg_strcasecmp(prev_wd, "COPY") == 0 ||
1599
pg_strcasecmp(prev_wd, "\\copy") == 0 ||
1600
(pg_strcasecmp(prev2_wd, "COPY") == 0 &&
1601
pg_strcasecmp(prev_wd, "BINARY") == 0))
1602
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1603
/* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
1604
else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
1605
pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
1606
pg_strcasecmp(prev2_wd, "BINARY") == 0)
1608
static const char *const list_FROMTO[] =
1609
{"FROM", "TO", NULL};
1611
COMPLETE_WITH_LIST(list_FROMTO);
1613
/* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
1614
else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
1615
pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
1616
pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
1617
(pg_strcasecmp(prev_wd, "FROM") == 0 ||
1618
pg_strcasecmp(prev_wd, "TO") == 0))
1619
matches = completion_matches(text, filename_completion_function);
1621
/* Handle COPY|BINARY <sth> FROM|TO filename */
1622
else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
1623
pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
1624
pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
1625
(pg_strcasecmp(prev2_wd, "FROM") == 0 ||
1626
pg_strcasecmp(prev2_wd, "TO") == 0))
1628
static const char *const list_COPY[] =
1629
{"BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING", NULL};
1631
COMPLETE_WITH_LIST(list_COPY);
1634
/* Handle COPY|BINARY <sth> FROM|TO filename CSV */
1635
else if (pg_strcasecmp(prev_wd, "CSV") == 0 &&
1636
(pg_strcasecmp(prev3_wd, "FROM") == 0 ||
1637
pg_strcasecmp(prev3_wd, "TO") == 0))
1639
static const char *const list_CSV[] =
1640
{"HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL", NULL};
1642
COMPLETE_WITH_LIST(list_CSV);
1645
/* CREATE DATABASE */
1646
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1647
pg_strcasecmp(prev2_wd, "DATABASE") == 0)
1649
static const char *const list_DATABASE[] =
1650
{"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
1653
COMPLETE_WITH_LIST(list_DATABASE);
1656
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1657
pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
1658
pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
1659
COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
1661
/* CREATE EXTENSION */
1662
/* Complete with available extensions rather than installed ones. */
1663
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1664
pg_strcasecmp(prev_wd, "EXTENSION") == 0)
1665
COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
1666
/* CREATE EXTENSION <name> */
1667
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1668
pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
1669
COMPLETE_WITH_CONST("WITH SCHEMA");
1671
/* CREATE FOREIGN */
1672
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1673
pg_strcasecmp(prev_wd, "FOREIGN") == 0)
1675
static const char *const list_CREATE_FOREIGN[] =
1676
{"DATA WRAPPER", "TABLE", NULL};
1678
COMPLETE_WITH_LIST(list_CREATE_FOREIGN);
1681
/* CREATE FOREIGN DATA WRAPPER */
1682
else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1683
pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
1684
pg_strcasecmp(prev3_wd, "DATA") == 0 &&
1685
pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
1687
static const char *const list_CREATE_FOREIGN_DATA_WRAPPER[] =
1688
{"HANDLER", "VALIDATOR", NULL};
1690
COMPLETE_WITH_LIST(list_CREATE_FOREIGN_DATA_WRAPPER);
1694
/* First off we complete CREATE UNIQUE with "INDEX" */
1695
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1696
pg_strcasecmp(prev_wd, "UNIQUE") == 0)
1697
COMPLETE_WITH_CONST("INDEX");
1698
/* If we have CREATE|UNIQUE INDEX, then add "ON" and existing indexes */
1699
else if (pg_strcasecmp(prev_wd, "INDEX") == 0 &&
1700
(pg_strcasecmp(prev2_wd, "CREATE") == 0 ||
1701
pg_strcasecmp(prev2_wd, "UNIQUE") == 0))
1702
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1703
" UNION SELECT 'ON'"
1704
" UNION SELECT 'CONCURRENTLY'");
1705
/* Complete ... INDEX [<name>] ON with a list of tables */
1706
else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1707
pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
1708
pg_strcasecmp(prev2_wd, "CONCURRENTLY") == 0) &&
1709
pg_strcasecmp(prev_wd, "ON") == 0)
1710
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1711
/* If we have CREATE|UNIQUE INDEX <sth> CONCURRENTLY, then add "ON" */
1712
else if ((pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1713
pg_strcasecmp(prev2_wd, "INDEX") == 0) &&
1714
pg_strcasecmp(prev_wd, "CONCURRENTLY") == 0)
1715
COMPLETE_WITH_CONST("ON");
1716
/* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" or "CONCURRENTLY" */
1717
else if ((pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
1718
pg_strcasecmp(prev3_wd, "UNIQUE") == 0) &&
1719
pg_strcasecmp(prev2_wd, "INDEX") == 0)
1721
static const char *const list_CREATE_INDEX[] =
1722
{"CONCURRENTLY", "ON", NULL};
1724
COMPLETE_WITH_LIST(list_CREATE_INDEX);
1728
* Complete INDEX <name> ON <table> with a list of table columns (which
1729
* should really be in parens)
1731
else if ((pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1732
pg_strcasecmp(prev3_wd, "INDEX") == 0 ||
1733
pg_strcasecmp(prev3_wd, "CONCURRENTLY") == 0) &&
1734
pg_strcasecmp(prev2_wd, "ON") == 0)
1736
static const char *const list_CREATE_INDEX2[] =
1737
{"(", "USING", NULL};
1739
COMPLETE_WITH_LIST(list_CREATE_INDEX2);
1741
else if ((pg_strcasecmp(prev5_wd, "INDEX") == 0 ||
1742
pg_strcasecmp(prev4_wd, "INDEX") == 0 ||
1743
pg_strcasecmp(prev4_wd, "CONCURRENTLY") == 0) &&
1744
pg_strcasecmp(prev3_wd, "ON") == 0 &&
1745
pg_strcasecmp(prev_wd, "(") == 0)
1746
COMPLETE_WITH_ATTR(prev2_wd, "");
1747
/* same if you put in USING */
1748
else if (pg_strcasecmp(prev5_wd, "ON") == 0 &&
1749
pg_strcasecmp(prev3_wd, "USING") == 0 &&
1750
pg_strcasecmp(prev_wd, "(") == 0)
1751
COMPLETE_WITH_ATTR(prev4_wd, "");
1752
/* Complete USING with an index method */
1753
else if (pg_strcasecmp(prev_wd, "USING") == 0)
1754
COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
1755
else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
1756
pg_strcasecmp(prev2_wd, "USING") == 0)
1757
COMPLETE_WITH_CONST("(");
1760
/* Complete "CREATE RULE <sth>" with "AS" */
1761
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1762
pg_strcasecmp(prev2_wd, "RULE") == 0)
1763
COMPLETE_WITH_CONST("AS");
1764
/* Complete "CREATE RULE <sth> AS with "ON" */
1765
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1766
pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1767
pg_strcasecmp(prev_wd, "AS") == 0)
1768
COMPLETE_WITH_CONST("ON");
1769
/* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
1770
else if (pg_strcasecmp(prev4_wd, "RULE") == 0 &&
1771
pg_strcasecmp(prev2_wd, "AS") == 0 &&
1772
pg_strcasecmp(prev_wd, "ON") == 0)
1774
static const char *const rule_events[] =
1775
{"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
1777
COMPLETE_WITH_LIST(rule_events);
1779
/* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
1780
else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
1781
pg_strcasecmp(prev2_wd, "ON") == 0 &&
1782
(pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
1783
pg_toupper((unsigned char) prev_wd[5]) == 'T'))
1784
COMPLETE_WITH_CONST("TO");
1785
/* Complete "AS ON <sth> TO" with a table name */
1786
else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
1787
pg_strcasecmp(prev3_wd, "ON") == 0 &&
1788
pg_strcasecmp(prev_wd, "TO") == 0)
1789
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1791
/* CREATE SERVER <name> */
1792
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1793
pg_strcasecmp(prev2_wd, "SERVER") == 0)
1795
static const char *const list_CREATE_SERVER[] =
1796
{"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
1798
COMPLETE_WITH_LIST(list_CREATE_SERVER);
1802
/* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
1803
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1804
(pg_strcasecmp(prev_wd, "TEMP") == 0 ||
1805
pg_strcasecmp(prev_wd, "TEMPORARY") == 0))
1807
static const char *const list_TEMP[] =
1808
{"SEQUENCE", "TABLE", "VIEW", NULL};
1810
COMPLETE_WITH_LIST(list_TEMP);
1812
/* Complete "CREATE UNLOGGED" with TABLE */
1813
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
1814
pg_strcasecmp(prev_wd, "UNLOGGED") == 0)
1816
COMPLETE_WITH_CONST("TABLE");
1819
/* CREATE TABLESPACE */
1820
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1821
pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
1823
static const char *const list_CREATETABLESPACE[] =
1824
{"OWNER", "LOCATION", NULL};
1826
COMPLETE_WITH_LIST(list_CREATETABLESPACE);
1828
/* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
1829
else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1830
pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
1831
pg_strcasecmp(prev2_wd, "OWNER") == 0)
1833
COMPLETE_WITH_CONST("LOCATION");
1836
/* CREATE TEXT SEARCH */
1837
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1838
pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
1839
pg_strcasecmp(prev_wd, "SEARCH") == 0)
1841
static const char *const list_CREATETEXTSEARCH[] =
1842
{"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
1844
COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
1846
else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
1847
pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
1848
pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
1849
COMPLETE_WITH_CONST("(");
1851
/* CREATE TRIGGER */
1852
/* complete CREATE TRIGGER <name> with BEFORE,AFTER */
1853
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1854
pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
1856
static const char *const list_CREATETRIGGER[] =
1857
{"BEFORE", "AFTER", "INSTEAD OF", NULL};
1859
COMPLETE_WITH_LIST(list_CREATETRIGGER);
1861
/* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
1862
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1863
pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
1864
(pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
1865
pg_strcasecmp(prev_wd, "AFTER") == 0))
1867
static const char *const list_CREATETRIGGER_EVENTS[] =
1868
{"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
1870
COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
1872
/* complete CREATE TRIGGER <name> INSTEAD OF with an event */
1873
else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1874
pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1875
pg_strcasecmp(prev2_wd, "INSTEAD") == 0 &&
1876
pg_strcasecmp(prev_wd, "OF") == 0)
1878
static const char *const list_CREATETRIGGER_EVENTS[] =
1879
{"INSERT", "DELETE", "UPDATE", NULL};
1881
COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
1883
/* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
1884
else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
1885
pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
1886
(pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1887
pg_strcasecmp(prev2_wd, "AFTER") == 0)) ||
1888
(pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
1889
pg_strcasecmp(prev3_wd, "INSTEAD") == 0 &&
1890
pg_strcasecmp(prev2_wd, "OF") == 0))
1892
static const char *const list_CREATETRIGGER2[] =
1895
COMPLETE_WITH_LIST(list_CREATETRIGGER2);
1899
* complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
1902
else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
1903
(pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
1904
pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
1905
pg_strcasecmp(prev_wd, "ON") == 0)
1906
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1907
/* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
1908
else if (pg_strcasecmp(prev4_wd, "INSTEAD") == 0 &&
1909
pg_strcasecmp(prev3_wd, "OF") == 0 &&
1910
pg_strcasecmp(prev_wd, "ON") == 0)
1911
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
1912
/* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
1913
else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0)
1914
COMPLETE_WITH_CONST("PROCEDURE");
1916
/* CREATE ROLE,USER,GROUP */
1917
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1918
!(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
1919
(pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
1920
pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
1922
static const char *const list_CREATEROLE[] =
1923
{"ADMIN", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
1924
"ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOCREATEDB",
1925
"NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN",
1926
"NOREPLICATION", "NOSUPERUSER", "REPLICATION", "ROLE",
1927
"SUPERUSER", "SYSID", "UNENCRYPTED", "VALID UNTIL", NULL};
1929
COMPLETE_WITH_LIST(list_CREATEROLE);
1933
* complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
1936
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1937
(pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1938
pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1939
(pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
1941
COMPLETE_WITH_CONST("PASSWORD");
1943
/* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
1944
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1945
(pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
1946
pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
1947
pg_strcasecmp(prev_wd, "IN") == 0)
1949
static const char *const list_CREATEROLE3[] =
1950
{"GROUP", "ROLE", NULL};
1952
COMPLETE_WITH_LIST(list_CREATEROLE3);
1956
/* Complete CREATE VIEW <name> with AS */
1957
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
1958
pg_strcasecmp(prev2_wd, "VIEW") == 0)
1959
COMPLETE_WITH_CONST("AS");
1960
/* Complete "CREATE VIEW <sth> AS with "SELECT" */
1961
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
1962
pg_strcasecmp(prev3_wd, "VIEW") == 0 &&
1963
pg_strcasecmp(prev_wd, "AS") == 0)
1964
COMPLETE_WITH_CONST("SELECT");
1967
else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0)
1969
static const char *const list_DECLARE[] =
1970
{"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL};
1972
COMPLETE_WITH_LIST(list_DECLARE);
1976
else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
1978
static const char *const list_DECLARECURSOR[] =
1979
{"WITH HOLD", "WITHOUT HOLD", "FOR", NULL};
1981
COMPLETE_WITH_LIST(list_DECLARECURSOR);
1988
* Complete DELETE with FROM (only if the word before that is not "ON"
1989
* (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
1991
else if (pg_strcasecmp(prev_wd, "DELETE") == 0 &&
1992
!(pg_strcasecmp(prev2_wd, "ON") == 0 ||
1993
pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
1994
pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
1995
pg_strcasecmp(prev2_wd, "AFTER") == 0))
1996
COMPLETE_WITH_CONST("FROM");
1997
/* Complete DELETE FROM with a list of tables */
1998
else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
1999
pg_strcasecmp(prev_wd, "FROM") == 0)
2000
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL);
2001
/* Complete DELETE FROM <table> */
2002
else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
2003
pg_strcasecmp(prev2_wd, "FROM") == 0)
2005
static const char *const list_DELETE[] =
2006
{"USING", "WHERE", "SET", NULL};
2008
COMPLETE_WITH_LIST(list_DELETE);
2010
/* XXX: implement tab completion for DELETE ... USING */
2013
else if (pg_strcasecmp(prev_wd, "DISCARD") == 0)
2015
static const char *const list_DISCARD[] =
2016
{"ALL", "PLANS", "TEMP", NULL};
2018
COMPLETE_WITH_LIST(list_DISCARD);
2024
* Complete DO with LANGUAGE.
2026
else if (pg_strcasecmp(prev_wd, "DO") == 0)
2028
static const char *const list_DO[] =
2031
COMPLETE_WITH_LIST(list_DO);
2034
/* DROP (when not the previous word) */
2035
/* DROP AGGREGATE */
2036
else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2037
pg_strcasecmp(prev2_wd, "AGGREGATE") == 0)
2038
COMPLETE_WITH_CONST("(");
2040
/* DROP object with CASCADE / RESTRICT */
2041
else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2042
(pg_strcasecmp(prev2_wd, "COLLATION") == 0 ||
2043
pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
2044
pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
2045
pg_strcasecmp(prev2_wd, "EXTENSION") == 0 ||
2046
pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
2047
pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
2048
pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
2049
pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
2050
pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
2051
pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
2052
pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
2053
pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
2054
pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
2055
(pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2056
pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
2057
prev_wd[strlen(prev_wd) - 1] == ')') ||
2058
(pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2059
pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
2060
pg_strcasecmp(prev3_wd, "DATA") == 0 &&
2061
pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
2062
(pg_strcasecmp(prev5_wd, "DROP") == 0 &&
2063
pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
2064
pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
2065
(pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
2066
pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
2067
pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
2068
pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
2071
if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2072
pg_strcasecmp(prev2_wd, "FUNCTION") == 0)
2074
COMPLETE_WITH_CONST("(");
2078
static const char *const list_DROPCR[] =
2079
{"CASCADE", "RESTRICT", NULL};
2081
COMPLETE_WITH_LIST(list_DROPCR);
2084
else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2085
pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2087
static const char *const drop_CREATE_FOREIGN[] =
2088
{"DATA WRAPPER", "TABLE", NULL};
2090
COMPLETE_WITH_LIST(drop_CREATE_FOREIGN);
2092
else if (pg_strcasecmp(prev4_wd, "DROP") == 0 &&
2093
(pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
2094
pg_strcasecmp(prev3_wd, "FUNCTION") == 0) &&
2095
pg_strcasecmp(prev_wd, "(") == 0)
2097
char *tmp_buf = malloc(strlen(Query_for_list_of_arguments) + strlen(prev2_wd));
2099
sprintf(tmp_buf, Query_for_list_of_arguments, prev2_wd);
2100
COMPLETE_WITH_QUERY(tmp_buf);
2104
else if (pg_strcasecmp(prev2_wd, "DROP") == 0 &&
2105
pg_strcasecmp(prev_wd, "OWNED") == 0)
2106
COMPLETE_WITH_CONST("BY");
2107
else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2108
pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2109
pg_strcasecmp(prev_wd, "BY") == 0)
2110
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2111
else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
2112
pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
2113
pg_strcasecmp(prev_wd, "SEARCH") == 0)
2116
static const char *const list_ALTERTEXTSEARCH[] =
2117
{"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
2119
COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
2125
* Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2127
else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
2129
static const char *const list_EXPLAIN[] =
2130
{"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE", NULL};
2132
COMPLETE_WITH_LIST(list_EXPLAIN);
2134
else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2135
pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2137
static const char *const list_EXPLAIN[] =
2138
{"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};
2140
COMPLETE_WITH_LIST(list_EXPLAIN);
2142
else if ((pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
2143
pg_strcasecmp(prev_wd, "VERBOSE") == 0) ||
2144
(pg_strcasecmp(prev3_wd, "EXPLAIN") == 0 &&
2145
pg_strcasecmp(prev2_wd, "ANALYZE") == 0 &&
2146
pg_strcasecmp(prev_wd, "VERBOSE") == 0))
2148
static const char *const list_EXPLAIN[] =
2149
{"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", NULL};
2151
COMPLETE_WITH_LIST(list_EXPLAIN);
2155
/* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
2156
else if (pg_strcasecmp(prev_wd, "FETCH") == 0 ||
2157
pg_strcasecmp(prev_wd, "MOVE") == 0)
2159
static const char *const list_FETCH1[] =
2160
{"ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE", NULL};
2162
COMPLETE_WITH_LIST(list_FETCH1);
2164
/* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
2165
else if (pg_strcasecmp(prev2_wd, "FETCH") == 0 ||
2166
pg_strcasecmp(prev2_wd, "MOVE") == 0)
2168
static const char *const list_FETCH2[] =
2169
{"ALL", "NEXT", "PRIOR", NULL};
2171
COMPLETE_WITH_LIST(list_FETCH2);
2175
* Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
2176
* but we may as well tab-complete both: perhaps some users prefer one
2177
* variant or the other.
2179
else if (pg_strcasecmp(prev3_wd, "FETCH") == 0 ||
2180
pg_strcasecmp(prev3_wd, "MOVE") == 0)
2182
static const char *const list_FROMIN[] =
2183
{"FROM", "IN", NULL};
2185
COMPLETE_WITH_LIST(list_FROMIN);
2188
/* FOREIGN DATA WRAPPER */
2189
/* applies in ALTER/DROP FDW and in CREATE SERVER */
2190
else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
2191
pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
2192
pg_strcasecmp(prev2_wd, "DATA") == 0 &&
2193
pg_strcasecmp(prev_wd, "WRAPPER") == 0)
2194
COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2197
else if (pg_strcasecmp(prev3_wd, "CREATE") != 0 &&
2198
pg_strcasecmp(prev2_wd, "FOREIGN") == 0 &&
2199
pg_strcasecmp(prev_wd, "TABLE") == 0)
2200
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
2202
/* GRANT && REVOKE */
2203
/* Complete GRANT/REVOKE with a list of privileges */
2204
else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
2205
pg_strcasecmp(prev_wd, "REVOKE") == 0)
2207
static const char *const list_privilege[] =
2208
{"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
2209
"TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
2212
COMPLETE_WITH_LIST(list_privilege);
2214
/* Complete GRANT/REVOKE <sth> with "ON" */
2215
else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
2216
pg_strcasecmp(prev2_wd, "REVOKE") == 0)
2217
COMPLETE_WITH_CONST("ON");
2220
* Complete GRANT/REVOKE <sth> ON with a list of tables, views, sequences,
2223
* keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result via
2224
* UNION; seems to work intuitively
2226
* Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
2227
* here will only work if the privilege list contains exactly one
2230
else if ((pg_strcasecmp(prev3_wd, "GRANT") == 0 ||
2231
pg_strcasecmp(prev3_wd, "REVOKE") == 0) &&
2232
pg_strcasecmp(prev_wd, "ON") == 0)
2233
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf,
2234
" UNION SELECT 'DATABASE'"
2235
" UNION SELECT 'FOREIGN DATA WRAPPER'"
2236
" UNION SELECT 'FOREIGN SERVER'"
2237
" UNION SELECT 'FOREIGN TABLE'"
2238
" UNION SELECT 'FUNCTION'"
2239
" UNION SELECT 'LANGUAGE'"
2240
" UNION SELECT 'LARGE OBJECT'"
2241
" UNION SELECT 'SCHEMA'"
2242
" UNION SELECT 'TABLESPACE'");
2243
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2244
pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2245
pg_strcasecmp(prev2_wd, "ON") == 0 &&
2246
pg_strcasecmp(prev_wd, "FOREIGN") == 0)
2248
static const char *const list_privilege_foreign[] =
2249
{"DATA WRAPPER", "SERVER", "TABLE", NULL};
2251
COMPLETE_WITH_LIST(list_privilege_foreign);
2254
/* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
2255
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
2256
pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
2257
pg_strcasecmp(prev2_wd, "ON") == 0)
2259
if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
2260
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2261
else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
2262
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2263
else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
2264
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2265
else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
2266
COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2267
else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
2268
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2269
else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
2270
COMPLETE_WITH_CONST("TO");
2272
COMPLETE_WITH_CONST("FROM");
2275
/* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
2276
else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
2277
pg_strcasecmp(prev3_wd, "ON") == 0)
2279
if (pg_strcasecmp(prev_wd, "TO") == 0)
2280
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2282
COMPLETE_WITH_CONST("TO");
2284
else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
2285
pg_strcasecmp(prev3_wd, "ON") == 0)
2287
if (pg_strcasecmp(prev_wd, "FROM") == 0)
2288
COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2290
COMPLETE_WITH_CONST("FROM");
2294
else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2295
pg_strcasecmp(prev_wd, "GROUP") == 0)
2296
COMPLETE_WITH_CONST("BY");
2299
/* Complete INSERT with "INTO" */
2300
else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
2301
COMPLETE_WITH_CONST("INTO");
2302
/* Complete INSERT INTO with table names */
2303
else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
2304
pg_strcasecmp(prev_wd, "INTO") == 0)
2305
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL);
2306
/* Complete "INSERT INTO <table> (" with attribute names */
2307
else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2308
pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2309
pg_strcasecmp(prev_wd, "(") == 0)
2310
COMPLETE_WITH_ATTR(prev2_wd, "");
2313
* Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
2314
* "TABLE" or "DEFAULT VALUES"
2316
else if (pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
2317
pg_strcasecmp(prev2_wd, "INTO") == 0)
2319
static const char *const list_INSERT[] =
2320
{"(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", NULL};
2322
COMPLETE_WITH_LIST(list_INSERT);
2326
* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
2329
else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
2330
pg_strcasecmp(prev3_wd, "INTO") == 0 &&
2331
prev_wd[strlen(prev_wd) - 1] == ')')
2333
static const char *const list_INSERT[] =
2334
{"SELECT", "TABLE", "VALUES", NULL};
2336
COMPLETE_WITH_LIST(list_INSERT);
2339
/* Insert an open parenthesis after "VALUES" */
2340
else if (pg_strcasecmp(prev_wd, "VALUES") == 0 &&
2341
pg_strcasecmp(prev2_wd, "DEFAULT") != 0)
2342
COMPLETE_WITH_CONST("(");
2345
/* Complete LOCK [TABLE] with a list of tables */
2346
else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
2347
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2348
" UNION SELECT 'TABLE'");
2349
else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
2350
pg_strcasecmp(prev2_wd, "LOCK") == 0)
2351
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
2353
/* For the following, handle the case of a single table only for now */
2355
/* Complete LOCK [TABLE] <table> with "IN" */
2356
else if ((pg_strcasecmp(prev2_wd, "LOCK") == 0 &&
2357
pg_strcasecmp(prev_wd, "TABLE")) ||
2358
(pg_strcasecmp(prev2_wd, "TABLE") == 0 &&
2359
pg_strcasecmp(prev3_wd, "LOCK") == 0))
2360
COMPLETE_WITH_CONST("IN");
2362
/* Complete LOCK [TABLE] <table> IN with a lock mode */
2363
else if (pg_strcasecmp(prev_wd, "IN") == 0 &&
2364
(pg_strcasecmp(prev3_wd, "LOCK") == 0 ||
2365
(pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
2366
pg_strcasecmp(prev4_wd, "LOCK") == 0)))
2368
static const char *const lock_modes[] =
2369
{"ACCESS SHARE MODE",
2370
"ROW SHARE MODE", "ROW EXCLUSIVE MODE",
2371
"SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
2372
"SHARE ROW EXCLUSIVE MODE",
2373
"EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
2375
COMPLETE_WITH_LIST(lock_modes);
2379
else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
2380
COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s'");
2383
else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
2384
COMPLETE_WITH_CONST("(");
2386
/* OWNER TO - complete with available roles */
2387
else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
2388
pg_strcasecmp(prev_wd, "TO") == 0)
2389
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2392
else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
2393
pg_strcasecmp(prev_wd, "ORDER") == 0)
2394
COMPLETE_WITH_CONST("BY");
2395
else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
2396
pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
2397
pg_strcasecmp(prev_wd, "BY") == 0)
2398
COMPLETE_WITH_ATTR(prev3_wd, "");
2401
else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
2402
pg_strcasecmp(prev3_wd, "PREPARE") == 0)
2404
static const char *const list_PREPARE[] =
2405
{"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
2407
COMPLETE_WITH_LIST(list_PREPARE);
2411
* PREPARE TRANSACTION is missing on purpose. It's intended for transaction
2412
* managers, not for manual use in interactive sessions.
2415
/* REASSIGN OWNED BY xxx TO yyy */
2416
else if (pg_strcasecmp(prev_wd, "REASSIGN") == 0)
2417
COMPLETE_WITH_CONST("OWNED");
2418
else if (pg_strcasecmp(prev_wd, "OWNED") == 0 &&
2419
pg_strcasecmp(prev2_wd, "REASSIGN") == 0)
2420
COMPLETE_WITH_CONST("BY");
2421
else if (pg_strcasecmp(prev_wd, "BY") == 0 &&
2422
pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
2423
pg_strcasecmp(prev3_wd, "REASSIGN") == 0)
2424
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2425
else if (pg_strcasecmp(prev2_wd, "BY") == 0 &&
2426
pg_strcasecmp(prev3_wd, "OWNED") == 0 &&
2427
pg_strcasecmp(prev4_wd, "REASSIGN") == 0)
2428
COMPLETE_WITH_CONST("TO");
2429
else if (pg_strcasecmp(prev_wd, "TO") == 0 &&
2430
pg_strcasecmp(prev3_wd, "BY") == 0 &&
2431
pg_strcasecmp(prev4_wd, "OWNED") == 0 &&
2432
pg_strcasecmp(prev5_wd, "REASSIGN") == 0)
2433
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2436
else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
2438
static const char *const list_REINDEX[] =
2439
{"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
2441
COMPLETE_WITH_LIST(list_REINDEX);
2443
else if (pg_strcasecmp(prev2_wd, "REINDEX") == 0)
2445
if (pg_strcasecmp(prev_wd, "TABLE") == 0)
2446
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2447
else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
2448
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2449
else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
2450
pg_strcasecmp(prev_wd, "DATABASE") == 0)
2451
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2454
/* SECURITY LABEL */
2455
else if (pg_strcasecmp(prev_wd, "SECURITY") == 0)
2456
COMPLETE_WITH_CONST("LABEL");
2457
else if (pg_strcasecmp(prev2_wd, "SECURITY") == 0 &&
2458
pg_strcasecmp(prev_wd, "LABEL") == 0)
2460
static const char *const list_SECURITY_LABEL_preposition[] =
2463
COMPLETE_WITH_LIST(list_SECURITY_LABEL_preposition);
2465
else if (pg_strcasecmp(prev4_wd, "SECURITY") == 0 &&
2466
pg_strcasecmp(prev3_wd, "LABEL") == 0 &&
2467
pg_strcasecmp(prev2_wd, "FOR") == 0)
2468
COMPLETE_WITH_CONST("ON");
2469
else if ((pg_strcasecmp(prev3_wd, "SECURITY") == 0 &&
2470
pg_strcasecmp(prev2_wd, "LABEL") == 0 &&
2471
pg_strcasecmp(prev_wd, "ON") == 0) ||
2472
(pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2473
pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2474
pg_strcasecmp(prev3_wd, "FOR") == 0 &&
2475
pg_strcasecmp(prev_wd, "ON") == 0))
2477
static const char *const list_SECURITY_LABEL[] =
2478
{"LANGUAGE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN",
2479
"AGGREGATE", "FUNCTION", "DOMAIN", "LARGE OBJECT",
2482
COMPLETE_WITH_LIST(list_SECURITY_LABEL);
2484
else if (pg_strcasecmp(prev5_wd, "SECURITY") == 0 &&
2485
pg_strcasecmp(prev4_wd, "LABEL") == 0 &&
2486
pg_strcasecmp(prev3_wd, "ON") == 0)
2487
COMPLETE_WITH_CONST("IS");
2492
/* SET, RESET, SHOW */
2493
/* Complete with a variable name */
2494
else if ((pg_strcasecmp(prev_wd, "SET") == 0 &&
2495
pg_strcasecmp(prev3_wd, "UPDATE") != 0) ||
2496
pg_strcasecmp(prev_wd, "RESET") == 0)
2497
COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
2498
else if (pg_strcasecmp(prev_wd, "SHOW") == 0)
2499
COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
2500
/* Complete "SET TRANSACTION" */
2501
else if ((pg_strcasecmp(prev2_wd, "SET") == 0 &&
2502
pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2503
|| (pg_strcasecmp(prev2_wd, "START") == 0
2504
&& pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2505
|| (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2506
&& pg_strcasecmp(prev_wd, "WORK") == 0)
2507
|| (pg_strcasecmp(prev2_wd, "BEGIN") == 0
2508
&& pg_strcasecmp(prev_wd, "TRANSACTION") == 0)
2509
|| (pg_strcasecmp(prev4_wd, "SESSION") == 0
2510
&& pg_strcasecmp(prev3_wd, "CHARACTERISTICS") == 0
2511
&& pg_strcasecmp(prev2_wd, "AS") == 0
2512
&& pg_strcasecmp(prev_wd, "TRANSACTION") == 0))
2514
static const char *const my_list[] =
2515
{"ISOLATION LEVEL", "READ", NULL};
2517
COMPLETE_WITH_LIST(my_list);
2519
else if ((pg_strcasecmp(prev3_wd, "SET") == 0
2520
|| pg_strcasecmp(prev3_wd, "BEGIN") == 0
2521
|| pg_strcasecmp(prev3_wd, "START") == 0
2522
|| (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
2523
&& pg_strcasecmp(prev3_wd, "AS") == 0))
2524
&& (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
2525
|| pg_strcasecmp(prev2_wd, "WORK") == 0)
2526
&& pg_strcasecmp(prev_wd, "ISOLATION") == 0)
2527
COMPLETE_WITH_CONST("LEVEL");
2528
else if ((pg_strcasecmp(prev4_wd, "SET") == 0
2529
|| pg_strcasecmp(prev4_wd, "BEGIN") == 0
2530
|| pg_strcasecmp(prev4_wd, "START") == 0
2531
|| pg_strcasecmp(prev4_wd, "AS") == 0)
2532
&& (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
2533
|| pg_strcasecmp(prev3_wd, "WORK") == 0)
2534
&& pg_strcasecmp(prev2_wd, "ISOLATION") == 0
2535
&& pg_strcasecmp(prev_wd, "LEVEL") == 0)
2537
static const char *const my_list[] =
2538
{"READ", "REPEATABLE", "SERIALIZABLE", NULL};
2540
COMPLETE_WITH_LIST(my_list);
2542
else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2543
pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2544
pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2545
pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2546
pg_strcasecmp(prev_wd, "READ") == 0)
2548
static const char *const my_list[] =
2549
{"UNCOMMITTED", "COMMITTED", NULL};
2551
COMPLETE_WITH_LIST(my_list);
2553
else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
2554
pg_strcasecmp(prev4_wd, "WORK") == 0) &&
2555
pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
2556
pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
2557
pg_strcasecmp(prev_wd, "REPEATABLE") == 0)
2558
COMPLETE_WITH_CONST("READ");
2559
else if ((pg_strcasecmp(prev3_wd, "SET") == 0 ||
2560
pg_strcasecmp(prev3_wd, "BEGIN") == 0 ||
2561
pg_strcasecmp(prev3_wd, "START") == 0 ||
2562
pg_strcasecmp(prev3_wd, "AS") == 0) &&
2563
(pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 ||
2564
pg_strcasecmp(prev2_wd, "WORK") == 0) &&
2565
pg_strcasecmp(prev_wd, "READ") == 0)
2567
static const char *const my_list[] =
2568
{"ONLY", "WRITE", NULL};
2570
COMPLETE_WITH_LIST(my_list);
2572
/* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
2573
else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2574
pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
2576
static const char *const constraint_list[] =
2577
{"DEFERRED", "IMMEDIATE", NULL};
2579
COMPLETE_WITH_LIST(constraint_list);
2581
/* Complete SET ROLE */
2582
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2583
pg_strcasecmp(prev_wd, "ROLE") == 0)
2584
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2585
/* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
2586
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2587
pg_strcasecmp(prev_wd, "SESSION") == 0)
2589
static const char *const my_list[] =
2590
{"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL};
2592
COMPLETE_WITH_LIST(my_list);
2594
/* Complete SET SESSION AUTHORIZATION with username */
2595
else if (pg_strcasecmp(prev3_wd, "SET") == 0
2596
&& pg_strcasecmp(prev2_wd, "SESSION") == 0
2597
&& pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
2598
COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
2599
/* Complete RESET SESSION with AUTHORIZATION */
2600
else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
2601
pg_strcasecmp(prev_wd, "SESSION") == 0)
2602
COMPLETE_WITH_CONST("AUTHORIZATION");
2603
/* Complete SET <var> with "TO" */
2604
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2605
pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
2606
pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
2607
pg_strcasecmp(prev_wd, "SCHEMA") != 0 &&
2608
prev_wd[strlen(prev_wd) - 1] != ')' &&
2609
pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
2610
COMPLETE_WITH_CONST("TO");
2611
/* Suggest possible variable values */
2612
else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
2613
(pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
2615
if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
2617
static const char *const my_list[] =
2618
{"ISO", "SQL", "Postgres", "German",
2619
"YMD", "DMY", "MDY",
2620
"US", "European", "NonEuropean",
2623
COMPLETE_WITH_LIST(my_list);
2625
else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
2627
static const char *const my_list[] =
2628
{"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
2630
COMPLETE_WITH_LIST(my_list);
2632
else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
2634
static const char *const my_list[] =
2635
{"ON", "OFF", "DEFAULT", NULL};
2637
COMPLETE_WITH_LIST(my_list);
2641
static const char *const my_list[] =
2644
COMPLETE_WITH_LIST(my_list);
2648
/* START TRANSACTION */
2649
else if (pg_strcasecmp(prev_wd, "START") == 0)
2650
COMPLETE_WITH_CONST("TRANSACTION");
2653
else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0)
2654
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2657
else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 0)
2658
COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s' UNION SELECT '*'");
2661
/* If prev. word is UPDATE suggest a list of tables */
2662
else if (pg_strcasecmp(prev_wd, "UPDATE") == 0)
2663
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
2664
/* Complete UPDATE <table> with "SET" */
2665
else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
2666
COMPLETE_WITH_CONST("SET");
2669
* If the previous word is SET (and it wasn't caught above as the _first_
2670
* word) the word before it was (hopefully) a table name and we'll now
2671
* make a list of attributes.
2673
else if (pg_strcasecmp(prev_wd, "SET") == 0)
2674
COMPLETE_WITH_ATTR(prev2_wd, "");
2676
/* UPDATE xx SET yy = */
2677
else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
2678
pg_strcasecmp(prev4_wd, "UPDATE") == 0)
2679
COMPLETE_WITH_CONST("=");
2682
else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
2683
pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
2684
pg_strcasecmp(prev3_wd, "DROP") == 0) &&
2685
pg_strcasecmp(prev2_wd, "USER") == 0 &&
2686
pg_strcasecmp(prev_wd, "MAPPING") == 0)
2687
COMPLETE_WITH_CONST("FOR");
2688
else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
2689
pg_strcasecmp(prev3_wd, "USER") == 0 &&
2690
pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2691
pg_strcasecmp(prev_wd, "FOR") == 0)
2692
COMPLETE_WITH_QUERY(Query_for_list_of_roles
2693
" UNION SELECT 'CURRENT_USER'"
2694
" UNION SELECT 'PUBLIC'"
2695
" UNION SELECT 'USER'");
2696
else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
2697
pg_strcasecmp(prev4_wd, "DROP") == 0) &&
2698
pg_strcasecmp(prev3_wd, "USER") == 0 &&
2699
pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
2700
pg_strcasecmp(prev_wd, "FOR") == 0)
2701
COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2702
else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
2703
pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
2704
pg_strcasecmp(prev5_wd, "DROP") == 0) &&
2705
pg_strcasecmp(prev4_wd, "USER") == 0 &&
2706
pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
2707
pg_strcasecmp(prev2_wd, "FOR") == 0)
2708
COMPLETE_WITH_CONST("SERVER");
2711
* VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
2712
* VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
2714
else if (pg_strcasecmp(prev_wd, "VACUUM") == 0)
2715
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2716
" UNION SELECT 'FULL'"
2717
" UNION SELECT 'FREEZE'"
2718
" UNION SELECT 'ANALYZE'"
2719
" UNION SELECT 'VERBOSE'");
2720
else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2721
(pg_strcasecmp(prev_wd, "FULL") == 0 ||
2722
pg_strcasecmp(prev_wd, "FREEZE") == 0))
2723
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2724
" UNION SELECT 'ANALYZE'"
2725
" UNION SELECT 'VERBOSE'");
2726
else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2727
pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2728
(pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2729
pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2730
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2731
" UNION SELECT 'VERBOSE'");
2732
else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 &&
2733
pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2734
(pg_strcasecmp(prev2_wd, "FULL") == 0 ||
2735
pg_strcasecmp(prev2_wd, "FREEZE") == 0))
2736
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2737
" UNION SELECT 'ANALYZE'");
2738
else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2739
pg_strcasecmp(prev_wd, "VERBOSE") == 0)
2740
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2741
" UNION SELECT 'ANALYZE'");
2742
else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 &&
2743
pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2744
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2745
" UNION SELECT 'VERBOSE'");
2746
else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 &&
2747
pg_strcasecmp(prev2_wd, "VERBOSE") == 0) ||
2748
(pg_strcasecmp(prev_wd, "VERBOSE") == 0 &&
2749
pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
2750
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2752
/* WITH [RECURSIVE] */
2753
else if (pg_strcasecmp(prev_wd, "WITH") == 0)
2754
COMPLETE_WITH_CONST("RECURSIVE");
2757
/* If the previous word is ANALYZE, produce list of tables */
2758
else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
2759
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2762
/* Simple case of the word before the where being the table name */
2763
else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
2764
COMPLETE_WITH_ATTR(prev2_wd, "");
2767
/* TODO: also include SRF ? */
2768
else if (pg_strcasecmp(prev_wd, "FROM") == 0 &&
2769
pg_strcasecmp(prev3_wd, "COPY") != 0 &&
2770
pg_strcasecmp(prev3_wd, "\\copy") != 0)
2771
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2774
else if (pg_strcasecmp(prev_wd, "JOIN") == 0)
2775
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2777
/* Backslash commands */
2778
/* TODO: \dc \dd \dl */
2779
else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
2780
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2782
else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0)
2783
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
2784
else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)
2785
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2786
else if (strncmp(prev_wd, "\\dD", strlen("\\dD")) == 0)
2787
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2788
else if (strncmp(prev_wd, "\\des", strlen("\\des")) == 0)
2789
COMPLETE_WITH_QUERY(Query_for_list_of_servers);
2790
else if (strncmp(prev_wd, "\\deu", strlen("\\deu")) == 0)
2791
COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
2792
else if (strncmp(prev_wd, "\\dew", strlen("\\dew")) == 0)
2793
COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2795
else if (strncmp(prev_wd, "\\df", strlen("\\df")) == 0)
2796
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2797
else if (strncmp(prev_wd, "\\dFd", strlen("\\dFd")) == 0)
2798
COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
2799
else if (strncmp(prev_wd, "\\dFp", strlen("\\dFp")) == 0)
2800
COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
2801
else if (strncmp(prev_wd, "\\dFt", strlen("\\dFt")) == 0)
2802
COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
2803
/* must be at end of \dF */
2804
else if (strncmp(prev_wd, "\\dF", strlen("\\dF")) == 0)
2805
COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
2807
else if (strncmp(prev_wd, "\\di", strlen("\\di")) == 0)
2808
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2809
else if (strncmp(prev_wd, "\\dL", strlen("\\dL")) == 0)
2810
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2811
else if (strncmp(prev_wd, "\\dn", strlen("\\dn")) == 0)
2812
COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2813
else if (strncmp(prev_wd, "\\dp", strlen("\\dp")) == 0
2814
|| strncmp(prev_wd, "\\z", strlen("\\z")) == 0)
2815
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, NULL);
2816
else if (strncmp(prev_wd, "\\ds", strlen("\\ds")) == 0)
2817
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
2818
else if (strncmp(prev_wd, "\\dt", strlen("\\dt")) == 0)
2819
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2820
else if (strncmp(prev_wd, "\\dT", strlen("\\dT")) == 0)
2821
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2822
else if (strncmp(prev_wd, "\\du", strlen("\\du")) == 0
2823
|| (strncmp(prev_wd, "\\dg", strlen("\\dg")) == 0))
2824
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2825
else if (strncmp(prev_wd, "\\dv", strlen("\\dv")) == 0)
2826
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2828
/* must be at end of \d list */
2829
else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
2830
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisvf, NULL);
2832
else if (strcmp(prev_wd, "\\ef") == 0)
2833
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2835
else if (strcmp(prev_wd, "\\encoding") == 0)
2836
COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
2837
else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
2838
COMPLETE_WITH_LIST(sql_commands);
2839
else if (strcmp(prev_wd, "\\password") == 0)
2840
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2841
else if (strcmp(prev_wd, "\\pset") == 0)
2843
static const char *const my_list[] =
2844
{"format", "border", "expanded",
2845
"null", "fieldsep", "tuples_only", "title", "tableattr",
2846
"linestyle", "pager", "recordsep", NULL};
2848
COMPLETE_WITH_LIST(my_list);
2850
else if (strcmp(prev2_wd, "\\pset") == 0)
2852
if (strcmp(prev_wd, "format") == 0)
2854
static const char *const my_list[] =
2855
{"unaligned", "aligned", "wrapped", "html", "latex",
2858
COMPLETE_WITH_LIST(my_list);
2860
else if (strcmp(prev_wd, "linestyle") == 0)
2862
static const char *const my_list[] =
2863
{"ascii", "old-ascii", "unicode", NULL};
2865
COMPLETE_WITH_LIST(my_list);
2868
else if (strcmp(prev_wd, "\\set") == 0)
2870
matches = complete_from_variables(text, "", "");
2872
else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
2873
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2874
else if (strcmp(prev_wd, "\\cd") == 0 ||
2875
strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
2876
strcmp(prev_wd, "\\g") == 0 ||
2877
strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
2878
strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
2879
strcmp(prev_wd, "\\s") == 0 ||
2880
strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
2882
matches = completion_matches(text, filename_completion_function);
2885
* Finally, we look through the list of "things", such as TABLE, INDEX and
2886
* check if that was the previous word. If so, execute the query to get a
2893
for (i = 0; words_after_create[i].name; i++)
2895
if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
2897
if (words_after_create[i].query)
2898
COMPLETE_WITH_QUERY(words_after_create[i].query);
2899
else if (words_after_create[i].squery)
2900
COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
2908
* If we still don't have anything to match we have to fabricate some sort
2909
* of default list. If we were to just return NULL, readline automatically
2910
* attempts filename completion, and that's usually no good.
2912
if (matches == NULL)
2914
COMPLETE_WITH_CONST("");
2915
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
2916
rl_completion_append_character = '\0';
2927
/* Return our Grand List O' Matches */
2933
* GENERATOR FUNCTIONS
2935
* These functions do all the actual work of completing the input. They get
2936
* passed the text so far and the count how many times they have been called
2937
* so far with the same text.
2938
* If you read the above carefully, you'll see that these don't get called
2939
* directly but through the readline interface.
2940
* The return value is expected to be the full completion of the text, going
2941
* through a list each time, or NULL if there are no more matches. The string
2942
* will be free()'d by readline, so you must run it through strdup() or
2943
* something of that sort.
2947
* Common routine for create_command_generator and drop_command_generator.
2948
* Entries that have 'excluded' flags are not returned.
2951
create_or_drop_command_generator(const char *text, int state, bits32 excluded)
2953
static int list_index,
2957
/* If this is the first time for this completion, init some values */
2961
string_length = strlen(text);
2964
/* find something that matches */
2965
while ((name = words_after_create[list_index++].name))
2967
if ((pg_strncasecmp(name, text, string_length) == 0) &&
2968
!(words_after_create[list_index - 1].flags & excluded))
2969
return pg_strdup(name);
2971
/* if nothing matches, return NULL */
2976
* This one gives you one from a list of things you can put after CREATE
2980
create_command_generator(const char *text, int state)
2982
return create_or_drop_command_generator(text, state, THING_NO_CREATE);
2986
* This function gives you a list of things you can put after a DROP command.
2989
drop_command_generator(const char *text, int state)
2991
return create_or_drop_command_generator(text, state, THING_NO_DROP);
2994
/* The following two functions are wrappers for _complete_from_query */
2997
complete_from_query(const char *text, int state)
2999
return _complete_from_query(0, text, state);
3003
complete_from_schema_query(const char *text, int state)
3005
return _complete_from_query(1, text, state);
3010
* This creates a list of matching things, according to a query pointed to
3011
* by completion_charp.
3012
* The query can be one of two kinds:
3014
* 1. A simple query which must contain a %d and a %s, which will be replaced
3015
* by the string length of the text and the text itself. The query may also
3016
* have up to four more %s in it; the first two such will be replaced by the
3017
* value of completion_info_charp, the next two by the value of
3018
* completion_info_charp2.
3020
* 2. A schema query used for completion of both schema and relation names.
3021
* These are more complex and must contain in the following order:
3022
* %d %s %d %s %d %s %s %d %s
3023
* where %d is the string length of the text and %s the text itself.
3025
* It is assumed that strings should be escaped to become SQL literals
3026
* (that is, what is in the query is actually ... '%s' ...)
3028
* See top of file for examples of both kinds of query.
3031
_complete_from_query(int is_schema_query, const char *text, int state)
3033
static int list_index,
3035
static PGresult *result = NULL;
3038
* If this is the first time for this completion, we fetch a list of our
3039
* "things" from the backend.
3043
PQExpBufferData query_buffer;
3046
char *e_info_charp2;
3049
string_length = strlen(text);
3051
/* Free any prior result */
3055
/* Set up suitably-escaped copies of textual inputs */
3056
e_text = pg_malloc(string_length * 2 + 1);
3057
PQescapeString(e_text, text, string_length);
3059
if (completion_info_charp)
3063
charp_len = strlen(completion_info_charp);
3064
e_info_charp = pg_malloc(charp_len * 2 + 1);
3065
PQescapeString(e_info_charp, completion_info_charp,
3069
e_info_charp = NULL;
3071
if (completion_info_charp2)
3075
charp_len = strlen(completion_info_charp2);
3076
e_info_charp2 = pg_malloc(charp_len * 2 + 1);
3077
PQescapeString(e_info_charp2, completion_info_charp2,
3081
e_info_charp2 = NULL;
3083
initPQExpBuffer(&query_buffer);
3085
if (is_schema_query)
3087
/* completion_squery gives us the pieces to assemble */
3088
const char *qualresult = completion_squery->qualresult;
3090
if (qualresult == NULL)
3091
qualresult = completion_squery->result;
3093
/* Get unqualified names matching the input-so-far */
3094
appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
3095
completion_squery->result,
3096
completion_squery->catname);
3097
if (completion_squery->selcondition)
3098
appendPQExpBuffer(&query_buffer, "%s AND ",
3099
completion_squery->selcondition);
3100
appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
3101
completion_squery->result,
3102
string_length, e_text);
3103
appendPQExpBuffer(&query_buffer, " AND %s",
3104
completion_squery->viscondition);
3107
* When fetching relation names, suppress system catalogs unless
3108
* the input-so-far begins with "pg_". This is a compromise
3109
* between not offering system catalogs for completion at all, and
3110
* having them swamp the result when the input is just "p".
3112
if (strcmp(completion_squery->catname,
3113
"pg_catalog.pg_class c") == 0 &&
3114
strncmp(text, "pg_", 3) !=0)
3116
appendPQExpBuffer(&query_buffer,
3117
" AND c.relnamespace <> (SELECT oid FROM"
3118
" pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
3122
* Add in matching schema names, but only if there is more than
3123
* one potential match among schema names.
3125
appendPQExpBuffer(&query_buffer, "\nUNION\n"
3126
"SELECT pg_catalog.quote_ident(n.nspname) || '.' "
3127
"FROM pg_catalog.pg_namespace n "
3128
"WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
3129
string_length, e_text);
3130
appendPQExpBuffer(&query_buffer,
3131
" AND (SELECT pg_catalog.count(*)"
3132
" FROM pg_catalog.pg_namespace"
3133
" WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3134
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
3135
string_length, e_text);
3138
* Add in matching qualified names, but only if there is exactly
3139
* one schema matching the input-so-far.
3141
appendPQExpBuffer(&query_buffer, "\nUNION\n"
3142
"SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
3143
"FROM %s, pg_catalog.pg_namespace n "
3144
"WHERE %s = n.oid AND ",
3146
completion_squery->catname,
3147
completion_squery->namespace);
3148
if (completion_squery->selcondition)
3149
appendPQExpBuffer(&query_buffer, "%s AND ",
3150
completion_squery->selcondition);
3151
appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
3153
string_length, e_text);
3156
* This condition exploits the single-matching-schema rule to
3157
* speed up the query
3159
appendPQExpBuffer(&query_buffer,
3160
" AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
3161
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
3162
string_length, e_text);
3163
appendPQExpBuffer(&query_buffer,
3164
" AND (SELECT pg_catalog.count(*)"
3165
" FROM pg_catalog.pg_namespace"
3166
" WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3167
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
3168
string_length, e_text);
3170
/* If an addon query was provided, use it */
3171
if (completion_charp)
3172
appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
3176
/* completion_charp is an sprintf-style format string */
3177
appendPQExpBuffer(&query_buffer, completion_charp,
3178
string_length, e_text,
3179
e_info_charp, e_info_charp,
3180
e_info_charp2, e_info_charp2);
3183
/* Limit the number of records in the result */
3184
appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
3185
completion_max_records);
3187
result = exec_query(query_buffer.data);
3189
termPQExpBuffer(&query_buffer);
3194
free(e_info_charp2);
3197
/* Find something that matches */
3198
if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
3202
while (list_index < PQntuples(result) &&
3203
(item = PQgetvalue(result, list_index++, 0)))
3204
if (pg_strncasecmp(text, item, string_length) == 0)
3205
return pg_strdup(item);
3208
/* If nothing matches, free the db structure and return null */
3216
* This function returns in order one of a fixed, NULL pointer terminated list
3217
* of strings (if matching). This can be used if there are only a fixed number
3218
* SQL words that can appear at certain spot.
3221
complete_from_list(const char *text, int state)
3223
static int string_length,
3226
static bool casesensitive;
3229
/* need to have a list */
3230
psql_assert(completion_charpp);
3232
/* Initialization */
3236
string_length = strlen(text);
3237
casesensitive = true;
3241
while ((item = completion_charpp[list_index++]))
3243
/* First pass is case sensitive */
3244
if (casesensitive && strncmp(text, item, string_length) == 0)
3247
return pg_strdup(item);
3250
/* Second pass is case insensitive, don't bother counting matches */
3251
if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
3252
return pg_strdup(item);
3256
* No matches found. If we're not case insensitive already, lets switch to
3257
* being case insensitive and try again
3259
if (casesensitive && matches == 0)
3261
casesensitive = false;
3264
return complete_from_list(text, state);
3267
/* If no more matches, return null. */
3273
* This function returns one fixed string the first time even if it doesn't
3274
* match what's there, and nothing the second time. This should be used if
3275
* there is only one possibility that can appear at a certain spot, so
3276
* misspellings will be overwritten. The string to be passed must be in
3280
complete_from_const(const char *text, int state)
3282
(void) text; /* We don't care about what was entered
3285
psql_assert(completion_charp);
3287
return pg_strdup(completion_charp);
3294
* This function supports completion with the name of a psql variable.
3295
* The variable names can be prefixed and suffixed with additional text
3296
* to support quoting usages.
3299
complete_from_variables(char *text, const char *prefix, const char *suffix)
3302
int overhead = strlen(prefix) + strlen(suffix) + 1;
3303
const char **varnames;
3307
struct _variable *ptr;
3309
varnames = (const char **) pg_malloc((maxvars + 1) * sizeof(char *));
3311
for (ptr = pset.vars->next; ptr; ptr = ptr->next)
3315
if (nvars >= maxvars)
3318
varnames = (const char **) realloc(varnames,
3319
(maxvars + 1) * sizeof(char *));
3322
psql_error("out of memory\n");
3327
buffer = (char *) pg_malloc(strlen(ptr->name) + overhead);
3328
sprintf(buffer, "%s%s%s", prefix, ptr->name, suffix);
3329
varnames[nvars++] = buffer;
3332
varnames[nvars] = NULL;
3333
COMPLETE_WITH_LIST(varnames);
3335
for (i = 0; i < nvars; i++)
3336
free((void *) varnames[i]);
3343
/* HELPER FUNCTIONS */
3347
* Execute a query and report any errors. This should be the preferred way of
3348
* talking to the database in this file.
3351
exec_query(const char *query)
3355
if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
3358
result = PQexec(pset.db, query);
3360
if (PQresultStatus(result) != PGRES_TUPLES_OK)
3363
psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
3364
PQerrorMessage(pset.db), query);
3375
* Return the word (space delimited) before point. Set skip > 0 to
3376
* skip that many words; e.g. skip=1 finds the word before the
3377
* previous one. Return value is NULL or a malloc'ed string.
3380
previous_word(int point, int skip)
3387
const char *buf = rl_line_buffer; /* alias */
3389
/* first we look for a space or a parenthesis before the current word */
3390
for (i = point - 1; i >= 0; i--)
3391
if (strchr(WORD_BREAKS, buf[i]))
3397
int parentheses = 0;
3399
/* now find the first non-space which then constitutes the end */
3400
for (i = point; i >= 0; i--)
3408
* If no end found we return null, because there is no word before the
3415
* Otherwise we now look for the start. The start is either the last
3416
* character before any space going backwards from the end, or it's
3417
* simply character 0. We also handle open quotes and parentheses.
3419
for (start = end; start > 0; start--)
3421
if (buf[start] == '"')
3422
inquotes = !inquotes;
3425
if (buf[start] == ')')
3427
else if (buf[start] == '(')
3429
if (--parentheses <= 0)
3432
else if (parentheses == 0 &&
3433
strchr(WORD_BREAKS, buf[start - 1]))
3442
s = pg_malloc(end - start + 2);
3443
strlcpy(s, &buf[start], end - start + 2);
3451
* Surround a string with single quotes. This works for both SQL and
3452
* psql internal. Currently disabled because it is reported not to
3453
* cooperate with certain versions of readline.
3456
quote_file_name(char *text, int match_type, char *quote_pointer)
3461
(void) quote_pointer; /* not used */
3463
length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
3464
s = pg_malloc(length);
3466
strcpy(s + 1, text);
3467
if (match_type == SINGLE_MATCH)
3468
s[length - 2] = '\'';
3469
s[length - 1] = '\0';
3474
dequote_file_name(char *text, char quote_char)
3480
return pg_strdup(text);
3482
length = strlen(text);
3483
s = pg_malloc(length - 2 + 1);
3484
strlcpy(s, text +1, length - 2 + 1);
3488
#endif /* NOT_USED */
3490
#endif /* USE_READLINE */