-
Notifications
You must be signed in to change notification settings - Fork 5
/
tab-complete.c
6238 lines (5633 loc) · 218 KB
/
tab-complete.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* psql - the PostgreSQL interactive terminal
*
* Copyright (c) 2000-2022, PostgreSQL Global Development Group
*
* src/bin/psql/tab-complete.c
*/
/*----------------------------------------------------------------------
* This file implements a somewhat more sophisticated readline "TAB
* completion" in psql. It is not intended to be AI, to replace
* learning SQL, or to relieve you from thinking about what you're
* doing. Also it does not always give you all the syntactically legal
* completions, only those that are the most common or the ones that
* the programmer felt most like implementing.
*
* CAVEAT: Tab completion causes queries to be sent to the backend.
* The number of tuples returned gets limited, in most default
* installations to 1000, but if you still don't like this prospect,
* you can turn off tab completion in your ~/.inputrc (or else
* ${INPUTRC}) file so:
*
* $if psql
* set disable-completion on
* $endif
*
* See `man 3 readline' or `info readline' for the full details.
*
* BUGS:
* - Quotes, parentheses, and other funny characters are not handled
* all that gracefully.
*----------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include "input.h"
#include "tab-complete.h"
/* If we don't have this, we might as well forget about the whole thing: */
#ifdef USE_READLINE
#include <ctype.h>
#include <sys/stat.h>
#include "catalog/pg_am_d.h"
#include "catalog/pg_class_d.h"
#include "common.h"
#include "common/keywords.h"
#include "libpq-fe.h"
#include "mb/pg_wchar.h"
#include "pqexpbuffer.h"
#include "settings.h"
#include "stringutils.h"
/*
* Ancient versions of libedit provide filename_completion_function()
* instead of rl_filename_completion_function(). Likewise for
* [rl_]completion_matches().
*/
#ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION
#define rl_filename_completion_function filename_completion_function
#endif
#ifndef HAVE_RL_COMPLETION_MATCHES
#define rl_completion_matches completion_matches
#endif
/*
* Currently we assume that rl_filename_dequoting_function exists if
* rl_filename_quoting_function does. If that proves not to be the case,
* we'd need to test for the former, or possibly both, in configure.
*/
#ifdef HAVE_RL_FILENAME_QUOTING_FUNCTION
#define USE_FILENAME_QUOTING_FUNCTIONS 1
#endif
/* word break characters */
#define WORD_BREAKS "\t\n@$><=;|&{() "
/*
* Since readline doesn't let us pass any state through to the tab completion
* callback, we have to use this global variable to let get_previous_words()
* get at the previous lines of the current command. Ick.
*/
PQExpBuffer tab_completion_query_buf = NULL;
/*
* In some situations, the query to find out what names are available to
* complete with must vary depending on server version. We handle this by
* storing a list of queries, each tagged with the minimum server version
* it will work for. Each list must be stored in descending server version
* order, so that the first satisfactory query is the one to use.
*
* When the query string is otherwise constant, an array of VersionedQuery
* suffices. Terminate the array with an entry having min_server_version = 0.
* That entry's query string can be a query that works in all supported older
* server versions, or NULL to give up and do no completion.
*/
typedef struct VersionedQuery
{
int min_server_version;
const char *query;
} VersionedQuery;
/*
* This struct is used to define "schema queries", which are custom-built
* to obtain possibly-schema-qualified names of database objects. There is
* enough similarity in the structure that we don't want to repeat it each
* time. So we put the components of each query into this struct and
* assemble them with the common boilerplate in _complete_from_query().
*
* We also use this struct to define queries that use completion_ref_object,
* which is some object related to the one(s) we want to get the names of
* (for example, the table we want the indexes of). In that usage the
* objects we're completing might not have a schema of their own, but the
* reference object almost always does (passed in completion_ref_schema).
*
* As with VersionedQuery, we can use an array of these if the query details
* must vary across versions.
*/
typedef struct SchemaQuery
{
/*
* If not zero, minimum server version this struct applies to. If not
* zero, there should be a following struct with a smaller minimum server
* version; use catname == NULL in the last entry if we should do nothing.
*/
int min_server_version;
/*
* Name of catalog or catalogs to be queried, with alias(es), eg.
* "pg_catalog.pg_class c". Note that "pg_namespace n" and/or
* "pg_namespace nr" will be added automatically when needed.
*/
const char *catname;
/*
* Selection condition --- only rows meeting this condition are candidates
* to display. If catname mentions multiple tables, include the necessary
* join condition here. For example, this might look like "c.relkind = "
* CppAsString2(RELKIND_RELATION). Write NULL (not an empty string) if
* not needed.
*/
const char *selcondition;
/*
* Visibility condition --- which rows are visible without schema
* qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
* NULL if not needed.
*/
const char *viscondition;
/*
* Namespace --- name of field to join to pg_namespace.oid when there is
* schema qualification. For example, "c.relnamespace". NULL if we don't
* want to join to pg_namespace (then any schema part in the input word
* will be ignored).
*/
const char *namespace;
/*
* Result --- the base object name to return. For example, "c.relname".
*/
const char *result;
/*
* In some cases, it's difficult to keep the query from returning the same
* object multiple times. Specify use_distinct to filter out duplicates.
*/
bool use_distinct;
/*
* Additional literal strings (usually keywords) to be offered along with
* the query results. Provide a NULL-terminated array of constant
* strings, or NULL if none.
*/
const char *const *keywords;
/*
* If this query uses completion_ref_object/completion_ref_schema,
* populate the remaining fields, else leave them NULL. When using this
* capability, catname must include the catalog that defines the
* completion_ref_object, and selcondition must include the join condition
* that connects it to the result's catalog.
*
* refname is the field that should be equated to completion_ref_object,
* for example "cr.relname".
*/
const char *refname;
/*
* Visibility condition to use when completion_ref_schema is not set. For
* example, "pg_catalog.pg_table_is_visible(cr.oid)". NULL if not needed.
*/
const char *refviscondition;
/*
* Name of field to join to pg_namespace.oid when completion_ref_schema is
* set. For example, "cr.relnamespace". NULL if we don't want to
* consider completion_ref_schema.
*/
const char *refnamespace;
} SchemaQuery;
/* Store maximum number of records we want from database queries
* (implemented via SELECT ... LIMIT xx).
*/
static int completion_max_records;
/*
* Communication variables set by psql_completion (mostly in COMPLETE_WITH_FOO
* macros) and then used by the completion callback functions. Ugly but there
* is no better way.
*/
static char completion_last_char; /* last char of input word */
static const char *completion_charp; /* to pass a string */
static const char *const *completion_charpp; /* to pass a list of strings */
static const VersionedQuery *completion_vquery; /* to pass a VersionedQuery */
static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
static char *completion_ref_object; /* name of reference object */
static char *completion_ref_schema; /* schema name of reference object */
static bool completion_case_sensitive; /* completion is case sensitive */
static bool completion_verbatim; /* completion is verbatim */
static bool completion_force_quote; /* true to force-quote filenames */
/*
* A few macros to ease typing. You can use these to complete the given
* string with
* 1) The result from a query you pass it. (Perhaps one of those below?)
* We support both simple and versioned queries.
* 2) The result from a schema query you pass it.
* We support both simple and versioned schema queries.
* 3) The items from a null-pointer-terminated list (with or without
* case-sensitive comparison); if the list is constant you can build it
* with COMPLETE_WITH() or COMPLETE_WITH_CS(). The QUERY_LIST and
* QUERY_PLUS forms combine such literal lists with a query result.
* 4) The list of attributes of the given table (possibly schema-qualified).
* 5) The list of arguments to the given function (possibly schema-qualified).
*
* The query is generally expected to return raw SQL identifiers; matching
* to what the user typed is done in a quoting-aware fashion. If what is
* returned is not SQL identifiers, use one of the VERBATIM forms, in which
* case the query results are matched to the user's text without double-quote
* processing (so if quoting is needed, you must provide it in the query
* results).
*/
#define COMPLETE_WITH_QUERY(query) \
COMPLETE_WITH_QUERY_LIST(query, NULL)
#define COMPLETE_WITH_QUERY_LIST(query, list) \
do { \
completion_charp = query; \
completion_charpp = list; \
completion_verbatim = false; \
matches = rl_completion_matches(text, complete_from_query); \
} while (0)
#define COMPLETE_WITH_QUERY_PLUS(query, ...) \
do { \
static const char *const list[] = { __VA_ARGS__, NULL }; \
COMPLETE_WITH_QUERY_LIST(query, list); \
} while (0)
#define COMPLETE_WITH_QUERY_VERBATIM(query) \
COMPLETE_WITH_QUERY_VERBATIM_LIST(query, NULL)
#define COMPLETE_WITH_QUERY_VERBATIM_LIST(query, list) \
do { \
completion_charp = query; \
completion_charpp = list; \
completion_verbatim = true; \
matches = rl_completion_matches(text, complete_from_query); \
} while (0)
#define COMPLETE_WITH_QUERY_VERBATIM_PLUS(query, ...) \
do { \
static const char *const list[] = { __VA_ARGS__, NULL }; \
COMPLETE_WITH_QUERY_VERBATIM_LIST(query, list); \
} while (0)
#define COMPLETE_WITH_VERSIONED_QUERY(query) \
COMPLETE_WITH_VERSIONED_QUERY_LIST(query, NULL)
#define COMPLETE_WITH_VERSIONED_QUERY_LIST(query, list) \
do { \
completion_vquery = query; \
completion_charpp = list; \
completion_verbatim = false; \
matches = rl_completion_matches(text, complete_from_versioned_query); \
} while (0)
#define COMPLETE_WITH_VERSIONED_QUERY_PLUS(query, ...) \
do { \
static const char *const list[] = { __VA_ARGS__, NULL }; \
COMPLETE_WITH_VERSIONED_QUERY_LIST(query, list); \
} while (0)
#define COMPLETE_WITH_SCHEMA_QUERY(query) \
COMPLETE_WITH_SCHEMA_QUERY_LIST(query, NULL)
#define COMPLETE_WITH_SCHEMA_QUERY_LIST(query, list) \
do { \
completion_squery = &(query); \
completion_charpp = list; \
completion_verbatim = false; \
matches = rl_completion_matches(text, complete_from_schema_query); \
} while (0)
#define COMPLETE_WITH_SCHEMA_QUERY_PLUS(query, ...) \
do { \
static const char *const list[] = { __VA_ARGS__, NULL }; \
COMPLETE_WITH_SCHEMA_QUERY_LIST(query, list); \
} while (0)
#define COMPLETE_WITH_SCHEMA_QUERY_VERBATIM(query) \
do { \
completion_squery = &(query); \
completion_charpp = NULL; \
completion_verbatim = true; \
matches = rl_completion_matches(text, complete_from_schema_query); \
} while (0)
#define COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(query) \
COMPLETE_WITH_VERSIONED_SCHEMA_QUERY_LIST(query, NULL)
#define COMPLETE_WITH_VERSIONED_SCHEMA_QUERY_LIST(query, list) \
do { \
completion_squery = query; \
completion_charpp = list; \
completion_verbatim = false; \
matches = rl_completion_matches(text, complete_from_versioned_schema_query); \
} while (0)
#define COMPLETE_WITH_VERSIONED_SCHEMA_QUERY_PLUS(query, ...) \
do { \
static const char *const list[] = { __VA_ARGS__, NULL }; \
COMPLETE_WITH_VERSIONED_SCHEMA_QUERY_LIST(query, list); \
} while (0)
/*
* Caution: COMPLETE_WITH_CONST is not for general-purpose use; you probably
* want COMPLETE_WITH() with one element, instead.
*/
#define COMPLETE_WITH_CONST(cs, con) \
do { \
completion_case_sensitive = (cs); \
completion_charp = (con); \
matches = rl_completion_matches(text, complete_from_const); \
} while (0)
#define COMPLETE_WITH_LIST_INT(cs, list) \
do { \
completion_case_sensitive = (cs); \
completion_charpp = (list); \
matches = rl_completion_matches(text, complete_from_list); \
} while (0)
#define COMPLETE_WITH_LIST(list) COMPLETE_WITH_LIST_INT(false, list)
#define COMPLETE_WITH_LIST_CS(list) COMPLETE_WITH_LIST_INT(true, list)
#define COMPLETE_WITH(...) \
do { \
static const char *const list[] = { __VA_ARGS__, NULL }; \
COMPLETE_WITH_LIST(list); \
} while (0)
#define COMPLETE_WITH_CS(...) \
do { \
static const char *const list[] = { __VA_ARGS__, NULL }; \
COMPLETE_WITH_LIST_CS(list); \
} while (0)
#define COMPLETE_WITH_ATTR(relation) \
COMPLETE_WITH_ATTR_LIST(relation, NULL)
#define COMPLETE_WITH_ATTR_LIST(relation, list) \
do { \
set_completion_reference(relation); \
completion_squery = &(Query_for_list_of_attributes); \
completion_charpp = list; \
completion_verbatim = false; \
matches = rl_completion_matches(text, complete_from_schema_query); \
} while (0)
#define COMPLETE_WITH_ATTR_PLUS(relation, ...) \
do { \
static const char *const list[] = { __VA_ARGS__, NULL }; \
COMPLETE_WITH_ATTR_LIST(relation, list); \
} while (0)
/*
* libedit will typically include the literal's leading single quote in
* "text", while readline will not. Adapt our offered strings to fit.
* But include a quote if there's not one just before "text", to get the
* user off to the right start.
*/
#define COMPLETE_WITH_ENUM_VALUE(type) \
do { \
set_completion_reference(type); \
if (text[0] == '\'' || \
start == 0 || rl_line_buffer[start - 1] != '\'') \
completion_squery = &(Query_for_list_of_enum_values_quoted); \
else \
completion_squery = &(Query_for_list_of_enum_values_unquoted); \
completion_charpp = NULL; \
completion_verbatim = true; \
matches = rl_completion_matches(text, complete_from_schema_query); \
} while (0)
/*
* Timezone completion is mostly like enum label completion, but we work
* a little harder since this is a more common use-case.
*/
#define COMPLETE_WITH_TIMEZONE_NAME() \
do { \
static const char *const list[] = { "DEFAULT", NULL }; \
if (text[0] == '\'') \
completion_charp = Query_for_list_of_timezone_names_quoted_in; \
else if (start == 0 || rl_line_buffer[start - 1] != '\'') \
completion_charp = Query_for_list_of_timezone_names_quoted_out; \
else \
completion_charp = Query_for_list_of_timezone_names_unquoted; \
completion_charpp = list; \
completion_verbatim = true; \
matches = rl_completion_matches(text, complete_from_query); \
} while (0)
#define COMPLETE_WITH_FUNCTION_ARG(function) \
do { \
set_completion_reference(function); \
completion_squery = &(Query_for_list_of_arguments); \
completion_charpp = NULL; \
completion_verbatim = true; \
matches = rl_completion_matches(text, complete_from_schema_query); \
} while (0)
/*
* Assembly instructions for schema queries
*
* Note that toast tables are not included in those queries to avoid
* unnecessary bloat in the completions generated.
*/
static const SchemaQuery Query_for_constraint_of_table = {
.catname = "pg_catalog.pg_constraint con, pg_catalog.pg_class c1",
.selcondition = "con.conrelid=c1.oid",
.result = "con.conname",
.refname = "c1.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
.refnamespace = "c1.relnamespace",
};
static const SchemaQuery Query_for_constraint_of_table_not_validated = {
.catname = "pg_catalog.pg_constraint con, pg_catalog.pg_class c1",
.selcondition = "con.conrelid=c1.oid and not con.convalidated",
.result = "con.conname",
.refname = "c1.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
.refnamespace = "c1.relnamespace",
};
static const SchemaQuery Query_for_constraint_of_type = {
.catname = "pg_catalog.pg_constraint con, pg_catalog.pg_type t",
.selcondition = "con.contypid=t.oid",
.result = "con.conname",
.refname = "t.typname",
.refviscondition = "pg_catalog.pg_type_is_visible(t.oid)",
.refnamespace = "t.typnamespace",
};
static const SchemaQuery Query_for_index_of_table = {
.catname = "pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i",
.selcondition = "c1.oid=i.indrelid and i.indexrelid=c2.oid",
.result = "c2.relname",
.refname = "c1.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
.refnamespace = "c1.relnamespace",
};
static const SchemaQuery Query_for_unique_index_of_table = {
.catname = "pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i",
.selcondition = "c1.oid=i.indrelid and i.indexrelid=c2.oid and i.indisunique",
.result = "c2.relname",
.refname = "c1.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
.refnamespace = "c1.relnamespace",
};
static const SchemaQuery Query_for_list_of_aggregates[] = {
{
.min_server_version = 110000,
.catname = "pg_catalog.pg_proc p",
.selcondition = "p.prokind = 'a'",
.viscondition = "pg_catalog.pg_function_is_visible(p.oid)",
.namespace = "p.pronamespace",
.result = "p.proname",
},
{
.catname = "pg_catalog.pg_proc p",
.selcondition = "p.proisagg",
.viscondition = "pg_catalog.pg_function_is_visible(p.oid)",
.namespace = "p.pronamespace",
.result = "p.proname",
}
};
static const SchemaQuery Query_for_list_of_arguments = {
.catname = "pg_catalog.pg_proc p",
.result = "pg_catalog.oidvectortypes(p.proargtypes)||')'",
.refname = "p.proname",
.refviscondition = "pg_catalog.pg_function_is_visible(p.oid)",
.refnamespace = "p.pronamespace",
};
static const SchemaQuery Query_for_list_of_attributes = {
.catname = "pg_catalog.pg_attribute a, pg_catalog.pg_class c",
.selcondition = "c.oid = a.attrelid and a.attnum > 0 and not a.attisdropped",
.result = "a.attname",
.refname = "c.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.refnamespace = "c.relnamespace",
};
static const SchemaQuery Query_for_list_of_attribute_numbers = {
.catname = "pg_catalog.pg_attribute a, pg_catalog.pg_class c",
.selcondition = "c.oid = a.attrelid and a.attnum > 0 and not a.attisdropped",
.result = "a.attnum::pg_catalog.text",
.refname = "c.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.refnamespace = "c.relnamespace",
};
static const char *const Keywords_for_list_of_datatypes[] = {
"bigint",
"boolean",
"character",
"double precision",
"integer",
"real",
"smallint",
/*
* Note: currently there's no value in offering the following multiword
* type names, because tab completion cannot succeed for them: we can't
* disambiguate until somewhere in the second word, at which point we
* won't have the first word as context. ("double precision" does work,
* as long as no other type name begins with "double".) Leave them out to
* encourage users to use the PG-specific aliases, which we can complete.
*/
#ifdef NOT_USED
"bit varying",
"character varying",
"time with time zone",
"time without time zone",
"timestamp with time zone",
"timestamp without time zone",
#endif
NULL
};
static const SchemaQuery Query_for_list_of_datatypes = {
.catname = "pg_catalog.pg_type t",
/* selcondition --- ignore table rowtypes and array types */
.selcondition = "(t.typrelid = 0 "
" OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
" FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
"AND t.typname !~ '^_'",
.viscondition = "pg_catalog.pg_type_is_visible(t.oid)",
.namespace = "t.typnamespace",
.result = "t.typname",
.keywords = Keywords_for_list_of_datatypes,
};
static const SchemaQuery Query_for_list_of_composite_datatypes = {
.catname = "pg_catalog.pg_type t",
/* selcondition --- only get composite types */
.selcondition = "(SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
" FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) "
"AND t.typname !~ '^_'",
.viscondition = "pg_catalog.pg_type_is_visible(t.oid)",
.namespace = "t.typnamespace",
.result = "t.typname",
};
static const SchemaQuery Query_for_list_of_domains = {
.catname = "pg_catalog.pg_type t",
.selcondition = "t.typtype = 'd'",
.viscondition = "pg_catalog.pg_type_is_visible(t.oid)",
.namespace = "t.typnamespace",
.result = "t.typname",
};
static const SchemaQuery Query_for_list_of_enum_values_quoted = {
.catname = "pg_catalog.pg_enum e, pg_catalog.pg_type t",
.selcondition = "t.oid = e.enumtypid",
.result = "pg_catalog.quote_literal(enumlabel)",
.refname = "t.typname",
.refviscondition = "pg_catalog.pg_type_is_visible(t.oid)",
.refnamespace = "t.typnamespace",
};
static const SchemaQuery Query_for_list_of_enum_values_unquoted = {
.catname = "pg_catalog.pg_enum e, pg_catalog.pg_type t",
.selcondition = "t.oid = e.enumtypid",
.result = "e.enumlabel",
.refname = "t.typname",
.refviscondition = "pg_catalog.pg_type_is_visible(t.oid)",
.refnamespace = "t.typnamespace",
};
/* Note: this intentionally accepts aggregates as well as plain functions */
static const SchemaQuery Query_for_list_of_functions[] = {
{
.min_server_version = 110000,
.catname = "pg_catalog.pg_proc p",
.selcondition = "p.prokind != 'p'",
.viscondition = "pg_catalog.pg_function_is_visible(p.oid)",
.namespace = "p.pronamespace",
.result = "p.proname",
},
{
.catname = "pg_catalog.pg_proc p",
.viscondition = "pg_catalog.pg_function_is_visible(p.oid)",
.namespace = "p.pronamespace",
.result = "p.proname",
}
};
static const SchemaQuery Query_for_list_of_procedures[] = {
{
.min_server_version = 110000,
.catname = "pg_catalog.pg_proc p",
.selcondition = "p.prokind = 'p'",
.viscondition = "pg_catalog.pg_function_is_visible(p.oid)",
.namespace = "p.pronamespace",
.result = "p.proname",
},
{
/* not supported in older versions */
.catname = NULL,
}
};
static const SchemaQuery Query_for_list_of_routines = {
.catname = "pg_catalog.pg_proc p",
.viscondition = "pg_catalog.pg_function_is_visible(p.oid)",
.namespace = "p.pronamespace",
.result = "p.proname",
};
static const SchemaQuery Query_for_list_of_sequences = {
.catname = "pg_catalog.pg_class c",
.selcondition = "c.relkind IN (" CppAsString2(RELKIND_SEQUENCE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_foreign_tables = {
.catname = "pg_catalog.pg_class c",
.selcondition = "c.relkind IN (" CppAsString2(RELKIND_FOREIGN_TABLE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_tables = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_partitioned_tables = {
.catname = "pg_catalog.pg_class c",
.selcondition = "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_tables_for_constraint = {
.catname = "pg_catalog.pg_class c, pg_catalog.pg_constraint con",
.selcondition = "c.oid=con.conrelid and c.relkind IN ("
CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
.use_distinct = true,
.refname = "con.conname",
};
static const SchemaQuery Query_for_list_of_tables_for_policy = {
.catname = "pg_catalog.pg_class c, pg_catalog.pg_policy p",
.selcondition = "c.oid=p.polrelid",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
.use_distinct = true,
.refname = "p.polname",
};
static const SchemaQuery Query_for_list_of_tables_for_rule = {
.catname = "pg_catalog.pg_class c, pg_catalog.pg_rewrite r",
.selcondition = "c.oid=r.ev_class",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
.use_distinct = true,
.refname = "r.rulename",
};
static const SchemaQuery Query_for_list_of_tables_for_trigger = {
.catname = "pg_catalog.pg_class c, pg_catalog.pg_trigger t",
.selcondition = "c.oid=t.tgrelid",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
.use_distinct = true,
.refname = "t.tgname",
};
static const SchemaQuery Query_for_list_of_ts_configurations = {
.catname = "pg_catalog.pg_ts_config c",
.viscondition = "pg_catalog.pg_ts_config_is_visible(c.oid)",
.namespace = "c.cfgnamespace",
.result = "c.cfgname",
};
static const SchemaQuery Query_for_list_of_ts_dictionaries = {
.catname = "pg_catalog.pg_ts_dict d",
.viscondition = "pg_catalog.pg_ts_dict_is_visible(d.oid)",
.namespace = "d.dictnamespace",
.result = "d.dictname",
};
static const SchemaQuery Query_for_list_of_ts_parsers = {
.catname = "pg_catalog.pg_ts_parser p",
.viscondition = "pg_catalog.pg_ts_parser_is_visible(p.oid)",
.namespace = "p.prsnamespace",
.result = "p.prsname",
};
static const SchemaQuery Query_for_list_of_ts_templates = {
.catname = "pg_catalog.pg_ts_template t",
.viscondition = "pg_catalog.pg_ts_template_is_visible(t.oid)",
.namespace = "t.tmplnamespace",
.result = "t.tmplname",
};
static const SchemaQuery Query_for_list_of_views = {
.catname = "pg_catalog.pg_class c",
.selcondition = "c.relkind IN (" CppAsString2(RELKIND_VIEW) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_matviews = {
.catname = "pg_catalog.pg_class c",
.selcondition = "c.relkind IN (" CppAsString2(RELKIND_MATVIEW) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_indexes = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_INDEX) ", "
CppAsString2(RELKIND_PARTITIONED_INDEX) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_partitioned_indexes = {
.catname = "pg_catalog.pg_class c",
.selcondition = "c.relkind = " CppAsString2(RELKIND_PARTITIONED_INDEX),
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
/* All relations */
static const SchemaQuery Query_for_list_of_relations = {
.catname = "pg_catalog.pg_class c",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
/* partitioned relations */
static const SchemaQuery Query_for_list_of_partitioned_relations = {
.catname = "pg_catalog.pg_class c",
.selcondition = "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE)
", " CppAsString2(RELKIND_PARTITIONED_INDEX) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_operator_families = {
.catname = "pg_catalog.pg_opfamily c",
.viscondition = "pg_catalog.pg_opfamily_is_visible(c.oid)",
.namespace = "c.opfnamespace",
.result = "c.opfname",
};
/* Relations supporting INSERT, UPDATE or DELETE */
static const SchemaQuery Query_for_list_of_updatables = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_FOREIGN_TABLE) ", "
CppAsString2(RELKIND_VIEW) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
/* Relations supporting MERGE */
static const SchemaQuery Query_for_list_of_mergetargets = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ") ",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
/* Relations supporting SELECT */
static const SchemaQuery Query_for_list_of_selectables = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_SEQUENCE) ", "
CppAsString2(RELKIND_VIEW) ", "
CppAsString2(RELKIND_MATVIEW) ", "
CppAsString2(RELKIND_FOREIGN_TABLE) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
/* Relations supporting TRUNCATE */
static const SchemaQuery Query_for_list_of_truncatables = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_FOREIGN_TABLE) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
/* Relations supporting GRANT are currently same as those supporting SELECT */
#define Query_for_list_of_grantables Query_for_list_of_selectables
/* Relations supporting ANALYZE */
static const SchemaQuery Query_for_list_of_analyzables = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
CppAsString2(RELKIND_MATVIEW) ", "
CppAsString2(RELKIND_FOREIGN_TABLE) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
/* Relations supporting index creation */
static const SchemaQuery Query_for_list_of_indexables = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
CppAsString2(RELKIND_MATVIEW) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
/*
* Relations supporting VACUUM are currently same as those supporting
* indexing.
*/
#define Query_for_list_of_vacuumables Query_for_list_of_indexables
/* Relations supporting CLUSTER */
static const SchemaQuery Query_for_list_of_clusterables = {
.catname = "pg_catalog.pg_class c",
.selcondition =
"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
CppAsString2(RELKIND_MATVIEW) ")",
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
.namespace = "c.relnamespace",
.result = "c.relname",
};
static const SchemaQuery Query_for_list_of_constraints_with_schema = {
.catname = "pg_catalog.pg_constraint c",
.selcondition = "c.conrelid <> 0",
.namespace = "c.connamespace",
.result = "c.conname",
};
static const SchemaQuery Query_for_list_of_statistics = {
.catname = "pg_catalog.pg_statistic_ext s",
.viscondition = "pg_catalog.pg_statistics_obj_is_visible(s.oid)",
.namespace = "s.stxnamespace",
.result = "s.stxname",
};
static const SchemaQuery Query_for_list_of_collations = {
.catname = "pg_catalog.pg_collation c",
.selcondition = "c.collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding()))",
.viscondition = "pg_catalog.pg_collation_is_visible(c.oid)",
.namespace = "c.collnamespace",
.result = "c.collname",
};
static const SchemaQuery Query_for_partition_of_table = {
.catname = "pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_inherits i",
.selcondition = "c1.oid=i.inhparent and i.inhrelid=c2.oid and c2.relispartition",
.viscondition = "pg_catalog.pg_table_is_visible(c2.oid)",
.namespace = "c2.relnamespace",
.result = "c2.relname",
.refname = "c1.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
.refnamespace = "c1.relnamespace",
};
static const SchemaQuery Query_for_rule_of_table = {
.catname = "pg_catalog.pg_rewrite r, pg_catalog.pg_class c1",
.selcondition = "r.ev_class=c1.oid",
.result = "r.rulename",
.refname = "c1.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
.refnamespace = "c1.relnamespace",
};
static const SchemaQuery Query_for_trigger_of_table = {
.catname = "pg_catalog.pg_trigger t, pg_catalog.pg_class c1",
.selcondition = "t.tgrelid=c1.oid and not t.tgisinternal",
.result = "t.tgname",
.refname = "c1.relname",
.refviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
.refnamespace = "c1.relnamespace",
};
/*
* Queries to get lists of names of various kinds of things, possibly
* restricted to names matching a partially entered name. Don't use
* this method where the user might wish to enter a schema-qualified
* name; make a SchemaQuery instead.
*
* In these queries, there must be a restriction clause of the form
* output LIKE '%s'
* where "output" is the same string that the query returns. The %s
* will be replaced by a LIKE pattern to match the already-typed text.
*
* There can be a second '%s', which will be replaced by a suitably-escaped
* version of the string provided in completion_ref_object. If there is a
* third '%s', it will be replaced by a suitably-escaped version of the string
* provided in completion_ref_schema. NOTE: using completion_ref_object
* that way is usually the wrong thing, and using completion_ref_schema
* that way is always the wrong thing. Make a SchemaQuery instead.
*/
#define Query_for_list_of_template_databases \
"SELECT d.datname "\
" FROM pg_catalog.pg_database d "\
" WHERE d.datname LIKE '%s' "\
" AND (d.datistemplate OR pg_catalog.pg_has_role(d.datdba, 'USAGE'))"
#define Query_for_list_of_databases \
"SELECT datname FROM pg_catalog.pg_database "\
" WHERE datname LIKE '%s'"
#define Query_for_list_of_tablespaces \
"SELECT spcname FROM pg_catalog.pg_tablespace "\
" WHERE spcname LIKE '%s'"
#define Query_for_list_of_encodings \
" SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\