YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

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