Line data Source code
1 : /*
2 : * psql - the PostgreSQL interactive terminal
3 : *
4 : * Copyright (c) 2000-2017, PostgreSQL Global Development Group
5 : *
6 : * src/bin/psql/tab-complete.c
7 : */
8 :
9 : /*----------------------------------------------------------------------
10 : * This file implements a somewhat more sophisticated readline "TAB
11 : * completion" in psql. It is not intended to be AI, to replace
12 : * learning SQL, or to relieve you from thinking about what you're
13 : * doing. Also it does not always give you all the syntactically legal
14 : * completions, only those that are the most common or the ones that
15 : * the programmer felt most like implementing.
16 : *
17 : * CAVEAT: Tab completion causes queries to be sent to the backend.
18 : * The number of tuples returned gets limited, in most default
19 : * installations to 1000, but if you still don't like this prospect,
20 : * you can turn off tab completion in your ~/.inputrc (or else
21 : * ${INPUTRC}) file so:
22 : *
23 : * $if psql
24 : * set disable-completion on
25 : * $endif
26 : *
27 : * See `man 3 readline' or `info readline' for the full details.
28 : *
29 : * BUGS:
30 : * - Quotes, parentheses, and other funny characters are not handled
31 : * all that gracefully.
32 : *----------------------------------------------------------------------
33 : */
34 :
35 : #include "postgres_fe.h"
36 : #include "tab-complete.h"
37 : #include "input.h"
38 :
39 : /* If we don't have this, we might as well forget about the whole thing: */
40 : #ifdef USE_READLINE
41 :
42 : #include <ctype.h>
43 :
44 : #include "catalog/pg_class.h"
45 :
46 : #include "libpq-fe.h"
47 : #include "pqexpbuffer.h"
48 : #include "common.h"
49 : #include "settings.h"
50 : #include "stringutils.h"
51 :
52 : #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
53 : #define filename_completion_function rl_filename_completion_function
54 : #else
55 : /* missing in some header files */
56 : extern char *filename_completion_function();
57 : #endif
58 :
59 : #ifdef HAVE_RL_COMPLETION_MATCHES
60 : #define completion_matches rl_completion_matches
61 : #endif
62 :
63 : /* word break characters */
64 : #define WORD_BREAKS "\t\n@$><=;|&{() "
65 :
66 : /*
67 : * Since readline doesn't let us pass any state through to the tab completion
68 : * callback, we have to use this global variable to let get_previous_words()
69 : * get at the previous lines of the current command. Ick.
70 : */
71 : PQExpBuffer tab_completion_query_buf = NULL;
72 :
73 : /*
74 : * This struct is used to define "schema queries", which are custom-built
75 : * to obtain possibly-schema-qualified names of database objects. There is
76 : * enough similarity in the structure that we don't want to repeat it each
77 : * time. So we put the components of each query into this struct and
78 : * assemble them with the common boilerplate in _complete_from_query().
79 : */
80 : typedef struct SchemaQuery
81 : {
82 : /*
83 : * Name of catalog or catalogs to be queried, with alias, eg.
84 : * "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
85 : */
86 : const char *catname;
87 :
88 : /*
89 : * Selection condition --- only rows meeting this condition are candidates
90 : * to display. If catname mentions multiple tables, include the necessary
91 : * join condition here. For example, this might look like "c.relkind = "
92 : * CppAsString2(RELKIND_RELATION). Write NULL (not an empty string) if
93 : * not needed.
94 : */
95 : const char *selcondition;
96 :
97 : /*
98 : * Visibility condition --- which rows are visible without schema
99 : * qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
100 : */
101 : const char *viscondition;
102 :
103 : /*
104 : * Namespace --- name of field to join to pg_namespace.oid. For example,
105 : * "c.relnamespace".
106 : */
107 : const char *namespace;
108 :
109 : /*
110 : * Result --- the appropriately-quoted name to return, in the case of an
111 : * unqualified name. For example, "pg_catalog.quote_ident(c.relname)".
112 : */
113 : const char *result;
114 :
115 : /*
116 : * In some cases a different result must be used for qualified names.
117 : * Enter that here, or write NULL if result can be used.
118 : */
119 : const char *qualresult;
120 : } SchemaQuery;
121 :
122 :
123 : /* Store maximum number of records we want from database queries
124 : * (implemented via SELECT ... LIMIT xx).
125 : */
126 : static int completion_max_records;
127 :
128 : /*
129 : * Communication variables set by COMPLETE_WITH_FOO macros and then used by
130 : * the completion callback functions. Ugly but there is no better way.
131 : */
132 : static const char *completion_charp; /* to pass a string */
133 : static const char *const *completion_charpp; /* to pass a list of strings */
134 : static const char *completion_info_charp; /* to pass a second string */
135 : static const char *completion_info_charp2; /* to pass a third string */
136 : static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
137 : static bool completion_case_sensitive; /* completion is case sensitive */
138 :
139 : /*
140 : * A few macros to ease typing. You can use these to complete the given
141 : * string with
142 : * 1) The results from a query you pass it. (Perhaps one of those below?)
143 : * 2) The results from a schema query you pass it.
144 : * 3) The items from a null-pointer-terminated list (with or without
145 : * case-sensitive comparison; see also COMPLETE_WITH_LISTn, below).
146 : * 4) A string constant.
147 : * 5) The list of attributes of the given table (possibly schema-qualified).
148 : * 6/ The list of arguments to the given function (possibly schema-qualified).
149 : */
150 : #define COMPLETE_WITH_QUERY(query) \
151 : do { \
152 : completion_charp = query; \
153 : matches = completion_matches(text, complete_from_query); \
154 : } while (0)
155 :
156 : #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
157 : do { \
158 : completion_squery = &(query); \
159 : completion_charp = addon; \
160 : matches = completion_matches(text, complete_from_schema_query); \
161 : } while (0)
162 :
163 : #define COMPLETE_WITH_LIST_CS(list) \
164 : do { \
165 : completion_charpp = list; \
166 : completion_case_sensitive = true; \
167 : matches = completion_matches(text, complete_from_list); \
168 : } while (0)
169 :
170 : #define COMPLETE_WITH_LIST(list) \
171 : do { \
172 : completion_charpp = list; \
173 : completion_case_sensitive = false; \
174 : matches = completion_matches(text, complete_from_list); \
175 : } while (0)
176 :
177 : #define COMPLETE_WITH_CONST(string) \
178 : do { \
179 : completion_charp = string; \
180 : completion_case_sensitive = false; \
181 : matches = completion_matches(text, complete_from_const); \
182 : } while (0)
183 :
184 : #define COMPLETE_WITH_ATTR(relation, addon) \
185 : do { \
186 : char *_completion_schema; \
187 : char *_completion_table; \
188 : \
189 : _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
190 : false, false, pset.encoding); \
191 : (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
192 : false, false, pset.encoding); \
193 : _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
194 : false, false, pset.encoding); \
195 : if (_completion_table == NULL) \
196 : { \
197 : completion_charp = Query_for_list_of_attributes addon; \
198 : completion_info_charp = relation; \
199 : } \
200 : else \
201 : { \
202 : completion_charp = Query_for_list_of_attributes_with_schema addon; \
203 : completion_info_charp = _completion_table; \
204 : completion_info_charp2 = _completion_schema; \
205 : } \
206 : matches = completion_matches(text, complete_from_query); \
207 : } while (0)
208 :
209 : #define COMPLETE_WITH_ENUM_VALUE(type) \
210 : do { \
211 : char *_completion_schema; \
212 : char *_completion_type; \
213 : \
214 : _completion_schema = strtokx(type, " \t\n\r", ".", "\"", 0, \
215 : false, false, pset.encoding); \
216 : (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
217 : false, false, pset.encoding); \
218 : _completion_type = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
219 : false, false, pset.encoding); \
220 : if (_completion_type == NULL)\
221 : { \
222 : completion_charp = Query_for_list_of_enum_values; \
223 : completion_info_charp = type; \
224 : } \
225 : else \
226 : { \
227 : completion_charp = Query_for_list_of_enum_values_with_schema; \
228 : completion_info_charp = _completion_type; \
229 : completion_info_charp2 = _completion_schema; \
230 : } \
231 : matches = completion_matches(text, complete_from_query); \
232 : } while (0)
233 :
234 : #define COMPLETE_WITH_FUNCTION_ARG(function) \
235 : do { \
236 : char *_completion_schema; \
237 : char *_completion_function; \
238 : \
239 : _completion_schema = strtokx(function, " \t\n\r", ".", "\"", 0, \
240 : false, false, pset.encoding); \
241 : (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
242 : false, false, pset.encoding); \
243 : _completion_function = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
244 : false, false, pset.encoding); \
245 : if (_completion_function == NULL) \
246 : { \
247 : completion_charp = Query_for_list_of_arguments; \
248 : completion_info_charp = function; \
249 : } \
250 : else \
251 : { \
252 : completion_charp = Query_for_list_of_arguments_with_schema; \
253 : completion_info_charp = _completion_function; \
254 : completion_info_charp2 = _completion_schema; \
255 : } \
256 : matches = completion_matches(text, complete_from_query); \
257 : } while (0)
258 :
259 : /*
260 : * These macros simplify use of COMPLETE_WITH_LIST for short, fixed lists.
261 : * There is no COMPLETE_WITH_LIST1; use COMPLETE_WITH_CONST for that case.
262 : */
263 : #define COMPLETE_WITH_LIST2(s1, s2) \
264 : do { \
265 : static const char *const list[] = { s1, s2, NULL }; \
266 : COMPLETE_WITH_LIST(list); \
267 : } while (0)
268 :
269 : #define COMPLETE_WITH_LIST3(s1, s2, s3) \
270 : do { \
271 : static const char *const list[] = { s1, s2, s3, NULL }; \
272 : COMPLETE_WITH_LIST(list); \
273 : } while (0)
274 :
275 : #define COMPLETE_WITH_LIST4(s1, s2, s3, s4) \
276 : do { \
277 : static const char *const list[] = { s1, s2, s3, s4, NULL }; \
278 : COMPLETE_WITH_LIST(list); \
279 : } while (0)
280 :
281 : #define COMPLETE_WITH_LIST5(s1, s2, s3, s4, s5) \
282 : do { \
283 : static const char *const list[] = { s1, s2, s3, s4, s5, NULL }; \
284 : COMPLETE_WITH_LIST(list); \
285 : } while (0)
286 :
287 : #define COMPLETE_WITH_LIST6(s1, s2, s3, s4, s5, s6) \
288 : do { \
289 : static const char *const list[] = { s1, s2, s3, s4, s5, s6, NULL }; \
290 : COMPLETE_WITH_LIST(list); \
291 : } while (0)
292 :
293 : #define COMPLETE_WITH_LIST7(s1, s2, s3, s4, s5, s6, s7) \
294 : do { \
295 : static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, NULL }; \
296 : COMPLETE_WITH_LIST(list); \
297 : } while (0)
298 :
299 : #define COMPLETE_WITH_LIST8(s1, s2, s3, s4, s5, s6, s7, s8) \
300 : do { \
301 : static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, NULL }; \
302 : COMPLETE_WITH_LIST(list); \
303 : } while (0)
304 :
305 : #define COMPLETE_WITH_LIST9(s1, s2, s3, s4, s5, s6, s7, s8, s9) \
306 : do { \
307 : static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, s9, NULL }; \
308 : COMPLETE_WITH_LIST(list); \
309 : } while (0)
310 :
311 : #define COMPLETE_WITH_LIST10(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10) \
312 : do { \
313 : static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, NULL }; \
314 : COMPLETE_WITH_LIST(list); \
315 : } while (0)
316 :
317 : /*
318 : * Likewise for COMPLETE_WITH_LIST_CS.
319 : */
320 : #define COMPLETE_WITH_LIST_CS2(s1, s2) \
321 : do { \
322 : static const char *const list[] = { s1, s2, NULL }; \
323 : COMPLETE_WITH_LIST_CS(list); \
324 : } while (0)
325 :
326 : #define COMPLETE_WITH_LIST_CS3(s1, s2, s3) \
327 : do { \
328 : static const char *const list[] = { s1, s2, s3, NULL }; \
329 : COMPLETE_WITH_LIST_CS(list); \
330 : } while (0)
331 :
332 : #define COMPLETE_WITH_LIST_CS4(s1, s2, s3, s4) \
333 : do { \
334 : static const char *const list[] = { s1, s2, s3, s4, NULL }; \
335 : COMPLETE_WITH_LIST_CS(list); \
336 : } while (0)
337 :
338 : #define COMPLETE_WITH_LIST_CS5(s1, s2, s3, s4, s5) \
339 : do { \
340 : static const char *const list[] = { s1, s2, s3, s4, s5, NULL }; \
341 : COMPLETE_WITH_LIST_CS(list); \
342 : } while (0)
343 :
344 : /*
345 : * Assembly instructions for schema queries
346 : */
347 :
348 : static const SchemaQuery Query_for_list_of_aggregates = {
349 : /* catname */
350 : "pg_catalog.pg_proc p",
351 : /* selcondition */
352 : "p.proisagg",
353 : /* viscondition */
354 : "pg_catalog.pg_function_is_visible(p.oid)",
355 : /* namespace */
356 : "p.pronamespace",
357 : /* result */
358 : "pg_catalog.quote_ident(p.proname)",
359 : /* qualresult */
360 : NULL
361 : };
362 :
363 : static const SchemaQuery Query_for_list_of_datatypes = {
364 : /* catname */
365 : "pg_catalog.pg_type t",
366 : /* selcondition --- ignore table rowtypes and array types */
367 : "(t.typrelid = 0 "
368 : " OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
369 : " FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
370 : "AND t.typname !~ '^_'",
371 : /* viscondition */
372 : "pg_catalog.pg_type_is_visible(t.oid)",
373 : /* namespace */
374 : "t.typnamespace",
375 : /* result */
376 : "pg_catalog.format_type(t.oid, NULL)",
377 : /* qualresult */
378 : "pg_catalog.quote_ident(t.typname)"
379 : };
380 :
381 : static const SchemaQuery Query_for_list_of_domains = {
382 : /* catname */
383 : "pg_catalog.pg_type t",
384 : /* selcondition */
385 : "t.typtype = 'd'",
386 : /* viscondition */
387 : "pg_catalog.pg_type_is_visible(t.oid)",
388 : /* namespace */
389 : "t.typnamespace",
390 : /* result */
391 : "pg_catalog.quote_ident(t.typname)",
392 : /* qualresult */
393 : NULL
394 : };
395 :
396 : static const SchemaQuery Query_for_list_of_functions = {
397 : /* catname */
398 : "pg_catalog.pg_proc p",
399 : /* selcondition */
400 : NULL,
401 : /* viscondition */
402 : "pg_catalog.pg_function_is_visible(p.oid)",
403 : /* namespace */
404 : "p.pronamespace",
405 : /* result */
406 : "pg_catalog.quote_ident(p.proname)",
407 : /* qualresult */
408 : NULL
409 : };
410 :
411 : static const SchemaQuery Query_for_list_of_indexes = {
412 : /* catname */
413 : "pg_catalog.pg_class c",
414 : /* selcondition */
415 : "c.relkind IN (" CppAsString2(RELKIND_INDEX) ")",
416 : /* viscondition */
417 : "pg_catalog.pg_table_is_visible(c.oid)",
418 : /* namespace */
419 : "c.relnamespace",
420 : /* result */
421 : "pg_catalog.quote_ident(c.relname)",
422 : /* qualresult */
423 : NULL
424 : };
425 :
426 : static const SchemaQuery Query_for_list_of_sequences = {
427 : /* catname */
428 : "pg_catalog.pg_class c",
429 : /* selcondition */
430 : "c.relkind IN (" CppAsString2(RELKIND_SEQUENCE) ")",
431 : /* viscondition */
432 : "pg_catalog.pg_table_is_visible(c.oid)",
433 : /* namespace */
434 : "c.relnamespace",
435 : /* result */
436 : "pg_catalog.quote_ident(c.relname)",
437 : /* qualresult */
438 : NULL
439 : };
440 :
441 : static const SchemaQuery Query_for_list_of_foreign_tables = {
442 : /* catname */
443 : "pg_catalog.pg_class c",
444 : /* selcondition */
445 : "c.relkind IN (" CppAsString2(RELKIND_FOREIGN_TABLE) ")",
446 : /* viscondition */
447 : "pg_catalog.pg_table_is_visible(c.oid)",
448 : /* namespace */
449 : "c.relnamespace",
450 : /* result */
451 : "pg_catalog.quote_ident(c.relname)",
452 : /* qualresult */
453 : NULL
454 : };
455 :
456 : static const SchemaQuery Query_for_list_of_tables = {
457 : /* catname */
458 : "pg_catalog.pg_class c",
459 : /* selcondition */
460 : "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
461 : CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
462 : /* viscondition */
463 : "pg_catalog.pg_table_is_visible(c.oid)",
464 : /* namespace */
465 : "c.relnamespace",
466 : /* result */
467 : "pg_catalog.quote_ident(c.relname)",
468 : /* qualresult */
469 : NULL
470 : };
471 :
472 : static const SchemaQuery Query_for_list_of_partitioned_tables = {
473 : /* catname */
474 : "pg_catalog.pg_class c",
475 : /* selcondition */
476 : "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
477 : /* viscondition */
478 : "pg_catalog.pg_table_is_visible(c.oid)",
479 : /* namespace */
480 : "c.relnamespace",
481 : /* result */
482 : "pg_catalog.quote_ident(c.relname)",
483 : /* qualresult */
484 : NULL
485 : };
486 :
487 : static const SchemaQuery Query_for_list_of_constraints_with_schema = {
488 : /* catname */
489 : "pg_catalog.pg_constraint c",
490 : /* selcondition */
491 : "c.conrelid <> 0",
492 : /* viscondition */
493 : "true", /* there is no pg_constraint_is_visible */
494 : /* namespace */
495 : "c.connamespace",
496 : /* result */
497 : "pg_catalog.quote_ident(c.conname)",
498 : /* qualresult */
499 : NULL
500 : };
501 :
502 : /* Relations supporting INSERT, UPDATE or DELETE */
503 : static const SchemaQuery Query_for_list_of_updatables = {
504 : /* catname */
505 : "pg_catalog.pg_class c",
506 : /* selcondition */
507 : "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
508 : CppAsString2(RELKIND_FOREIGN_TABLE) ", "
509 : CppAsString2(RELKIND_VIEW) ", "
510 : CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
511 : /* viscondition */
512 : "pg_catalog.pg_table_is_visible(c.oid)",
513 : /* namespace */
514 : "c.relnamespace",
515 : /* result */
516 : "pg_catalog.quote_ident(c.relname)",
517 : /* qualresult */
518 : NULL
519 : };
520 :
521 : static const SchemaQuery Query_for_list_of_relations = {
522 : /* catname */
523 : "pg_catalog.pg_class c",
524 : /* selcondition */
525 : NULL,
526 : /* viscondition */
527 : "pg_catalog.pg_table_is_visible(c.oid)",
528 : /* namespace */
529 : "c.relnamespace",
530 : /* result */
531 : "pg_catalog.quote_ident(c.relname)",
532 : /* qualresult */
533 : NULL
534 : };
535 :
536 : static const SchemaQuery Query_for_list_of_tsvmf = {
537 : /* catname */
538 : "pg_catalog.pg_class c",
539 : /* selcondition */
540 : "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
541 : CppAsString2(RELKIND_SEQUENCE) ", "
542 : CppAsString2(RELKIND_VIEW) ", "
543 : CppAsString2(RELKIND_MATVIEW) ", "
544 : CppAsString2(RELKIND_FOREIGN_TABLE) ", "
545 : CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
546 : /* viscondition */
547 : "pg_catalog.pg_table_is_visible(c.oid)",
548 : /* namespace */
549 : "c.relnamespace",
550 : /* result */
551 : "pg_catalog.quote_ident(c.relname)",
552 : /* qualresult */
553 : NULL
554 : };
555 :
556 : static const SchemaQuery Query_for_list_of_tmf = {
557 : /* catname */
558 : "pg_catalog.pg_class c",
559 : /* selcondition */
560 : "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
561 : CppAsString2(RELKIND_MATVIEW) ", "
562 : CppAsString2(RELKIND_FOREIGN_TABLE) ")",
563 : /* viscondition */
564 : "pg_catalog.pg_table_is_visible(c.oid)",
565 : /* namespace */
566 : "c.relnamespace",
567 : /* result */
568 : "pg_catalog.quote_ident(c.relname)",
569 : /* qualresult */
570 : NULL
571 : };
572 :
573 : static const SchemaQuery Query_for_list_of_tm = {
574 : /* catname */
575 : "pg_catalog.pg_class c",
576 : /* selcondition */
577 : "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
578 : CppAsString2(RELKIND_MATVIEW) ")",
579 : /* viscondition */
580 : "pg_catalog.pg_table_is_visible(c.oid)",
581 : /* namespace */
582 : "c.relnamespace",
583 : /* result */
584 : "pg_catalog.quote_ident(c.relname)",
585 : /* qualresult */
586 : NULL
587 : };
588 :
589 : static const SchemaQuery Query_for_list_of_views = {
590 : /* catname */
591 : "pg_catalog.pg_class c",
592 : /* selcondition */
593 : "c.relkind IN (" CppAsString2(RELKIND_VIEW) ")",
594 : /* viscondition */
595 : "pg_catalog.pg_table_is_visible(c.oid)",
596 : /* namespace */
597 : "c.relnamespace",
598 : /* result */
599 : "pg_catalog.quote_ident(c.relname)",
600 : /* qualresult */
601 : NULL
602 : };
603 :
604 : static const SchemaQuery Query_for_list_of_matviews = {
605 : /* catname */
606 : "pg_catalog.pg_class c",
607 : /* selcondition */
608 : "c.relkind IN (" CppAsString2(RELKIND_MATVIEW) ")",
609 : /* viscondition */
610 : "pg_catalog.pg_table_is_visible(c.oid)",
611 : /* namespace */
612 : "c.relnamespace",
613 : /* result */
614 : "pg_catalog.quote_ident(c.relname)",
615 : /* qualresult */
616 : NULL
617 : };
618 :
619 : static const SchemaQuery Query_for_list_of_statistics = {
620 : /* catname */
621 : "pg_catalog.pg_statistic_ext s",
622 : /* selcondition */
623 : NULL,
624 : /* viscondition */
625 : "pg_catalog.pg_statistics_obj_is_visible(s.oid)",
626 : /* namespace */
627 : "s.stxnamespace",
628 : /* result */
629 : "pg_catalog.quote_ident(s.stxname)",
630 : /* qualresult */
631 : NULL
632 : };
633 :
634 :
635 : /*
636 : * Queries to get lists of names of various kinds of things, possibly
637 : * restricted to names matching a partially entered name. In these queries,
638 : * the first %s will be replaced by the text entered so far (suitably escaped
639 : * to become a SQL literal string). %d will be replaced by the length of the
640 : * string (in unescaped form). A second and third %s, if present, will be
641 : * replaced by a suitably-escaped version of the string provided in
642 : * completion_info_charp. A fourth and fifth %s are similarly replaced by
643 : * completion_info_charp2.
644 : *
645 : * Beware that the allowed sequences of %s and %d are determined by
646 : * _complete_from_query().
647 : */
648 :
649 : #define Query_for_list_of_attributes \
650 : "SELECT pg_catalog.quote_ident(attname) "\
651 : " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
652 : " WHERE c.oid = a.attrelid "\
653 : " AND a.attnum > 0 "\
654 : " AND NOT a.attisdropped "\
655 : " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
656 : " AND (pg_catalog.quote_ident(relname)='%s' "\
657 : " OR '\"' || relname || '\"'='%s') "\
658 : " AND pg_catalog.pg_table_is_visible(c.oid)"
659 :
660 : #define Query_for_list_of_attributes_with_schema \
661 : "SELECT pg_catalog.quote_ident(attname) "\
662 : " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
663 : " WHERE c.oid = a.attrelid "\
664 : " AND n.oid = c.relnamespace "\
665 : " AND a.attnum > 0 "\
666 : " AND NOT a.attisdropped "\
667 : " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
668 : " AND (pg_catalog.quote_ident(relname)='%s' "\
669 : " OR '\"' || relname || '\"' ='%s') "\
670 : " AND (pg_catalog.quote_ident(nspname)='%s' "\
671 : " OR '\"' || nspname || '\"' ='%s') "
672 :
673 : #define Query_for_list_of_enum_values \
674 : "SELECT pg_catalog.quote_literal(enumlabel) "\
675 : " FROM pg_catalog.pg_enum e, pg_catalog.pg_type t "\
676 : " WHERE t.oid = e.enumtypid "\
677 : " AND substring(pg_catalog.quote_literal(enumlabel),1,%d)='%s' "\
678 : " AND (pg_catalog.quote_ident(typname)='%s' "\
679 : " OR '\"' || typname || '\"'='%s') "\
680 : " AND pg_catalog.pg_type_is_visible(t.oid)"
681 :
682 : #define Query_for_list_of_enum_values_with_schema \
683 : "SELECT pg_catalog.quote_literal(enumlabel) "\
684 : " FROM pg_catalog.pg_enum e, pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
685 : " WHERE t.oid = e.enumtypid "\
686 : " AND n.oid = t.typnamespace "\
687 : " AND substring(pg_catalog.quote_literal(enumlabel),1,%d)='%s' "\
688 : " AND (pg_catalog.quote_ident(typname)='%s' "\
689 : " OR '\"' || typname || '\"'='%s') "\
690 : " AND (pg_catalog.quote_ident(nspname)='%s' "\
691 : " OR '\"' || nspname || '\"' ='%s') "
692 :
693 : #define Query_for_list_of_template_databases \
694 : "SELECT pg_catalog.quote_ident(d.datname) "\
695 : " FROM pg_catalog.pg_database d "\
696 : " WHERE substring(pg_catalog.quote_ident(d.datname),1,%d)='%s' "\
697 : " AND (d.datistemplate OR pg_catalog.pg_has_role(d.datdba, 'USAGE'))"
698 :
699 : #define Query_for_list_of_databases \
700 : "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
701 : " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
702 :
703 : #define Query_for_list_of_tablespaces \
704 : "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
705 : " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
706 :
707 : #define Query_for_list_of_encodings \
708 : " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
709 : " FROM pg_catalog.pg_conversion "\
710 : " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
711 :
712 : #define Query_for_list_of_languages \
713 : "SELECT pg_catalog.quote_ident(lanname) "\
714 : " FROM pg_catalog.pg_language "\
715 : " WHERE lanname != 'internal' "\
716 : " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
717 :
718 : #define Query_for_list_of_schemas \
719 : "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
720 : " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
721 :
722 : #define Query_for_list_of_alter_system_set_vars \
723 : "SELECT name FROM "\
724 : " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
725 : " WHERE context != 'internal' "\
726 : " UNION ALL SELECT 'all') ss "\
727 : " WHERE substring(name,1,%d)='%s'"
728 :
729 : #define Query_for_list_of_set_vars \
730 : "SELECT name FROM "\
731 : " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
732 : " WHERE context IN ('user', 'superuser') "\
733 : " UNION ALL SELECT 'constraints' "\
734 : " UNION ALL SELECT 'transaction' "\
735 : " UNION ALL SELECT 'session' "\
736 : " UNION ALL SELECT 'role' "\
737 : " UNION ALL SELECT 'tablespace' "\
738 : " UNION ALL SELECT 'all') ss "\
739 : " WHERE substring(name,1,%d)='%s'"
740 :
741 : #define Query_for_list_of_show_vars \
742 : "SELECT name FROM "\
743 : " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
744 : " UNION ALL SELECT 'session authorization' "\
745 : " UNION ALL SELECT 'all') ss "\
746 : " WHERE substring(name,1,%d)='%s'"
747 :
748 : #define Query_for_list_of_roles \
749 : " SELECT pg_catalog.quote_ident(rolname) "\
750 : " FROM pg_catalog.pg_roles "\
751 : " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
752 :
753 : #define Query_for_list_of_grant_roles \
754 : " SELECT pg_catalog.quote_ident(rolname) "\
755 : " FROM pg_catalog.pg_roles "\
756 : " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
757 : " UNION ALL SELECT 'PUBLIC'"\
758 : " UNION ALL SELECT 'CURRENT_USER'"\
759 : " UNION ALL SELECT 'SESSION_USER'"
760 :
761 : /* the silly-looking length condition is just to eat up the current word */
762 : #define Query_for_table_owning_index \
763 : "SELECT pg_catalog.quote_ident(c1.relname) "\
764 : " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
765 : " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
766 : " and (%d = pg_catalog.length('%s'))"\
767 : " and pg_catalog.quote_ident(c2.relname)='%s'"\
768 : " and pg_catalog.pg_table_is_visible(c2.oid)"
769 :
770 : /* the silly-looking length condition is just to eat up the current word */
771 : #define Query_for_index_of_table \
772 : "SELECT pg_catalog.quote_ident(c2.relname) "\
773 : " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
774 : " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
775 : " and (%d = pg_catalog.length('%s'))"\
776 : " and pg_catalog.quote_ident(c1.relname)='%s'"\
777 : " and pg_catalog.pg_table_is_visible(c2.oid)"
778 :
779 : /* the silly-looking length condition is just to eat up the current word */
780 : #define Query_for_constraint_of_table \
781 : "SELECT pg_catalog.quote_ident(conname) "\
782 : " FROM pg_catalog.pg_class c1, pg_catalog.pg_constraint con "\
783 : " WHERE c1.oid=conrelid and (%d = pg_catalog.length('%s'))"\
784 : " and pg_catalog.quote_ident(c1.relname)='%s'"\
785 : " and pg_catalog.pg_table_is_visible(c1.oid)"
786 :
787 : #define Query_for_all_table_constraints \
788 : "SELECT pg_catalog.quote_ident(conname) "\
789 : " FROM pg_catalog.pg_constraint c "\
790 : " WHERE c.conrelid <> 0 "
791 :
792 : /* the silly-looking length condition is just to eat up the current word */
793 : #define Query_for_constraint_of_type \
794 : "SELECT pg_catalog.quote_ident(conname) "\
795 : " FROM pg_catalog.pg_type t, pg_catalog.pg_constraint con "\
796 : " WHERE t.oid=contypid and (%d = pg_catalog.length('%s'))"\
797 : " and pg_catalog.quote_ident(t.typname)='%s'"\
798 : " and pg_catalog.pg_type_is_visible(t.oid)"
799 :
800 : /* the silly-looking length condition is just to eat up the current word */
801 : #define Query_for_list_of_tables_for_constraint \
802 : "SELECT pg_catalog.quote_ident(relname) "\
803 : " FROM pg_catalog.pg_class"\
804 : " WHERE (%d = pg_catalog.length('%s'))"\
805 : " AND oid IN "\
806 : " (SELECT conrelid FROM pg_catalog.pg_constraint "\
807 : " WHERE pg_catalog.quote_ident(conname)='%s')"
808 :
809 : /* the silly-looking length condition is just to eat up the current word */
810 : #define Query_for_rule_of_table \
811 : "SELECT pg_catalog.quote_ident(rulename) "\
812 : " FROM pg_catalog.pg_class c1, pg_catalog.pg_rewrite "\
813 : " WHERE c1.oid=ev_class and (%d = pg_catalog.length('%s'))"\
814 : " and pg_catalog.quote_ident(c1.relname)='%s'"\
815 : " and pg_catalog.pg_table_is_visible(c1.oid)"
816 :
817 : /* the silly-looking length condition is just to eat up the current word */
818 : #define Query_for_list_of_tables_for_rule \
819 : "SELECT pg_catalog.quote_ident(relname) "\
820 : " FROM pg_catalog.pg_class"\
821 : " WHERE (%d = pg_catalog.length('%s'))"\
822 : " AND oid IN "\
823 : " (SELECT ev_class FROM pg_catalog.pg_rewrite "\
824 : " WHERE pg_catalog.quote_ident(rulename)='%s')"
825 :
826 : /* the silly-looking length condition is just to eat up the current word */
827 : #define Query_for_trigger_of_table \
828 : "SELECT pg_catalog.quote_ident(tgname) "\
829 : " FROM pg_catalog.pg_class c1, pg_catalog.pg_trigger "\
830 : " WHERE c1.oid=tgrelid and (%d = pg_catalog.length('%s'))"\
831 : " and pg_catalog.quote_ident(c1.relname)='%s'"\
832 : " and pg_catalog.pg_table_is_visible(c1.oid)"\
833 : " and not tgisinternal"
834 :
835 : /* the silly-looking length condition is just to eat up the current word */
836 : #define Query_for_list_of_tables_for_trigger \
837 : "SELECT pg_catalog.quote_ident(relname) "\
838 : " FROM pg_catalog.pg_class"\
839 : " WHERE (%d = pg_catalog.length('%s'))"\
840 : " AND oid IN "\
841 : " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
842 : " WHERE pg_catalog.quote_ident(tgname)='%s')"
843 :
844 : #define Query_for_list_of_ts_configurations \
845 : "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
846 : " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
847 :
848 : #define Query_for_list_of_ts_dictionaries \
849 : "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
850 : " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
851 :
852 : #define Query_for_list_of_ts_parsers \
853 : "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
854 : " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
855 :
856 : #define Query_for_list_of_ts_templates \
857 : "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
858 : " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
859 :
860 : #define Query_for_list_of_fdws \
861 : " SELECT pg_catalog.quote_ident(fdwname) "\
862 : " FROM pg_catalog.pg_foreign_data_wrapper "\
863 : " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
864 :
865 : #define Query_for_list_of_servers \
866 : " SELECT pg_catalog.quote_ident(srvname) "\
867 : " FROM pg_catalog.pg_foreign_server "\
868 : " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
869 :
870 : #define Query_for_list_of_user_mappings \
871 : " SELECT pg_catalog.quote_ident(usename) "\
872 : " FROM pg_catalog.pg_user_mappings "\
873 : " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
874 :
875 : #define Query_for_list_of_access_methods \
876 : " SELECT pg_catalog.quote_ident(amname) "\
877 : " FROM pg_catalog.pg_am "\
878 : " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
879 :
880 : #define Query_for_list_of_publications \
881 : " SELECT pg_catalog.quote_ident(pubname) "\
882 : " FROM pg_catalog.pg_publication "\
883 : " WHERE substring(pg_catalog.quote_ident(pubname),1,%d)='%s'"
884 :
885 : #define Query_for_list_of_subscriptions \
886 : " SELECT pg_catalog.quote_ident(s.subname) "\
887 : " FROM pg_catalog.pg_subscription s, pg_catalog.pg_database d "\
888 : " WHERE substring(pg_catalog.quote_ident(s.subname),1,%d)='%s' "\
889 : " AND d.datname = pg_catalog.current_database() "\
890 : " AND s.subdbid = d.oid"
891 :
892 : /* the silly-looking length condition is just to eat up the current word */
893 : #define Query_for_list_of_arguments \
894 : "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
895 : " FROM pg_catalog.pg_proc "\
896 : " WHERE (%d = pg_catalog.length('%s'))"\
897 : " AND (pg_catalog.quote_ident(proname)='%s'"\
898 : " OR '\"' || proname || '\"'='%s') "\
899 : " AND (pg_catalog.pg_function_is_visible(pg_proc.oid))"
900 :
901 : /* the silly-looking length condition is just to eat up the current word */
902 : #define Query_for_list_of_arguments_with_schema \
903 : "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
904 : " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
905 : " WHERE (%d = pg_catalog.length('%s'))"\
906 : " AND n.oid = p.pronamespace "\
907 : " AND (pg_catalog.quote_ident(proname)='%s' "\
908 : " OR '\"' || proname || '\"' ='%s') "\
909 : " AND (pg_catalog.quote_ident(nspname)='%s' "\
910 : " OR '\"' || nspname || '\"' ='%s') "
911 :
912 : #define Query_for_list_of_extensions \
913 : " SELECT pg_catalog.quote_ident(extname) "\
914 : " FROM pg_catalog.pg_extension "\
915 : " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
916 :
917 : #define Query_for_list_of_available_extensions \
918 : " SELECT pg_catalog.quote_ident(name) "\
919 : " FROM pg_catalog.pg_available_extensions "\
920 : " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
921 :
922 : /* the silly-looking length condition is just to eat up the current word */
923 : #define Query_for_list_of_available_extension_versions \
924 : " SELECT pg_catalog.quote_ident(version) "\
925 : " FROM pg_catalog.pg_available_extension_versions "\
926 : " WHERE (%d = pg_catalog.length('%s'))"\
927 : " AND pg_catalog.quote_ident(name)='%s'"
928 :
929 : /* the silly-looking length condition is just to eat up the current word */
930 : #define Query_for_list_of_available_extension_versions_with_TO \
931 : " SELECT 'TO ' || pg_catalog.quote_ident(version) "\
932 : " FROM pg_catalog.pg_available_extension_versions "\
933 : " WHERE (%d = pg_catalog.length('%s'))"\
934 : " AND pg_catalog.quote_ident(name)='%s'"
935 :
936 : #define Query_for_list_of_prepared_statements \
937 : " SELECT pg_catalog.quote_ident(name) "\
938 : " FROM pg_catalog.pg_prepared_statements "\
939 : " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'"
940 :
941 : #define Query_for_list_of_event_triggers \
942 : " SELECT pg_catalog.quote_ident(evtname) "\
943 : " FROM pg_catalog.pg_event_trigger "\
944 : " WHERE substring(pg_catalog.quote_ident(evtname),1,%d)='%s'"
945 :
946 : #define Query_for_list_of_tablesample_methods \
947 : " SELECT pg_catalog.quote_ident(proname) "\
948 : " FROM pg_catalog.pg_proc "\
949 : " WHERE prorettype = 'pg_catalog.tsm_handler'::pg_catalog.regtype AND "\
950 : " proargtypes[0] = 'pg_catalog.internal'::pg_catalog.regtype AND "\
951 : " substring(pg_catalog.quote_ident(proname),1,%d)='%s'"
952 :
953 : #define Query_for_list_of_policies \
954 : " SELECT pg_catalog.quote_ident(polname) "\
955 : " FROM pg_catalog.pg_policy "\
956 : " WHERE substring(pg_catalog.quote_ident(polname),1,%d)='%s'"
957 :
958 : #define Query_for_list_of_tables_for_policy \
959 : "SELECT pg_catalog.quote_ident(relname) "\
960 : " FROM pg_catalog.pg_class"\
961 : " WHERE (%d = pg_catalog.length('%s'))"\
962 : " AND oid IN "\
963 : " (SELECT polrelid FROM pg_catalog.pg_policy "\
964 : " WHERE pg_catalog.quote_ident(polname)='%s')"
965 :
966 : #define Query_for_enum \
967 : " SELECT name FROM ( "\
968 : " SELECT pg_catalog.quote_ident(pg_catalog.unnest(enumvals)) AS name "\
969 : " FROM pg_catalog.pg_settings "\
970 : " WHERE pg_catalog.lower(name)=pg_catalog.lower('%s') "\
971 : " UNION ALL " \
972 : " SELECT 'DEFAULT' ) ss "\
973 : " WHERE pg_catalog.substring(name,1,%%d)='%%s'"
974 :
975 : /* the silly-looking length condition is just to eat up the current word */
976 : #define Query_for_partition_of_table \
977 : "SELECT pg_catalog.quote_ident(c2.relname) "\
978 : " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_inherits i"\
979 : " WHERE c1.oid=i.inhparent and i.inhrelid=c2.oid"\
980 : " and (%d = pg_catalog.length('%s'))"\
981 : " and pg_catalog.quote_ident(c1.relname)='%s'"\
982 : " and pg_catalog.pg_table_is_visible(c2.oid)"\
983 : " and c2.relispartition = 'true'"
984 :
985 : /*
986 : * This is a list of all "things" in Pgsql, which can show up after CREATE or
987 : * DROP; and there is also a query to get a list of them.
988 : */
989 :
990 : typedef struct
991 : {
992 : const char *name;
993 : const char *query; /* simple query, or NULL */
994 : const SchemaQuery *squery; /* schema query, or NULL */
995 : const bits32 flags; /* visibility flags, see below */
996 : } pgsql_thing_t;
997 :
998 : #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
999 : #define THING_NO_DROP (1 << 1) /* should not show up after DROP */
1000 : #define THING_NO_ALTER (1 << 2) /* should not show up after ALTER */
1001 : #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP | THING_NO_ALTER)
1002 :
1003 : static const pgsql_thing_t words_after_create[] = {
1004 : {"ACCESS METHOD", NULL, NULL, THING_NO_ALTER},
1005 : {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
1006 : {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
1007 : * skip it */
1008 : {"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'"},
1009 :
1010 : /*
1011 : * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
1012 : * to be used only by pg_dump.
1013 : */
1014 : {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
1015 : {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
1016 : {"DATABASE", Query_for_list_of_databases},
1017 : {"DEFAULT PRIVILEGES", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
1018 : {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
1019 : {"DOMAIN", NULL, &Query_for_list_of_domains},
1020 : {"EVENT TRIGGER", NULL, NULL},
1021 : {"EXTENSION", Query_for_list_of_extensions},
1022 : {"FOREIGN DATA WRAPPER", NULL, NULL},
1023 : {"FOREIGN TABLE", NULL, NULL},
1024 : {"FUNCTION", NULL, &Query_for_list_of_functions},
1025 : {"GROUP", Query_for_list_of_roles},
1026 : {"INDEX", NULL, &Query_for_list_of_indexes},
1027 : {"LANGUAGE", Query_for_list_of_languages},
1028 : {"LARGE OBJECT", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
1029 : {"MATERIALIZED VIEW", NULL, &Query_for_list_of_matviews},
1030 : {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
1031 : * good idea. */
1032 : {"OWNED", NULL, NULL, THING_NO_CREATE | THING_NO_ALTER}, /* for DROP OWNED BY ... */
1033 : {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
1034 : {"POLICY", NULL, NULL},
1035 : {"PUBLICATION", Query_for_list_of_publications},
1036 : {"ROLE", Query_for_list_of_roles},
1037 : {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
1038 : {"SCHEMA", Query_for_list_of_schemas},
1039 : {"SEQUENCE", NULL, &Query_for_list_of_sequences},
1040 : {"SERVER", Query_for_list_of_servers},
1041 : {"STATISTICS", NULL, &Query_for_list_of_statistics},
1042 : {"SUBSCRIPTION", Query_for_list_of_subscriptions},
1043 : {"SYSTEM", NULL, NULL, THING_NO_CREATE | THING_NO_DROP},
1044 : {"TABLE", NULL, &Query_for_list_of_tables},
1045 : {"TABLESPACE", Query_for_list_of_tablespaces},
1046 : {"TEMP", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE TEMP TABLE
1047 : * ... */
1048 : {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
1049 : {"TEMPORARY", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE TEMPORARY
1050 : * TABLE ... */
1051 : {"TEXT SEARCH", NULL, NULL},
1052 : {"TRANSFORM", NULL, NULL},
1053 : {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s' AND NOT tgisinternal"},
1054 : {"TYPE", NULL, &Query_for_list_of_datatypes},
1055 : {"UNIQUE", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE UNIQUE
1056 : * INDEX ... */
1057 : {"UNLOGGED", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE UNLOGGED
1058 : * TABLE ... */
1059 : {"USER", Query_for_list_of_roles " UNION SELECT 'MAPPING FOR'"},
1060 : {"USER MAPPING FOR", NULL, NULL},
1061 : {"VIEW", NULL, &Query_for_list_of_views},
1062 : {NULL} /* end of list */
1063 : };
1064 :
1065 :
1066 : /* Forward declaration of functions */
1067 : static char **psql_completion(const char *text, int start, int end);
1068 : static char *create_command_generator(const char *text, int state);
1069 : static char *drop_command_generator(const char *text, int state);
1070 : static char *alter_command_generator(const char *text, int state);
1071 : static char *complete_from_query(const char *text, int state);
1072 : static char *complete_from_schema_query(const char *text, int state);
1073 : static char *_complete_from_query(int is_schema_query,
1074 : const char *text, int state);
1075 : static char *complete_from_list(const char *text, int state);
1076 : static char *complete_from_const(const char *text, int state);
1077 : static void append_variable_names(char ***varnames, int *nvars,
1078 : int *maxvars, const char *varname,
1079 : const char *prefix, const char *suffix);
1080 : static char **complete_from_variables(const char *text,
1081 : const char *prefix, const char *suffix, bool need_value);
1082 : static char *complete_from_files(const char *text, int state);
1083 :
1084 : static char *pg_strdup_keyword_case(const char *s, const char *ref);
1085 : static char *escape_string(const char *text);
1086 : static PGresult *exec_query(const char *query);
1087 :
1088 : static char **get_previous_words(int point, char **buffer, int *nwords);
1089 :
1090 : static char *get_guctype(const char *varname);
1091 :
1092 : #ifdef NOT_USED
1093 : static char *quote_file_name(char *text, int match_type, char *quote_pointer);
1094 : static char *dequote_file_name(char *text, char quote_char);
1095 : #endif
1096 :
1097 :
1098 : /*
1099 : * Initialize the readline library for our purposes.
1100 : */
1101 : void
1102 0 : initialize_readline(void)
1103 : {
1104 0 : rl_readline_name = (char *) pset.progname;
1105 0 : rl_attempted_completion_function = psql_completion;
1106 :
1107 0 : rl_basic_word_break_characters = WORD_BREAKS;
1108 :
1109 0 : completion_max_records = 1000;
1110 :
1111 : /*
1112 : * There is a variable rl_completion_query_items for this but apparently
1113 : * it's not defined everywhere.
1114 : */
1115 0 : }
1116 :
1117 : /*
1118 : * Check if 'word' matches any of the '|'-separated strings in 'pattern',
1119 : * using case-insensitive or case-sensitive comparisons.
1120 : *
1121 : * If pattern is NULL, it's a wild card that matches any word.
1122 : * If pattern begins with '!', the result is negated, ie we check that 'word'
1123 : * does *not* match any alternative appearing in the rest of 'pattern'.
1124 : * Any alternative can end with '*' which is a wild card, i.e., it means
1125 : * match any word that matches the characters so far. (We do not currently
1126 : * support '*' elsewhere than the end of an alternative.)
1127 : *
1128 : * For readability, callers should use the macros MatchAny and MatchAnyExcept
1129 : * to invoke those two special cases for 'pattern'. (But '|' and '*' must
1130 : * just be written directly in patterns.)
1131 : */
1132 : #define MatchAny NULL
1133 : #define MatchAnyExcept(pattern) ("!" pattern)
1134 :
1135 : static bool
1136 0 : word_matches_internal(const char *pattern,
1137 : const char *word,
1138 : bool case_sensitive)
1139 : {
1140 : size_t wordlen,
1141 : patternlen;
1142 :
1143 : /* NULL pattern matches anything. */
1144 0 : if (pattern == NULL)
1145 0 : return true;
1146 :
1147 : /* Handle negated patterns from the MatchAnyExcept macro. */
1148 0 : if (*pattern == '!')
1149 0 : return !word_matches_internal(pattern + 1, word, case_sensitive);
1150 :
1151 : /* Else consider each alternative in the pattern. */
1152 0 : wordlen = strlen(word);
1153 : for (;;)
1154 : {
1155 : const char *c;
1156 :
1157 : /* Find end of current alternative. */
1158 0 : c = pattern;
1159 0 : while (*c != '\0' && *c != '|')
1160 0 : c++;
1161 : /* Was there a wild card? (Assumes first alternative is not empty) */
1162 0 : if (c[-1] == '*')
1163 : {
1164 : /* Yes, wildcard match? */
1165 0 : patternlen = c - pattern - 1;
1166 0 : if (wordlen >= patternlen &&
1167 : (case_sensitive ?
1168 0 : strncmp(word, pattern, patternlen) == 0 :
1169 0 : pg_strncasecmp(word, pattern, patternlen) == 0))
1170 0 : return true;
1171 : }
1172 : else
1173 : {
1174 : /* No, plain match? */
1175 0 : patternlen = c - pattern;
1176 0 : if (wordlen == patternlen &&
1177 : (case_sensitive ?
1178 0 : strncmp(word, pattern, wordlen) == 0 :
1179 0 : pg_strncasecmp(word, pattern, wordlen) == 0))
1180 0 : return true;
1181 : }
1182 : /* Out of alternatives? */
1183 0 : if (*c == '\0')
1184 0 : break;
1185 : /* Nope, try next alternative. */
1186 0 : pattern = c + 1;
1187 0 : }
1188 :
1189 0 : return false;
1190 : }
1191 :
1192 : /*
1193 : * There are enough matching calls below that it seems worth having these two
1194 : * interface routines rather than including a third parameter in every call.
1195 : *
1196 : * word_matches --- match case-insensitively.
1197 : */
1198 : static bool
1199 0 : word_matches(const char *pattern, const char *word)
1200 : {
1201 0 : return word_matches_internal(pattern, word, false);
1202 : }
1203 :
1204 : /*
1205 : * word_matches_cs --- match case-sensitively.
1206 : */
1207 : static bool
1208 0 : word_matches_cs(const char *pattern, const char *word)
1209 : {
1210 0 : return word_matches_internal(pattern, word, true);
1211 : }
1212 :
1213 : /*
1214 : * Check if the final character of 's' is 'c'.
1215 : */
1216 : static bool
1217 0 : ends_with(const char *s, char c)
1218 : {
1219 0 : size_t length = strlen(s);
1220 :
1221 0 : return (length > 0 && s[length - 1] == c);
1222 : }
1223 :
1224 : /*
1225 : * The completion function.
1226 : *
1227 : * According to readline spec this gets passed the text entered so far and its
1228 : * start and end positions in the readline buffer. The return value is some
1229 : * partially obscure list format that can be generated by readline's
1230 : * completion_matches() function, so we don't have to worry about it.
1231 : */
1232 : static char **
1233 0 : psql_completion(const char *text, int start, int end)
1234 : {
1235 : /* This is the variable we'll return. */
1236 0 : char **matches = NULL;
1237 :
1238 : /* Workspace for parsed words. */
1239 : char *words_buffer;
1240 :
1241 : /* This array will contain pointers to parsed words. */
1242 : char **previous_words;
1243 :
1244 : /* The number of words found on the input line. */
1245 : int previous_words_count;
1246 :
1247 : /*
1248 : * For compactness, we use these macros to reference previous_words[].
1249 : * Caution: do not access a previous_words[] entry without having checked
1250 : * previous_words_count to be sure it's valid. In most cases below, that
1251 : * check is implicit in a TailMatches() or similar macro, but in some
1252 : * places we have to check it explicitly.
1253 : */
1254 : #define prev_wd (previous_words[0])
1255 : #define prev2_wd (previous_words[1])
1256 : #define prev3_wd (previous_words[2])
1257 : #define prev4_wd (previous_words[3])
1258 : #define prev5_wd (previous_words[4])
1259 : #define prev6_wd (previous_words[5])
1260 : #define prev7_wd (previous_words[6])
1261 : #define prev8_wd (previous_words[7])
1262 : #define prev9_wd (previous_words[8])
1263 :
1264 : /* Macros for matching the last N words before point, case-insensitively. */
1265 : #define TailMatches1(p1) \
1266 : (previous_words_count >= 1 && \
1267 : word_matches(p1, prev_wd))
1268 :
1269 : #define TailMatches2(p2, p1) \
1270 : (previous_words_count >= 2 && \
1271 : word_matches(p1, prev_wd) && \
1272 : word_matches(p2, prev2_wd))
1273 :
1274 : #define TailMatches3(p3, p2, p1) \
1275 : (previous_words_count >= 3 && \
1276 : word_matches(p1, prev_wd) && \
1277 : word_matches(p2, prev2_wd) && \
1278 : word_matches(p3, prev3_wd))
1279 :
1280 : #define TailMatches4(p4, p3, p2, p1) \
1281 : (previous_words_count >= 4 && \
1282 : word_matches(p1, prev_wd) && \
1283 : word_matches(p2, prev2_wd) && \
1284 : word_matches(p3, prev3_wd) && \
1285 : word_matches(p4, prev4_wd))
1286 :
1287 : #define TailMatches5(p5, p4, p3, p2, p1) \
1288 : (previous_words_count >= 5 && \
1289 : word_matches(p1, prev_wd) && \
1290 : word_matches(p2, prev2_wd) && \
1291 : word_matches(p3, prev3_wd) && \
1292 : word_matches(p4, prev4_wd) && \
1293 : word_matches(p5, prev5_wd))
1294 :
1295 : #define TailMatches6(p6, p5, p4, p3, p2, p1) \
1296 : (previous_words_count >= 6 && \
1297 : word_matches(p1, prev_wd) && \
1298 : word_matches(p2, prev2_wd) && \
1299 : word_matches(p3, prev3_wd) && \
1300 : word_matches(p4, prev4_wd) && \
1301 : word_matches(p5, prev5_wd) && \
1302 : word_matches(p6, prev6_wd))
1303 :
1304 : #define TailMatches7(p7, p6, p5, p4, p3, p2, p1) \
1305 : (previous_words_count >= 7 && \
1306 : word_matches(p1, prev_wd) && \
1307 : word_matches(p2, prev2_wd) && \
1308 : word_matches(p3, prev3_wd) && \
1309 : word_matches(p4, prev4_wd) && \
1310 : word_matches(p5, prev5_wd) && \
1311 : word_matches(p6, prev6_wd) && \
1312 : word_matches(p7, prev7_wd))
1313 :
1314 : #define TailMatches8(p8, p7, p6, p5, p4, p3, p2, p1) \
1315 : (previous_words_count >= 8 && \
1316 : word_matches(p1, prev_wd) && \
1317 : word_matches(p2, prev2_wd) && \
1318 : word_matches(p3, prev3_wd) && \
1319 : word_matches(p4, prev4_wd) && \
1320 : word_matches(p5, prev5_wd) && \
1321 : word_matches(p6, prev6_wd) && \
1322 : word_matches(p7, prev7_wd) && \
1323 : word_matches(p8, prev8_wd))
1324 :
1325 : #define TailMatches9(p9, p8, p7, p6, p5, p4, p3, p2, p1) \
1326 : (previous_words_count >= 9 && \
1327 : word_matches(p1, prev_wd) && \
1328 : word_matches(p2, prev2_wd) && \
1329 : word_matches(p3, prev3_wd) && \
1330 : word_matches(p4, prev4_wd) && \
1331 : word_matches(p5, prev5_wd) && \
1332 : word_matches(p6, prev6_wd) && \
1333 : word_matches(p7, prev7_wd) && \
1334 : word_matches(p8, prev8_wd) && \
1335 : word_matches(p9, prev9_wd))
1336 :
1337 : /* Macros for matching the last N words before point, case-sensitively. */
1338 : #define TailMatchesCS1(p1) \
1339 : (previous_words_count >= 1 && \
1340 : word_matches_cs(p1, prev_wd))
1341 : #define TailMatchesCS2(p2, p1) \
1342 : (previous_words_count >= 2 && \
1343 : word_matches_cs(p1, prev_wd) && \
1344 : word_matches_cs(p2, prev2_wd))
1345 : #define TailMatchesCS3(p3, p2, p1) \
1346 : (previous_words_count >= 3 && \
1347 : word_matches_cs(p1, prev_wd) && \
1348 : word_matches_cs(p2, prev2_wd) && \
1349 : word_matches_cs(p3, prev3_wd))
1350 : #define TailMatchesCS4(p4, p3, p2, p1) \
1351 : (previous_words_count >= 4 && \
1352 : word_matches_cs(p1, prev_wd) && \
1353 : word_matches_cs(p2, prev2_wd) && \
1354 : word_matches_cs(p3, prev3_wd) && \
1355 : word_matches_cs(p4, prev4_wd))
1356 :
1357 : /*
1358 : * Macros for matching N words beginning at the start of the line,
1359 : * case-insensitively.
1360 : */
1361 : #define Matches1(p1) \
1362 : (previous_words_count == 1 && \
1363 : TailMatches1(p1))
1364 : #define Matches2(p1, p2) \
1365 : (previous_words_count == 2 && \
1366 : TailMatches2(p1, p2))
1367 : #define Matches3(p1, p2, p3) \
1368 : (previous_words_count == 3 && \
1369 : TailMatches3(p1, p2, p3))
1370 : #define Matches4(p1, p2, p3, p4) \
1371 : (previous_words_count == 4 && \
1372 : TailMatches4(p1, p2, p3, p4))
1373 : #define Matches5(p1, p2, p3, p4, p5) \
1374 : (previous_words_count == 5 && \
1375 : TailMatches5(p1, p2, p3, p4, p5))
1376 : #define Matches6(p1, p2, p3, p4, p5, p6) \
1377 : (previous_words_count == 6 && \
1378 : TailMatches6(p1, p2, p3, p4, p5, p6))
1379 : #define Matches7(p1, p2, p3, p4, p5, p6, p7) \
1380 : (previous_words_count == 7 && \
1381 : TailMatches7(p1, p2, p3, p4, p5, p6, p7))
1382 : #define Matches8(p1, p2, p3, p4, p5, p6, p7, p8) \
1383 : (previous_words_count == 8 && \
1384 : TailMatches8(p1, p2, p3, p4, p5, p6, p7, p8))
1385 : #define Matches9(p1, p2, p3, p4, p5, p6, p7, p8, p9) \
1386 : (previous_words_count == 9 && \
1387 : TailMatches9(p1, p2, p3, p4, p5, p6, p7, p8, p9))
1388 :
1389 : /*
1390 : * Macros for matching N words at the start of the line, regardless of
1391 : * what is after them, case-insensitively.
1392 : */
1393 : #define HeadMatches1(p1) \
1394 : (previous_words_count >= 1 && \
1395 : word_matches(p1, previous_words[previous_words_count - 1]))
1396 :
1397 : #define HeadMatches2(p1, p2) \
1398 : (previous_words_count >= 2 && \
1399 : word_matches(p1, previous_words[previous_words_count - 1]) && \
1400 : word_matches(p2, previous_words[previous_words_count - 2]))
1401 :
1402 : #define HeadMatches3(p1, p2, p3) \
1403 : (previous_words_count >= 3 && \
1404 : word_matches(p1, previous_words[previous_words_count - 1]) && \
1405 : word_matches(p2, previous_words[previous_words_count - 2]) && \
1406 : word_matches(p3, previous_words[previous_words_count - 3]))
1407 :
1408 : /* Known command-starting keywords. */
1409 : static const char *const sql_commands[] = {
1410 : "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
1411 : "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
1412 : "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN",
1413 : "FETCH", "GRANT", "IMPORT", "INSERT", "LISTEN", "LOAD", "LOCK",
1414 : "MOVE", "NOTIFY", "PREPARE",
1415 : "REASSIGN", "REFRESH MATERIALIZED VIEW", "REINDEX", "RELEASE",
1416 : "RESET", "REVOKE", "ROLLBACK",
1417 : "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
1418 : "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
1419 : NULL
1420 : };
1421 :
1422 : /* psql's backslash commands. */
1423 : static const char *const backslash_commands[] = {
1424 : "\\a",
1425 : "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy",
1426 : "\\copyright", "\\crosstabview",
1427 : "\\d", "\\da", "\\dA", "\\db", "\\dc", "\\dC", "\\dd", "\\ddp", "\\dD",
1428 : "\\des", "\\det", "\\deu", "\\dew", "\\dE", "\\df",
1429 : "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
1430 : "\\dm", "\\dn", "\\do", "\\dO", "\\dp",
1431 : "\\drds", "\\dRs", "\\dRp", "\\ds", "\\dS",
1432 : "\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy",
1433 : "\\e", "\\echo", "\\ef", "\\elif", "\\else", "\\encoding",
1434 : "\\endif", "\\errverbose", "\\ev",
1435 : "\\f",
1436 : "\\g", "\\gexec", "\\gset", "\\gx",
1437 : "\\h", "\\help", "\\H",
1438 : "\\i", "\\if", "\\ir",
1439 : "\\l", "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
1440 : "\\o",
1441 : "\\p", "\\password", "\\prompt", "\\pset",
1442 : "\\q", "\\qecho",
1443 : "\\r",
1444 : "\\s", "\\set", "\\setenv", "\\sf", "\\sv",
1445 : "\\t", "\\T", "\\timing",
1446 : "\\unset",
1447 : "\\x",
1448 : "\\w", "\\watch",
1449 : "\\z",
1450 : "\\!", "\\?",
1451 : NULL
1452 : };
1453 :
1454 : (void) end; /* "end" is not used */
1455 :
1456 : #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1457 0 : rl_completion_append_character = ' ';
1458 : #endif
1459 :
1460 : /* Clear a few things. */
1461 0 : completion_charp = NULL;
1462 0 : completion_charpp = NULL;
1463 0 : completion_info_charp = NULL;
1464 0 : completion_info_charp2 = NULL;
1465 :
1466 : /*
1467 : * Scan the input line to extract the words before our current position.
1468 : * According to those we'll make some smart decisions on what the user is
1469 : * probably intending to type.
1470 : */
1471 0 : previous_words = get_previous_words(start,
1472 : &words_buffer,
1473 : &previous_words_count);
1474 :
1475 : /* If current word is a backslash command, offer completions for that */
1476 0 : if (text[0] == '\\')
1477 0 : COMPLETE_WITH_LIST_CS(backslash_commands);
1478 :
1479 : /* If current word is a variable interpolation, handle that case */
1480 0 : else if (text[0] == ':' && text[1] != ':')
1481 : {
1482 0 : if (text[1] == '\'')
1483 0 : matches = complete_from_variables(text, ":'", "'", true);
1484 0 : else if (text[1] == '"')
1485 0 : matches = complete_from_variables(text, ":\"", "\"", true);
1486 : else
1487 0 : matches = complete_from_variables(text, ":", "", true);
1488 : }
1489 :
1490 : /* If no previous word, suggest one of the basic sql commands */
1491 0 : else if (previous_words_count == 0)
1492 0 : COMPLETE_WITH_LIST(sql_commands);
1493 :
1494 : /* CREATE */
1495 : /* complete with something you can create */
1496 0 : else if (TailMatches1("CREATE"))
1497 0 : matches = completion_matches(text, create_command_generator);
1498 :
1499 : /* DROP, but not DROP embedded in other commands */
1500 : /* complete with something you can drop */
1501 0 : else if (Matches1("DROP"))
1502 0 : matches = completion_matches(text, drop_command_generator);
1503 :
1504 : /* ALTER */
1505 :
1506 : /* ALTER TABLE */
1507 0 : else if (Matches2("ALTER", "TABLE"))
1508 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
1509 : "UNION SELECT 'ALL IN TABLESPACE'");
1510 :
1511 : /* ALTER something */
1512 0 : else if (Matches1("ALTER"))
1513 0 : matches = completion_matches(text, alter_command_generator);
1514 : /* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx */
1515 0 : else if (TailMatches4("ALL", "IN", "TABLESPACE", MatchAny))
1516 0 : COMPLETE_WITH_LIST2("SET TABLESPACE", "OWNED BY");
1517 : /* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx OWNED BY */
1518 0 : else if (TailMatches6("ALL", "IN", "TABLESPACE", MatchAny, "OWNED", "BY"))
1519 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
1520 : /* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx OWNED BY xxx */
1521 0 : else if (TailMatches7("ALL", "IN", "TABLESPACE", MatchAny, "OWNED", "BY", MatchAny))
1522 0 : COMPLETE_WITH_CONST("SET TABLESPACE");
1523 : /* ALTER AGGREGATE,FUNCTION <name> */
1524 0 : else if (Matches3("ALTER", "AGGREGATE|FUNCTION", MatchAny))
1525 0 : COMPLETE_WITH_CONST("(");
1526 : /* ALTER AGGREGATE,FUNCTION <name> (...) */
1527 0 : else if (Matches4("ALTER", "AGGREGATE|FUNCTION", MatchAny, MatchAny))
1528 : {
1529 0 : if (ends_with(prev_wd, ')'))
1530 0 : COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA");
1531 : else
1532 0 : COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
1533 : }
1534 : /* ALTER PUBLICATION <name> */
1535 0 : else if (Matches3("ALTER", "PUBLICATION", MatchAny))
1536 0 : COMPLETE_WITH_LIST5("ADD TABLE", "DROP TABLE", "OWNER TO", "RENAME TO", "SET");
1537 : /* ALTER PUBLICATION <name> SET */
1538 0 : else if (Matches4("ALTER", "PUBLICATION", MatchAny, "SET"))
1539 0 : COMPLETE_WITH_LIST2("(", "TABLE");
1540 : /* ALTER PUBLICATION <name> SET ( */
1541 0 : else if (HeadMatches3("ALTER", "PUBLICATION", MatchAny) && TailMatches2("SET", "("))
1542 0 : COMPLETE_WITH_CONST("publish");
1543 : /* ALTER SUBSCRIPTION <name> */
1544 0 : else if (Matches3("ALTER", "SUBSCRIPTION", MatchAny))
1545 0 : COMPLETE_WITH_LIST7("CONNECTION", "ENABLE", "DISABLE", "OWNER TO",
1546 : "RENAME TO", "REFRESH PUBLICATION", "SET");
1547 : /* ALTER SUBSCRIPTION <name> REFRESH PUBLICATION */
1548 0 : else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) &&
1549 0 : TailMatches2("REFRESH", "PUBLICATION"))
1550 0 : COMPLETE_WITH_CONST("WITH (");
1551 : /* ALTER SUBSCRIPTION <name> REFRESH PUBLICATION WITH ( */
1552 0 : else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) &&
1553 0 : TailMatches4("REFRESH", "PUBLICATION", "WITH", "("))
1554 0 : COMPLETE_WITH_CONST("copy_data");
1555 : /* ALTER SUBSCRIPTION <name> SET */
1556 0 : else if (Matches4("ALTER", "SUBSCRIPTION", MatchAny, "SET"))
1557 0 : COMPLETE_WITH_LIST2("(", "PUBLICATION");
1558 : /* ALTER SUBSCRIPTION <name> SET ( */
1559 0 : else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) && TailMatches2("SET", "("))
1560 0 : COMPLETE_WITH_LIST2("slot_name", "synchronous_commit");
1561 : /* ALTER SUBSCRIPTION <name> SET PUBLICATION */
1562 0 : else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) && TailMatches2("SET", "PUBLICATION"))
1563 : {
1564 : /* complete with nothing here as this refers to remote publications */
1565 : }
1566 : /* ALTER SUBSCRIPTION <name> SET PUBLICATION <name> */
1567 0 : else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) &&
1568 0 : TailMatches3("SET", "PUBLICATION", MatchAny))
1569 0 : COMPLETE_WITH_CONST("WITH (");
1570 : /* ALTER SUBSCRIPTION <name> SET PUBLICATION <name> WITH ( */
1571 0 : else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) &&
1572 0 : TailMatches5("SET", "PUBLICATION", MatchAny, "WITH", "("))
1573 0 : COMPLETE_WITH_LIST2("copy_data", "refresh");
1574 : /* ALTER SCHEMA <name> */
1575 0 : else if (Matches3("ALTER", "SCHEMA", MatchAny))
1576 0 : COMPLETE_WITH_LIST2("OWNER TO", "RENAME TO");
1577 :
1578 : /* ALTER COLLATION <name> */
1579 0 : else if (Matches3("ALTER", "COLLATION", MatchAny))
1580 0 : COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA");
1581 :
1582 : /* ALTER CONVERSION <name> */
1583 0 : else if (Matches3("ALTER", "CONVERSION", MatchAny))
1584 0 : COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA");
1585 :
1586 : /* ALTER DATABASE <name> */
1587 0 : else if (Matches3("ALTER", "DATABASE", MatchAny))
1588 0 : COMPLETE_WITH_LIST7("RESET", "SET", "OWNER TO", "RENAME TO",
1589 : "IS_TEMPLATE", "ALLOW_CONNECTIONS",
1590 : "CONNECTION LIMIT");
1591 :
1592 : /* ALTER EVENT TRIGGER */
1593 0 : else if (Matches3("ALTER", "EVENT", "TRIGGER"))
1594 0 : COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
1595 :
1596 : /* ALTER EVENT TRIGGER <name> */
1597 0 : else if (Matches4("ALTER", "EVENT", "TRIGGER", MatchAny))
1598 0 : COMPLETE_WITH_LIST4("DISABLE", "ENABLE", "OWNER TO", "RENAME TO");
1599 :
1600 : /* ALTER EVENT TRIGGER <name> ENABLE */
1601 0 : else if (Matches5("ALTER", "EVENT", "TRIGGER", MatchAny, "ENABLE"))
1602 0 : COMPLETE_WITH_LIST2("REPLICA", "ALWAYS");
1603 :
1604 : /* ALTER EXTENSION <name> */
1605 0 : else if (Matches3("ALTER", "EXTENSION", MatchAny))
1606 0 : COMPLETE_WITH_LIST4("ADD", "DROP", "UPDATE", "SET SCHEMA");
1607 :
1608 : /* ALTER EXTENSION <name> UPDATE */
1609 0 : else if (Matches4("ALTER", "EXTENSION", MatchAny, "UPDATE"))
1610 : {
1611 0 : completion_info_charp = prev2_wd;
1612 0 : COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions_with_TO);
1613 : }
1614 :
1615 : /* ALTER EXTENSION <name> UPDATE TO */
1616 0 : else if (Matches5("ALTER", "EXTENSION", MatchAny, "UPDATE", "TO"))
1617 : {
1618 0 : completion_info_charp = prev3_wd;
1619 0 : COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions);
1620 : }
1621 :
1622 : /* ALTER FOREIGN */
1623 0 : else if (Matches2("ALTER", "FOREIGN"))
1624 0 : COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
1625 :
1626 : /* ALTER FOREIGN DATA WRAPPER <name> */
1627 0 : else if (Matches5("ALTER", "FOREIGN", "DATA", "WRAPPER", MatchAny))
1628 0 : COMPLETE_WITH_LIST5("HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", "RENAME TO");
1629 :
1630 : /* ALTER FOREIGN TABLE <name> */
1631 0 : else if (Matches4("ALTER", "FOREIGN", "TABLE", MatchAny))
1632 0 : {
1633 : static const char *const list_ALTER_FOREIGN_TABLE[] =
1634 : {"ADD", "ALTER", "DISABLE TRIGGER", "DROP", "ENABLE", "INHERIT",
1635 : "NO INHERIT", "OPTIONS", "OWNER TO", "RENAME", "SET",
1636 : "VALIDATE CONSTRAINT", NULL};
1637 :
1638 0 : COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
1639 : }
1640 :
1641 : /* ALTER INDEX */
1642 0 : else if (Matches2("ALTER", "INDEX"))
1643 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
1644 : "UNION SELECT 'ALL IN TABLESPACE'");
1645 : /* ALTER INDEX <name> */
1646 0 : else if (Matches3("ALTER", "INDEX", MatchAny))
1647 0 : COMPLETE_WITH_LIST4("OWNER TO", "RENAME TO", "SET", "RESET");
1648 : /* ALTER INDEX <name> SET */
1649 0 : else if (Matches4("ALTER", "INDEX", MatchAny, "SET"))
1650 0 : COMPLETE_WITH_LIST2("(", "TABLESPACE");
1651 : /* ALTER INDEX <name> RESET */
1652 0 : else if (Matches4("ALTER", "INDEX", MatchAny, "RESET"))
1653 0 : COMPLETE_WITH_CONST("(");
1654 : /* ALTER INDEX <foo> SET|RESET ( */
1655 0 : else if (Matches5("ALTER", "INDEX", MatchAny, "RESET", "("))
1656 0 : COMPLETE_WITH_LIST3("fillfactor", "fastupdate",
1657 : "gin_pending_list_limit");
1658 0 : else if (Matches5("ALTER", "INDEX", MatchAny, "SET", "("))
1659 0 : COMPLETE_WITH_LIST3("fillfactor =", "fastupdate =",
1660 : "gin_pending_list_limit =");
1661 :
1662 : /* ALTER LANGUAGE <name> */
1663 0 : else if (Matches3("ALTER", "LANGUAGE", MatchAny))
1664 0 : COMPLETE_WITH_LIST2("OWNER_TO", "RENAME TO");
1665 :
1666 : /* ALTER LARGE OBJECT <oid> */
1667 0 : else if (Matches4("ALTER", "LARGE", "OBJECT", MatchAny))
1668 0 : COMPLETE_WITH_CONST("OWNER TO");
1669 :
1670 : /* ALTER MATERIALIZED VIEW */
1671 0 : else if (Matches3("ALTER", "MATERIALIZED", "VIEW"))
1672 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
1673 : "UNION SELECT 'ALL IN TABLESPACE'");
1674 :
1675 : /* ALTER USER,ROLE <name> */
1676 0 : else if (Matches3("ALTER", "USER|ROLE", MatchAny) &&
1677 0 : !TailMatches2("USER", "MAPPING"))
1678 0 : {
1679 : static const char *const list_ALTERUSER[] =
1680 : {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
1681 : "ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS",
1682 : "NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
1683 : "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
1684 : "REPLICATION", "RESET", "SET", "SUPERUSER",
1685 : "VALID UNTIL", "WITH", NULL};
1686 :
1687 0 : COMPLETE_WITH_LIST(list_ALTERUSER);
1688 : }
1689 :
1690 : /* ALTER USER,ROLE <name> WITH */
1691 0 : else if (Matches4("ALTER", "USER|ROLE", MatchAny, "WITH"))
1692 0 : {
1693 : /* Similar to the above, but don't complete "WITH" again. */
1694 : static const char *const list_ALTERUSER_WITH[] =
1695 : {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
1696 : "ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS",
1697 : "NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
1698 : "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
1699 : "REPLICATION", "RESET", "SET", "SUPERUSER",
1700 : "VALID UNTIL", NULL};
1701 :
1702 0 : COMPLETE_WITH_LIST(list_ALTERUSER_WITH);
1703 : }
1704 :
1705 : /* ALTER DEFAULT PRIVILEGES */
1706 0 : else if (Matches3("ALTER", "DEFAULT", "PRIVILEGES"))
1707 0 : COMPLETE_WITH_LIST2("FOR ROLE", "IN SCHEMA");
1708 : /* ALTER DEFAULT PRIVILEGES FOR */
1709 0 : else if (Matches4("ALTER", "DEFAULT", "PRIVILEGES", "FOR"))
1710 0 : COMPLETE_WITH_CONST("ROLE");
1711 : /* ALTER DEFAULT PRIVILEGES IN */
1712 0 : else if (Matches4("ALTER", "DEFAULT", "PRIVILEGES", "IN"))
1713 0 : COMPLETE_WITH_CONST("SCHEMA");
1714 : /* ALTER DEFAULT PRIVILEGES FOR ROLE|USER ... */
1715 0 : else if (Matches6("ALTER", "DEFAULT", "PRIVILEGES", "FOR", "ROLE|USER",
1716 : MatchAny))
1717 0 : COMPLETE_WITH_LIST3("GRANT", "REVOKE", "IN SCHEMA");
1718 : /* ALTER DEFAULT PRIVILEGES IN SCHEMA ... */
1719 0 : else if (Matches6("ALTER", "DEFAULT", "PRIVILEGES", "IN", "SCHEMA",
1720 : MatchAny))
1721 0 : COMPLETE_WITH_LIST3("GRANT", "REVOKE", "FOR ROLE");
1722 : /* ALTER DEFAULT PRIVILEGES IN SCHEMA ... FOR */
1723 0 : else if (Matches7("ALTER", "DEFAULT", "PRIVILEGES", "IN", "SCHEMA",
1724 : MatchAny, "FOR"))
1725 0 : COMPLETE_WITH_CONST("ROLE");
1726 : /* ALTER DEFAULT PRIVILEGES FOR ROLE|USER ... IN SCHEMA ... */
1727 : /* ALTER DEFAULT PRIVILEGES IN SCHEMA ... FOR ROLE|USER ... */
1728 0 : else if (Matches9("ALTER", "DEFAULT", "PRIVILEGES", "FOR", "ROLE|USER",
1729 0 : MatchAny, "IN", "SCHEMA", MatchAny) ||
1730 0 : Matches9("ALTER", "DEFAULT", "PRIVILEGES", "IN", "SCHEMA",
1731 : MatchAny, "FOR", "ROLE|USER", MatchAny))
1732 0 : COMPLETE_WITH_LIST2("GRANT", "REVOKE");
1733 : /* ALTER DOMAIN <name> */
1734 0 : else if (Matches3("ALTER", "DOMAIN", MatchAny))
1735 0 : COMPLETE_WITH_LIST6("ADD", "DROP", "OWNER TO", "RENAME", "SET",
1736 : "VALIDATE CONSTRAINT");
1737 : /* ALTER DOMAIN <sth> DROP */
1738 0 : else if (Matches4("ALTER", "DOMAIN", MatchAny, "DROP"))
1739 0 : COMPLETE_WITH_LIST3("CONSTRAINT", "DEFAULT", "NOT NULL");
1740 : /* ALTER DOMAIN <sth> DROP|RENAME|VALIDATE CONSTRAINT */
1741 0 : else if (Matches5("ALTER", "DOMAIN", MatchAny, "DROP|RENAME|VALIDATE", "CONSTRAINT"))
1742 : {
1743 0 : completion_info_charp = prev3_wd;
1744 0 : COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
1745 : }
1746 : /* ALTER DOMAIN <sth> RENAME */
1747 0 : else if (Matches4("ALTER", "DOMAIN", MatchAny, "RENAME"))
1748 0 : COMPLETE_WITH_LIST2("CONSTRAINT", "TO");
1749 : /* ALTER DOMAIN <sth> RENAME CONSTRAINT <sth> */
1750 0 : else if (Matches6("ALTER", "DOMAIN", MatchAny, "RENAME", "CONSTRAINT", MatchAny))
1751 0 : COMPLETE_WITH_CONST("TO");
1752 :
1753 : /* ALTER DOMAIN <sth> SET */
1754 0 : else if (Matches4("ALTER", "DOMAIN", MatchAny, "SET"))
1755 0 : COMPLETE_WITH_LIST3("DEFAULT", "NOT NULL", "SCHEMA");
1756 : /* ALTER SEQUENCE <name> */
1757 0 : else if (Matches3("ALTER", "SEQUENCE", MatchAny))
1758 0 : {
1759 : static const char *const list_ALTERSEQUENCE[] =
1760 : {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
1761 : "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
1762 :
1763 0 : COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
1764 : }
1765 : /* ALTER SEQUENCE <name> NO */
1766 0 : else if (Matches4("ALTER", "SEQUENCE", MatchAny, "NO"))
1767 0 : COMPLETE_WITH_LIST3("MINVALUE", "MAXVALUE", "CYCLE");
1768 : /* ALTER SERVER <name> */
1769 0 : else if (Matches3("ALTER", "SERVER", MatchAny))
1770 0 : COMPLETE_WITH_LIST4("VERSION", "OPTIONS", "OWNER TO", "RENAME TO");
1771 : /* ALTER SERVER <name> VERSION <version> */
1772 0 : else if (Matches5("ALTER", "SERVER", MatchAny, "VERSION", MatchAny))
1773 0 : COMPLETE_WITH_CONST("OPTIONS");
1774 : /* ALTER SYSTEM SET, RESET, RESET ALL */
1775 0 : else if (Matches2("ALTER", "SYSTEM"))
1776 0 : COMPLETE_WITH_LIST2("SET", "RESET");
1777 0 : else if (Matches3("ALTER", "SYSTEM", "SET|RESET"))
1778 0 : COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
1779 0 : else if (Matches4("ALTER", "SYSTEM", "SET", MatchAny))
1780 0 : COMPLETE_WITH_CONST("TO");
1781 : /* ALTER VIEW <name> */
1782 0 : else if (Matches3("ALTER", "VIEW", MatchAny))
1783 0 : COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO",
1784 : "SET SCHEMA");
1785 : /* ALTER MATERIALIZED VIEW <name> */
1786 0 : else if (Matches4("ALTER", "MATERIALIZED", "VIEW", MatchAny))
1787 0 : COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO",
1788 : "SET SCHEMA");
1789 :
1790 : /* ALTER POLICY <name> */
1791 0 : else if (Matches2("ALTER", "POLICY"))
1792 0 : COMPLETE_WITH_QUERY(Query_for_list_of_policies);
1793 : /* ALTER POLICY <name> ON */
1794 0 : else if (Matches3("ALTER", "POLICY", MatchAny))
1795 0 : COMPLETE_WITH_CONST("ON");
1796 : /* ALTER POLICY <name> ON <table> */
1797 0 : else if (Matches4("ALTER", "POLICY", MatchAny, "ON"))
1798 : {
1799 0 : completion_info_charp = prev2_wd;
1800 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy);
1801 : }
1802 : /* ALTER POLICY <name> ON <table> - show options */
1803 0 : else if (Matches5("ALTER", "POLICY", MatchAny, "ON", MatchAny))
1804 0 : COMPLETE_WITH_LIST4("RENAME TO", "TO", "USING (", "WITH CHECK (");
1805 : /* ALTER POLICY <name> ON <table> TO <role> */
1806 0 : else if (Matches6("ALTER", "POLICY", MatchAny, "ON", MatchAny, "TO"))
1807 0 : COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
1808 : /* ALTER POLICY <name> ON <table> USING ( */
1809 0 : else if (Matches6("ALTER", "POLICY", MatchAny, "ON", MatchAny, "USING"))
1810 0 : COMPLETE_WITH_CONST("(");
1811 : /* ALTER POLICY <name> ON <table> WITH CHECK ( */
1812 0 : else if (Matches7("ALTER", "POLICY", MatchAny, "ON", MatchAny, "WITH", "CHECK"))
1813 0 : COMPLETE_WITH_CONST("(");
1814 :
1815 : /* ALTER RULE <name>, add ON */
1816 0 : else if (Matches3("ALTER", "RULE", MatchAny))
1817 0 : COMPLETE_WITH_CONST("ON");
1818 :
1819 : /* If we have ALTER RULE <name> ON, then add the correct tablename */
1820 0 : else if (Matches4("ALTER", "RULE", MatchAny, "ON"))
1821 : {
1822 0 : completion_info_charp = prev2_wd;
1823 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
1824 : }
1825 :
1826 : /* ALTER RULE <name> ON <name> */
1827 0 : else if (Matches5("ALTER", "RULE", MatchAny, "ON", MatchAny))
1828 0 : COMPLETE_WITH_CONST("RENAME TO");
1829 :
1830 : /* ALTER STATISTICS <name> */
1831 0 : else if (Matches3("ALTER", "STATISTICS", MatchAny))
1832 0 : COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA");
1833 :
1834 : /* ALTER TRIGGER <name>, add ON */
1835 0 : else if (Matches3("ALTER", "TRIGGER", MatchAny))
1836 0 : COMPLETE_WITH_CONST("ON");
1837 :
1838 0 : else if (Matches4("ALTER", "TRIGGER", MatchAny, MatchAny))
1839 : {
1840 0 : completion_info_charp = prev2_wd;
1841 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
1842 : }
1843 :
1844 : /*
1845 : * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
1846 : */
1847 0 : else if (Matches4("ALTER", "TRIGGER", MatchAny, "ON"))
1848 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
1849 :
1850 : /* ALTER TRIGGER <name> ON <name> */
1851 0 : else if (Matches5("ALTER", "TRIGGER", MatchAny, "ON", MatchAny))
1852 0 : COMPLETE_WITH_CONST("RENAME TO");
1853 :
1854 : /*
1855 : * If we detect ALTER TABLE <name>, suggest sub commands
1856 : */
1857 0 : else if (Matches3("ALTER", "TABLE", MatchAny))
1858 0 : {
1859 : static const char *const list_ALTER2[] =
1860 : {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
1861 : "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
1862 : "VALIDATE CONSTRAINT", "REPLICA IDENTITY", "ATTACH PARTITION",
1863 : "DETACH PARTITION", NULL};
1864 :
1865 0 : COMPLETE_WITH_LIST(list_ALTER2);
1866 : }
1867 : /* ALTER TABLE xxx ENABLE */
1868 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "ENABLE"))
1869 0 : COMPLETE_WITH_LIST5("ALWAYS", "REPLICA", "ROW LEVEL SECURITY", "RULE",
1870 : "TRIGGER");
1871 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "REPLICA|ALWAYS"))
1872 0 : COMPLETE_WITH_LIST2("RULE", "TRIGGER");
1873 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "RULE"))
1874 : {
1875 0 : completion_info_charp = prev3_wd;
1876 0 : COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1877 : }
1878 0 : else if (Matches6("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "RULE"))
1879 : {
1880 0 : completion_info_charp = prev4_wd;
1881 0 : COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1882 : }
1883 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "TRIGGER"))
1884 : {
1885 0 : completion_info_charp = prev3_wd;
1886 0 : COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1887 : }
1888 0 : else if (Matches6("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "TRIGGER"))
1889 : {
1890 0 : completion_info_charp = prev4_wd;
1891 0 : COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1892 : }
1893 : /* ALTER TABLE xxx INHERIT */
1894 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "INHERIT"))
1895 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1896 : /* ALTER TABLE xxx NO INHERIT */
1897 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "NO", "INHERIT"))
1898 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
1899 : /* ALTER TABLE xxx DISABLE */
1900 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "DISABLE"))
1901 0 : COMPLETE_WITH_LIST3("ROW LEVEL SECURITY", "RULE", "TRIGGER");
1902 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "DISABLE", "RULE"))
1903 : {
1904 0 : completion_info_charp = prev3_wd;
1905 0 : COMPLETE_WITH_QUERY(Query_for_rule_of_table);
1906 : }
1907 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "DISABLE", "TRIGGER"))
1908 : {
1909 0 : completion_info_charp = prev3_wd;
1910 0 : COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
1911 : }
1912 :
1913 : /* ALTER TABLE xxx ALTER */
1914 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "ALTER"))
1915 0 : COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT'");
1916 :
1917 : /* ALTER TABLE xxx RENAME */
1918 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "RENAME"))
1919 0 : COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'");
1920 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME", "COLUMN"))
1921 0 : COMPLETE_WITH_ATTR(prev3_wd, "");
1922 :
1923 : /* ALTER TABLE xxx RENAME yyy */
1924 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "RENAME", MatchAnyExcept("CONSTRAINT|TO")))
1925 0 : COMPLETE_WITH_CONST("TO");
1926 :
1927 : /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */
1928 0 : else if (Matches6("ALTER", "TABLE", MatchAny, "RENAME", "COLUMN|CONSTRAINT", MatchAnyExcept("TO")))
1929 0 : COMPLETE_WITH_CONST("TO");
1930 :
1931 : /* If we have ALTER TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
1932 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "DROP"))
1933 0 : COMPLETE_WITH_LIST2("COLUMN", "CONSTRAINT");
1934 : /* If we have ALTER TABLE <sth> DROP COLUMN, provide list of columns */
1935 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN"))
1936 0 : COMPLETE_WITH_ATTR(prev3_wd, "");
1937 :
1938 : /*
1939 : * If we have ALTER TABLE <sth> ALTER|DROP|RENAME|VALIDATE CONSTRAINT,
1940 : * provide list of constraints
1941 : */
1942 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|DROP|RENAME|VALIDATE", "CONSTRAINT"))
1943 : {
1944 0 : completion_info_charp = prev3_wd;
1945 0 : COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
1946 : }
1947 : /* ALTER TABLE ALTER [COLUMN] <foo> */
1948 0 : else if (Matches6("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny) ||
1949 0 : Matches5("ALTER", "TABLE", MatchAny, "ALTER", MatchAny))
1950 0 : COMPLETE_WITH_LIST6("TYPE", "SET", "RESET", "RESTART", "ADD", "DROP");
1951 : /* ALTER TABLE ALTER [COLUMN] <foo> SET */
1952 0 : else if (Matches7("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET") ||
1953 0 : Matches6("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "SET"))
1954 0 : COMPLETE_WITH_LIST5("(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE");
1955 : /* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
1956 0 : else if (Matches8("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET", "(") ||
1957 0 : Matches7("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "SET", "("))
1958 0 : COMPLETE_WITH_LIST2("n_distinct", "n_distinct_inherited");
1959 : /* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
1960 0 : else if (Matches8("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET", "STORAGE") ||
1961 0 : Matches7("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "SET", "STORAGE"))
1962 0 : COMPLETE_WITH_LIST4("PLAIN", "EXTERNAL", "EXTENDED", "MAIN");
1963 : /* ALTER TABLE ALTER [COLUMN] <foo> DROP */
1964 0 : else if (Matches7("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "DROP") ||
1965 0 : Matches6("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "DROP"))
1966 0 : COMPLETE_WITH_LIST3("DEFAULT", "IDENTITY", "NOT NULL");
1967 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "CLUSTER"))
1968 0 : COMPLETE_WITH_CONST("ON");
1969 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "CLUSTER", "ON"))
1970 : {
1971 0 : completion_info_charp = prev3_wd;
1972 0 : COMPLETE_WITH_QUERY(Query_for_index_of_table);
1973 : }
1974 : /* If we have ALTER TABLE <sth> SET, provide list of attributes and '(' */
1975 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "SET"))
1976 0 : COMPLETE_WITH_LIST7("(", "LOGGED", "SCHEMA", "TABLESPACE", "UNLOGGED",
1977 : "WITH", "WITHOUT");
1978 :
1979 : /*
1980 : * If we have ALTER TABLE <sth> SET TABLESPACE provide a list of
1981 : * tablespaces
1982 : */
1983 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "SET", "TABLESPACE"))
1984 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
1985 : /* If we have ALTER TABLE <sth> SET WITH provide OIDS */
1986 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "SET", "WITH"))
1987 0 : COMPLETE_WITH_CONST("OIDS");
1988 : /* If we have ALTER TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
1989 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "SET", "WITHOUT"))
1990 0 : COMPLETE_WITH_LIST2("CLUSTER", "OIDS");
1991 : /* ALTER TABLE <foo> RESET */
1992 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "RESET"))
1993 0 : COMPLETE_WITH_CONST("(");
1994 : /* ALTER TABLE <foo> SET|RESET ( */
1995 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "SET|RESET", "("))
1996 0 : {
1997 : static const char *const list_TABLEOPTIONS[] =
1998 : {
1999 : "autovacuum_analyze_scale_factor",
2000 : "autovacuum_analyze_threshold",
2001 : "autovacuum_enabled",
2002 : "autovacuum_freeze_max_age",
2003 : "autovacuum_freeze_min_age",
2004 : "autovacuum_freeze_table_age",
2005 : "autovacuum_multixact_freeze_max_age",
2006 : "autovacuum_multixact_freeze_min_age",
2007 : "autovacuum_multixact_freeze_table_age",
2008 : "autovacuum_vacuum_cost_delay",
2009 : "autovacuum_vacuum_cost_limit",
2010 : "autovacuum_vacuum_scale_factor",
2011 : "autovacuum_vacuum_threshold",
2012 : "fillfactor",
2013 : "parallel_workers",
2014 : "log_autovacuum_min_duration",
2015 : "toast.autovacuum_enabled",
2016 : "toast.autovacuum_freeze_max_age",
2017 : "toast.autovacuum_freeze_min_age",
2018 : "toast.autovacuum_freeze_table_age",
2019 : "toast.autovacuum_multixact_freeze_max_age",
2020 : "toast.autovacuum_multixact_freeze_min_age",
2021 : "toast.autovacuum_multixact_freeze_table_age",
2022 : "toast.autovacuum_vacuum_cost_delay",
2023 : "toast.autovacuum_vacuum_cost_limit",
2024 : "toast.autovacuum_vacuum_scale_factor",
2025 : "toast.autovacuum_vacuum_threshold",
2026 : "toast.log_autovacuum_min_duration",
2027 : "user_catalog_table",
2028 : NULL
2029 : };
2030 :
2031 0 : COMPLETE_WITH_LIST(list_TABLEOPTIONS);
2032 : }
2033 0 : else if (Matches7("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING", "INDEX"))
2034 : {
2035 0 : completion_info_charp = prev5_wd;
2036 0 : COMPLETE_WITH_QUERY(Query_for_index_of_table);
2037 : }
2038 0 : else if (Matches6("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING"))
2039 0 : COMPLETE_WITH_CONST("INDEX");
2040 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY"))
2041 0 : COMPLETE_WITH_LIST4("FULL", "NOTHING", "DEFAULT", "USING");
2042 0 : else if (Matches4("ALTER", "TABLE", MatchAny, "REPLICA"))
2043 0 : COMPLETE_WITH_CONST("IDENTITY");
2044 :
2045 : /*
2046 : * If we have ALTER TABLE <foo> ATTACH PARTITION, provide a list of
2047 : * tables.
2048 : */
2049 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "ATTACH", "PARTITION"))
2050 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
2051 : /* Limited completion support for partition bound specification */
2052 0 : else if (TailMatches3("ATTACH", "PARTITION", MatchAny))
2053 0 : COMPLETE_WITH_CONST("FOR VALUES");
2054 0 : else if (TailMatches2("FOR", "VALUES"))
2055 0 : COMPLETE_WITH_LIST2("FROM (", "IN (");
2056 :
2057 : /*
2058 : * If we have ALTER TABLE <foo> DETACH PARTITION, provide a list of
2059 : * partitions of <foo>.
2060 : */
2061 0 : else if (Matches5("ALTER", "TABLE", MatchAny, "DETACH", "PARTITION"))
2062 : {
2063 0 : completion_info_charp = prev3_wd;
2064 0 : COMPLETE_WITH_QUERY(Query_for_partition_of_table);
2065 : }
2066 :
2067 : /* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
2068 0 : else if (Matches3("ALTER", "TABLESPACE", MatchAny))
2069 0 : COMPLETE_WITH_LIST4("RENAME TO", "OWNER TO", "SET", "RESET");
2070 : /* ALTER TABLESPACE <foo> SET|RESET */
2071 0 : else if (Matches4("ALTER", "TABLESPACE", MatchAny, "SET|RESET"))
2072 0 : COMPLETE_WITH_CONST("(");
2073 : /* ALTER TABLESPACE <foo> SET|RESET ( */
2074 0 : else if (Matches5("ALTER", "TABLESPACE", MatchAny, "SET|RESET", "("))
2075 0 : COMPLETE_WITH_LIST3("seq_page_cost", "random_page_cost",
2076 : "effective_io_concurrency");
2077 :
2078 : /* ALTER TEXT SEARCH */
2079 0 : else if (Matches3("ALTER", "TEXT", "SEARCH"))
2080 0 : COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
2081 0 : else if (Matches5("ALTER", "TEXT", "SEARCH", "TEMPLATE|PARSER", MatchAny))
2082 0 : COMPLETE_WITH_LIST2("RENAME TO", "SET SCHEMA");
2083 0 : else if (Matches5("ALTER", "TEXT", "SEARCH", "DICTIONARY", MatchAny))
2084 0 : COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA");
2085 0 : else if (Matches5("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny))
2086 0 : COMPLETE_WITH_LIST6("ADD MAPPING FOR", "ALTER MAPPING",
2087 : "DROP MAPPING FOR",
2088 : "OWNER TO", "RENAME TO", "SET SCHEMA");
2089 :
2090 : /* complete ALTER TYPE <foo> with actions */
2091 0 : else if (Matches3("ALTER", "TYPE", MatchAny))
2092 0 : COMPLETE_WITH_LIST7("ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE",
2093 : "DROP ATTRIBUTE",
2094 : "OWNER TO", "RENAME", "SET SCHEMA");
2095 : /* complete ALTER TYPE <foo> ADD with actions */
2096 0 : else if (Matches4("ALTER", "TYPE", MatchAny, "ADD"))
2097 0 : COMPLETE_WITH_LIST2("ATTRIBUTE", "VALUE");
2098 : /* ALTER TYPE <foo> RENAME */
2099 0 : else if (Matches4("ALTER", "TYPE", MatchAny, "RENAME"))
2100 0 : COMPLETE_WITH_LIST3("ATTRIBUTE", "TO", "VALUE");
2101 : /* ALTER TYPE xxx RENAME (ATTRIBUTE|VALUE) yyy */
2102 0 : else if (Matches6("ALTER", "TYPE", MatchAny, "RENAME", "ATTRIBUTE|VALUE", MatchAny))
2103 0 : COMPLETE_WITH_CONST("TO");
2104 :
2105 : /*
2106 : * If we have ALTER TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list
2107 : * of attributes
2108 : */
2109 0 : else if (Matches5("ALTER", "TYPE", MatchAny, "ALTER|DROP|RENAME", "ATTRIBUTE"))
2110 0 : COMPLETE_WITH_ATTR(prev3_wd, "");
2111 : /* ALTER TYPE ALTER ATTRIBUTE <foo> */
2112 0 : else if (Matches6("ALTER", "TYPE", MatchAny, "ALTER", "ATTRIBUTE", MatchAny))
2113 0 : COMPLETE_WITH_CONST("TYPE");
2114 : /* complete ALTER GROUP <foo> */
2115 0 : else if (Matches3("ALTER", "GROUP", MatchAny))
2116 0 : COMPLETE_WITH_LIST3("ADD USER", "DROP USER", "RENAME TO");
2117 : /* complete ALTER GROUP <foo> ADD|DROP with USER */
2118 0 : else if (Matches4("ALTER", "GROUP", MatchAny, "ADD|DROP"))
2119 0 : COMPLETE_WITH_CONST("USER");
2120 : /* complete ALTER GROUP <foo> ADD|DROP USER with a user name */
2121 0 : else if (Matches5("ALTER", "GROUP", MatchAny, "ADD|DROP", "USER"))
2122 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2123 :
2124 : /*
2125 : * If we have ALTER TYPE <sth> RENAME VALUE, provide list of enum values
2126 : */
2127 0 : else if (Matches5("ALTER", "TYPE", MatchAny, "RENAME", "VALUE"))
2128 0 : COMPLETE_WITH_ENUM_VALUE(prev3_wd);
2129 :
2130 : /* BEGIN */
2131 0 : else if (Matches1("BEGIN"))
2132 0 : COMPLETE_WITH_LIST6("WORK", "TRANSACTION", "ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE");
2133 : /* END, ABORT */
2134 0 : else if (Matches1("END|ABORT"))
2135 0 : COMPLETE_WITH_LIST2("WORK", "TRANSACTION");
2136 : /* COMMIT */
2137 0 : else if (Matches1("COMMIT"))
2138 0 : COMPLETE_WITH_LIST3("WORK", "TRANSACTION", "PREPARED");
2139 : /* RELEASE SAVEPOINT */
2140 0 : else if (Matches1("RELEASE"))
2141 0 : COMPLETE_WITH_CONST("SAVEPOINT");
2142 : /* ROLLBACK */
2143 0 : else if (Matches1("ROLLBACK"))
2144 0 : COMPLETE_WITH_LIST4("WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED");
2145 : /* CLUSTER */
2146 0 : else if (Matches1("CLUSTER"))
2147 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "UNION SELECT 'VERBOSE'");
2148 0 : else if (Matches2("CLUSTER", "VERBOSE"))
2149 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
2150 : /* If we have CLUSTER <sth>, then add "USING" */
2151 0 : else if (Matches2("CLUSTER", MatchAnyExcept("VERBOSE|ON")))
2152 0 : COMPLETE_WITH_CONST("USING");
2153 : /* If we have CLUSTER VERBOSE <sth>, then add "USING" */
2154 0 : else if (Matches3("CLUSTER", "VERBOSE", MatchAny))
2155 0 : COMPLETE_WITH_CONST("USING");
2156 : /* If we have CLUSTER <sth> USING, then add the index as well */
2157 0 : else if (Matches3("CLUSTER", MatchAny, "USING") ||
2158 0 : Matches4("CLUSTER", "VERBOSE", MatchAny, "USING"))
2159 : {
2160 0 : completion_info_charp = prev2_wd;
2161 0 : COMPLETE_WITH_QUERY(Query_for_index_of_table);
2162 : }
2163 :
2164 : /* COMMENT */
2165 0 : else if (Matches1("COMMENT"))
2166 0 : COMPLETE_WITH_CONST("ON");
2167 0 : else if (Matches2("COMMENT", "ON"))
2168 0 : {
2169 : static const char *const list_COMMENT[] =
2170 : {"ACCESS METHOD", "CAST", "COLLATION", "CONVERSION", "DATABASE",
2171 : "EVENT TRIGGER", "EXTENSION",
2172 : "FOREIGN DATA WRAPPER", "FOREIGN TABLE",
2173 : "SERVER", "INDEX", "LANGUAGE", "POLICY", "PUBLICATION", "RULE",
2174 : "SCHEMA", "SEQUENCE", "STATISTICS", "SUBSCRIPTION",
2175 : "TABLE", "TYPE", "VIEW", "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
2176 : "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
2177 : "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
2178 :
2179 0 : COMPLETE_WITH_LIST(list_COMMENT);
2180 : }
2181 0 : else if (Matches4("COMMENT", "ON", "ACCESS", "METHOD"))
2182 0 : COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
2183 0 : else if (Matches3("COMMENT", "ON", "FOREIGN"))
2184 0 : COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
2185 0 : else if (Matches4("COMMENT", "ON", "TEXT", "SEARCH"))
2186 0 : COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
2187 0 : else if (Matches3("COMMENT", "ON", "CONSTRAINT"))
2188 0 : COMPLETE_WITH_QUERY(Query_for_all_table_constraints);
2189 0 : else if (Matches4("COMMENT", "ON", "CONSTRAINT", MatchAny))
2190 0 : COMPLETE_WITH_CONST("ON");
2191 0 : else if (Matches5("COMMENT", "ON", "CONSTRAINT", MatchAny, "ON"))
2192 : {
2193 0 : completion_info_charp = prev2_wd;
2194 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint);
2195 : }
2196 0 : else if (Matches4("COMMENT", "ON", "MATERIALIZED", "VIEW"))
2197 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
2198 0 : else if (Matches4("COMMENT", "ON", "EVENT", "TRIGGER"))
2199 0 : COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
2200 0 : else if (Matches4("COMMENT", "ON", MatchAny, MatchAnyExcept("IS")) ||
2201 0 : Matches5("COMMENT", "ON", MatchAny, MatchAny, MatchAnyExcept("IS")) ||
2202 0 : Matches6("COMMENT", "ON", MatchAny, MatchAny, MatchAny, MatchAnyExcept("IS")))
2203 0 : COMPLETE_WITH_CONST("IS");
2204 :
2205 : /* COPY */
2206 :
2207 : /*
2208 : * If we have COPY, offer list of tables or "(" (Also cover the analogous
2209 : * backslash command).
2210 : */
2211 0 : else if (Matches1("COPY|\\copy"))
2212 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
2213 : " UNION ALL SELECT '('");
2214 : /* If we have COPY BINARY, complete with list of tables */
2215 0 : else if (Matches2("COPY", "BINARY"))
2216 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2217 : /* If we have COPY (, complete it with legal commands */
2218 0 : else if (Matches2("COPY|\\copy", "("))
2219 0 : COMPLETE_WITH_LIST7("SELECT", "TABLE", "VALUES", "INSERT", "UPDATE", "DELETE", "WITH");
2220 : /* If we have COPY [BINARY] <sth>, complete it with "TO" or "FROM" */
2221 0 : else if (Matches2("COPY|\\copy", MatchAny) ||
2222 0 : Matches3("COPY", "BINARY", MatchAny))
2223 0 : COMPLETE_WITH_LIST2("FROM", "TO");
2224 : /* If we have COPY [BINARY] <sth> FROM|TO, complete with filename */
2225 0 : else if (Matches3("COPY|\\copy", MatchAny, "FROM|TO") ||
2226 0 : Matches4("COPY", "BINARY", MatchAny, "FROM|TO"))
2227 : {
2228 0 : completion_charp = "";
2229 0 : matches = completion_matches(text, complete_from_files);
2230 : }
2231 :
2232 : /* Handle COPY [BINARY] <sth> FROM|TO filename */
2233 0 : else if (Matches4("COPY|\\copy", MatchAny, "FROM|TO", MatchAny) ||
2234 0 : Matches5("COPY", "BINARY", MatchAny, "FROM|TO", MatchAny))
2235 0 : COMPLETE_WITH_LIST6("BINARY", "OIDS", "DELIMITER", "NULL", "CSV",
2236 : "ENCODING");
2237 :
2238 : /* Handle COPY [BINARY] <sth> FROM|TO filename CSV */
2239 0 : else if (Matches5("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "CSV") ||
2240 0 : Matches6("COPY", "BINARY", MatchAny, "FROM|TO", MatchAny, "CSV"))
2241 0 : COMPLETE_WITH_LIST5("HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE",
2242 : "FORCE NOT NULL");
2243 :
2244 : /* CREATE ACCESS METHOD */
2245 : /* Complete "CREATE ACCESS METHOD <name>" */
2246 0 : else if (Matches4("CREATE", "ACCESS", "METHOD", MatchAny))
2247 0 : COMPLETE_WITH_CONST("TYPE");
2248 : /* Complete "CREATE ACCESS METHOD <name> TYPE" */
2249 0 : else if (Matches5("CREATE", "ACCESS", "METHOD", MatchAny, "TYPE"))
2250 0 : COMPLETE_WITH_CONST("INDEX");
2251 : /* Complete "CREATE ACCESS METHOD <name> TYPE <type>" */
2252 0 : else if (Matches6("CREATE", "ACCESS", "METHOD", MatchAny, "TYPE", MatchAny))
2253 0 : COMPLETE_WITH_CONST("HANDLER");
2254 :
2255 : /* CREATE DATABASE */
2256 0 : else if (Matches3("CREATE", "DATABASE", MatchAny))
2257 0 : COMPLETE_WITH_LIST9("OWNER", "TEMPLATE", "ENCODING", "TABLESPACE",
2258 : "IS_TEMPLATE",
2259 : "ALLOW_CONNECTIONS", "CONNECTION LIMIT",
2260 : "LC_COLLATE", "LC_CTYPE");
2261 :
2262 0 : else if (Matches4("CREATE", "DATABASE", MatchAny, "TEMPLATE"))
2263 0 : COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
2264 :
2265 : /* CREATE EXTENSION */
2266 : /* Complete with available extensions rather than installed ones. */
2267 0 : else if (Matches2("CREATE", "EXTENSION"))
2268 0 : COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
2269 : /* CREATE EXTENSION <name> */
2270 0 : else if (Matches3("CREATE", "EXTENSION", MatchAny))
2271 0 : COMPLETE_WITH_LIST3("WITH SCHEMA", "CASCADE", "VERSION");
2272 : /* CREATE EXTENSION <name> VERSION */
2273 0 : else if (Matches4("CREATE", "EXTENSION", MatchAny, "VERSION"))
2274 : {
2275 0 : completion_info_charp = prev2_wd;
2276 0 : COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions);
2277 : }
2278 :
2279 : /* CREATE FOREIGN */
2280 0 : else if (Matches2("CREATE", "FOREIGN"))
2281 0 : COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
2282 :
2283 : /* CREATE FOREIGN DATA WRAPPER */
2284 0 : else if (Matches5("CREATE", "FOREIGN", "DATA", "WRAPPER", MatchAny))
2285 0 : COMPLETE_WITH_LIST3("HANDLER", "VALIDATOR", "OPTIONS");
2286 :
2287 : /* CREATE INDEX --- is allowed inside CREATE SCHEMA, so use TailMatches */
2288 : /* First off we complete CREATE UNIQUE with "INDEX" */
2289 0 : else if (TailMatches2("CREATE", "UNIQUE"))
2290 0 : COMPLETE_WITH_CONST("INDEX");
2291 :
2292 : /*
2293 : * If we have CREATE|UNIQUE INDEX, then add "ON", "CONCURRENTLY", and
2294 : * existing indexes
2295 : */
2296 0 : else if (TailMatches2("CREATE|UNIQUE", "INDEX"))
2297 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
2298 : " UNION SELECT 'ON'"
2299 : " UNION SELECT 'CONCURRENTLY'");
2300 : /* Complete ... INDEX|CONCURRENTLY [<name>] ON with a list of tables */
2301 0 : else if (TailMatches3("INDEX|CONCURRENTLY", MatchAny, "ON") ||
2302 0 : TailMatches2("INDEX|CONCURRENTLY", "ON"))
2303 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
2304 :
2305 : /*
2306 : * Complete CREATE|UNIQUE INDEX CONCURRENTLY with "ON" and existing
2307 : * indexes
2308 : */
2309 0 : else if (TailMatches3("CREATE|UNIQUE", "INDEX", "CONCURRENTLY"))
2310 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
2311 : " UNION SELECT 'ON'");
2312 : /* Complete CREATE|UNIQUE INDEX [CONCURRENTLY] <sth> with "ON" */
2313 0 : else if (TailMatches3("CREATE|UNIQUE", "INDEX", MatchAny) ||
2314 0 : TailMatches4("CREATE|UNIQUE", "INDEX", "CONCURRENTLY", MatchAny))
2315 0 : COMPLETE_WITH_CONST("ON");
2316 :
2317 : /*
2318 : * Complete INDEX <name> ON <table> with a list of table columns (which
2319 : * should really be in parens)
2320 : */
2321 0 : else if (TailMatches4("INDEX", MatchAny, "ON", MatchAny) ||
2322 0 : TailMatches3("INDEX|CONCURRENTLY", "ON", MatchAny))
2323 0 : COMPLETE_WITH_LIST2("(", "USING");
2324 0 : else if (TailMatches5("INDEX", MatchAny, "ON", MatchAny, "(") ||
2325 0 : TailMatches4("INDEX|CONCURRENTLY", "ON", MatchAny, "("))
2326 0 : COMPLETE_WITH_ATTR(prev2_wd, "");
2327 : /* same if you put in USING */
2328 0 : else if (TailMatches5("ON", MatchAny, "USING", MatchAny, "("))
2329 0 : COMPLETE_WITH_ATTR(prev4_wd, "");
2330 : /* Complete USING with an index method */
2331 0 : else if (TailMatches6("INDEX", MatchAny, MatchAny, "ON", MatchAny, "USING") ||
2332 0 : TailMatches5("INDEX", MatchAny, "ON", MatchAny, "USING") ||
2333 0 : TailMatches4("INDEX", "ON", MatchAny, "USING"))
2334 0 : COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
2335 0 : else if (TailMatches4("ON", MatchAny, "USING", MatchAny) &&
2336 0 : !TailMatches6("POLICY", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny) &&
2337 0 : !TailMatches4("FOR", MatchAny, MatchAny, MatchAny))
2338 0 : COMPLETE_WITH_CONST("(");
2339 :
2340 : /* CREATE POLICY */
2341 : /* Complete "CREATE POLICY <name> ON" */
2342 0 : else if (Matches3("CREATE", "POLICY", MatchAny))
2343 0 : COMPLETE_WITH_CONST("ON");
2344 : /* Complete "CREATE POLICY <name> ON <table>" */
2345 0 : else if (Matches4("CREATE", "POLICY", MatchAny, "ON"))
2346 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2347 : /* Complete "CREATE POLICY <name> ON <table> AS|FOR|TO|USING|WITH CHECK" */
2348 0 : else if (Matches5("CREATE", "POLICY", MatchAny, "ON", MatchAny))
2349 0 : COMPLETE_WITH_LIST5("AS", "FOR", "TO", "USING (", "WITH CHECK (");
2350 : /* CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE */
2351 0 : else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS"))
2352 0 : COMPLETE_WITH_LIST2("PERMISSIVE", "RESTRICTIVE");
2353 :
2354 : /*
2355 : * CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE
2356 : * FOR|TO|USING|WITH CHECK
2357 : */
2358 0 : else if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny))
2359 0 : COMPLETE_WITH_LIST4("FOR", "TO", "USING", "WITH CHECK");
2360 : /* CREATE POLICY <name> ON <table> FOR ALL|SELECT|INSERT|UPDATE|DELETE */
2361 0 : else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR"))
2362 0 : COMPLETE_WITH_LIST5("ALL", "SELECT", "INSERT", "UPDATE", "DELETE");
2363 : /* Complete "CREATE POLICY <name> ON <table> FOR INSERT TO|WITH CHECK" */
2364 0 : else if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "INSERT"))
2365 0 : COMPLETE_WITH_LIST2("TO", "WITH CHECK (");
2366 : /* Complete "CREATE POLICY <name> ON <table> FOR SELECT|DELETE TO|USING" */
2367 0 : else if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "SELECT|DELETE"))
2368 0 : COMPLETE_WITH_LIST2("TO", "USING (");
2369 : /* CREATE POLICY <name> ON <table> FOR ALL|UPDATE TO|USING|WITH CHECK */
2370 0 : else if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "ALL|UPDATE"))
2371 0 : COMPLETE_WITH_LIST3("TO", "USING (", "WITH CHECK (");
2372 : /* Complete "CREATE POLICY <name> ON <table> TO <role>" */
2373 0 : else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "TO"))
2374 0 : COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2375 : /* Complete "CREATE POLICY <name> ON <table> USING (" */
2376 0 : else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "USING"))
2377 0 : COMPLETE_WITH_CONST("(");
2378 :
2379 : /*
2380 : * CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE FOR
2381 : * ALL|SELECT|INSERT|UPDATE|DELETE
2382 : */
2383 0 : else if (Matches8("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "FOR"))
2384 0 : COMPLETE_WITH_LIST5("ALL", "SELECT", "INSERT", "UPDATE", "DELETE");
2385 :
2386 : /*
2387 : * Complete "CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE FOR
2388 : * INSERT TO|WITH CHECK"
2389 : */
2390 0 : else if (Matches9("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "FOR", "INSERT"))
2391 0 : COMPLETE_WITH_LIST2("TO", "WITH CHECK (");
2392 :
2393 : /*
2394 : * Complete "CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE FOR
2395 : * SELECT|DELETE TO|USING"
2396 : */
2397 0 : else if (Matches9("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "FOR", "SELECT|DELETE"))
2398 0 : COMPLETE_WITH_LIST2("TO", "USING (");
2399 :
2400 : /*
2401 : * CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE FOR
2402 : * ALL|UPDATE TO|USING|WITH CHECK
2403 : */
2404 0 : else if (Matches9("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "FOR", "ALL|UPDATE"))
2405 0 : COMPLETE_WITH_LIST3("TO", "USING (", "WITH CHECK (");
2406 :
2407 : /*
2408 : * Complete "CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE TO
2409 : * <role>"
2410 : */
2411 0 : else if (Matches8("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "TO"))
2412 0 : COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2413 :
2414 : /*
2415 : * Complete "CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE
2416 : * USING ("
2417 : */
2418 0 : else if (Matches8("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "USING"))
2419 0 : COMPLETE_WITH_CONST("(");
2420 :
2421 :
2422 : /* CREATE PUBLICATION */
2423 0 : else if (Matches3("CREATE", "PUBLICATION", MatchAny))
2424 0 : COMPLETE_WITH_LIST3("FOR TABLE", "FOR ALL TABLES", "WITH (");
2425 0 : else if (Matches4("CREATE", "PUBLICATION", MatchAny, "FOR"))
2426 0 : COMPLETE_WITH_LIST2("TABLE", "ALL TABLES");
2427 : /* Complete "CREATE PUBLICATION <name> FOR TABLE <table>" */
2428 0 : else if (Matches4("CREATE", "PUBLICATION", MatchAny, "FOR TABLE"))
2429 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2430 : /* Complete "CREATE PUBLICATION <name> [...] WITH" */
2431 0 : else if (HeadMatches2("CREATE", "PUBLICATION") && TailMatches2("WITH", "("))
2432 0 : COMPLETE_WITH_CONST("publish");
2433 :
2434 : /* CREATE RULE */
2435 : /* Complete "CREATE RULE <sth>" with "AS ON" */
2436 0 : else if (Matches3("CREATE", "RULE", MatchAny))
2437 0 : COMPLETE_WITH_CONST("AS ON");
2438 : /* Complete "CREATE RULE <sth> AS" with "ON" */
2439 0 : else if (Matches4("CREATE", "RULE", MatchAny, "AS"))
2440 0 : COMPLETE_WITH_CONST("ON");
2441 : /* Complete "CREATE RULE <sth> AS ON" with SELECT|UPDATE|INSERT|DELETE */
2442 0 : else if (Matches5("CREATE", "RULE", MatchAny, "AS", "ON"))
2443 0 : COMPLETE_WITH_LIST4("SELECT", "UPDATE", "INSERT", "DELETE");
2444 : /* Complete "AS ON SELECT|UPDATE|INSERT|DELETE" with a "TO" */
2445 0 : else if (TailMatches3("AS", "ON", "SELECT|UPDATE|INSERT|DELETE"))
2446 0 : COMPLETE_WITH_CONST("TO");
2447 : /* Complete "AS ON <sth> TO" with a table name */
2448 0 : else if (TailMatches4("AS", "ON", "SELECT|UPDATE|INSERT|DELETE", "TO"))
2449 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2450 :
2451 : /* CREATE SEQUENCE --- is allowed inside CREATE SCHEMA, so use TailMatches */
2452 0 : else if (TailMatches3("CREATE", "SEQUENCE", MatchAny) ||
2453 0 : TailMatches4("CREATE", "TEMP|TEMPORARY", "SEQUENCE", MatchAny))
2454 0 : COMPLETE_WITH_LIST8("INCREMENT BY", "MINVALUE", "MAXVALUE", "NO", "CACHE",
2455 : "CYCLE", "OWNED BY", "START WITH");
2456 0 : else if (TailMatches4("CREATE", "SEQUENCE", MatchAny, "NO") ||
2457 0 : TailMatches5("CREATE", "TEMP|TEMPORARY", "SEQUENCE", MatchAny, "NO"))
2458 0 : COMPLETE_WITH_LIST3("MINVALUE", "MAXVALUE", "CYCLE");
2459 :
2460 : /* CREATE SERVER <name> */
2461 0 : else if (Matches3("CREATE", "SERVER", MatchAny))
2462 0 : COMPLETE_WITH_LIST3("TYPE", "VERSION", "FOREIGN DATA WRAPPER");
2463 :
2464 : /* CREATE STATISTICS <name> */
2465 0 : else if (Matches3("CREATE", "STATISTICS", MatchAny))
2466 0 : COMPLETE_WITH_LIST2("(", "ON");
2467 0 : else if (Matches4("CREATE", "STATISTICS", MatchAny, "("))
2468 0 : COMPLETE_WITH_LIST2("ndistinct", "dependencies");
2469 0 : else if (HeadMatches3("CREATE", "STATISTICS", MatchAny) &&
2470 0 : previous_words[0][0] == '(' &&
2471 0 : previous_words[0][strlen(previous_words[0]) - 1] == ')')
2472 0 : COMPLETE_WITH_CONST("ON");
2473 0 : else if (HeadMatches3("CREATE", "STATISTICS", MatchAny) &&
2474 0 : TailMatches1("FROM"))
2475 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2476 :
2477 : /* CREATE TABLE --- is allowed inside CREATE SCHEMA, so use TailMatches */
2478 : /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
2479 0 : else if (TailMatches2("CREATE", "TEMP|TEMPORARY"))
2480 0 : COMPLETE_WITH_LIST3("SEQUENCE", "TABLE", "VIEW");
2481 : /* Complete "CREATE UNLOGGED" with TABLE or MATVIEW */
2482 0 : else if (TailMatches2("CREATE", "UNLOGGED"))
2483 0 : COMPLETE_WITH_LIST2("TABLE", "MATERIALIZED VIEW");
2484 : /* Complete PARTITION BY with RANGE ( or LIST ( or ... */
2485 0 : else if (TailMatches2("PARTITION", "BY"))
2486 0 : COMPLETE_WITH_LIST2("RANGE (", "LIST (");
2487 : /* If we have xxx PARTITION OF, provide a list of partitioned tables */
2488 0 : else if (TailMatches2("PARTITION", "OF"))
2489 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_partitioned_tables, "");
2490 : /* Limited completion support for partition bound specification */
2491 0 : else if (TailMatches3("PARTITION", "OF", MatchAny))
2492 0 : COMPLETE_WITH_CONST("FOR VALUES");
2493 :
2494 : /* CREATE TABLESPACE */
2495 0 : else if (Matches3("CREATE", "TABLESPACE", MatchAny))
2496 0 : COMPLETE_WITH_LIST2("OWNER", "LOCATION");
2497 : /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */
2498 0 : else if (Matches5("CREATE", "TABLESPACE", MatchAny, "OWNER", MatchAny))
2499 0 : COMPLETE_WITH_CONST("LOCATION");
2500 :
2501 : /* CREATE TEXT SEARCH */
2502 0 : else if (Matches3("CREATE", "TEXT", "SEARCH"))
2503 0 : COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
2504 0 : else if (Matches5("CREATE", "TEXT", "SEARCH", "CONFIGURATION", MatchAny))
2505 0 : COMPLETE_WITH_CONST("(");
2506 :
2507 : /* CREATE SUBSCRIPTION */
2508 0 : else if (Matches3("CREATE", "SUBSCRIPTION", MatchAny))
2509 0 : COMPLETE_WITH_CONST("CONNECTION");
2510 0 : else if (Matches5("CREATE", "SUBSCRIPTION", MatchAny, "CONNECTION", MatchAny))
2511 0 : COMPLETE_WITH_CONST("PUBLICATION");
2512 0 : else if (Matches6("CREATE", "SUBSCRIPTION", MatchAny, "CONNECTION",
2513 : MatchAny, "PUBLICATION"))
2514 : {
2515 : /* complete with nothing here as this refers to remote publications */
2516 : }
2517 0 : else if (HeadMatches2("CREATE", "SUBSCRIPTION") && TailMatches2("PUBLICATION", MatchAny))
2518 0 : COMPLETE_WITH_CONST("WITH (");
2519 : /* Complete "CREATE SUBSCRIPTION <name> ... WITH ( <opt>" */
2520 0 : else if (HeadMatches2("CREATE", "SUBSCRIPTION") && TailMatches2("WITH", "("))
2521 0 : COMPLETE_WITH_LIST6("copy_data", "connect", "create_slot", "enabled",
2522 : "slot_name", "synchronous_commit");
2523 :
2524 : /* CREATE TRIGGER --- is allowed inside CREATE SCHEMA, so use TailMatches */
2525 : /* complete CREATE TRIGGER <name> with BEFORE,AFTER,INSTEAD OF */
2526 0 : else if (TailMatches3("CREATE", "TRIGGER", MatchAny))
2527 0 : COMPLETE_WITH_LIST3("BEFORE", "AFTER", "INSTEAD OF");
2528 : /* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
2529 0 : else if (TailMatches4("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER"))
2530 0 : COMPLETE_WITH_LIST4("INSERT", "DELETE", "UPDATE", "TRUNCATE");
2531 : /* complete CREATE TRIGGER <name> INSTEAD OF with an event */
2532 0 : else if (TailMatches5("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF"))
2533 0 : COMPLETE_WITH_LIST3("INSERT", "DELETE", "UPDATE");
2534 : /* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
2535 0 : else if (TailMatches5("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny) ||
2536 0 : TailMatches6("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF", MatchAny))
2537 0 : COMPLETE_WITH_LIST2("ON", "OR");
2538 :
2539 : /*
2540 : * complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of
2541 : * tables
2542 : */
2543 0 : else if (TailMatches6("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny, "ON"))
2544 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
2545 : /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
2546 0 : else if (TailMatches7("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF", MatchAny, "ON"))
2547 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
2548 0 : else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("ON", MatchAny))
2549 0 : COMPLETE_WITH_LIST7("NOT DEFERRABLE", "DEFERRABLE", "INITIALLY",
2550 : "REFERENCING", "FOR", "WHEN (", "EXECUTE PROCEDURE");
2551 0 : else if (HeadMatches2("CREATE", "TRIGGER") &&
2552 0 : (TailMatches1("DEFERRABLE") || TailMatches2("INITIALLY", "IMMEDIATE|DEFERRED")))
2553 0 : COMPLETE_WITH_LIST4("REFERENCING", "FOR", "WHEN (", "EXECUTE PROCEDURE");
2554 0 : else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("REFERENCING"))
2555 0 : COMPLETE_WITH_LIST2("OLD TABLE", "NEW TABLE");
2556 0 : else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("OLD|NEW", "TABLE"))
2557 0 : COMPLETE_WITH_CONST("AS");
2558 0 : else if (HeadMatches2("CREATE", "TRIGGER") &&
2559 0 : (TailMatches5("REFERENCING", "OLD", "TABLE", "AS", MatchAny) ||
2560 0 : TailMatches4("REFERENCING", "OLD", "TABLE", MatchAny)))
2561 0 : COMPLETE_WITH_LIST4("NEW TABLE", "FOR", "WHEN (", "EXECUTE PROCEDURE");
2562 0 : else if (HeadMatches2("CREATE", "TRIGGER") &&
2563 0 : (TailMatches5("REFERENCING", "NEW", "TABLE", "AS", MatchAny) ||
2564 0 : TailMatches4("REFERENCING", "NEW", "TABLE", MatchAny)))
2565 0 : COMPLETE_WITH_LIST4("OLD TABLE", "FOR", "WHEN (", "EXECUTE PROCEDURE");
2566 0 : else if (HeadMatches2("CREATE", "TRIGGER") &&
2567 0 : (TailMatches9("REFERENCING", "OLD|NEW", "TABLE", "AS", MatchAny, "OLD|NEW", "TABLE", "AS", MatchAny) ||
2568 0 : TailMatches8("REFERENCING", "OLD|NEW", "TABLE", MatchAny, "OLD|NEW", "TABLE", "AS", MatchAny) ||
2569 0 : TailMatches8("REFERENCING", "OLD|NEW", "TABLE", "AS", MatchAny, "OLD|NEW", "TABLE", MatchAny) ||
2570 0 : TailMatches7("REFERENCING", "OLD|NEW", "TABLE", MatchAny, "OLD|NEW", "TABLE", MatchAny)))
2571 0 : COMPLETE_WITH_LIST3("FOR", "WHEN (", "EXECUTE PROCEDURE");
2572 0 : else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("FOR"))
2573 0 : COMPLETE_WITH_LIST3("EACH", "ROW", "STATEMENT");
2574 0 : else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("FOR", "EACH"))
2575 0 : COMPLETE_WITH_LIST2("ROW", "STATEMENT");
2576 0 : else if (HeadMatches2("CREATE", "TRIGGER") &&
2577 0 : (TailMatches3("FOR", "EACH", "ROW|STATEMENT") ||
2578 0 : TailMatches2("FOR", "ROW|STATEMENT")))
2579 0 : COMPLETE_WITH_LIST2("WHEN (", "EXECUTE PROCEDURE");
2580 : /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
2581 0 : else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("EXECUTE"))
2582 0 : COMPLETE_WITH_CONST("PROCEDURE");
2583 0 : else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("EXECUTE", "PROCEDURE"))
2584 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2585 :
2586 : /* CREATE ROLE,USER,GROUP <name> */
2587 0 : else if (Matches3("CREATE", "ROLE|GROUP|USER", MatchAny) &&
2588 0 : !TailMatches2("USER", "MAPPING"))
2589 0 : {
2590 : static const char *const list_CREATEROLE[] =
2591 : {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
2592 : "ENCRYPTED PASSWORD", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
2593 : "NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
2594 : "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
2595 : "REPLICATION", "ROLE", "SUPERUSER", "SYSID",
2596 : "VALID UNTIL", "WITH", NULL};
2597 :
2598 0 : COMPLETE_WITH_LIST(list_CREATEROLE);
2599 : }
2600 :
2601 : /* CREATE ROLE,USER,GROUP <name> WITH */
2602 0 : else if (Matches4("CREATE", "ROLE|GROUP|USER", MatchAny, "WITH"))
2603 0 : {
2604 : /* Similar to the above, but don't complete "WITH" again. */
2605 : static const char *const list_CREATEROLE_WITH[] =
2606 : {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
2607 : "ENCRYPTED PASSWORD", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
2608 : "NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
2609 : "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
2610 : "REPLICATION", "ROLE", "SUPERUSER", "SYSID",
2611 : "VALID UNTIL", NULL};
2612 :
2613 0 : COMPLETE_WITH_LIST(list_CREATEROLE_WITH);
2614 : }
2615 :
2616 : /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
2617 0 : else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "IN"))
2618 0 : COMPLETE_WITH_LIST2("GROUP", "ROLE");
2619 :
2620 : /* CREATE VIEW --- is allowed inside CREATE SCHEMA, so use TailMatches */
2621 : /* Complete CREATE VIEW <name> with AS */
2622 0 : else if (TailMatches3("CREATE", "VIEW", MatchAny))
2623 0 : COMPLETE_WITH_CONST("AS");
2624 : /* Complete "CREATE VIEW <sth> AS with "SELECT" */
2625 0 : else if (TailMatches4("CREATE", "VIEW", MatchAny, "AS"))
2626 0 : COMPLETE_WITH_CONST("SELECT");
2627 :
2628 : /* CREATE MATERIALIZED VIEW */
2629 0 : else if (Matches2("CREATE", "MATERIALIZED"))
2630 0 : COMPLETE_WITH_CONST("VIEW");
2631 : /* Complete CREATE MATERIALIZED VIEW <name> with AS */
2632 0 : else if (Matches4("CREATE", "MATERIALIZED", "VIEW", MatchAny))
2633 0 : COMPLETE_WITH_CONST("AS");
2634 : /* Complete "CREATE MATERIALIZED VIEW <sth> AS with "SELECT" */
2635 0 : else if (Matches5("CREATE", "MATERIALIZED", "VIEW", MatchAny, "AS"))
2636 0 : COMPLETE_WITH_CONST("SELECT");
2637 :
2638 : /* CREATE EVENT TRIGGER */
2639 0 : else if (Matches2("CREATE", "EVENT"))
2640 0 : COMPLETE_WITH_CONST("TRIGGER");
2641 : /* Complete CREATE EVENT TRIGGER <name> with ON */
2642 0 : else if (Matches4("CREATE", "EVENT", "TRIGGER", MatchAny))
2643 0 : COMPLETE_WITH_CONST("ON");
2644 : /* Complete CREATE EVENT TRIGGER <name> ON with event_type */
2645 0 : else if (Matches5("CREATE", "EVENT", "TRIGGER", MatchAny, "ON"))
2646 0 : COMPLETE_WITH_LIST3("ddl_command_start", "ddl_command_end", "sql_drop");
2647 :
2648 : /* DEALLOCATE */
2649 0 : else if (Matches1("DEALLOCATE"))
2650 0 : COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
2651 :
2652 : /* DECLARE */
2653 0 : else if (Matches2("DECLARE", MatchAny))
2654 0 : COMPLETE_WITH_LIST5("BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL",
2655 : "CURSOR");
2656 0 : else if (HeadMatches1("DECLARE") && TailMatches1("CURSOR"))
2657 0 : COMPLETE_WITH_LIST3("WITH HOLD", "WITHOUT HOLD", "FOR");
2658 :
2659 : /* DELETE --- can be inside EXPLAIN, RULE, etc */
2660 : /* ... despite which, only complete DELETE with FROM at start of line */
2661 0 : else if (Matches1("DELETE"))
2662 0 : COMPLETE_WITH_CONST("FROM");
2663 : /* Complete DELETE FROM with a list of tables */
2664 0 : else if (TailMatches2("DELETE", "FROM"))
2665 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
2666 : /* Complete DELETE FROM <table> */
2667 0 : else if (TailMatches3("DELETE", "FROM", MatchAny))
2668 0 : COMPLETE_WITH_LIST2("USING", "WHERE");
2669 : /* XXX: implement tab completion for DELETE ... USING */
2670 :
2671 : /* DISCARD */
2672 0 : else if (Matches1("DISCARD"))
2673 0 : COMPLETE_WITH_LIST4("ALL", "PLANS", "SEQUENCES", "TEMP");
2674 :
2675 : /* DO */
2676 0 : else if (Matches1("DO"))
2677 0 : COMPLETE_WITH_CONST("LANGUAGE");
2678 :
2679 : /* DROP */
2680 : /* Complete DROP object with CASCADE / RESTRICT */
2681 0 : else if (Matches3("DROP",
2682 : "COLLATION|CONVERSION|DOMAIN|EXTENSION|LANGUAGE|PUBLICATION|SCHEMA|SEQUENCE|SERVER|SUBSCRIPTION|STATISTICS|TABLE|TYPE|VIEW",
2683 0 : MatchAny) ||
2684 0 : Matches4("DROP", "ACCESS", "METHOD", MatchAny) ||
2685 0 : (Matches4("DROP", "AGGREGATE|FUNCTION", MatchAny, MatchAny) &&
2686 0 : ends_with(prev_wd, ')')) ||
2687 0 : Matches4("DROP", "EVENT", "TRIGGER", MatchAny) ||
2688 0 : Matches5("DROP", "FOREIGN", "DATA", "WRAPPER", MatchAny) ||
2689 0 : Matches4("DROP", "FOREIGN", "TABLE", MatchAny) ||
2690 0 : Matches5("DROP", "TEXT", "SEARCH", "CONFIGURATION|DICTIONARY|PARSER|TEMPLATE", MatchAny))
2691 0 : COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
2692 :
2693 : /* help completing some of the variants */
2694 0 : else if (Matches3("DROP", "AGGREGATE|FUNCTION", MatchAny))
2695 0 : COMPLETE_WITH_CONST("(");
2696 0 : else if (Matches4("DROP", "AGGREGATE|FUNCTION", MatchAny, "("))
2697 0 : COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
2698 0 : else if (Matches2("DROP", "FOREIGN"))
2699 0 : COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
2700 :
2701 : /* DROP INDEX */
2702 0 : else if (Matches2("DROP", "INDEX"))
2703 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
2704 : " UNION SELECT 'CONCURRENTLY'");
2705 0 : else if (Matches3("DROP", "INDEX", "CONCURRENTLY"))
2706 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
2707 0 : else if (Matches3("DROP", "INDEX", MatchAny))
2708 0 : COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
2709 0 : else if (Matches4("DROP", "INDEX", "CONCURRENTLY", MatchAny))
2710 0 : COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
2711 :
2712 : /* DROP MATERIALIZED VIEW */
2713 0 : else if (Matches2("DROP", "MATERIALIZED"))
2714 0 : COMPLETE_WITH_CONST("VIEW");
2715 0 : else if (Matches3("DROP", "MATERIALIZED", "VIEW"))
2716 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
2717 :
2718 : /* DROP OWNED BY */
2719 0 : else if (Matches2("DROP", "OWNED"))
2720 0 : COMPLETE_WITH_CONST("BY");
2721 0 : else if (Matches3("DROP", "OWNED", "BY"))
2722 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
2723 :
2724 : /* DROP TEXT SEARCH */
2725 0 : else if (Matches3("DROP", "TEXT", "SEARCH"))
2726 0 : COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
2727 :
2728 : /* DROP TRIGGER */
2729 0 : else if (Matches3("DROP", "TRIGGER", MatchAny))
2730 0 : COMPLETE_WITH_CONST("ON");
2731 0 : else if (Matches4("DROP", "TRIGGER", MatchAny, "ON"))
2732 : {
2733 0 : completion_info_charp = prev2_wd;
2734 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
2735 : }
2736 0 : else if (Matches5("DROP", "TRIGGER", MatchAny, "ON", MatchAny))
2737 0 : COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
2738 :
2739 : /* DROP ACCESS METHOD */
2740 0 : else if (Matches2("DROP", "ACCESS"))
2741 0 : COMPLETE_WITH_CONST("METHOD");
2742 0 : else if (Matches3("DROP", "ACCESS", "METHOD"))
2743 0 : COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
2744 :
2745 : /* DROP EVENT TRIGGER */
2746 0 : else if (Matches2("DROP", "EVENT"))
2747 0 : COMPLETE_WITH_CONST("TRIGGER");
2748 0 : else if (Matches3("DROP", "EVENT", "TRIGGER"))
2749 0 : COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
2750 :
2751 : /* DROP POLICY <name> */
2752 0 : else if (Matches2("DROP", "POLICY"))
2753 0 : COMPLETE_WITH_QUERY(Query_for_list_of_policies);
2754 : /* DROP POLICY <name> ON */
2755 0 : else if (Matches3("DROP", "POLICY", MatchAny))
2756 0 : COMPLETE_WITH_CONST("ON");
2757 : /* DROP POLICY <name> ON <table> */
2758 0 : else if (Matches4("DROP", "POLICY", MatchAny, "ON"))
2759 : {
2760 0 : completion_info_charp = prev2_wd;
2761 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy);
2762 : }
2763 :
2764 : /* DROP RULE */
2765 0 : else if (Matches3("DROP", "RULE", MatchAny))
2766 0 : COMPLETE_WITH_CONST("ON");
2767 0 : else if (Matches4("DROP", "RULE", MatchAny, "ON"))
2768 : {
2769 0 : completion_info_charp = prev2_wd;
2770 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
2771 : }
2772 0 : else if (Matches5("DROP", "RULE", MatchAny, "ON", MatchAny))
2773 0 : COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
2774 :
2775 : /* EXECUTE */
2776 0 : else if (Matches1("EXECUTE"))
2777 0 : COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
2778 :
2779 : /* EXPLAIN */
2780 :
2781 : /*
2782 : * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2783 : */
2784 0 : else if (Matches1("EXPLAIN"))
2785 0 : COMPLETE_WITH_LIST7("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE",
2786 : "ANALYZE", "VERBOSE");
2787 0 : else if (Matches2("EXPLAIN", "ANALYZE"))
2788 0 : COMPLETE_WITH_LIST6("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE",
2789 : "VERBOSE");
2790 0 : else if (Matches2("EXPLAIN", "VERBOSE") ||
2791 0 : Matches3("EXPLAIN", "ANALYZE", "VERBOSE"))
2792 0 : COMPLETE_WITH_LIST5("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE");
2793 :
2794 : /* FETCH && MOVE */
2795 : /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
2796 0 : else if (Matches1("FETCH|MOVE"))
2797 0 : COMPLETE_WITH_LIST4("ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE");
2798 : /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
2799 0 : else if (Matches2("FETCH|MOVE", MatchAny))
2800 0 : COMPLETE_WITH_LIST3("ALL", "NEXT", "PRIOR");
2801 :
2802 : /*
2803 : * Complete FETCH <sth1> <sth2> with "FROM" or "IN". These are equivalent,
2804 : * but we may as well tab-complete both: perhaps some users prefer one
2805 : * variant or the other.
2806 : */
2807 0 : else if (Matches3("FETCH|MOVE", MatchAny, MatchAny))
2808 0 : COMPLETE_WITH_LIST2("FROM", "IN");
2809 :
2810 : /* FOREIGN DATA WRAPPER */
2811 : /* applies in ALTER/DROP FDW and in CREATE SERVER */
2812 0 : else if (TailMatches3("FOREIGN", "DATA", "WRAPPER") &&
2813 0 : !TailMatches4("CREATE", MatchAny, MatchAny, MatchAny))
2814 0 : COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
2815 : /* applies in CREATE SERVER */
2816 0 : else if (TailMatches4("FOREIGN", "DATA", "WRAPPER", MatchAny) &&
2817 0 : HeadMatches2("CREATE", "SERVER"))
2818 0 : COMPLETE_WITH_CONST("OPTIONS");
2819 :
2820 : /* FOREIGN TABLE */
2821 0 : else if (TailMatches2("FOREIGN", "TABLE") &&
2822 0 : !TailMatches3("CREATE", MatchAny, MatchAny))
2823 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
2824 :
2825 : /* FOREIGN SERVER */
2826 0 : else if (TailMatches2("FOREIGN", "SERVER"))
2827 0 : COMPLETE_WITH_QUERY(Query_for_list_of_servers);
2828 :
2829 : /*
2830 : * GRANT and REVOKE are allowed inside CREATE SCHEMA and
2831 : * ALTER DEFAULT PRIVILEGES, so use TailMatches
2832 : */
2833 : /* Complete GRANT/REVOKE with a list of roles and privileges */
2834 0 : else if (TailMatches1("GRANT|REVOKE"))
2835 : {
2836 : /*
2837 : * With ALTER DEFAULT PRIVILEGES, restrict completion to grantable
2838 : * privileges (can't grant roles)
2839 : */
2840 0 : if (HeadMatches3("ALTER", "DEFAULT", "PRIVILEGES"))
2841 0 : COMPLETE_WITH_LIST10("SELECT", "INSERT", "UPDATE",
2842 : "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER",
2843 : "EXECUTE", "USAGE", "ALL");
2844 : else
2845 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles
2846 : " UNION SELECT 'SELECT'"
2847 : " UNION SELECT 'INSERT'"
2848 : " UNION SELECT 'UPDATE'"
2849 : " UNION SELECT 'DELETE'"
2850 : " UNION SELECT 'TRUNCATE'"
2851 : " UNION SELECT 'REFERENCES'"
2852 : " UNION SELECT 'TRIGGER'"
2853 : " UNION SELECT 'CREATE'"
2854 : " UNION SELECT 'CONNECT'"
2855 : " UNION SELECT 'TEMPORARY'"
2856 : " UNION SELECT 'EXECUTE'"
2857 : " UNION SELECT 'USAGE'"
2858 : " UNION SELECT 'ALL'");
2859 : }
2860 :
2861 : /*
2862 : * Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
2863 : * TO/FROM
2864 : */
2865 0 : else if (TailMatches2("GRANT|REVOKE", MatchAny))
2866 : {
2867 0 : if (TailMatches1("SELECT|INSERT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER|CREATE|CONNECT|TEMPORARY|TEMP|EXECUTE|USAGE|ALL"))
2868 0 : COMPLETE_WITH_CONST("ON");
2869 0 : else if (TailMatches2("GRANT", MatchAny))
2870 0 : COMPLETE_WITH_CONST("TO");
2871 : else
2872 0 : COMPLETE_WITH_CONST("FROM");
2873 : }
2874 :
2875 : /*
2876 : * Complete GRANT/REVOKE <sth> ON with a list of tables, views, and
2877 : * sequences.
2878 : *
2879 : * Keywords like DATABASE, FUNCTION, LANGUAGE and SCHEMA added to query
2880 : * result via UNION; seems to work intuitively.
2881 : *
2882 : * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
2883 : * here will only work if the privilege list contains exactly one
2884 : * privilege.
2885 : */
2886 0 : else if (TailMatches3("GRANT|REVOKE", MatchAny, "ON"))
2887 : {
2888 : /*
2889 : * With ALTER DEFAULT PRIVILEGES, restrict completion to the kinds of
2890 : * objects supported.
2891 : */
2892 0 : if (HeadMatches3("ALTER", "DEFAULT", "PRIVILEGES"))
2893 0 : COMPLETE_WITH_LIST5("TABLES", "SEQUENCES", "FUNCTIONS", "TYPES", "SCHEMAS");
2894 : else
2895 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
2896 : " UNION SELECT 'ALL FUNCTIONS IN SCHEMA'"
2897 : " UNION SELECT 'ALL SEQUENCES IN SCHEMA'"
2898 : " UNION SELECT 'ALL TABLES IN SCHEMA'"
2899 : " UNION SELECT 'DATABASE'"
2900 : " UNION SELECT 'DOMAIN'"
2901 : " UNION SELECT 'FOREIGN DATA WRAPPER'"
2902 : " UNION SELECT 'FOREIGN SERVER'"
2903 : " UNION SELECT 'FUNCTION'"
2904 : " UNION SELECT 'LANGUAGE'"
2905 : " UNION SELECT 'LARGE OBJECT'"
2906 : " UNION SELECT 'SCHEMA'"
2907 : " UNION SELECT 'SEQUENCE'"
2908 : " UNION SELECT 'TABLE'"
2909 : " UNION SELECT 'TABLESPACE'"
2910 : " UNION SELECT 'TYPE'");
2911 : }
2912 0 : else if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", "ALL"))
2913 0 : COMPLETE_WITH_LIST3("FUNCTIONS IN SCHEMA", "SEQUENCES IN SCHEMA",
2914 : "TABLES IN SCHEMA");
2915 0 : else if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", "FOREIGN"))
2916 0 : COMPLETE_WITH_LIST2("DATA WRAPPER", "SERVER");
2917 :
2918 : /*
2919 : * Complete "GRANT/REVOKE * ON DATABASE/DOMAIN/..." with a list of
2920 : * appropriate objects.
2921 : *
2922 : * Complete "GRANT/REVOKE * ON *" with "TO/FROM".
2923 : */
2924 0 : else if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", MatchAny))
2925 : {
2926 0 : if (TailMatches1("DATABASE"))
2927 0 : COMPLETE_WITH_QUERY(Query_for_list_of_databases);
2928 0 : else if (TailMatches1("DOMAIN"))
2929 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
2930 0 : else if (TailMatches1("FUNCTION"))
2931 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
2932 0 : else if (TailMatches1("LANGUAGE"))
2933 0 : COMPLETE_WITH_QUERY(Query_for_list_of_languages);
2934 0 : else if (TailMatches1("SCHEMA"))
2935 0 : COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
2936 0 : else if (TailMatches1("SEQUENCE"))
2937 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
2938 0 : else if (TailMatches1("TABLE"))
2939 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
2940 0 : else if (TailMatches1("TABLESPACE"))
2941 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
2942 0 : else if (TailMatches1("TYPE"))
2943 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
2944 0 : else if (TailMatches4("GRANT", MatchAny, MatchAny, MatchAny))
2945 0 : COMPLETE_WITH_CONST("TO");
2946 : else
2947 0 : COMPLETE_WITH_CONST("FROM");
2948 : }
2949 :
2950 : /*
2951 : * Complete "GRANT/REVOKE ... TO/FROM" with username, PUBLIC,
2952 : * CURRENT_USER, or SESSION_USER.
2953 : */
2954 0 : else if ((HeadMatches1("GRANT") && TailMatches1("TO")) ||
2955 0 : (HeadMatches1("REVOKE") && TailMatches1("FROM")))
2956 0 : COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2957 : /* Complete "ALTER DEFAULT PRIVILEGES ... GRANT/REVOKE ... TO/FROM */
2958 0 : else if (HeadMatches3("ALTER", "DEFAULT", "PRIVILEGES") && TailMatches1("TO|FROM"))
2959 0 : COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
2960 : /* Complete "GRANT/REVOKE ... ON * *" with TO/FROM */
2961 0 : else if (HeadMatches1("GRANT") && TailMatches3("ON", MatchAny, MatchAny))
2962 0 : COMPLETE_WITH_CONST("TO");
2963 0 : else if (HeadMatches1("REVOKE") && TailMatches3("ON", MatchAny, MatchAny))
2964 0 : COMPLETE_WITH_CONST("FROM");
2965 :
2966 : /* Complete "GRANT/REVOKE * ON ALL * IN SCHEMA *" with TO/FROM */
2967 0 : else if (TailMatches8("GRANT|REVOKE", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny))
2968 : {
2969 0 : if (TailMatches8("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny))
2970 0 : COMPLETE_WITH_CONST("TO");
2971 : else
2972 0 : COMPLETE_WITH_CONST("FROM");
2973 : }
2974 :
2975 : /* Complete "GRANT/REVOKE * ON FOREIGN DATA WRAPPER *" with TO/FROM */
2976 0 : else if (TailMatches7("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny))
2977 : {
2978 0 : if (TailMatches7("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny))
2979 0 : COMPLETE_WITH_CONST("TO");
2980 : else
2981 0 : COMPLETE_WITH_CONST("FROM");
2982 : }
2983 :
2984 : /* Complete "GRANT/REVOKE * ON FOREIGN SERVER *" with TO/FROM */
2985 0 : else if (TailMatches6("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny))
2986 : {
2987 0 : if (TailMatches6("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny))
2988 0 : COMPLETE_WITH_CONST("TO");
2989 : else
2990 0 : COMPLETE_WITH_CONST("FROM");
2991 : }
2992 :
2993 : /* GROUP BY */
2994 0 : else if (TailMatches3("FROM", MatchAny, "GROUP"))
2995 0 : COMPLETE_WITH_CONST("BY");
2996 :
2997 : /* IMPORT FOREIGN SCHEMA */
2998 0 : else if (Matches1("IMPORT"))
2999 0 : COMPLETE_WITH_CONST("FOREIGN SCHEMA");
3000 0 : else if (Matches2("IMPORT", "FOREIGN"))
3001 0 : COMPLETE_WITH_CONST("SCHEMA");
3002 :
3003 : /* INSERT --- can be inside EXPLAIN, RULE, etc */
3004 : /* Complete INSERT with "INTO" */
3005 0 : else if (TailMatches1("INSERT"))
3006 0 : COMPLETE_WITH_CONST("INTO");
3007 : /* Complete INSERT INTO with table names */
3008 0 : else if (TailMatches2("INSERT", "INTO"))
3009 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
3010 : /* Complete "INSERT INTO <table> (" with attribute names */
3011 0 : else if (TailMatches4("INSERT", "INTO", MatchAny, "("))
3012 0 : COMPLETE_WITH_ATTR(prev2_wd, "");
3013 :
3014 : /*
3015 : * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
3016 : * "TABLE" or "DEFAULT VALUES" or "OVERRIDING"
3017 : */
3018 0 : else if (TailMatches3("INSERT", "INTO", MatchAny))
3019 0 : COMPLETE_WITH_LIST6("(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES", "OVERRIDING");
3020 :
3021 : /*
3022 : * Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" or
3023 : * "TABLE" or "OVERRIDING"
3024 : */
3025 0 : else if (TailMatches4("INSERT", "INTO", MatchAny, MatchAny) &&
3026 0 : ends_with(prev_wd, ')'))
3027 0 : COMPLETE_WITH_LIST4("SELECT", "TABLE", "VALUES", "OVERRIDING");
3028 :
3029 : /* Complete OVERRIDING */
3030 0 : else if (TailMatches1("OVERRIDING"))
3031 0 : COMPLETE_WITH_LIST2("SYSTEM VALUE", "USER VALUE");
3032 :
3033 : /* Complete after OVERRIDING clause */
3034 0 : else if (TailMatches3("OVERRIDING", MatchAny, "VALUE"))
3035 0 : COMPLETE_WITH_LIST3("SELECT", "TABLE", "VALUES");
3036 :
3037 : /* Insert an open parenthesis after "VALUES" */
3038 0 : else if (TailMatches1("VALUES") && !TailMatches2("DEFAULT", "VALUES"))
3039 0 : COMPLETE_WITH_CONST("(");
3040 :
3041 : /* LOCK */
3042 : /* Complete LOCK [TABLE] with a list of tables */
3043 0 : else if (Matches1("LOCK"))
3044 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
3045 : " UNION SELECT 'TABLE'");
3046 0 : else if (Matches2("LOCK", "TABLE"))
3047 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
3048 :
3049 : /* For the following, handle the case of a single table only for now */
3050 :
3051 : /* Complete LOCK [TABLE] <table> with "IN" */
3052 0 : else if (Matches2("LOCK", MatchAnyExcept("TABLE")) ||
3053 0 : Matches3("LOCK", "TABLE", MatchAny))
3054 0 : COMPLETE_WITH_CONST("IN");
3055 :
3056 : /* Complete LOCK [TABLE] <table> IN with a lock mode */
3057 0 : else if (Matches3("LOCK", MatchAny, "IN") ||
3058 0 : Matches4("LOCK", "TABLE", MatchAny, "IN"))
3059 0 : COMPLETE_WITH_LIST8("ACCESS SHARE MODE",
3060 : "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
3061 : "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
3062 : "SHARE ROW EXCLUSIVE MODE",
3063 : "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE");
3064 :
3065 : /* Complete LOCK [TABLE] <table> IN ACCESS|ROW with rest of lock mode */
3066 0 : else if (Matches4("LOCK", MatchAny, "IN", "ACCESS|ROW") ||
3067 0 : Matches5("LOCK", "TABLE", MatchAny, "IN", "ACCESS|ROW"))
3068 0 : COMPLETE_WITH_LIST2("EXCLUSIVE MODE", "SHARE MODE");
3069 :
3070 : /* Complete LOCK [TABLE] <table> IN SHARE with rest of lock mode */
3071 0 : else if (Matches4("LOCK", MatchAny, "IN", "SHARE") ||
3072 0 : Matches5("LOCK", "TABLE", MatchAny, "IN", "SHARE"))
3073 0 : COMPLETE_WITH_LIST3("MODE", "ROW EXCLUSIVE MODE",
3074 : "UPDATE EXCLUSIVE MODE");
3075 :
3076 : /* NOTIFY --- can be inside EXPLAIN, RULE, etc */
3077 0 : else if (TailMatches1("NOTIFY"))
3078 0 : 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'");
3079 :
3080 : /* OPTIONS */
3081 0 : else if (TailMatches1("OPTIONS"))
3082 0 : COMPLETE_WITH_CONST("(");
3083 :
3084 : /* OWNER TO - complete with available roles */
3085 0 : else if (TailMatches2("OWNER", "TO"))
3086 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3087 :
3088 : /* ORDER BY */
3089 0 : else if (TailMatches3("FROM", MatchAny, "ORDER"))
3090 0 : COMPLETE_WITH_CONST("BY");
3091 0 : else if (TailMatches4("FROM", MatchAny, "ORDER", "BY"))
3092 0 : COMPLETE_WITH_ATTR(prev3_wd, "");
3093 :
3094 : /* PREPARE xx AS */
3095 0 : else if (Matches3("PREPARE", MatchAny, "AS"))
3096 0 : COMPLETE_WITH_LIST4("SELECT", "UPDATE", "INSERT", "DELETE FROM");
3097 :
3098 : /*
3099 : * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
3100 : * managers, not for manual use in interactive sessions.
3101 : */
3102 :
3103 : /* REASSIGN OWNED BY xxx TO yyy */
3104 0 : else if (Matches1("REASSIGN"))
3105 0 : COMPLETE_WITH_CONST("OWNED BY");
3106 0 : else if (Matches2("REASSIGN", "OWNED"))
3107 0 : COMPLETE_WITH_CONST("BY");
3108 0 : else if (Matches3("REASSIGN", "OWNED", "BY"))
3109 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3110 0 : else if (Matches4("REASSIGN", "OWNED", "BY", MatchAny))
3111 0 : COMPLETE_WITH_CONST("TO");
3112 0 : else if (Matches5("REASSIGN", "OWNED", "BY", MatchAny, "TO"))
3113 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3114 :
3115 : /* REFRESH MATERIALIZED VIEW */
3116 0 : else if (Matches1("REFRESH"))
3117 0 : COMPLETE_WITH_CONST("MATERIALIZED VIEW");
3118 0 : else if (Matches2("REFRESH", "MATERIALIZED"))
3119 0 : COMPLETE_WITH_CONST("VIEW");
3120 0 : else if (Matches3("REFRESH", "MATERIALIZED", "VIEW"))
3121 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
3122 : " UNION SELECT 'CONCURRENTLY'");
3123 0 : else if (Matches4("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY"))
3124 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
3125 0 : else if (Matches4("REFRESH", "MATERIALIZED", "VIEW", MatchAny))
3126 0 : COMPLETE_WITH_CONST("WITH");
3127 0 : else if (Matches5("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny))
3128 0 : COMPLETE_WITH_CONST("WITH");
3129 0 : else if (Matches5("REFRESH", "MATERIALIZED", "VIEW", MatchAny, "WITH"))
3130 0 : COMPLETE_WITH_LIST2("NO DATA", "DATA");
3131 0 : else if (Matches6("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny, "WITH"))
3132 0 : COMPLETE_WITH_LIST2("NO DATA", "DATA");
3133 0 : else if (Matches6("REFRESH", "MATERIALIZED", "VIEW", MatchAny, "WITH", "NO"))
3134 0 : COMPLETE_WITH_CONST("DATA");
3135 0 : else if (Matches7("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny, "WITH", "NO"))
3136 0 : COMPLETE_WITH_CONST("DATA");
3137 :
3138 : /* REINDEX */
3139 0 : else if (Matches1("REINDEX"))
3140 0 : COMPLETE_WITH_LIST5("TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE");
3141 0 : else if (Matches2("REINDEX", "TABLE"))
3142 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
3143 0 : else if (Matches2("REINDEX", "INDEX"))
3144 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
3145 0 : else if (Matches2("REINDEX", "SCHEMA"))
3146 0 : COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3147 0 : else if (Matches2("REINDEX", "SYSTEM|DATABASE"))
3148 0 : COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3149 :
3150 : /* SECURITY LABEL */
3151 0 : else if (Matches1("SECURITY"))
3152 0 : COMPLETE_WITH_CONST("LABEL");
3153 0 : else if (Matches2("SECURITY", "LABEL"))
3154 0 : COMPLETE_WITH_LIST2("ON", "FOR");
3155 0 : else if (Matches4("SECURITY", "LABEL", "FOR", MatchAny))
3156 0 : COMPLETE_WITH_CONST("ON");
3157 0 : else if (Matches3("SECURITY", "LABEL", "ON") ||
3158 0 : Matches5("SECURITY", "LABEL", "FOR", MatchAny, "ON"))
3159 0 : {
3160 : static const char *const list_SECURITY_LABEL[] =
3161 : {"TABLE", "COLUMN", "AGGREGATE", "DATABASE", "DOMAIN",
3162 : "EVENT TRIGGER", "FOREIGN TABLE", "FUNCTION", "LARGE OBJECT",
3163 : "MATERIALIZED VIEW", "LANGUAGE", "PUBLICATION", "ROLE", "SCHEMA",
3164 : "SEQUENCE", "SUBSCRIPTION", "TABLESPACE", "TYPE", "VIEW", NULL};
3165 :
3166 0 : COMPLETE_WITH_LIST(list_SECURITY_LABEL);
3167 : }
3168 0 : else if (Matches5("SECURITY", "LABEL", "ON", MatchAny, MatchAny))
3169 0 : COMPLETE_WITH_CONST("IS");
3170 :
3171 : /* SELECT */
3172 : /* naah . . . */
3173 :
3174 : /* SET, RESET, SHOW */
3175 : /* Complete with a variable name */
3176 0 : else if (TailMatches1("SET|RESET") && !TailMatches3("UPDATE", MatchAny, "SET"))
3177 0 : COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
3178 0 : else if (Matches1("SHOW"))
3179 0 : COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
3180 : /* Complete "SET TRANSACTION" */
3181 0 : else if (Matches2("SET", "TRANSACTION"))
3182 0 : COMPLETE_WITH_LIST5("SNAPSHOT", "ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE");
3183 0 : else if (Matches2("BEGIN|START", "TRANSACTION") ||
3184 0 : Matches2("BEGIN", "WORK") ||
3185 0 : Matches1("BEGIN") ||
3186 0 : Matches5("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION"))
3187 0 : COMPLETE_WITH_LIST4("ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE");
3188 0 : else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "NOT") ||
3189 0 : Matches2("BEGIN", "NOT") ||
3190 0 : Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "NOT"))
3191 0 : COMPLETE_WITH_CONST("DEFERRABLE");
3192 0 : else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION") ||
3193 0 : Matches2("BEGIN", "ISOLATION") ||
3194 0 : Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION"))
3195 0 : COMPLETE_WITH_CONST("LEVEL");
3196 0 : else if (Matches4("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL") ||
3197 0 : Matches3("BEGIN", "ISOLATION", "LEVEL") ||
3198 0 : Matches7("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL"))
3199 0 : COMPLETE_WITH_LIST3("READ", "REPEATABLE READ", "SERIALIZABLE");
3200 0 : else if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "READ") ||
3201 0 : Matches4("BEGIN", "ISOLATION", "LEVEL", "READ") ||
3202 0 : Matches8("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL", "READ"))
3203 0 : COMPLETE_WITH_LIST2("UNCOMMITTED", "COMMITTED");
3204 0 : else if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "REPEATABLE") ||
3205 0 : Matches4("BEGIN", "ISOLATION", "LEVEL", "REPEATABLE") ||
3206 0 : Matches8("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL", "REPEATABLE"))
3207 0 : COMPLETE_WITH_CONST("READ");
3208 0 : else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "READ") ||
3209 0 : Matches2("BEGIN", "READ") ||
3210 0 : Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "READ"))
3211 0 : COMPLETE_WITH_LIST2("ONLY", "WRITE");
3212 : /* SET CONSTRAINTS */
3213 0 : else if (Matches2("SET", "CONSTRAINTS"))
3214 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, "UNION SELECT 'ALL'");
3215 : /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
3216 0 : else if (Matches3("SET", "CONSTRAINTS", MatchAny))
3217 0 : COMPLETE_WITH_LIST2("DEFERRED", "IMMEDIATE");
3218 : /* Complete SET ROLE */
3219 0 : else if (Matches2("SET", "ROLE"))
3220 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3221 : /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
3222 0 : else if (Matches2("SET", "SESSION"))
3223 0 : COMPLETE_WITH_LIST2("AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION");
3224 : /* Complete SET SESSION AUTHORIZATION with username */
3225 0 : else if (Matches3("SET", "SESSION", "AUTHORIZATION"))
3226 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
3227 : /* Complete RESET SESSION with AUTHORIZATION */
3228 0 : else if (Matches2("RESET", "SESSION"))
3229 0 : COMPLETE_WITH_CONST("AUTHORIZATION");
3230 : /* Complete SET <var> with "TO" */
3231 0 : else if (Matches2("SET", MatchAny))
3232 0 : COMPLETE_WITH_CONST("TO");
3233 : /* Complete ALTER DATABASE|FUNCTION|ROLE|USER ... SET <name> */
3234 0 : else if (HeadMatches2("ALTER", "DATABASE|FUNCTION|ROLE|USER") &&
3235 0 : TailMatches2("SET", MatchAny))
3236 0 : COMPLETE_WITH_LIST2("FROM CURRENT", "TO");
3237 : /* Suggest possible variable values */
3238 0 : else if (TailMatches3("SET", MatchAny, "TO|="))
3239 : {
3240 : /* special cased code for individual GUCs */
3241 0 : if (TailMatches2("DateStyle", "TO|="))
3242 0 : {
3243 : static const char *const my_list[] =
3244 : {"ISO", "SQL", "Postgres", "German",
3245 : "YMD", "DMY", "MDY",
3246 : "US", "European", "NonEuropean",
3247 : "DEFAULT", NULL};
3248 :
3249 0 : COMPLETE_WITH_LIST(my_list);
3250 : }
3251 0 : else if (TailMatches2("search_path", "TO|="))
3252 0 : COMPLETE_WITH_QUERY(Query_for_list_of_schemas
3253 : " AND nspname not like 'pg\\_toast%%' "
3254 : " AND nspname not like 'pg\\_temp%%' "
3255 : " UNION SELECT 'DEFAULT' ");
3256 : else
3257 : {
3258 : /* generic, type based, GUC support */
3259 0 : char *guctype = get_guctype(prev2_wd);
3260 :
3261 0 : if (guctype && strcmp(guctype, "enum") == 0)
3262 0 : {
3263 : char querybuf[1024];
3264 :
3265 0 : snprintf(querybuf, sizeof(querybuf), Query_for_enum, prev2_wd);
3266 0 : COMPLETE_WITH_QUERY(querybuf);
3267 : }
3268 0 : else if (guctype && strcmp(guctype, "bool") == 0)
3269 0 : COMPLETE_WITH_LIST9("on", "off", "true", "false", "yes", "no",
3270 : "1", "0", "DEFAULT");
3271 : else
3272 0 : COMPLETE_WITH_CONST("DEFAULT");
3273 :
3274 0 : if (guctype)
3275 0 : free(guctype);
3276 : }
3277 : }
3278 :
3279 : /* START TRANSACTION */
3280 0 : else if (Matches1("START"))
3281 0 : COMPLETE_WITH_CONST("TRANSACTION");
3282 :
3283 : /* TABLE, but not TABLE embedded in other commands */
3284 0 : else if (Matches1("TABLE"))
3285 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3286 :
3287 : /* TABLESAMPLE */
3288 0 : else if (TailMatches1("TABLESAMPLE"))
3289 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tablesample_methods);
3290 0 : else if (TailMatches2("TABLESAMPLE", MatchAny))
3291 0 : COMPLETE_WITH_CONST("(");
3292 :
3293 : /* TRUNCATE */
3294 0 : else if (Matches1("TRUNCATE"))
3295 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3296 :
3297 : /* UNLISTEN */
3298 0 : else if (Matches1("UNLISTEN"))
3299 0 : 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 '*'");
3300 :
3301 : /* UPDATE --- can be inside EXPLAIN, RULE, etc */
3302 : /* If prev. word is UPDATE suggest a list of tables */
3303 0 : else if (TailMatches1("UPDATE"))
3304 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
3305 : /* Complete UPDATE <table> with "SET" */
3306 0 : else if (TailMatches2("UPDATE", MatchAny))
3307 0 : COMPLETE_WITH_CONST("SET");
3308 : /* Complete UPDATE <table> SET with list of attributes */
3309 0 : else if (TailMatches3("UPDATE", MatchAny, "SET"))
3310 0 : COMPLETE_WITH_ATTR(prev2_wd, "");
3311 : /* UPDATE <table> SET <attr> = */
3312 0 : else if (TailMatches4("UPDATE", MatchAny, "SET", MatchAny))
3313 0 : COMPLETE_WITH_CONST("=");
3314 :
3315 : /* USER MAPPING */
3316 0 : else if (Matches3("ALTER|CREATE|DROP", "USER", "MAPPING"))
3317 0 : COMPLETE_WITH_CONST("FOR");
3318 0 : else if (Matches4("CREATE", "USER", "MAPPING", "FOR"))
3319 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles
3320 : " UNION SELECT 'CURRENT_USER'"
3321 : " UNION SELECT 'PUBLIC'"
3322 : " UNION SELECT 'USER'");
3323 0 : else if (Matches4("ALTER|DROP", "USER", "MAPPING", "FOR"))
3324 0 : COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3325 0 : else if (Matches5("CREATE|ALTER|DROP", "USER", "MAPPING", "FOR", MatchAny))
3326 0 : COMPLETE_WITH_CONST("SERVER");
3327 0 : else if (Matches7("CREATE|ALTER", "USER", "MAPPING", "FOR", MatchAny, "SERVER", MatchAny))
3328 0 : COMPLETE_WITH_CONST("OPTIONS");
3329 :
3330 : /*
3331 : * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
3332 : * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
3333 : */
3334 0 : else if (Matches1("VACUUM"))
3335 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3336 : " UNION SELECT 'FULL'"
3337 : " UNION SELECT 'FREEZE'"
3338 : " UNION SELECT 'ANALYZE'"
3339 : " UNION SELECT 'VERBOSE'");
3340 0 : else if (Matches2("VACUUM", "FULL|FREEZE"))
3341 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3342 : " UNION SELECT 'ANALYZE'"
3343 : " UNION SELECT 'VERBOSE'");
3344 0 : else if (Matches3("VACUUM", "FULL|FREEZE", "ANALYZE"))
3345 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3346 : " UNION SELECT 'VERBOSE'");
3347 0 : else if (Matches3("VACUUM", "FULL|FREEZE", "VERBOSE"))
3348 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3349 : " UNION SELECT 'ANALYZE'");
3350 0 : else if (Matches2("VACUUM", "VERBOSE"))
3351 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3352 : " UNION SELECT 'ANALYZE'");
3353 0 : else if (Matches2("VACUUM", "ANALYZE"))
3354 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
3355 : " UNION SELECT 'VERBOSE'");
3356 0 : else if (HeadMatches1("VACUUM"))
3357 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
3358 :
3359 : /* WITH [RECURSIVE] */
3360 :
3361 : /*
3362 : * Only match when WITH is the first word, as WITH may appear in many
3363 : * other contexts.
3364 : */
3365 0 : else if (Matches1("WITH"))
3366 0 : COMPLETE_WITH_CONST("RECURSIVE");
3367 :
3368 : /* ANALYZE */
3369 : /* Complete with list of tables */
3370 0 : else if (Matches1("ANALYZE"))
3371 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, NULL);
3372 :
3373 : /* WHERE */
3374 : /* Simple case of the word before the where being the table name */
3375 0 : else if (TailMatches2(MatchAny, "WHERE"))
3376 0 : COMPLETE_WITH_ATTR(prev2_wd, "");
3377 :
3378 : /* ... FROM ... */
3379 : /* TODO: also include SRF ? */
3380 0 : else if (TailMatches1("FROM") && !Matches3("COPY|\\copy", MatchAny, "FROM"))
3381 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3382 :
3383 : /* ... JOIN ... */
3384 0 : else if (TailMatches1("JOIN"))
3385 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3386 :
3387 : /* Backslash commands */
3388 : /* TODO: \dc \dd \dl */
3389 0 : else if (TailMatchesCS1("\\?"))
3390 0 : COMPLETE_WITH_LIST_CS3("commands", "options", "variables");
3391 0 : else if (TailMatchesCS1("\\connect|\\c"))
3392 : {
3393 0 : if (!recognized_connection_string(text))
3394 0 : COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3395 : }
3396 0 : else if (TailMatchesCS2("\\connect|\\c", MatchAny))
3397 : {
3398 0 : if (!recognized_connection_string(prev_wd))
3399 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3400 : }
3401 0 : else if (TailMatchesCS1("\\da*"))
3402 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
3403 0 : else if (TailMatchesCS1("\\dA*"))
3404 0 : COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
3405 0 : else if (TailMatchesCS1("\\db*"))
3406 0 : COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
3407 0 : else if (TailMatchesCS1("\\dD*"))
3408 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
3409 0 : else if (TailMatchesCS1("\\des*"))
3410 0 : COMPLETE_WITH_QUERY(Query_for_list_of_servers);
3411 0 : else if (TailMatchesCS1("\\deu*"))
3412 0 : COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
3413 0 : else if (TailMatchesCS1("\\dew*"))
3414 0 : COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
3415 0 : else if (TailMatchesCS1("\\df*"))
3416 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3417 :
3418 0 : else if (TailMatchesCS1("\\dFd*"))
3419 0 : COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
3420 0 : else if (TailMatchesCS1("\\dFp*"))
3421 0 : COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
3422 0 : else if (TailMatchesCS1("\\dFt*"))
3423 0 : COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
3424 : /* must be at end of \dF alternatives: */
3425 0 : else if (TailMatchesCS1("\\dF*"))
3426 0 : COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
3427 :
3428 0 : else if (TailMatchesCS1("\\di*"))
3429 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
3430 0 : else if (TailMatchesCS1("\\dL*"))
3431 0 : COMPLETE_WITH_QUERY(Query_for_list_of_languages);
3432 0 : else if (TailMatchesCS1("\\dn*"))
3433 0 : COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
3434 0 : else if (TailMatchesCS1("\\dp") || TailMatchesCS1("\\z"))
3435 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
3436 0 : else if (TailMatchesCS1("\\ds*"))
3437 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
3438 0 : else if (TailMatchesCS1("\\dt*"))
3439 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
3440 0 : else if (TailMatchesCS1("\\dT*"))
3441 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
3442 0 : else if (TailMatchesCS1("\\du*") || TailMatchesCS1("\\dg*"))
3443 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3444 0 : else if (TailMatchesCS1("\\dv*"))
3445 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
3446 0 : else if (TailMatchesCS1("\\dx*"))
3447 0 : COMPLETE_WITH_QUERY(Query_for_list_of_extensions);
3448 0 : else if (TailMatchesCS1("\\dm*"))
3449 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
3450 0 : else if (TailMatchesCS1("\\dE*"))
3451 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
3452 0 : else if (TailMatchesCS1("\\dy*"))
3453 0 : COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
3454 :
3455 : /* must be at end of \d alternatives: */
3456 0 : else if (TailMatchesCS1("\\d*"))
3457 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
3458 :
3459 0 : else if (TailMatchesCS1("\\ef"))
3460 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3461 0 : else if (TailMatchesCS1("\\ev"))
3462 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
3463 :
3464 0 : else if (TailMatchesCS1("\\encoding"))
3465 0 : COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
3466 0 : else if (TailMatchesCS1("\\h|\\help"))
3467 0 : COMPLETE_WITH_LIST(sql_commands);
3468 0 : else if (TailMatchesCS2("\\h|\\help", MatchAny))
3469 : {
3470 0 : if (TailMatches1("DROP"))
3471 0 : matches = completion_matches(text, drop_command_generator);
3472 0 : else if (TailMatches1("ALTER"))
3473 0 : matches = completion_matches(text, alter_command_generator);
3474 :
3475 : /*
3476 : * CREATE is recognized by tail match elsewhere, so doesn't need to be
3477 : * repeated here
3478 : */
3479 : }
3480 0 : else if (TailMatchesCS3("\\h|\\help", MatchAny, MatchAny))
3481 : {
3482 0 : if (TailMatches2("CREATE|DROP", "ACCESS"))
3483 0 : COMPLETE_WITH_CONST("METHOD");
3484 0 : else if (TailMatches2("ALTER", "DEFAULT"))
3485 0 : COMPLETE_WITH_CONST("PRIVILEGES");
3486 0 : else if (TailMatches2("CREATE|ALTER|DROP", "EVENT"))
3487 0 : COMPLETE_WITH_CONST("TRIGGER");
3488 0 : else if (TailMatches2("CREATE|ALTER|DROP", "FOREIGN"))
3489 0 : COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
3490 0 : else if (TailMatches2("ALTER", "LARGE"))
3491 0 : COMPLETE_WITH_CONST("OBJECT");
3492 0 : else if (TailMatches2("CREATE|ALTER|DROP", "MATERIALIZED"))
3493 0 : COMPLETE_WITH_CONST("VIEW");
3494 0 : else if (TailMatches2("CREATE|ALTER|DROP", "TEXT"))
3495 0 : COMPLETE_WITH_CONST("SEARCH");
3496 0 : else if (TailMatches2("CREATE|ALTER|DROP", "USER"))
3497 0 : COMPLETE_WITH_CONST("MAPPING FOR");
3498 : }
3499 0 : else if (TailMatchesCS4("\\h|\\help", MatchAny, MatchAny, MatchAny))
3500 : {
3501 0 : if (TailMatches3("CREATE|ALTER|DROP", "FOREIGN", "DATA"))
3502 0 : COMPLETE_WITH_CONST("WRAPPER");
3503 0 : else if (TailMatches3("CREATE|ALTER|DROP", "TEXT", "SEARCH"))
3504 0 : COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
3505 0 : else if (TailMatches3("CREATE|ALTER|DROP", "USER", "MAPPING"))
3506 0 : COMPLETE_WITH_CONST("FOR");
3507 : }
3508 0 : else if (TailMatchesCS1("\\l*") && !TailMatchesCS1("\\lo*"))
3509 0 : COMPLETE_WITH_QUERY(Query_for_list_of_databases);
3510 0 : else if (TailMatchesCS1("\\password"))
3511 0 : COMPLETE_WITH_QUERY(Query_for_list_of_roles);
3512 0 : else if (TailMatchesCS1("\\pset"))
3513 0 : {
3514 : static const char *const my_list[] =
3515 : {"border", "columns", "expanded", "fieldsep", "fieldsep_zero",
3516 : "footer", "format", "linestyle", "null", "numericlocale",
3517 : "pager", "pager_min_lines", "recordsep", "recordsep_zero",
3518 : "tableattr", "title", "tuples_only", "unicode_border_linestyle",
3519 : "unicode_column_linestyle", "unicode_header_linestyle", NULL};
3520 :
3521 0 : COMPLETE_WITH_LIST_CS(my_list);
3522 : }
3523 0 : else if (TailMatchesCS2("\\pset", MatchAny))
3524 : {
3525 0 : if (TailMatchesCS1("format"))
3526 0 : {
3527 : static const char *const my_list[] =
3528 : {"unaligned", "aligned", "wrapped", "html", "asciidoc",
3529 : "latex", "latex-longtable", "troff-ms", NULL};
3530 :
3531 0 : COMPLETE_WITH_LIST_CS(my_list);
3532 : }
3533 0 : else if (TailMatchesCS1("linestyle"))
3534 0 : COMPLETE_WITH_LIST_CS3("ascii", "old-ascii", "unicode");
3535 0 : else if (TailMatchesCS1("pager"))
3536 0 : COMPLETE_WITH_LIST_CS3("on", "off", "always");
3537 0 : else if (TailMatchesCS1("unicode_border_linestyle|"
3538 : "unicode_column_linestyle|"
3539 : "unicode_header_linestyle"))
3540 0 : COMPLETE_WITH_LIST_CS2("single", "double");
3541 : }
3542 0 : else if (TailMatchesCS1("\\unset"))
3543 0 : matches = complete_from_variables(text, "", "", true);
3544 0 : else if (TailMatchesCS1("\\set"))
3545 0 : matches = complete_from_variables(text, "", "", false);
3546 0 : else if (TailMatchesCS2("\\set", MatchAny))
3547 : {
3548 0 : if (TailMatchesCS1("AUTOCOMMIT|ON_ERROR_STOP|QUIET|"
3549 : "SINGLELINE|SINGLESTEP"))
3550 0 : COMPLETE_WITH_LIST_CS2("on", "off");
3551 0 : else if (TailMatchesCS1("COMP_KEYWORD_CASE"))
3552 0 : COMPLETE_WITH_LIST_CS4("lower", "upper",
3553 : "preserve-lower", "preserve-upper");
3554 0 : else if (TailMatchesCS1("ECHO"))
3555 0 : COMPLETE_WITH_LIST_CS4("errors", "queries", "all", "none");
3556 0 : else if (TailMatchesCS1("ECHO_HIDDEN"))
3557 0 : COMPLETE_WITH_LIST_CS3("noexec", "off", "on");
3558 0 : else if (TailMatchesCS1("HISTCONTROL"))
3559 0 : COMPLETE_WITH_LIST_CS4("ignorespace", "ignoredups",
3560 : "ignoreboth", "none");
3561 0 : else if (TailMatchesCS1("ON_ERROR_ROLLBACK"))
3562 0 : COMPLETE_WITH_LIST_CS3("on", "off", "interactive");
3563 0 : else if (TailMatchesCS1("SHOW_CONTEXT"))
3564 0 : COMPLETE_WITH_LIST_CS3("never", "errors", "always");
3565 0 : else if (TailMatchesCS1("VERBOSITY"))
3566 0 : COMPLETE_WITH_LIST_CS3("default", "verbose", "terse");
3567 : }
3568 0 : else if (TailMatchesCS1("\\sf*"))
3569 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
3570 0 : else if (TailMatchesCS1("\\sv*"))
3571 0 : COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
3572 0 : else if (TailMatchesCS1("\\cd|\\e|\\edit|\\g|\\i|\\include|"
3573 : "\\ir|\\include_relative|\\o|\\out|"
3574 : "\\s|\\w|\\write|\\lo_import"))
3575 : {
3576 0 : completion_charp = "\\";
3577 0 : matches = completion_matches(text, complete_from_files);
3578 : }
3579 :
3580 : /*
3581 : * Finally, we look through the list of "things", such as TABLE, INDEX and
3582 : * check if that was the previous word. If so, execute the query to get a
3583 : * list of them.
3584 : */
3585 : else
3586 : {
3587 : int i;
3588 :
3589 0 : for (i = 0; words_after_create[i].name; i++)
3590 : {
3591 0 : if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
3592 : {
3593 0 : if (words_after_create[i].query)
3594 0 : COMPLETE_WITH_QUERY(words_after_create[i].query);
3595 0 : else if (words_after_create[i].squery)
3596 0 : COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
3597 : NULL);
3598 0 : break;
3599 : }
3600 : }
3601 : }
3602 :
3603 : /*
3604 : * If we still don't have anything to match we have to fabricate some sort
3605 : * of default list. If we were to just return NULL, readline automatically
3606 : * attempts filename completion, and that's usually no good.
3607 : */
3608 0 : if (matches == NULL)
3609 : {
3610 0 : COMPLETE_WITH_CONST("");
3611 : #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
3612 0 : rl_completion_append_character = '\0';
3613 : #endif
3614 : }
3615 :
3616 : /* free storage */
3617 0 : free(previous_words);
3618 0 : free(words_buffer);
3619 :
3620 : /* Return our Grand List O' Matches */
3621 0 : return matches;
3622 : }
3623 :
3624 :
3625 : /*
3626 : * GENERATOR FUNCTIONS
3627 : *
3628 : * These functions do all the actual work of completing the input. They get
3629 : * passed the text so far and the count how many times they have been called
3630 : * so far with the same text.
3631 : * If you read the above carefully, you'll see that these don't get called
3632 : * directly but through the readline interface.
3633 : * The return value is expected to be the full completion of the text, going
3634 : * through a list each time, or NULL if there are no more matches. The string
3635 : * will be free()'d by readline, so you must run it through strdup() or
3636 : * something of that sort.
3637 : */
3638 :
3639 : /*
3640 : * Common routine for create_command_generator and drop_command_generator.
3641 : * Entries that have 'excluded' flags are not returned.
3642 : */
3643 : static char *
3644 0 : create_or_drop_command_generator(const char *text, int state, bits32 excluded)
3645 : {
3646 : static int list_index,
3647 : string_length;
3648 : const char *name;
3649 :
3650 : /* If this is the first time for this completion, init some values */
3651 0 : if (state == 0)
3652 : {
3653 0 : list_index = 0;
3654 0 : string_length = strlen(text);
3655 : }
3656 :
3657 : /* find something that matches */
3658 0 : while ((name = words_after_create[list_index++].name))
3659 : {
3660 0 : if ((pg_strncasecmp(name, text, string_length) == 0) &&
3661 0 : !(words_after_create[list_index - 1].flags & excluded))
3662 0 : return pg_strdup_keyword_case(name, text);
3663 : }
3664 : /* if nothing matches, return NULL */
3665 0 : return NULL;
3666 : }
3667 :
3668 : /*
3669 : * This one gives you one from a list of things you can put after CREATE
3670 : * as defined above.
3671 : */
3672 : static char *
3673 0 : create_command_generator(const char *text, int state)
3674 : {
3675 0 : return create_or_drop_command_generator(text, state, THING_NO_CREATE);
3676 : }
3677 :
3678 : /*
3679 : * This function gives you a list of things you can put after a DROP command.
3680 : */
3681 : static char *
3682 0 : drop_command_generator(const char *text, int state)
3683 : {
3684 0 : return create_or_drop_command_generator(text, state, THING_NO_DROP);
3685 : }
3686 :
3687 : /*
3688 : * This function gives you a list of things you can put after an ALTER command.
3689 : */
3690 : static char *
3691 0 : alter_command_generator(const char *text, int state)
3692 : {
3693 0 : return create_or_drop_command_generator(text, state, THING_NO_ALTER);
3694 : }
3695 :
3696 : /* The following two functions are wrappers for _complete_from_query */
3697 :
3698 : static char *
3699 0 : complete_from_query(const char *text, int state)
3700 : {
3701 0 : return _complete_from_query(0, text, state);
3702 : }
3703 :
3704 : static char *
3705 0 : complete_from_schema_query(const char *text, int state)
3706 : {
3707 0 : return _complete_from_query(1, text, state);
3708 : }
3709 :
3710 :
3711 : /*
3712 : * This creates a list of matching things, according to a query pointed to
3713 : * by completion_charp.
3714 : * The query can be one of two kinds:
3715 : *
3716 : * 1. A simple query which must contain a %d and a %s, which will be replaced
3717 : * by the string length of the text and the text itself. The query may also
3718 : * have up to four more %s in it; the first two such will be replaced by the
3719 : * value of completion_info_charp, the next two by the value of
3720 : * completion_info_charp2.
3721 : *
3722 : * 2. A schema query used for completion of both schema and relation names.
3723 : * These are more complex and must contain in the following order:
3724 : * %d %s %d %s %d %s %s %d %s
3725 : * where %d is the string length of the text and %s the text itself.
3726 : *
3727 : * It is assumed that strings should be escaped to become SQL literals
3728 : * (that is, what is in the query is actually ... '%s' ...)
3729 : *
3730 : * See top of file for examples of both kinds of query.
3731 : */
3732 : static char *
3733 0 : _complete_from_query(int is_schema_query, const char *text, int state)
3734 : {
3735 : static int list_index,
3736 : byte_length;
3737 : static PGresult *result = NULL;
3738 :
3739 : /*
3740 : * If this is the first time for this completion, we fetch a list of our
3741 : * "things" from the backend.
3742 : */
3743 0 : if (state == 0)
3744 : {
3745 : PQExpBufferData query_buffer;
3746 : char *e_text;
3747 : char *e_info_charp;
3748 : char *e_info_charp2;
3749 0 : const char *pstr = text;
3750 0 : int char_length = 0;
3751 :
3752 0 : list_index = 0;
3753 0 : byte_length = strlen(text);
3754 :
3755 : /*
3756 : * Count length as number of characters (not bytes), for passing to
3757 : * substring
3758 : */
3759 0 : while (*pstr)
3760 : {
3761 0 : char_length++;
3762 0 : pstr += PQmblen(pstr, pset.encoding);
3763 : }
3764 :
3765 : /* Free any prior result */
3766 0 : PQclear(result);
3767 0 : result = NULL;
3768 :
3769 : /* Set up suitably-escaped copies of textual inputs */
3770 0 : e_text = escape_string(text);
3771 :
3772 0 : if (completion_info_charp)
3773 0 : e_info_charp = escape_string(completion_info_charp);
3774 : else
3775 0 : e_info_charp = NULL;
3776 :
3777 0 : if (completion_info_charp2)
3778 0 : e_info_charp2 = escape_string(completion_info_charp2);
3779 : else
3780 0 : e_info_charp2 = NULL;
3781 :
3782 0 : initPQExpBuffer(&query_buffer);
3783 :
3784 0 : if (is_schema_query)
3785 : {
3786 : /* completion_squery gives us the pieces to assemble */
3787 0 : const char *qualresult = completion_squery->qualresult;
3788 :
3789 0 : if (qualresult == NULL)
3790 0 : qualresult = completion_squery->result;
3791 :
3792 : /* Get unqualified names matching the input-so-far */
3793 0 : appendPQExpBuffer(&query_buffer, "SELECT %s FROM %s WHERE ",
3794 0 : completion_squery->result,
3795 0 : completion_squery->catname);
3796 0 : if (completion_squery->selcondition)
3797 0 : appendPQExpBuffer(&query_buffer, "%s AND ",
3798 0 : completion_squery->selcondition);
3799 0 : appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
3800 0 : completion_squery->result,
3801 : char_length, e_text);
3802 0 : appendPQExpBuffer(&query_buffer, " AND %s",
3803 0 : completion_squery->viscondition);
3804 :
3805 : /*
3806 : * When fetching relation names, suppress system catalogs unless
3807 : * the input-so-far begins with "pg_". This is a compromise
3808 : * between not offering system catalogs for completion at all, and
3809 : * having them swamp the result when the input is just "p".
3810 : */
3811 0 : if (strcmp(completion_squery->catname,
3812 0 : "pg_catalog.pg_class c") == 0 &&
3813 0 : strncmp(text, "pg_", 3) !=0)
3814 : {
3815 0 : appendPQExpBufferStr(&query_buffer,
3816 : " AND c.relnamespace <> (SELECT oid FROM"
3817 : " pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
3818 : }
3819 :
3820 : /*
3821 : * Add in matching schema names, but only if there is more than
3822 : * one potential match among schema names.
3823 : */
3824 0 : appendPQExpBuffer(&query_buffer, "\nUNION\n"
3825 : "SELECT pg_catalog.quote_ident(n.nspname) || '.' "
3826 : "FROM pg_catalog.pg_namespace n "
3827 : "WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
3828 : char_length, e_text);
3829 0 : appendPQExpBuffer(&query_buffer,
3830 : " AND (SELECT pg_catalog.count(*)"
3831 : " FROM pg_catalog.pg_namespace"
3832 : " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3833 : " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
3834 : char_length, e_text);
3835 :
3836 : /*
3837 : * Add in matching qualified names, but only if there is exactly
3838 : * one schema matching the input-so-far.
3839 : */
3840 0 : appendPQExpBuffer(&query_buffer, "\nUNION\n"
3841 : "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s "
3842 : "FROM %s, pg_catalog.pg_namespace n "
3843 : "WHERE %s = n.oid AND ",
3844 : qualresult,
3845 0 : completion_squery->catname,
3846 0 : completion_squery->namespace);
3847 0 : if (completion_squery->selcondition)
3848 0 : appendPQExpBuffer(&query_buffer, "%s AND ",
3849 0 : completion_squery->selcondition);
3850 0 : appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
3851 : qualresult,
3852 : char_length, e_text);
3853 :
3854 : /*
3855 : * This condition exploits the single-matching-schema rule to
3856 : * speed up the query
3857 : */
3858 0 : appendPQExpBuffer(&query_buffer,
3859 : " AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
3860 : " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
3861 : char_length, e_text);
3862 0 : appendPQExpBuffer(&query_buffer,
3863 : " AND (SELECT pg_catalog.count(*)"
3864 : " FROM pg_catalog.pg_namespace"
3865 : " WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
3866 : " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
3867 : char_length, e_text);
3868 :
3869 : /* If an addon query was provided, use it */
3870 0 : if (completion_charp)
3871 0 : appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
3872 : }
3873 : else
3874 : {
3875 : /* completion_charp is an sprintf-style format string */
3876 0 : appendPQExpBuffer(&query_buffer, completion_charp,
3877 : char_length, e_text,
3878 : e_info_charp, e_info_charp,
3879 : e_info_charp2, e_info_charp2);
3880 : }
3881 :
3882 : /* Limit the number of records in the result */
3883 0 : appendPQExpBuffer(&query_buffer, "\nLIMIT %d",
3884 : completion_max_records);
3885 :
3886 0 : result = exec_query(query_buffer.data);
3887 :
3888 0 : termPQExpBuffer(&query_buffer);
3889 0 : free(e_text);
3890 0 : if (e_info_charp)
3891 0 : free(e_info_charp);
3892 0 : if (e_info_charp2)
3893 0 : free(e_info_charp2);
3894 : }
3895 :
3896 : /* Find something that matches */
3897 0 : if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
3898 : {
3899 : const char *item;
3900 :
3901 0 : while (list_index < PQntuples(result) &&
3902 0 : (item = PQgetvalue(result, list_index++, 0)))
3903 0 : if (pg_strncasecmp(text, item, byte_length) == 0)
3904 0 : return pg_strdup(item);
3905 : }
3906 :
3907 : /* If nothing matches, free the db structure and return null */
3908 0 : PQclear(result);
3909 0 : result = NULL;
3910 0 : return NULL;
3911 : }
3912 :
3913 :
3914 : /*
3915 : * This function returns in order one of a fixed, NULL pointer terminated list
3916 : * of strings (if matching). This can be used if there are only a fixed number
3917 : * SQL words that can appear at certain spot.
3918 : */
3919 : static char *
3920 0 : complete_from_list(const char *text, int state)
3921 : {
3922 : static int string_length,
3923 : list_index,
3924 : matches;
3925 : static bool casesensitive;
3926 : const char *item;
3927 :
3928 : /* need to have a list */
3929 0 : Assert(completion_charpp != NULL);
3930 :
3931 : /* Initialization */
3932 0 : if (state == 0)
3933 : {
3934 0 : list_index = 0;
3935 0 : string_length = strlen(text);
3936 0 : casesensitive = completion_case_sensitive;
3937 0 : matches = 0;
3938 : }
3939 :
3940 0 : while ((item = completion_charpp[list_index++]))
3941 : {
3942 : /* First pass is case sensitive */
3943 0 : if (casesensitive && strncmp(text, item, string_length) == 0)
3944 : {
3945 0 : matches++;
3946 0 : return pg_strdup(item);
3947 : }
3948 :
3949 : /* Second pass is case insensitive, don't bother counting matches */
3950 0 : if (!casesensitive && pg_strncasecmp(text, item, string_length) == 0)
3951 : {
3952 0 : if (completion_case_sensitive)
3953 0 : return pg_strdup(item);
3954 : else
3955 :
3956 : /*
3957 : * If case insensitive matching was requested initially,
3958 : * adjust the case according to setting.
3959 : */
3960 0 : return pg_strdup_keyword_case(item, text);
3961 : }
3962 : }
3963 :
3964 : /*
3965 : * No matches found. If we're not case insensitive already, lets switch to
3966 : * being case insensitive and try again
3967 : */
3968 0 : if (casesensitive && matches == 0)
3969 : {
3970 0 : casesensitive = false;
3971 0 : list_index = 0;
3972 0 : state++;
3973 0 : return complete_from_list(text, state);
3974 : }
3975 :
3976 : /* If no more matches, return null. */
3977 0 : return NULL;
3978 : }
3979 :
3980 :
3981 : /*
3982 : * This function returns one fixed string the first time even if it doesn't
3983 : * match what's there, and nothing the second time. This should be used if
3984 : * there is only one possibility that can appear at a certain spot, so
3985 : * misspellings will be overwritten. The string to be passed must be in
3986 : * completion_charp.
3987 : */
3988 : static char *
3989 0 : complete_from_const(const char *text, int state)
3990 : {
3991 0 : Assert(completion_charp != NULL);
3992 0 : if (state == 0)
3993 : {
3994 0 : if (completion_case_sensitive)
3995 0 : return pg_strdup(completion_charp);
3996 : else
3997 :
3998 : /*
3999 : * If case insensitive matching was requested initially, adjust
4000 : * the case according to setting.
4001 : */
4002 0 : return pg_strdup_keyword_case(completion_charp, text);
4003 : }
4004 : else
4005 0 : return NULL;
4006 : }
4007 :
4008 :
4009 : /*
4010 : * This function appends the variable name with prefix and suffix to
4011 : * the variable names array.
4012 : */
4013 : static void
4014 0 : append_variable_names(char ***varnames, int *nvars,
4015 : int *maxvars, const char *varname,
4016 : const char *prefix, const char *suffix)
4017 : {
4018 0 : if (*nvars >= *maxvars)
4019 : {
4020 0 : *maxvars *= 2;
4021 0 : *varnames = (char **) pg_realloc(*varnames,
4022 0 : ((*maxvars) + 1) * sizeof(char *));
4023 : }
4024 :
4025 0 : (*varnames)[(*nvars)++] = psprintf("%s%s%s", prefix, varname, suffix);
4026 0 : }
4027 :
4028 :
4029 : /*
4030 : * This function supports completion with the name of a psql variable.
4031 : * The variable names can be prefixed and suffixed with additional text
4032 : * to support quoting usages. If need_value is true, only variables
4033 : * that are currently set are included; otherwise, special variables
4034 : * (those that have hooks) are included even if currently unset.
4035 : */
4036 : static char **
4037 0 : complete_from_variables(const char *text, const char *prefix, const char *suffix,
4038 : bool need_value)
4039 : {
4040 : char **matches;
4041 : char **varnames;
4042 0 : int nvars = 0;
4043 0 : int maxvars = 100;
4044 : int i;
4045 : struct _variable *ptr;
4046 :
4047 0 : varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *));
4048 :
4049 0 : for (ptr = pset.vars->next; ptr; ptr = ptr->next)
4050 : {
4051 0 : if (need_value && !(ptr->value))
4052 0 : continue;
4053 0 : append_variable_names(&varnames, &nvars, &maxvars, ptr->name,
4054 : prefix, suffix);
4055 : }
4056 :
4057 0 : varnames[nvars] = NULL;
4058 0 : COMPLETE_WITH_LIST_CS((const char *const *) varnames);
4059 :
4060 0 : for (i = 0; i < nvars; i++)
4061 0 : free(varnames[i]);
4062 0 : free(varnames);
4063 :
4064 0 : return matches;
4065 : }
4066 :
4067 :
4068 : /*
4069 : * This function wraps rl_filename_completion_function() to strip quotes from
4070 : * the input before searching for matches and to quote any matches for which
4071 : * the consuming command will require it.
4072 : */
4073 : static char *
4074 0 : complete_from_files(const char *text, int state)
4075 : {
4076 : static const char *unquoted_text;
4077 : char *unquoted_match;
4078 0 : char *ret = NULL;
4079 :
4080 0 : if (state == 0)
4081 : {
4082 : /* Initialization: stash the unquoted input. */
4083 0 : unquoted_text = strtokx(text, "", NULL, "'", *completion_charp,
4084 : false, true, pset.encoding);
4085 : /* expect a NULL return for the empty string only */
4086 0 : if (!unquoted_text)
4087 : {
4088 0 : Assert(*text == '\0');
4089 0 : unquoted_text = text;
4090 : }
4091 : }
4092 :
4093 0 : unquoted_match = filename_completion_function(unquoted_text, state);
4094 0 : if (unquoted_match)
4095 : {
4096 : /*
4097 : * Caller sets completion_charp to a zero- or one-character string
4098 : * containing the escape character. This is necessary since \copy has
4099 : * no escape character, but every other backslash command recognizes
4100 : * "\" as an escape character. Since we have only two callers, don't
4101 : * bother providing a macro to simplify this.
4102 : */
4103 0 : ret = quote_if_needed(unquoted_match, " \t\r\n\"`",
4104 0 : '\'', *completion_charp, pset.encoding);
4105 0 : if (ret)
4106 0 : free(unquoted_match);
4107 : else
4108 0 : ret = unquoted_match;
4109 : }
4110 :
4111 0 : return ret;
4112 : }
4113 :
4114 :
4115 : /* HELPER FUNCTIONS */
4116 :
4117 :
4118 : /*
4119 : * Make a pg_strdup copy of s and convert the case according to
4120 : * COMP_KEYWORD_CASE setting, using ref as the text that was already entered.
4121 : */
4122 : static char *
4123 0 : pg_strdup_keyword_case(const char *s, const char *ref)
4124 : {
4125 : char *ret,
4126 : *p;
4127 0 : unsigned char first = ref[0];
4128 :
4129 0 : ret = pg_strdup(s);
4130 :
4131 0 : if (pset.comp_case == PSQL_COMP_CASE_LOWER ||
4132 0 : ((pset.comp_case == PSQL_COMP_CASE_PRESERVE_LOWER ||
4133 0 : pset.comp_case == PSQL_COMP_CASE_PRESERVE_UPPER) && islower(first)) ||
4134 0 : (pset.comp_case == PSQL_COMP_CASE_PRESERVE_LOWER && !isalpha(first)))
4135 : {
4136 0 : for (p = ret; *p; p++)
4137 0 : *p = pg_tolower((unsigned char) *p);
4138 : }
4139 : else
4140 : {
4141 0 : for (p = ret; *p; p++)
4142 0 : *p = pg_toupper((unsigned char) *p);
4143 : }
4144 :
4145 0 : return ret;
4146 : }
4147 :
4148 :
4149 : /*
4150 : * escape_string - Escape argument for use as string literal.
4151 : *
4152 : * The returned value has to be freed.
4153 : */
4154 : static char *
4155 0 : escape_string(const char *text)
4156 : {
4157 : size_t text_length;
4158 : char *result;
4159 :
4160 0 : text_length = strlen(text);
4161 :
4162 0 : result = pg_malloc(text_length * 2 + 1);
4163 0 : PQescapeStringConn(pset.db, result, text, text_length, NULL);
4164 :
4165 0 : return result;
4166 : }
4167 :
4168 :
4169 : /*
4170 : * Execute a query and report any errors. This should be the preferred way of
4171 : * talking to the database in this file.
4172 : */
4173 : static PGresult *
4174 0 : exec_query(const char *query)
4175 : {
4176 : PGresult *result;
4177 :
4178 0 : if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
4179 0 : return NULL;
4180 :
4181 0 : result = PQexec(pset.db, query);
4182 :
4183 0 : if (PQresultStatus(result) != PGRES_TUPLES_OK)
4184 : {
4185 : #ifdef NOT_USED
4186 : psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
4187 : PQerrorMessage(pset.db), query);
4188 : #endif
4189 0 : PQclear(result);
4190 0 : result = NULL;
4191 : }
4192 :
4193 0 : return result;
4194 : }
4195 :
4196 :
4197 : /*
4198 : * Parse all the word(s) before point.
4199 : *
4200 : * Returns a malloc'd array of character pointers that point into the malloc'd
4201 : * data array returned to *buffer; caller must free() both of these when done.
4202 : * *nwords receives the number of words found, ie, the valid length of the
4203 : * return array.
4204 : *
4205 : * Words are returned right to left, that is, previous_words[0] gets the last
4206 : * word before point, previous_words[1] the next-to-last, etc.
4207 : */
4208 : static char **
4209 0 : get_previous_words(int point, char **buffer, int *nwords)
4210 : {
4211 : char **previous_words;
4212 : char *buf;
4213 : char *outptr;
4214 0 : int words_found = 0;
4215 : int i;
4216 :
4217 : /*
4218 : * If we have anything in tab_completion_query_buf, paste it together with
4219 : * rl_line_buffer to construct the full query. Otherwise we can just use
4220 : * rl_line_buffer as the input string.
4221 : */
4222 0 : if (tab_completion_query_buf && tab_completion_query_buf->len > 0)
4223 : {
4224 0 : i = tab_completion_query_buf->len;
4225 0 : buf = pg_malloc(point + i + 2);
4226 0 : memcpy(buf, tab_completion_query_buf->data, i);
4227 0 : buf[i++] = '\n';
4228 0 : memcpy(buf + i, rl_line_buffer, point);
4229 0 : i += point;
4230 0 : buf[i] = '\0';
4231 : /* Readjust point to reference appropriate offset in buf */
4232 0 : point = i;
4233 : }
4234 : else
4235 0 : buf = rl_line_buffer;
4236 :
4237 : /*
4238 : * Allocate an array of string pointers and a buffer to hold the strings
4239 : * themselves. The worst case is that the line contains only
4240 : * non-whitespace WORD_BREAKS characters, making each one a separate word.
4241 : * This is usually much more space than we need, but it's cheaper than
4242 : * doing a separate malloc() for each word.
4243 : */
4244 0 : previous_words = (char **) pg_malloc(point * sizeof(char *));
4245 0 : *buffer = outptr = (char *) pg_malloc(point * 2);
4246 :
4247 : /*
4248 : * First we look for a non-word char before the current point. (This is
4249 : * probably useless, if readline is on the same page as we are about what
4250 : * is a word, but if so it's cheap.)
4251 : */
4252 0 : for (i = point - 1; i >= 0; i--)
4253 : {
4254 0 : if (strchr(WORD_BREAKS, buf[i]))
4255 0 : break;
4256 : }
4257 0 : point = i;
4258 :
4259 : /*
4260 : * Now parse words, working backwards, until we hit start of line. The
4261 : * backwards scan has some interesting but intentional properties
4262 : * concerning parenthesis handling.
4263 : */
4264 0 : while (point >= 0)
4265 : {
4266 : int start,
4267 : end;
4268 0 : bool inquotes = false;
4269 0 : int parentheses = 0;
4270 :
4271 : /* now find the first non-space which then constitutes the end */
4272 0 : end = -1;
4273 0 : for (i = point; i >= 0; i--)
4274 : {
4275 0 : if (!isspace((unsigned char) buf[i]))
4276 : {
4277 0 : end = i;
4278 0 : break;
4279 : }
4280 : }
4281 : /* if no end found, we're done */
4282 0 : if (end < 0)
4283 0 : break;
4284 :
4285 : /*
4286 : * Otherwise we now look for the start. The start is either the last
4287 : * character before any word-break character going backwards from the
4288 : * end, or it's simply character 0. We also handle open quotes and
4289 : * parentheses.
4290 : */
4291 0 : for (start = end; start > 0; start--)
4292 : {
4293 0 : if (buf[start] == '"')
4294 0 : inquotes = !inquotes;
4295 0 : if (!inquotes)
4296 : {
4297 0 : if (buf[start] == ')')
4298 0 : parentheses++;
4299 0 : else if (buf[start] == '(')
4300 : {
4301 0 : if (--parentheses <= 0)
4302 0 : break;
4303 : }
4304 0 : else if (parentheses == 0 &&
4305 0 : strchr(WORD_BREAKS, buf[start - 1]))
4306 0 : break;
4307 : }
4308 : }
4309 :
4310 : /* Return the word located at start to end inclusive */
4311 0 : previous_words[words_found++] = outptr;
4312 0 : i = end - start + 1;
4313 0 : memcpy(outptr, &buf[start], i);
4314 0 : outptr += i;
4315 0 : *outptr++ = '\0';
4316 :
4317 : /* Continue searching */
4318 0 : point = start - 1;
4319 : }
4320 :
4321 : /* Release parsing input workspace, if we made one above */
4322 0 : if (buf != rl_line_buffer)
4323 0 : free(buf);
4324 :
4325 0 : *nwords = words_found;
4326 0 : return previous_words;
4327 : }
4328 :
4329 : /*
4330 : * Look up the type for the GUC variable with the passed name.
4331 : *
4332 : * Returns NULL if the variable is unknown. Otherwise the returned string,
4333 : * containing the type, has to be freed.
4334 : */
4335 : static char *
4336 0 : get_guctype(const char *varname)
4337 : {
4338 : PQExpBufferData query_buffer;
4339 : char *e_varname;
4340 : PGresult *result;
4341 0 : char *guctype = NULL;
4342 :
4343 0 : e_varname = escape_string(varname);
4344 :
4345 0 : initPQExpBuffer(&query_buffer);
4346 0 : appendPQExpBuffer(&query_buffer,
4347 : "SELECT vartype FROM pg_catalog.pg_settings "
4348 : "WHERE pg_catalog.lower(name) = pg_catalog.lower('%s')",
4349 : e_varname);
4350 :
4351 0 : result = exec_query(query_buffer.data);
4352 0 : termPQExpBuffer(&query_buffer);
4353 0 : free(e_varname);
4354 :
4355 0 : if (PQresultStatus(result) == PGRES_TUPLES_OK && PQntuples(result) > 0)
4356 0 : guctype = pg_strdup(PQgetvalue(result, 0, 0));
4357 :
4358 0 : PQclear(result);
4359 :
4360 0 : return guctype;
4361 : }
4362 :
4363 : #ifdef NOT_USED
4364 :
4365 : /*
4366 : * Surround a string with single quotes. This works for both SQL and
4367 : * psql internal. Currently disabled because it is reported not to
4368 : * cooperate with certain versions of readline.
4369 : */
4370 : static char *
4371 : quote_file_name(char *text, int match_type, char *quote_pointer)
4372 : {
4373 : char *s;
4374 : size_t length;
4375 :
4376 : (void) quote_pointer; /* not used */
4377 :
4378 : length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
4379 : s = pg_malloc(length);
4380 : s[0] = '\'';
4381 : strcpy(s + 1, text);
4382 : if (match_type == SINGLE_MATCH)
4383 : s[length - 2] = '\'';
4384 : s[length - 1] = '\0';
4385 : return s;
4386 : }
4387 :
4388 : static char *
4389 : dequote_file_name(char *text, char quote_char)
4390 : {
4391 : char *s;
4392 : size_t length;
4393 :
4394 : if (!quote_char)
4395 : return pg_strdup(text);
4396 :
4397 : length = strlen(text);
4398 : s = pg_malloc(length - 2 + 1);
4399 : strlcpy(s, text +1, length - 2 + 1);
4400 :
4401 : return s;
4402 : }
4403 : #endif /* NOT_USED */
4404 :
4405 : #endif /* USE_READLINE */
|