neon 2.47.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/_shared/auth_selection.js +76 -79
- package/dist/_shared/credentials.js +166 -187
- package/dist/_shared/env-core/env.js +395 -0
- package/dist/_shared/env-core/reuse-secrets.js +179 -0
- package/dist/_shared/paths.js +129 -126
- package/dist/_shared/profiles.js +192 -242
- package/dist/_shared/secure_file.js +36 -38
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/analytics.js +163 -207
- package/dist/api.js +815 -758
- package/dist/auth.js +121 -141
- package/dist/auth_context.js +39 -53
- package/dist/cli.js +4 -7
- package/dist/commands/api.js +220 -250
- package/dist/commands/api_keys.js +251 -314
- package/dist/commands/auth.js +283 -328
- package/dist/commands/bootstrap.js +372 -437
- package/dist/commands/branches.js +304 -455
- package/dist/commands/bucket.js +374 -514
- package/dist/commands/checkout.js +213 -298
- package/dist/commands/config.js +575 -658
- package/dist/commands/connection_string.js +137 -165
- package/dist/commands/data_api.js +238 -260
- package/dist/commands/databases.js +67 -76
- package/dist/commands/deploy.js +31 -25
- package/dist/commands/dev.js +642 -681
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +243 -303
- package/dist/commands/functions.js +275 -341
- package/dist/commands/index.js +70 -65
- package/dist/commands/init.js +84 -119
- package/dist/commands/inspect.js +55 -55
- package/dist/commands/ip_allow.js +88 -120
- package/dist/commands/link.js +874 -1019
- package/dist/commands/logs.js +291 -0
- package/dist/commands/neon_auth.js +725 -933
- package/dist/commands/operations.js +34 -25
- package/dist/commands/orgs.js +28 -18
- package/dist/commands/profile.js +614 -845
- package/dist/commands/projects.js +313 -373
- package/dist/commands/psql.js +60 -58
- package/dist/commands/roles.js +55 -58
- package/dist/commands/schema_diff.js +87 -131
- package/dist/commands/set_context.js +34 -26
- package/dist/commands/snapshots.js +288 -413
- package/dist/commands/status.js +41 -37
- package/dist/commands/user.js +21 -10
- package/dist/commands/vpc_endpoints.js +85 -113
- package/dist/config.js +7 -6
- package/dist/config_format.js +50 -66
- package/dist/config_template.js +128 -157
- package/dist/context.js +183 -235
- package/dist/current_branch_fast_path.js +40 -49
- package/dist/dev/env.js +313 -394
- package/dist/dev/functions.js +54 -64
- package/dist/dev/inputs.js +46 -58
- package/dist/dev/runtime.js +135 -164
- package/dist/dev/websocket.js +766 -959
- package/dist/env.js +27 -33
- package/dist/env_file.js +118 -132
- package/dist/env_services.js +36 -38
- package/dist/errors.js +57 -68
- package/dist/functions_api.js +45 -43
- package/dist/help.js +189 -140
- package/dist/index.js +182 -257
- package/dist/init/agents.js +137 -118
- package/dist/init/auth.js +58 -68
- package/dist/init/bootstrap.js +325 -396
- package/dist/init/build_config.js +4 -2
- package/dist/init/detect_agent.js +56 -101
- package/dist/init/editors.js +35 -52
- package/dist/init/enrich_output.js +51 -66
- package/dist/init/extension.js +134 -171
- package/dist/init/inspect.js +179 -266
- package/dist/init/interactive.js +510 -622
- package/dist/init/neonctl.js +117 -168
- package/dist/init/orchestrate.js +157 -173
- package/dist/init/phases/auth.js +188 -202
- package/dist/init/phases/cleanup.js +23 -23
- package/dist/init/phases/db.js +251 -277
- package/dist/init/phases/getting_started.js +213 -223
- package/dist/init/phases/mcp.js +174 -224
- package/dist/init/phases/migrations.js +247 -248
- package/dist/init/phases/neon_auth.js +114 -133
- package/dist/init/phases/setup.js +546 -703
- package/dist/init/phases/skills.js +75 -86
- package/dist/init/phases/status.js +72 -67
- package/dist/init/resolve_context.js +102 -99
- package/dist/init/route_command.js +91 -98
- package/dist/init/skills.js +174 -218
- package/dist/init/vsix.js +77 -99
- package/dist/log.js +17 -16
- package/dist/neon_services.js +104 -129
- package/dist/parameters.gen.js +481 -471
- package/dist/pkg.js +17 -19
- package/dist/profile_keys.js +44 -47
- package/dist/psql/cli.js +44 -47
- package/dist/psql/command/cmd_cond.js +231 -406
- package/dist/psql/command/cmd_connect.js +557 -764
- package/dist/psql/command/cmd_copy.js +727 -983
- package/dist/psql/command/cmd_describe.js +1499 -1688
- package/dist/psql/command/cmd_format.js +733 -905
- package/dist/psql/command/cmd_io.js +1293 -2082
- package/dist/psql/command/cmd_lo.js +297 -359
- package/dist/psql/command/cmd_meta.js +727 -878
- package/dist/psql/command/cmd_misc.js +138 -172
- package/dist/psql/command/cmd_pipeline.js +547 -1099
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +261 -325
- package/dist/psql/command/inputQueue.js +35 -33
- package/dist/psql/command/shared.js +49 -63
- package/dist/psql/complete/filenames.js +90 -133
- package/dist/psql/complete/index.js +59 -97
- package/dist/psql/complete/matcher.js +236 -300
- package/dist/psql/complete/psqlVars.js +218 -223
- package/dist/psql/complete/queries.js +159 -177
- package/dist/psql/complete/rules.js +1493 -2299
- package/dist/psql/core/common.js +762 -1180
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1302
- package/dist/psql/core/prompt.js +391 -408
- package/dist/psql/core/settings.js +429 -644
- package/dist/psql/core/sqlHelp.js +480 -554
- package/dist/psql/core/startup.js +626 -815
- package/dist/psql/core/syncVars.js +67 -110
- package/dist/psql/core/variables.js +156 -278
- package/dist/psql/describe/formatters.js +884 -1285
- package/dist/psql/describe/processNamePattern.js +173 -260
- package/dist/psql/describe/queries.js +1368 -2403
- package/dist/psql/describe/versionGate.js +32 -41
- package/dist/psql/index.js +1414 -1927
- package/dist/psql/io/history.js +232 -271
- package/dist/psql/io/input.js +103 -108
- package/dist/psql/io/lineEditor/buffer.js +238 -319
- package/dist/psql/io/lineEditor/complete.js +135 -213
- package/dist/psql/io/lineEditor/filename.js +139 -148
- package/dist/psql/io/lineEditor/index.js +653 -870
- package/dist/psql/io/lineEditor/keymap.js +544 -702
- package/dist/psql/io/lineEditor/vt100.js +294 -341
- package/dist/psql/io/pgpass.js +158 -187
- package/dist/psql/io/pgservice.js +146 -183
- package/dist/psql/io/psqlrc.js +328 -403
- package/dist/psql/print/aligned.js +1020 -1683
- package/dist/psql/print/asciidoc.js +180 -214
- package/dist/psql/print/crosstab.js +281 -442
- package/dist/psql/print/csv.js +48 -70
- package/dist/psql/print/html.js +195 -226
- package/dist/psql/print/json.js +75 -88
- package/dist/psql/print/latex.js +291 -364
- package/dist/psql/print/pager.js +171 -242
- package/dist/psql/print/troff.js +194 -226
- package/dist/psql/print/unaligned.js +69 -95
- package/dist/psql/print/units.js +167 -169
- package/dist/psql/scanner/slash.js +428 -483
- package/dist/psql/scanner/sql.js +445 -889
- package/dist/psql/scanner/stringutils.js +309 -379
- package/dist/psql/types/index.js +2 -7
- package/dist/psql/types/scanner.js +25 -22
- package/dist/psql/wire/connection.js +2042 -2803
- package/dist/psql/wire/copy.js +84 -100
- package/dist/psql/wire/notify.js +39 -59
- package/dist/psql/wire/pipeline.js +305 -518
- package/dist/psql/wire/protocol.js +349 -417
- package/dist/psql/wire/sasl.js +180 -265
- package/dist/psql/wire/tls.js +400 -561
- package/dist/storage_api.js +115 -129
- package/dist/test_utils/fixtures.js +94 -113
- package/dist/test_utils/oauth_server.js +10 -7
- package/dist/test_utils/project_dir.js +33 -0
- package/dist/utils/ai_gateway_notice.js +131 -162
- package/dist/utils/api_enums.js +21 -28
- package/dist/utils/auth.js +10 -4
- package/dist/utils/branch_notice.js +20 -19
- package/dist/utils/branch_picker.js +83 -89
- package/dist/utils/cli_name.js +15 -12
- package/dist/utils/compute_units.js +20 -27
- package/dist/utils/config_diff.js +127 -158
- package/dist/utils/enrichers.js +95 -148
- package/dist/utils/esbuild.js +133 -147
- package/dist/utils/flags.js +35 -47
- package/dist/utils/formats.js +8 -15
- package/dist/utils/git_diff.js +69 -80
- package/dist/utils/inspect_db.js +101 -143
- package/dist/utils/inspect_queries.js +179 -142
- package/dist/utils/middlewares.js +37 -44
- package/dist/utils/openapi.js +87 -99
- package/dist/utils/package_manager.js +312 -110
- package/dist/utils/point_in_time.js +49 -53
- package/dist/utils/psql.js +89 -106
- package/dist/utils/service_picker.js +55 -58
- package/dist/utils/string.js +5 -5
- package/dist/utils/ui.js +38 -55
- package/dist/utils/write_sync.js +26 -35
- package/dist/utils/zip.js +4 -3
- package/dist/writer.js +67 -87
- package/package.json +9 -7
|
@@ -1,2424 +1,1618 @@
|
|
|
1
|
-
|
|
2
|
-
* Tab-completion rule body.
|
|
3
|
-
*
|
|
4
|
-
* Port (selective — see "Coverage" below) of psql's `psql_completion()`
|
|
5
|
-
* from `src/bin/psql/tab-complete.in.c`. Given the tokenized "previous
|
|
6
|
-
* words" and the in-progress current word, we walk a chain of
|
|
7
|
-
* Matches/TailMatches/HeadMatches guards and return:
|
|
8
|
-
*
|
|
9
|
-
* - a STATIC list (for keyword / enum-value completion), filtered by the
|
|
10
|
-
* current word's prefix, OR
|
|
11
|
-
* - a CATALOG query (for table/view/role/schema/etc.) executed against
|
|
12
|
-
* the live Connection.
|
|
13
|
-
*
|
|
14
|
-
* Coverage (the parts of upstream we ship):
|
|
15
|
-
*
|
|
16
|
-
* - Backslash command name completion: `\` → list of commands.
|
|
17
|
-
* - Backslash arg completion for the high-traffic commands: `\c[onnect]`,
|
|
18
|
-
* `\dt`/`\d`/`\dv`/`\dm`/`\di`/`\ds`, `\df`, `\dn`, `\du`/`\dg`,
|
|
19
|
-
* `\dx`, `\dL`, `\dT`, `\do` (operators), `\dC` (casts), `\encoding`,
|
|
20
|
-
* `\pset`, `\set`.
|
|
21
|
-
* - Top-level SQL keyword set (SELECT/INSERT/UPDATE/DELETE/etc).
|
|
22
|
-
* - Mid-statement object completion in the most common contexts:
|
|
23
|
-
* FROM → tables/views/matviews/foreign tables.
|
|
24
|
-
* INTO (INSERT) → tables.
|
|
25
|
-
* JOIN → tables/views/matviews.
|
|
26
|
-
* UPDATE → tables.
|
|
27
|
-
* DELETE FROM → tables.
|
|
28
|
-
* ALTER TABLE → tables, then sub-action (ADD/DROP/…),
|
|
29
|
-
* then sub-action continuation (COLUMN/CONSTRAINT/…).
|
|
30
|
-
* ALTER VIEW → views + sub-actions.
|
|
31
|
-
* ALTER MATERIALIZED VIEW → mat-views + sub-actions.
|
|
32
|
-
* ALTER INDEX → indexes + sub-actions.
|
|
33
|
-
* ALTER SEQUENCE → sequences + sub-actions.
|
|
34
|
-
* ALTER FUNCTION / PROCEDURE / ROUTINE → functions + sub-actions.
|
|
35
|
-
* ALTER TYPE → types + sub-actions.
|
|
36
|
-
* ALTER ROLE/USER → roles + sub-actions.
|
|
37
|
-
* ALTER DATABASE → databases + sub-actions.
|
|
38
|
-
* ALTER SCHEMA → schemas + sub-actions.
|
|
39
|
-
* ALTER EXTENSION → extensions + sub-actions.
|
|
40
|
-
* ALTER POLICY → ON <table>, rename/owner.
|
|
41
|
-
* ALTER PUBLICATION / SUBSCRIPTION → sub-actions.
|
|
42
|
-
* DROP TABLE → tables.
|
|
43
|
-
* DROP VIEW → views.
|
|
44
|
-
* DROP INDEX → indexes.
|
|
45
|
-
* DROP MATERIALIZED VIEW → mat views.
|
|
46
|
-
* DROP SEQUENCE → sequences.
|
|
47
|
-
* DROP TYPE → types.
|
|
48
|
-
* DROP SCHEMA → schemas.
|
|
49
|
-
* DROP EXTENSION → extensions.
|
|
50
|
-
* DROP ROLE / USER → roles.
|
|
51
|
-
* DROP DATABASE → databases.
|
|
52
|
-
* DROP FUNCTION → functions.
|
|
53
|
-
* CREATE INDEX → CONCURRENTLY / IF NOT EXISTS / ON / USING (access methods).
|
|
54
|
-
* GRANT / REVOKE … ON … → tables.
|
|
55
|
-
* TRUNCATE [TABLE] → tables.
|
|
56
|
-
* LOCK TABLE → tables.
|
|
57
|
-
* COPY → tables.
|
|
58
|
-
* ANALYZE / VACUUM → tables.
|
|
59
|
-
* REINDEX → indexes/tables/databases (limited).
|
|
60
|
-
* SET <guc> → list of GUC names from pg_settings.
|
|
61
|
-
* SET ROLE → roles.
|
|
62
|
-
* SET SCHEMA → schemas.
|
|
63
|
-
* SHOW <guc> → list of GUC names from pg_settings.
|
|
64
|
-
* RESET <guc> → list of GUC names from pg_settings.
|
|
65
|
-
*
|
|
66
|
-
* - Window-function clauses: `OVER (` → PARTITION BY / ORDER BY / RANGE /
|
|
67
|
-
* ROWS / GROUPS.
|
|
68
|
-
* - Generic post-FROM/JOIN tail keywords: JOIN, WHERE, GROUP BY, ORDER BY,
|
|
69
|
-
* LIMIT, OFFSET, UNION, INTERSECT, EXCEPT, etc.
|
|
70
|
-
* - WHERE-expression continuations: AND / OR / IS / IN / NOT / BETWEEN.
|
|
71
|
-
* - `\set`/`\unset`: completion of psql variable names.
|
|
72
|
-
* - Variable expansion `:NAME` completion (inside any line).
|
|
73
|
-
*
|
|
74
|
-
* Upstream coverage notes (psql `tab-complete.in.c`):
|
|
75
|
-
* - We ported the ALTER-OBJECT arms around lines 2050-2700 (sub-actions
|
|
76
|
-
* for TABLE/VIEW/MV/INDEX/SEQUENCE/FUNCTION/TYPE/ROLE/DB/SCHEMA/
|
|
77
|
-
* EXTENSION/POLICY/PUBLICATION/SUBSCRIPTION) but elided the deep
|
|
78
|
-
* option-value continuations (e.g. ALTER TABLE … ADD CONSTRAINT …
|
|
79
|
-
* CHECK (…)) and partition-bound clauses.
|
|
80
|
-
* - We ported the post-FROM / JOIN tail-keyword set from lines ~4500-4700.
|
|
81
|
-
* - We ported the SET/SHOW/RESET GUC lookup from lines ~5500-5700, using
|
|
82
|
-
* a live pg_settings query rather than a static list.
|
|
83
|
-
* - We ported the CREATE INDEX block at ~3000-3100.
|
|
84
|
-
* - Skipped: ALTER-system fine-grained options, COMMENT ON full grammar,
|
|
85
|
-
* CREATE STATISTICS, CREATE EVENT TRIGGER bodies, FDW/USER MAPPING
|
|
86
|
-
* argument grammar, and most GRANT/REVOKE class continuations beyond
|
|
87
|
-
* the table object form.
|
|
88
|
-
*
|
|
89
|
-
* What's intentionally still stubbed:
|
|
90
|
-
*
|
|
91
|
-
* - psql `\h` SQL help index — exists in psql proper, would need the
|
|
92
|
-
* help index data.
|
|
93
|
-
* - Column-name completion after `SELECT … FROM t WHERE` (we don't carry
|
|
94
|
-
* a parsed alias→relation map; upstream parses the FROM clause).
|
|
95
|
-
*
|
|
96
|
-
* The shape mirrors the C source closely enough that adding new rules is
|
|
97
|
-
* mechanical: drop a new `if (TailMatches(...))` arm in the right region.
|
|
98
|
-
*/
|
|
1
|
+
import { HeadMatches, TailMatches, tokenize } from "./matcher.js";
|
|
99
2
|
import { completeFilenames, isCopyFromOrTo } from "./filenames.js";
|
|
100
|
-
import {
|
|
101
|
-
import {
|
|
102
|
-
|
|
3
|
+
import { ENCODINGS, PSET_OPTIONS, SPECIAL_VARIABLES, psetValuesFor, variableValuesFor } from "./psqlVars.js";
|
|
4
|
+
import { Query_for_constraint_of_table, Query_for_constraint_of_table_in_schema, Query_for_list_of_casts, Query_for_list_of_databases, Query_for_list_of_datatypes, Query_for_list_of_enum_values_quoted, Query_for_list_of_extensions, Query_for_list_of_functions, Query_for_list_of_index_access_methods, Query_for_list_of_indexes, Query_for_list_of_languages, Query_for_list_of_matviews, Query_for_list_of_operators, Query_for_list_of_publications, Query_for_list_of_relations_in_schema, Query_for_list_of_roles, Query_for_list_of_schemas, Query_for_list_of_sequences, Query_for_list_of_set_vars, Query_for_list_of_subscriptions, Query_for_list_of_tables, Query_for_list_of_tables_for_constraint, Query_for_list_of_tables_for_constraint_in_schema, Query_for_list_of_tables_views, Query_for_list_of_tablespaces, Query_for_list_of_timezone_names_quoted_in, Query_for_list_of_timezone_names_quoted_out, Query_for_list_of_types, Query_for_list_of_views, Query_for_values_of_enum_GUC, runCatalogQuery } from "./queries.js";
|
|
5
|
+
//#region src/psql/complete/rules.ts
|
|
103
6
|
/** Backslash command names psql tab-completes (mirrors backslash_commands[]). */
|
|
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
|
-
|
|
7
|
+
const BACKSLASH_COMMANDS = [
|
|
8
|
+
"\\a",
|
|
9
|
+
"\\bind",
|
|
10
|
+
"\\bind_named",
|
|
11
|
+
"\\c",
|
|
12
|
+
"\\C",
|
|
13
|
+
"\\cd",
|
|
14
|
+
"\\close_prepared",
|
|
15
|
+
"\\conninfo",
|
|
16
|
+
"\\connect",
|
|
17
|
+
"\\copy",
|
|
18
|
+
"\\copyright",
|
|
19
|
+
"\\crosstabview",
|
|
20
|
+
"\\d",
|
|
21
|
+
"\\dA",
|
|
22
|
+
"\\dAc",
|
|
23
|
+
"\\dAf",
|
|
24
|
+
"\\dAo",
|
|
25
|
+
"\\dAp",
|
|
26
|
+
"\\da",
|
|
27
|
+
"\\db",
|
|
28
|
+
"\\dC",
|
|
29
|
+
"\\dc",
|
|
30
|
+
"\\dconfig",
|
|
31
|
+
"\\dD",
|
|
32
|
+
"\\dd",
|
|
33
|
+
"\\ddp",
|
|
34
|
+
"\\dE",
|
|
35
|
+
"\\des",
|
|
36
|
+
"\\det",
|
|
37
|
+
"\\deu",
|
|
38
|
+
"\\dew",
|
|
39
|
+
"\\df",
|
|
40
|
+
"\\dF",
|
|
41
|
+
"\\dFd",
|
|
42
|
+
"\\dFp",
|
|
43
|
+
"\\dFt",
|
|
44
|
+
"\\dg",
|
|
45
|
+
"\\di",
|
|
46
|
+
"\\dl",
|
|
47
|
+
"\\dL",
|
|
48
|
+
"\\dm",
|
|
49
|
+
"\\dn",
|
|
50
|
+
"\\do",
|
|
51
|
+
"\\dO",
|
|
52
|
+
"\\dp",
|
|
53
|
+
"\\dP",
|
|
54
|
+
"\\dPi",
|
|
55
|
+
"\\dPt",
|
|
56
|
+
"\\drds",
|
|
57
|
+
"\\drg",
|
|
58
|
+
"\\dRs",
|
|
59
|
+
"\\dRp",
|
|
60
|
+
"\\ds",
|
|
61
|
+
"\\dt",
|
|
62
|
+
"\\dT",
|
|
63
|
+
"\\dv",
|
|
64
|
+
"\\du",
|
|
65
|
+
"\\dx",
|
|
66
|
+
"\\dX",
|
|
67
|
+
"\\dy",
|
|
68
|
+
"\\echo",
|
|
69
|
+
"\\edit",
|
|
70
|
+
"\\ef",
|
|
71
|
+
"\\elif",
|
|
72
|
+
"\\else",
|
|
73
|
+
"\\encoding",
|
|
74
|
+
"\\endif",
|
|
75
|
+
"\\endpipeline",
|
|
76
|
+
"\\errverbose",
|
|
77
|
+
"\\ev",
|
|
78
|
+
"\\f",
|
|
79
|
+
"\\flush",
|
|
80
|
+
"\\flushrequest",
|
|
81
|
+
"\\g",
|
|
82
|
+
"\\gdesc",
|
|
83
|
+
"\\getenv",
|
|
84
|
+
"\\getresults",
|
|
85
|
+
"\\gexec",
|
|
86
|
+
"\\gset",
|
|
87
|
+
"\\gx",
|
|
88
|
+
"\\help",
|
|
89
|
+
"\\html",
|
|
90
|
+
"\\if",
|
|
91
|
+
"\\include",
|
|
92
|
+
"\\include_relative",
|
|
93
|
+
"\\ir",
|
|
94
|
+
"\\l",
|
|
95
|
+
"\\list",
|
|
96
|
+
"\\lo_export",
|
|
97
|
+
"\\lo_import",
|
|
98
|
+
"\\lo_list",
|
|
99
|
+
"\\lo_unlink",
|
|
100
|
+
"\\o",
|
|
101
|
+
"\\out",
|
|
102
|
+
"\\parse",
|
|
103
|
+
"\\password",
|
|
104
|
+
"\\print",
|
|
105
|
+
"\\prompt",
|
|
106
|
+
"\\pset",
|
|
107
|
+
"\\q",
|
|
108
|
+
"\\qecho",
|
|
109
|
+
"\\quit",
|
|
110
|
+
"\\reset",
|
|
111
|
+
"\\restrict",
|
|
112
|
+
"\\s",
|
|
113
|
+
"\\sendpipeline",
|
|
114
|
+
"\\set",
|
|
115
|
+
"\\setenv",
|
|
116
|
+
"\\sf",
|
|
117
|
+
"\\startpipeline",
|
|
118
|
+
"\\sv",
|
|
119
|
+
"\\syncpipeline",
|
|
120
|
+
"\\t",
|
|
121
|
+
"\\T",
|
|
122
|
+
"\\timing",
|
|
123
|
+
"\\unrestrict",
|
|
124
|
+
"\\unset",
|
|
125
|
+
"\\w",
|
|
126
|
+
"\\warn",
|
|
127
|
+
"\\watch",
|
|
128
|
+
"\\write",
|
|
129
|
+
"\\x",
|
|
130
|
+
"\\z",
|
|
131
|
+
"\\!",
|
|
132
|
+
"\\?"
|
|
230
133
|
];
|
|
231
134
|
/** Top-level SQL statement keywords. */
|
|
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
|
-
|
|
135
|
+
const SQL_TOP_KEYWORDS = [
|
|
136
|
+
"ABORT",
|
|
137
|
+
"ALTER",
|
|
138
|
+
"ANALYZE",
|
|
139
|
+
"BEGIN",
|
|
140
|
+
"CALL",
|
|
141
|
+
"CHECKPOINT",
|
|
142
|
+
"CLOSE",
|
|
143
|
+
"CLUSTER",
|
|
144
|
+
"COMMENT",
|
|
145
|
+
"COMMIT",
|
|
146
|
+
"COPY",
|
|
147
|
+
"CREATE",
|
|
148
|
+
"DEALLOCATE",
|
|
149
|
+
"DECLARE",
|
|
150
|
+
"DELETE FROM",
|
|
151
|
+
"DISCARD",
|
|
152
|
+
"DO",
|
|
153
|
+
"DROP",
|
|
154
|
+
"END",
|
|
155
|
+
"EXECUTE",
|
|
156
|
+
"EXPLAIN",
|
|
157
|
+
"FETCH",
|
|
158
|
+
"GRANT",
|
|
159
|
+
"IMPORT",
|
|
160
|
+
"INSERT INTO",
|
|
161
|
+
"LISTEN",
|
|
162
|
+
"LOAD",
|
|
163
|
+
"LOCK",
|
|
164
|
+
"MERGE",
|
|
165
|
+
"MOVE",
|
|
166
|
+
"NOTIFY",
|
|
167
|
+
"PREPARE",
|
|
168
|
+
"REASSIGN",
|
|
169
|
+
"REFRESH MATERIALIZED VIEW",
|
|
170
|
+
"REINDEX",
|
|
171
|
+
"RELEASE",
|
|
172
|
+
"RESET",
|
|
173
|
+
"REVOKE",
|
|
174
|
+
"ROLLBACK",
|
|
175
|
+
"SAVEPOINT",
|
|
176
|
+
"SECURITY LABEL",
|
|
177
|
+
"SELECT",
|
|
178
|
+
"SET",
|
|
179
|
+
"SHOW",
|
|
180
|
+
"START TRANSACTION",
|
|
181
|
+
"TABLE",
|
|
182
|
+
"TRUNCATE",
|
|
183
|
+
"UNLISTEN",
|
|
184
|
+
"UPDATE",
|
|
185
|
+
"VACUUM",
|
|
186
|
+
"VALUES",
|
|
187
|
+
"WITH"
|
|
285
188
|
];
|
|
286
189
|
/** Keywords accepted after CREATE. */
|
|
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
|
-
|
|
190
|
+
const CREATE_OBJECTS = [
|
|
191
|
+
"ACCESS METHOD",
|
|
192
|
+
"AGGREGATE",
|
|
193
|
+
"CAST",
|
|
194
|
+
"COLLATION",
|
|
195
|
+
"CONVERSION",
|
|
196
|
+
"DATABASE",
|
|
197
|
+
"DEFAULT PRIVILEGES",
|
|
198
|
+
"DOMAIN",
|
|
199
|
+
"EVENT TRIGGER",
|
|
200
|
+
"EXTENSION",
|
|
201
|
+
"FOREIGN DATA WRAPPER",
|
|
202
|
+
"FOREIGN TABLE",
|
|
203
|
+
"FUNCTION",
|
|
204
|
+
"GLOBAL",
|
|
205
|
+
"GROUP",
|
|
206
|
+
"INDEX",
|
|
207
|
+
"LANGUAGE",
|
|
208
|
+
"LOCAL",
|
|
209
|
+
"MATERIALIZED VIEW",
|
|
210
|
+
"OPERATOR",
|
|
211
|
+
"OR REPLACE",
|
|
212
|
+
"POLICY",
|
|
213
|
+
"PROCEDURE",
|
|
214
|
+
"PUBLICATION",
|
|
215
|
+
"ROLE",
|
|
216
|
+
"RULE",
|
|
217
|
+
"SCHEMA",
|
|
218
|
+
"SEQUENCE",
|
|
219
|
+
"SERVER",
|
|
220
|
+
"STATISTICS",
|
|
221
|
+
"SUBSCRIPTION",
|
|
222
|
+
"TABLE",
|
|
223
|
+
"TABLESPACE",
|
|
224
|
+
"TEMP",
|
|
225
|
+
"TEMPORARY",
|
|
226
|
+
"TEXT SEARCH",
|
|
227
|
+
"TRANSFORM",
|
|
228
|
+
"TRIGGER",
|
|
229
|
+
"TYPE",
|
|
230
|
+
"UNIQUE",
|
|
231
|
+
"UNLOGGED",
|
|
232
|
+
"USER",
|
|
233
|
+
"VIEW"
|
|
331
234
|
];
|
|
332
235
|
/** Keywords accepted after DROP. */
|
|
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
|
-
|
|
236
|
+
const DROP_OBJECTS = [
|
|
237
|
+
"ACCESS METHOD",
|
|
238
|
+
"AGGREGATE",
|
|
239
|
+
"CAST",
|
|
240
|
+
"COLLATION",
|
|
241
|
+
"CONVERSION",
|
|
242
|
+
"DATABASE",
|
|
243
|
+
"DOMAIN",
|
|
244
|
+
"EVENT TRIGGER",
|
|
245
|
+
"EXTENSION",
|
|
246
|
+
"FOREIGN DATA WRAPPER",
|
|
247
|
+
"FOREIGN TABLE",
|
|
248
|
+
"FUNCTION",
|
|
249
|
+
"GROUP",
|
|
250
|
+
"INDEX",
|
|
251
|
+
"LANGUAGE",
|
|
252
|
+
"MATERIALIZED VIEW",
|
|
253
|
+
"OPERATOR",
|
|
254
|
+
"OWNED",
|
|
255
|
+
"POLICY",
|
|
256
|
+
"PROCEDURE",
|
|
257
|
+
"PUBLICATION",
|
|
258
|
+
"ROLE",
|
|
259
|
+
"RULE",
|
|
260
|
+
"SCHEMA",
|
|
261
|
+
"SEQUENCE",
|
|
262
|
+
"SERVER",
|
|
263
|
+
"STATISTICS",
|
|
264
|
+
"SUBSCRIPTION",
|
|
265
|
+
"TABLE",
|
|
266
|
+
"TABLESPACE",
|
|
267
|
+
"TEXT SEARCH",
|
|
268
|
+
"TRANSFORM",
|
|
269
|
+
"TRIGGER",
|
|
270
|
+
"TYPE",
|
|
271
|
+
"USER",
|
|
272
|
+
"VIEW"
|
|
370
273
|
];
|
|
371
274
|
/** Keywords accepted after ALTER. */
|
|
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
|
-
|
|
275
|
+
const ALTER_OBJECTS = [
|
|
276
|
+
"AGGREGATE",
|
|
277
|
+
"COLLATION",
|
|
278
|
+
"CONVERSION",
|
|
279
|
+
"DATABASE",
|
|
280
|
+
"DEFAULT PRIVILEGES",
|
|
281
|
+
"DOMAIN",
|
|
282
|
+
"EVENT TRIGGER",
|
|
283
|
+
"EXTENSION",
|
|
284
|
+
"FOREIGN DATA WRAPPER",
|
|
285
|
+
"FOREIGN TABLE",
|
|
286
|
+
"FUNCTION",
|
|
287
|
+
"GROUP",
|
|
288
|
+
"INDEX",
|
|
289
|
+
"LANGUAGE",
|
|
290
|
+
"LARGE OBJECT",
|
|
291
|
+
"MATERIALIZED VIEW",
|
|
292
|
+
"OPERATOR",
|
|
293
|
+
"POLICY",
|
|
294
|
+
"PROCEDURE",
|
|
295
|
+
"PUBLICATION",
|
|
296
|
+
"ROLE",
|
|
297
|
+
"RULE",
|
|
298
|
+
"SCHEMA",
|
|
299
|
+
"SEQUENCE",
|
|
300
|
+
"SERVER",
|
|
301
|
+
"STATISTICS",
|
|
302
|
+
"SUBSCRIPTION",
|
|
303
|
+
"SYSTEM",
|
|
304
|
+
"TABLE",
|
|
305
|
+
"TABLESPACE",
|
|
306
|
+
"TEXT SEARCH",
|
|
307
|
+
"TRIGGER",
|
|
308
|
+
"TYPE",
|
|
309
|
+
"USER",
|
|
310
|
+
"VIEW"
|
|
408
311
|
];
|
|
409
312
|
/** Sub-actions for ALTER TABLE. */
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
313
|
+
const ALTER_TABLE_ACTIONS = [
|
|
314
|
+
"ADD",
|
|
315
|
+
"ALTER",
|
|
316
|
+
"ATTACH PARTITION",
|
|
317
|
+
"CLUSTER ON",
|
|
318
|
+
"DETACH PARTITION",
|
|
319
|
+
"DISABLE",
|
|
320
|
+
"DROP",
|
|
321
|
+
"ENABLE",
|
|
322
|
+
"INHERIT",
|
|
323
|
+
"NO INHERIT",
|
|
324
|
+
"OF",
|
|
325
|
+
"NOT OF",
|
|
326
|
+
"OWNER TO",
|
|
327
|
+
"RENAME",
|
|
328
|
+
"REPLICA IDENTITY",
|
|
329
|
+
"RESET",
|
|
330
|
+
"SET",
|
|
331
|
+
"VALIDATE CONSTRAINT"
|
|
429
332
|
];
|
|
430
333
|
/** Continuation after `ALTER TABLE x ADD`. */
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
334
|
+
const ALTER_TABLE_ADD = [
|
|
335
|
+
"COLUMN",
|
|
336
|
+
"CONSTRAINT",
|
|
337
|
+
"CHECK",
|
|
338
|
+
"FOREIGN KEY",
|
|
339
|
+
"PRIMARY KEY",
|
|
340
|
+
"UNIQUE",
|
|
341
|
+
"EXCLUDE"
|
|
439
342
|
];
|
|
440
343
|
/** Continuation after `ALTER TABLE x ALTER [COLUMN] y`. */
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
344
|
+
const ALTER_TABLE_ALTER_COLUMN = [
|
|
345
|
+
"ADD GENERATED",
|
|
346
|
+
"DROP DEFAULT",
|
|
347
|
+
"DROP EXPRESSION",
|
|
348
|
+
"DROP IDENTITY",
|
|
349
|
+
"DROP NOT NULL",
|
|
350
|
+
"RESET",
|
|
351
|
+
"RESTART",
|
|
352
|
+
"SET",
|
|
353
|
+
"SET DATA TYPE",
|
|
354
|
+
"SET DEFAULT",
|
|
355
|
+
"SET EXPRESSION",
|
|
356
|
+
"SET GENERATED",
|
|
357
|
+
"SET NOT NULL",
|
|
358
|
+
"SET STATISTICS",
|
|
359
|
+
"SET STORAGE",
|
|
360
|
+
"TYPE"
|
|
458
361
|
];
|
|
459
362
|
/** Continuation after `ALTER TABLE x DROP`. */
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
363
|
+
const ALTER_TABLE_DROP = [
|
|
364
|
+
"COLUMN",
|
|
365
|
+
"CONSTRAINT",
|
|
366
|
+
"IF EXISTS"
|
|
464
367
|
];
|
|
465
368
|
/** Continuation after `ALTER TABLE x RENAME`. */
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
369
|
+
const ALTER_TABLE_RENAME = [
|
|
370
|
+
"COLUMN",
|
|
371
|
+
"CONSTRAINT",
|
|
372
|
+
"TO"
|
|
470
373
|
];
|
|
471
374
|
/** Continuation after `ALTER TABLE x SET`. */
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
375
|
+
const ALTER_TABLE_SET = [
|
|
376
|
+
"(",
|
|
377
|
+
"LOGGED",
|
|
378
|
+
"SCHEMA",
|
|
379
|
+
"TABLESPACE",
|
|
380
|
+
"UNLOGGED",
|
|
381
|
+
"WITHOUT CLUSTER",
|
|
382
|
+
"WITHOUT OIDS"
|
|
480
383
|
];
|
|
481
384
|
/** Continuation after `ALTER TABLE x ENABLE`. */
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
385
|
+
const ALTER_TABLE_ENABLE = [
|
|
386
|
+
"ALWAYS",
|
|
387
|
+
"REPLICA",
|
|
388
|
+
"ROW LEVEL SECURITY",
|
|
389
|
+
"RULE",
|
|
390
|
+
"TRIGGER"
|
|
488
391
|
];
|
|
489
392
|
/** Continuation after `ALTER TABLE x DISABLE`. */
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
393
|
+
const ALTER_TABLE_DISABLE = [
|
|
394
|
+
"ROW LEVEL SECURITY",
|
|
395
|
+
"RULE",
|
|
396
|
+
"TRIGGER"
|
|
494
397
|
];
|
|
495
398
|
/** Continuation after `ALTER TABLE x REPLICA IDENTITY`. */
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
399
|
+
const ALTER_TABLE_REPLICA_IDENTITY = [
|
|
400
|
+
"DEFAULT",
|
|
401
|
+
"FULL",
|
|
402
|
+
"NOTHING",
|
|
403
|
+
"USING INDEX"
|
|
501
404
|
];
|
|
502
405
|
/** Sub-actions for ALTER VIEW. */
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
406
|
+
const ALTER_VIEW_ACTIONS = [
|
|
407
|
+
"ALTER",
|
|
408
|
+
"OWNER TO",
|
|
409
|
+
"RENAME",
|
|
410
|
+
"RESET",
|
|
411
|
+
"SET"
|
|
509
412
|
];
|
|
510
413
|
/** Sub-actions for ALTER MATERIALIZED VIEW. */
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
414
|
+
const ALTER_MATVIEW_ACTIONS = [
|
|
415
|
+
"ALTER",
|
|
416
|
+
"CLUSTER ON",
|
|
417
|
+
"DEPENDS ON EXTENSION",
|
|
418
|
+
"NO DEPENDS ON EXTENSION",
|
|
419
|
+
"OWNER TO",
|
|
420
|
+
"RENAME",
|
|
421
|
+
"RESET",
|
|
422
|
+
"SET"
|
|
520
423
|
];
|
|
521
424
|
/** Sub-actions for ALTER INDEX. */
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
425
|
+
const ALTER_INDEX_ACTIONS = [
|
|
426
|
+
"ALTER COLUMN",
|
|
427
|
+
"ATTACH PARTITION",
|
|
428
|
+
"DEPENDS ON EXTENSION",
|
|
429
|
+
"NO DEPENDS ON EXTENSION",
|
|
430
|
+
"OWNER TO",
|
|
431
|
+
"RENAME",
|
|
432
|
+
"RESET",
|
|
433
|
+
"SET"
|
|
531
434
|
];
|
|
532
435
|
/** Sub-actions for ALTER SEQUENCE. */
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
436
|
+
const ALTER_SEQUENCE_ACTIONS = [
|
|
437
|
+
"AS",
|
|
438
|
+
"CACHE",
|
|
439
|
+
"CYCLE",
|
|
440
|
+
"INCREMENT BY",
|
|
441
|
+
"MAXVALUE",
|
|
442
|
+
"MINVALUE",
|
|
443
|
+
"NO CYCLE",
|
|
444
|
+
"NO MAXVALUE",
|
|
445
|
+
"NO MINVALUE",
|
|
446
|
+
"OWNED BY",
|
|
447
|
+
"OWNER TO",
|
|
448
|
+
"RENAME TO",
|
|
449
|
+
"RESTART",
|
|
450
|
+
"SET SCHEMA",
|
|
451
|
+
"START WITH"
|
|
549
452
|
];
|
|
550
453
|
/** Sub-actions for ALTER FUNCTION / PROCEDURE / ROUTINE. */
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
454
|
+
const ALTER_FUNCTION_ACTIONS = [
|
|
455
|
+
"CALLED ON NULL INPUT",
|
|
456
|
+
"COST",
|
|
457
|
+
"DEPENDS ON EXTENSION",
|
|
458
|
+
"IMMUTABLE",
|
|
459
|
+
"LEAKPROOF",
|
|
460
|
+
"NO DEPENDS ON EXTENSION",
|
|
461
|
+
"NOT LEAKPROOF",
|
|
462
|
+
"OWNER TO",
|
|
463
|
+
"PARALLEL",
|
|
464
|
+
"RENAME TO",
|
|
465
|
+
"RESET",
|
|
466
|
+
"RETURNS NULL ON NULL INPUT",
|
|
467
|
+
"ROWS",
|
|
468
|
+
"SECURITY DEFINER",
|
|
469
|
+
"SECURITY INVOKER",
|
|
470
|
+
"SET",
|
|
471
|
+
"SET SCHEMA",
|
|
472
|
+
"STABLE",
|
|
473
|
+
"STRICT",
|
|
474
|
+
"SUPPORT",
|
|
475
|
+
"VOLATILE"
|
|
573
476
|
];
|
|
574
477
|
/** Sub-actions for ALTER TYPE. */
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
478
|
+
const ALTER_TYPE_ACTIONS = [
|
|
479
|
+
"ADD ATTRIBUTE",
|
|
480
|
+
"ADD VALUE",
|
|
481
|
+
"ALTER ATTRIBUTE",
|
|
482
|
+
"DROP ATTRIBUTE",
|
|
483
|
+
"OWNER TO",
|
|
484
|
+
"RENAME",
|
|
485
|
+
"RENAME ATTRIBUTE",
|
|
486
|
+
"RENAME VALUE",
|
|
487
|
+
"SET SCHEMA",
|
|
488
|
+
"SET"
|
|
586
489
|
];
|
|
587
490
|
/** Sub-actions for ALTER ROLE / USER. */
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
491
|
+
const ALTER_ROLE_ACTIONS = [
|
|
492
|
+
"BYPASSRLS",
|
|
493
|
+
"CONNECTION LIMIT",
|
|
494
|
+
"CREATEDB",
|
|
495
|
+
"CREATEROLE",
|
|
496
|
+
"ENCRYPTED PASSWORD",
|
|
497
|
+
"IN DATABASE",
|
|
498
|
+
"INHERIT",
|
|
499
|
+
"LOGIN",
|
|
500
|
+
"NOBYPASSRLS",
|
|
501
|
+
"NOCREATEDB",
|
|
502
|
+
"NOCREATEROLE",
|
|
503
|
+
"NOINHERIT",
|
|
504
|
+
"NOLOGIN",
|
|
505
|
+
"NOREPLICATION",
|
|
506
|
+
"NOSUPERUSER",
|
|
507
|
+
"PASSWORD",
|
|
508
|
+
"RENAME TO",
|
|
509
|
+
"REPLICATION",
|
|
510
|
+
"RESET",
|
|
511
|
+
"SET",
|
|
512
|
+
"SUPERUSER",
|
|
513
|
+
"VALID UNTIL",
|
|
514
|
+
"WITH"
|
|
612
515
|
];
|
|
613
516
|
/** Sub-actions for ALTER DATABASE. */
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
517
|
+
const ALTER_DATABASE_ACTIONS = [
|
|
518
|
+
"ALLOW_CONNECTIONS",
|
|
519
|
+
"CONNECTION LIMIT",
|
|
520
|
+
"IS_TEMPLATE",
|
|
521
|
+
"OWNER TO",
|
|
522
|
+
"REFRESH COLLATION VERSION",
|
|
523
|
+
"RENAME TO",
|
|
524
|
+
"RESET",
|
|
525
|
+
"SET",
|
|
526
|
+
"SET TABLESPACE",
|
|
527
|
+
"WITH"
|
|
625
528
|
];
|
|
626
529
|
/** Sub-actions for ALTER SCHEMA. */
|
|
627
|
-
|
|
628
|
-
"OWNER TO",
|
|
629
|
-
"RENAME TO",
|
|
630
|
-
];
|
|
530
|
+
const ALTER_SCHEMA_ACTIONS = ["OWNER TO", "RENAME TO"];
|
|
631
531
|
/** Sub-actions for ALTER EXTENSION. */
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
532
|
+
const ALTER_EXTENSION_ACTIONS = [
|
|
533
|
+
"ADD",
|
|
534
|
+
"DROP",
|
|
535
|
+
"SET SCHEMA",
|
|
536
|
+
"UPDATE"
|
|
637
537
|
];
|
|
638
538
|
/** Sub-actions for ALTER POLICY. */
|
|
639
|
-
|
|
539
|
+
const ALTER_POLICY_ACTIONS = ["ON", "RENAME TO"];
|
|
640
540
|
/** Sub-actions for ALTER PUBLICATION. */
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
541
|
+
const ALTER_PUBLICATION_ACTIONS = [
|
|
542
|
+
"ADD",
|
|
543
|
+
"DROP",
|
|
544
|
+
"OWNER TO",
|
|
545
|
+
"RENAME TO",
|
|
546
|
+
"SET"
|
|
647
547
|
];
|
|
648
548
|
/** Sub-actions for ALTER SUBSCRIPTION. */
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
549
|
+
const ALTER_SUBSCRIPTION_ACTIONS = [
|
|
550
|
+
"ADD PUBLICATION",
|
|
551
|
+
"CONNECTION",
|
|
552
|
+
"DISABLE",
|
|
553
|
+
"DROP PUBLICATION",
|
|
554
|
+
"ENABLE",
|
|
555
|
+
"OWNER TO",
|
|
556
|
+
"REFRESH PUBLICATION",
|
|
557
|
+
"RENAME TO",
|
|
558
|
+
"SET",
|
|
559
|
+
"SET PUBLICATION",
|
|
560
|
+
"SKIP"
|
|
661
561
|
];
|
|
662
562
|
/** CREATE INDEX top-level options. */
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
563
|
+
const CREATE_INDEX_OPTIONS = [
|
|
564
|
+
"CONCURRENTLY",
|
|
565
|
+
"IF NOT EXISTS",
|
|
566
|
+
"ON",
|
|
567
|
+
"UNIQUE"
|
|
668
568
|
];
|
|
669
569
|
/** Window frame clauses after `OVER (`. */
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
570
|
+
const WINDOW_FRAME_KEYWORDS = [
|
|
571
|
+
"GROUPS",
|
|
572
|
+
"ORDER BY",
|
|
573
|
+
"PARTITION BY",
|
|
574
|
+
"RANGE",
|
|
575
|
+
"ROWS"
|
|
676
576
|
];
|
|
677
577
|
/** Tail keywords that follow a `FROM <table>` clause in a query. */
|
|
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
|
-
|
|
578
|
+
const POST_FROM_KEYWORDS = [
|
|
579
|
+
"AS",
|
|
580
|
+
"CROSS JOIN",
|
|
581
|
+
"EXCEPT",
|
|
582
|
+
"FETCH",
|
|
583
|
+
"FOR",
|
|
584
|
+
"FULL JOIN",
|
|
585
|
+
"FULL OUTER JOIN",
|
|
586
|
+
"GROUP BY",
|
|
587
|
+
"HAVING",
|
|
588
|
+
"INNER JOIN",
|
|
589
|
+
"INTERSECT",
|
|
590
|
+
"JOIN",
|
|
591
|
+
"LATERAL",
|
|
592
|
+
"LEFT JOIN",
|
|
593
|
+
"LEFT OUTER JOIN",
|
|
594
|
+
"LIMIT",
|
|
595
|
+
"NATURAL JOIN",
|
|
596
|
+
"OFFSET",
|
|
597
|
+
"ON",
|
|
598
|
+
"ORDER BY",
|
|
599
|
+
"RIGHT JOIN",
|
|
600
|
+
"RIGHT OUTER JOIN",
|
|
601
|
+
"TABLESAMPLE",
|
|
602
|
+
"UNION",
|
|
603
|
+
"USING",
|
|
604
|
+
"WHERE",
|
|
605
|
+
"WINDOW"
|
|
706
606
|
];
|
|
707
607
|
/** Continuations within a WHERE expression. */
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
608
|
+
const WHERE_CONTINUATIONS = [
|
|
609
|
+
"AND",
|
|
610
|
+
"BETWEEN",
|
|
611
|
+
"IN",
|
|
612
|
+
"IS",
|
|
613
|
+
"LIKE",
|
|
614
|
+
"NOT",
|
|
615
|
+
"OR"
|
|
716
616
|
];
|
|
717
617
|
/** Boolean-style values used with `\set` for AUTOCOMMIT etc. (extends ON_OFF). */
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
618
|
+
const DATESTYLE_VALUES = [
|
|
619
|
+
"GERMAN",
|
|
620
|
+
"ISO",
|
|
621
|
+
"POSTGRES",
|
|
622
|
+
"SQL"
|
|
723
623
|
];
|
|
724
624
|
/** GRANT / REVOKE privileges. */
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
625
|
+
const PRIVILEGE_KEYWORDS = [
|
|
626
|
+
"ALL",
|
|
627
|
+
"CREATE",
|
|
628
|
+
"CONNECT",
|
|
629
|
+
"DELETE",
|
|
630
|
+
"EXECUTE",
|
|
631
|
+
"INSERT",
|
|
632
|
+
"REFERENCES",
|
|
633
|
+
"SELECT",
|
|
634
|
+
"TEMPORARY",
|
|
635
|
+
"TRIGGER",
|
|
636
|
+
"TRUNCATE",
|
|
637
|
+
"UPDATE",
|
|
638
|
+
"USAGE"
|
|
739
639
|
];
|
|
740
640
|
/** Common transaction/savepoint keywords. */
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
641
|
+
const TRANSACTION_KEYWORDS = [
|
|
642
|
+
"ISOLATION LEVEL",
|
|
643
|
+
"READ ONLY",
|
|
644
|
+
"READ WRITE",
|
|
645
|
+
"TRANSACTION"
|
|
746
646
|
];
|
|
747
647
|
/**
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
648
|
+
* Built-in scalar type keywords that psql tab-completion mixes in
|
|
649
|
+
* wherever a type name is expected. Mirrors upstream's
|
|
650
|
+
* `Keywords_for_list_of_datatypes` (tab-complete.in.c). The multi-word
|
|
651
|
+
* names disabled under `#ifdef NOT_USED` upstream are intentionally
|
|
652
|
+
* omitted here too — tab completion can't disambiguate across word
|
|
653
|
+
* boundaries.
|
|
654
|
+
*/
|
|
655
|
+
const BUILTIN_DATATYPE_KEYWORDS = [
|
|
656
|
+
"bigint",
|
|
657
|
+
"boolean",
|
|
658
|
+
"character",
|
|
659
|
+
"double precision",
|
|
660
|
+
"integer",
|
|
661
|
+
"real",
|
|
662
|
+
"smallint"
|
|
763
663
|
];
|
|
764
664
|
/**
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
665
|
+
* COPY ... FROM ... WITH ( ... ) option keywords. Mirrors upstream's
|
|
666
|
+
* `Copy_from_options` macro = `Copy_common_options` + the FROM-specific
|
|
667
|
+
* extras (DEFAULT, FORCE_NOT_NULL, FORCE_NULL, FREEZE, LOG_VERBOSITY,
|
|
668
|
+
* ON_ERROR, REJECT_LIMIT).
|
|
669
|
+
*/
|
|
670
|
+
const COPY_FROM_OPTIONS = [
|
|
671
|
+
"DELIMITER",
|
|
672
|
+
"ENCODING",
|
|
673
|
+
"ESCAPE",
|
|
674
|
+
"FORMAT",
|
|
675
|
+
"HEADER",
|
|
676
|
+
"NULL",
|
|
677
|
+
"QUOTE",
|
|
678
|
+
"DEFAULT",
|
|
679
|
+
"FORCE_NOT_NULL",
|
|
680
|
+
"FORCE_NULL",
|
|
681
|
+
"FREEZE",
|
|
682
|
+
"LOG_VERBOSITY",
|
|
683
|
+
"ON_ERROR",
|
|
684
|
+
"REJECT_LIMIT"
|
|
785
685
|
];
|
|
786
686
|
/**
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
687
|
+
* COPY ... TO ... WITH ( ... ) option keywords. Mirrors upstream's
|
|
688
|
+
* `Copy_to_options` macro = `Copy_common_options` + `FORCE_QUOTE`.
|
|
689
|
+
*/
|
|
690
|
+
const COPY_TO_OPTIONS = [
|
|
691
|
+
"DELIMITER",
|
|
692
|
+
"ENCODING",
|
|
693
|
+
"ESCAPE",
|
|
694
|
+
"FORMAT",
|
|
695
|
+
"HEADER",
|
|
696
|
+
"NULL",
|
|
697
|
+
"QUOTE",
|
|
698
|
+
"FORCE_QUOTE"
|
|
799
699
|
];
|
|
800
700
|
/**
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
701
|
+
* Apply a case-insensitive prefix filter. Empty `prefix` returns the whole
|
|
702
|
+
* list. The match honours `compCase` — uppercase the candidates when the
|
|
703
|
+
* user is typing in uppercase, etc.
|
|
704
|
+
*/
|
|
805
705
|
const filterAndCase = (candidates, prefix, settings) => {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
result.push(applyCase(c, prefix, settings));
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
return result;
|
|
706
|
+
const lowPrefix = prefix.toLowerCase();
|
|
707
|
+
const result = [];
|
|
708
|
+
for (const c of candidates) if (c.toLowerCase().startsWith(lowPrefix)) result.push(applyCase(c, prefix, settings));
|
|
709
|
+
return result;
|
|
814
710
|
};
|
|
815
711
|
/**
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
712
|
+
* Render a candidate with the case psql would use, based on `COMP_KEYWORD_CASE`:
|
|
713
|
+
*
|
|
714
|
+
* - lower → always lowercase, regardless of input.
|
|
715
|
+
* - upper → always uppercase, regardless of input.
|
|
716
|
+
* - preserve-lower → lowercase by default; uppercase if the user typed
|
|
717
|
+
* a fragment containing an UPPERCASE letter.
|
|
718
|
+
* - preserve-upper → (default) uppercase by default; lowercase if the
|
|
719
|
+
* user typed a fragment containing a lowercase letter.
|
|
720
|
+
*
|
|
721
|
+
* Per psql docs: "preserve-upper, the default, returns the keyword in upper
|
|
722
|
+
* case unless the partial word entered is in lower case". The dichotomy is
|
|
723
|
+
* really "did the user type ANY lowercase letter" (for preserve-upper) and
|
|
724
|
+
* "did the user type ANY uppercase letter" (for preserve-lower) — matching
|
|
725
|
+
* upstream's `pg_str_endswith` / `pg_str_islower` heuristics.
|
|
726
|
+
*/
|
|
831
727
|
const applyCase = (candidate, typed, settings) => {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
// Mirror upstream `pg_strdup_keyword_case` (tab-complete.c): the case
|
|
842
|
-
// decision keys off the FIRST character of the user's input, not the
|
|
843
|
-
// presence of any case anywhere. Empty input (`first` = 0) is treated as
|
|
844
|
-
// neither lowercase nor alpha, so:
|
|
845
|
-
// - preserve-upper → UPPERCASE (default mode; matches vanilla psql 18
|
|
846
|
-
// for the `set <name> <TAB><TAB>` → `TO` case, upstream test
|
|
847
|
-
// 010_tab_completion.pl line 366).
|
|
848
|
-
// - preserve-lower → lowercase.
|
|
849
|
-
// The same rule applies when the first char is a non-letter (digit, `_`,
|
|
850
|
-
// punctuation) — those preserve the mode's default direction.
|
|
851
|
-
const first = typed[0] ?? "";
|
|
852
|
-
const firstIsLower = /[a-z]/.test(first);
|
|
853
|
-
const firstIsAlpha = /[A-Za-z]/.test(first);
|
|
854
|
-
const lowerCaseIt = mode === "lower" ||
|
|
855
|
-
((mode === "preserve-lower" || mode === "preserve-upper") &&
|
|
856
|
-
firstIsLower) ||
|
|
857
|
-
(mode === "preserve-lower" && !firstIsAlpha);
|
|
858
|
-
if (mode === "upper")
|
|
859
|
-
return candidate.toUpperCase();
|
|
860
|
-
return lowerCaseIt ? candidate.toLowerCase() : candidate.toUpperCase();
|
|
728
|
+
if (candidate.startsWith("\"") || candidate.startsWith("'")) return candidate;
|
|
729
|
+
if (containsNonKeywordChar(candidate)) return candidate;
|
|
730
|
+
const mode = settings.compCase;
|
|
731
|
+
const first = typed[0] ?? "";
|
|
732
|
+
const firstIsLower = /[a-z]/.test(first);
|
|
733
|
+
const firstIsAlpha = /[A-Za-z]/.test(first);
|
|
734
|
+
const lowerCaseIt = mode === "lower" || (mode === "preserve-lower" || mode === "preserve-upper") && firstIsLower || mode === "preserve-lower" && !firstIsAlpha;
|
|
735
|
+
if (mode === "upper") return candidate.toUpperCase();
|
|
736
|
+
return lowerCaseIt ? candidate.toLowerCase() : candidate.toUpperCase();
|
|
861
737
|
};
|
|
862
738
|
const containsNonKeywordChar = (s) => /[^A-Za-z0-9 ]/.test(s);
|
|
863
739
|
/**
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
740
|
+
* Split a candidate like `pg_catalog.tab_` into [schema, prefix]. Returns
|
|
741
|
+
* `null` if there's no schema qualifier. `schemaWasQuoted` records whether
|
|
742
|
+
* the user wrote the schema in `"..."` form so the caller can decide whether
|
|
743
|
+
* to fold its case in the rendered output.
|
|
744
|
+
*/
|
|
869
745
|
const splitSchemaPrefix = (word) => {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
return { schema, prefix: after, schemaWasQuoted };
|
|
746
|
+
const dot = word.indexOf(".");
|
|
747
|
+
if (dot < 0) return null;
|
|
748
|
+
const after = word.slice(dot + 1);
|
|
749
|
+
if (after.includes(".")) return null;
|
|
750
|
+
let schema = word.slice(0, dot);
|
|
751
|
+
let schemaWasQuoted = false;
|
|
752
|
+
if (schema.startsWith("\"") && schema.endsWith("\"")) {
|
|
753
|
+
schemaWasQuoted = true;
|
|
754
|
+
schema = schema.slice(1, -1).replace(/""/g, "\"");
|
|
755
|
+
}
|
|
756
|
+
return {
|
|
757
|
+
schema,
|
|
758
|
+
prefix: after,
|
|
759
|
+
schemaWasQuoted
|
|
760
|
+
};
|
|
886
761
|
};
|
|
887
762
|
/**
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
763
|
+
* Parse a table reference (the `<ref>` slot in
|
|
764
|
+
* `ALTER TABLE <ref> DROP CONSTRAINT y`) from the already-tokenized
|
|
765
|
+
* `prevWords` slice between `ALTER TABLE` and the action keyword.
|
|
766
|
+
*
|
|
767
|
+
* The scanner can produce the reference as 1 or 2 tokens depending on
|
|
768
|
+
* quoting:
|
|
769
|
+
*
|
|
770
|
+
* - `tab1` → `["tab1"]` (bare, case-folded)
|
|
771
|
+
* - `"tab1"` → `["\"tab1\""]` (quoted, exact-case)
|
|
772
|
+
* - `public.tab1` → `["public.tab1"]` (single token, dotted)
|
|
773
|
+
* - `public."tab1"` → `["public.\"tab1\""]` (single token, dotted+quoted)
|
|
774
|
+
*
|
|
775
|
+
* Returns the parsed parts with case-folding applied to UNQUOTED
|
|
776
|
+
* identifiers (matching `pg_strcasecmp` semantics) so the caller can
|
|
777
|
+
* pass them straight to a `WHERE relname = $N` catalog query.
|
|
778
|
+
*
|
|
779
|
+
* Returns `null` when the tokens don't look like a valid reference.
|
|
780
|
+
*/
|
|
906
781
|
const parseTableRef = (refTokens) => {
|
|
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
|
-
const t = stripQuote(tok);
|
|
956
|
-
if (t.v.length === 0)
|
|
957
|
-
return null;
|
|
958
|
-
return { schema: null, table: t.quoted ? t.v : t.v.toLowerCase() };
|
|
782
|
+
const stripQuote = (s) => {
|
|
783
|
+
if (s.length >= 2 && s.startsWith("\"") && s.endsWith("\"")) return {
|
|
784
|
+
v: s.slice(1, -1).replace(/""/g, "\""),
|
|
785
|
+
quoted: true
|
|
786
|
+
};
|
|
787
|
+
return {
|
|
788
|
+
v: s,
|
|
789
|
+
quoted: false
|
|
790
|
+
};
|
|
791
|
+
};
|
|
792
|
+
if (refTokens.length === 2) {
|
|
793
|
+
const first = refTokens[0];
|
|
794
|
+
if (!first.endsWith(".")) return null;
|
|
795
|
+
const s = stripQuote(first.slice(0, -1));
|
|
796
|
+
const t = stripQuote(refTokens[1]);
|
|
797
|
+
if (t.v.length === 0) return null;
|
|
798
|
+
return {
|
|
799
|
+
schema: s.quoted ? s.v : s.v.toLowerCase(),
|
|
800
|
+
table: t.quoted ? t.v : t.v.toLowerCase()
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
if (refTokens.length !== 1) return null;
|
|
804
|
+
const tok = refTokens[0];
|
|
805
|
+
let inQuote = false;
|
|
806
|
+
let dot = -1;
|
|
807
|
+
for (let i = 0; i < tok.length; i++) {
|
|
808
|
+
const ch = tok[i];
|
|
809
|
+
if (ch === "\"") inQuote = !inQuote;
|
|
810
|
+
else if (ch === "." && !inQuote) {
|
|
811
|
+
dot = i;
|
|
812
|
+
break;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
if (dot >= 0) {
|
|
816
|
+
const s = stripQuote(tok.slice(0, dot));
|
|
817
|
+
const t = stripQuote(tok.slice(dot + 1));
|
|
818
|
+
if (t.v.length === 0) return null;
|
|
819
|
+
return {
|
|
820
|
+
schema: s.quoted ? s.v : s.v.toLowerCase(),
|
|
821
|
+
table: t.quoted ? t.v : t.v.toLowerCase()
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
const t = stripQuote(tok);
|
|
825
|
+
if (t.v.length === 0) return null;
|
|
826
|
+
return {
|
|
827
|
+
schema: null,
|
|
828
|
+
table: t.quoted ? t.v : t.v.toLowerCase()
|
|
829
|
+
};
|
|
959
830
|
};
|
|
960
|
-
// ---------------------------------------------------------------------------
|
|
961
|
-
// Entry point.
|
|
962
|
-
// ---------------------------------------------------------------------------
|
|
963
831
|
/**
|
|
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
|
-
const cands = names
|
|
998
|
-
.filter((n) => lc(n).startsWith(lp))
|
|
999
|
-
.map((n) => ":'" + n + "'");
|
|
1000
|
-
return { candidates: cands };
|
|
1001
|
-
}
|
|
1002
|
-
if (currentWord.startsWith(':"')) {
|
|
1003
|
-
const prefix = currentWord.slice(2);
|
|
1004
|
-
const lp = lc(prefix);
|
|
1005
|
-
const cands = names
|
|
1006
|
-
.filter((n) => lc(n).startsWith(lp))
|
|
1007
|
-
.map((n) => ':"' + n + '"');
|
|
1008
|
-
return { candidates: cands };
|
|
1009
|
-
}
|
|
1010
|
-
// Plain `:NAME` — bare substitution.
|
|
1011
|
-
const prefix = currentWord.slice(1);
|
|
1012
|
-
const lp = lc(prefix);
|
|
1013
|
-
const filt = names
|
|
1014
|
-
.filter((n) => lc(n).startsWith(lp))
|
|
1015
|
-
.map((n) => ":" + n);
|
|
1016
|
-
return { candidates: filt };
|
|
1017
|
-
}
|
|
1018
|
-
// ----- Backslash-command name completion.
|
|
1019
|
-
// Trigger: the user is mid-token and the token starts with '\'.
|
|
1020
|
-
if (currentWord.startsWith("\\") && prevWords.length === 0) {
|
|
1021
|
-
return {
|
|
1022
|
-
candidates: BACKSLASH_COMMANDS.filter((c) => c.toLowerCase().startsWith(currentWord.toLowerCase())),
|
|
1023
|
-
};
|
|
1024
|
-
}
|
|
1025
|
-
// ----- Backslash-command argument completion.
|
|
1026
|
-
if (prevWords.length > 0 && prevWords[0].startsWith("\\")) {
|
|
1027
|
-
return await backslashArgRules(prevWords, currentWord, ctx, conn);
|
|
1028
|
-
}
|
|
1029
|
-
// ----- Multi-line SQL: rules that need to see across the line boundary
|
|
1030
|
-
// re-tokenize `queryBuf` and consult the COMBINED token sequence. The
|
|
1031
|
-
// standard single-line `prevWords` view stays untouched so the bulk of
|
|
1032
|
-
// the rule grammar (which is happy to match on the current line alone)
|
|
1033
|
-
// isn't disturbed.
|
|
1034
|
-
//
|
|
1035
|
-
// Upstream's `get_previous_words` pastes `tab_completion_query_buf` in
|
|
1036
|
-
// front of `rl_line_buffer` with a `\n` separator and tokenizes the
|
|
1037
|
-
// whole thing — see tab-complete.in.c ~line 6670. We mirror that, but
|
|
1038
|
-
// gate the cross-line view to specific rules so the existing tail-match
|
|
1039
|
-
// arms keep their familiar (line-local) semantics.
|
|
1040
|
-
const combined = combinedPrevWords(ctx.queryBuf, prevWords);
|
|
1041
|
-
const multiLine = await multiLineSqlRules(combined, prevWords, currentWord, ctx, conn);
|
|
1042
|
-
if (multiLine !== null)
|
|
1043
|
-
return multiLine;
|
|
1044
|
-
// ----- SQL: top-of-statement keyword completion.
|
|
1045
|
-
if (prevWords.length === 0) {
|
|
1046
|
-
return {
|
|
1047
|
-
candidates: filterAndCase(SQL_TOP_KEYWORDS, currentWord, ctx.settings),
|
|
1048
|
-
};
|
|
1049
|
-
}
|
|
1050
|
-
return await sqlRules(prevWords, currentWord, ctx, conn);
|
|
832
|
+
* Top-level rule dispatch.
|
|
833
|
+
*
|
|
834
|
+
* `prevWords` are the tokens BEFORE the current (in-progress) word; the
|
|
835
|
+
* current word's leading characters are what we're filtering candidates
|
|
836
|
+
* against.
|
|
837
|
+
*/
|
|
838
|
+
const findCompletions = async (prevWords, currentWord, ctx) => {
|
|
839
|
+
const conn = ctx.settings.db ?? ctx.conn ?? null;
|
|
840
|
+
if (currentWord.startsWith(":") && !currentWord.startsWith("::")) {
|
|
841
|
+
const names = listVarNames(ctx.settings);
|
|
842
|
+
const lc = (s) => s.toLowerCase();
|
|
843
|
+
if (currentWord.startsWith(":{?")) {
|
|
844
|
+
const lp = lc(currentWord.slice(3));
|
|
845
|
+
return { candidates: names.filter((n) => lc(n).startsWith(lp)).map((n) => ":{?" + n + "}") };
|
|
846
|
+
}
|
|
847
|
+
if (currentWord.startsWith(":'")) {
|
|
848
|
+
const lp = lc(currentWord.slice(2));
|
|
849
|
+
return { candidates: names.filter((n) => lc(n).startsWith(lp)).map((n) => ":'" + n + "'") };
|
|
850
|
+
}
|
|
851
|
+
if (currentWord.startsWith(":\"")) {
|
|
852
|
+
const lp = lc(currentWord.slice(2));
|
|
853
|
+
return { candidates: names.filter((n) => lc(n).startsWith(lp)).map((n) => ":\"" + n + "\"") };
|
|
854
|
+
}
|
|
855
|
+
const lp = lc(currentWord.slice(1));
|
|
856
|
+
return { candidates: names.filter((n) => lc(n).startsWith(lp)).map((n) => ":" + n) };
|
|
857
|
+
}
|
|
858
|
+
if (currentWord.startsWith("\\") && prevWords.length === 0) return { candidates: BACKSLASH_COMMANDS.filter((c) => c.toLowerCase().startsWith(currentWord.toLowerCase())) };
|
|
859
|
+
if (prevWords.length > 0 && prevWords[0].startsWith("\\")) return await backslashArgRules(prevWords, currentWord, ctx, conn);
|
|
860
|
+
const combined = combinedPrevWords(ctx.queryBuf, prevWords);
|
|
861
|
+
const multiLine = await multiLineSqlRules(combined, prevWords, currentWord, ctx, conn);
|
|
862
|
+
if (multiLine !== null) return multiLine;
|
|
863
|
+
if (prevWords.length === 0) return { candidates: filterAndCase(SQL_TOP_KEYWORDS, currentWord, ctx.settings) };
|
|
864
|
+
return await sqlRules(prevWords, currentWord, ctx, conn);
|
|
1051
865
|
};
|
|
1052
866
|
/**
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
867
|
+
* Tokenize `queryBuf` and concatenate with the current line's `prevWords`.
|
|
868
|
+
* The result matches what upstream's `get_previous_words` produces for a
|
|
869
|
+
* multi-line statement: tokens from prior lines first, then tokens from the
|
|
870
|
+
* current line up to the cursor.
|
|
871
|
+
*
|
|
872
|
+
* Tokens cross the line boundary harmlessly because our tokenizer treats
|
|
873
|
+
* `\n` as whitespace (a separator). Newlines INSIDE a `'...'`/`"..."`
|
|
874
|
+
* literal are absorbed by the quoted-string handling and don't split the
|
|
875
|
+
* literal into two tokens.
|
|
876
|
+
*/
|
|
1063
877
|
const combinedPrevWords = (queryBuf, prevWords) => {
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
const bufTokens = tokenize(queryBuf).map((t) => t.text);
|
|
1067
|
-
return [...bufTokens, ...prevWords];
|
|
878
|
+
if (queryBuf === void 0 || queryBuf.length === 0) return prevWords;
|
|
879
|
+
return [...tokenize(queryBuf).map((t) => t.text), ...prevWords];
|
|
1068
880
|
};
|
|
1069
881
|
/**
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
882
|
+
* Rules that fire only when the user is in the middle of a multi-line
|
|
883
|
+
* statement (`queryBuf` non-empty / the combined-token view is longer than
|
|
884
|
+
* the current-line view). Today this covers:
|
|
885
|
+
*
|
|
886
|
+
* - `ANALYZE (` opened on a previous line — emit the option list.
|
|
887
|
+
* - `COMMENT ON CONSTRAINT <name> ON <schema>.` continuation —
|
|
888
|
+
* resolve to the table holding that constraint in `<schema>`.
|
|
889
|
+
*
|
|
890
|
+
* Returns the rule's `RuleResult` when an arm matches, or `null` when the
|
|
891
|
+
* combined-token view doesn't add anything (so the caller continues with
|
|
892
|
+
* the line-local rule grammar).
|
|
893
|
+
*/
|
|
1082
894
|
const multiLineSqlRules = async (combined, prevWords, currentWord, ctx, conn) => {
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
if (TailMatches(combined, ["VERBOSE|SKIP_LOCKED"])) {
|
|
1119
|
-
return {
|
|
1120
|
-
candidates: filterAndCase(["ON", "OFF"], currentWord, ctx.settings),
|
|
1121
|
-
};
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
// ----- COMMENT ON CONSTRAINT <name> ON <schema>.<prefix> — resolve to the
|
|
1125
|
-
// table that has `<name>` as a constraint within `<schema>`. Upstream
|
|
1126
|
-
// calls `set_completion_reference(prev2_wd)` (the constraint name) and
|
|
1127
|
-
// runs `Query_for_list_of_tables_for_constraint` with the schema match
|
|
1128
|
-
// baked into the SchemaQuery shape (tab-complete.in.c ~line 3204).
|
|
1129
|
-
//
|
|
1130
|
-
// We allow the rule to fire even when the line-local `prevWords` only
|
|
1131
|
-
// sees the trailing `ON` — the COMBINED tokens carry the
|
|
1132
|
-
// `COMMENT ON CONSTRAINT <name>` prefix from the previous line.
|
|
1133
|
-
if (TailMatches(combined, ["COMMENT", "ON", "CONSTRAINT", MatchAny, "ON"])) {
|
|
1134
|
-
if (!conn)
|
|
1135
|
-
return { candidates: [] };
|
|
1136
|
-
// `combined` ends in `ON`. The constraint name is the token just
|
|
1137
|
-
// before that trailing `ON`. Indexing from the right avoids hard-coding
|
|
1138
|
-
// the queryBuf token count.
|
|
1139
|
-
const constraintNameRaw = combined[combined.length - 2];
|
|
1140
|
-
const constraintName = stripIdentifierQuote(constraintNameRaw);
|
|
1141
|
-
const split = splitSchemaPrefix(currentWord);
|
|
1142
|
-
if (split) {
|
|
1143
|
-
// Schema-qualified: emit tables in `<schema>` that have the named
|
|
1144
|
-
// constraint, with the canonical schema prefix re-attached so the
|
|
1145
|
-
// line ends up looking like `public.tab1`.
|
|
1146
|
-
const rows = await runCatalogQuery(conn, Query_for_list_of_tables_for_constraint_in_schema, split.prefix, [constraintName, split.schema]);
|
|
1147
|
-
const canonicalSchema = split.schemaWasQuoted
|
|
1148
|
-
? split.schema
|
|
1149
|
-
: split.schema.toLowerCase();
|
|
1150
|
-
return {
|
|
1151
|
-
candidates: rows.map((r) => canonicalSchema + "." + r),
|
|
1152
|
-
};
|
|
1153
|
-
}
|
|
1154
|
-
// Unqualified: list tables that have the constraint, plus the schemas
|
|
1155
|
-
// they live in (with trailing `.` so the user can drill into a schema).
|
|
1156
|
-
const [tables, schemas] = await Promise.all([
|
|
1157
|
-
runCatalogQuery(conn, Query_for_list_of_tables_for_constraint, currentWord, [constraintName]),
|
|
1158
|
-
runCatalogQuery(conn, Query_for_list_of_schemas, currentWord),
|
|
1159
|
-
]);
|
|
1160
|
-
return { candidates: [...tables, ...schemas.map((s) => s + ".")] };
|
|
1161
|
-
}
|
|
1162
|
-
void conn;
|
|
1163
|
-
return null;
|
|
895
|
+
if (combined.length === prevWords.length) return null;
|
|
896
|
+
if (HeadMatches(combined, ["ANALYZE"]) && isInsideOpenParen(combined.slice(1))) {
|
|
897
|
+
const lastTok = combined[combined.length - 1];
|
|
898
|
+
if (lastTok === "(" || lastTok === ",") return { candidates: filterAndCase([
|
|
899
|
+
"VERBOSE",
|
|
900
|
+
"SKIP_LOCKED",
|
|
901
|
+
"BUFFER_USAGE_LIMIT"
|
|
902
|
+
], currentWord, ctx.settings) };
|
|
903
|
+
if (currentWord.length > 0 && (lastTok === void 0 || /^[A-Za-z_]+$/.test(currentWord))) return { candidates: filterAndCase([
|
|
904
|
+
"VERBOSE",
|
|
905
|
+
"SKIP_LOCKED",
|
|
906
|
+
"BUFFER_USAGE_LIMIT"
|
|
907
|
+
], currentWord, ctx.settings) };
|
|
908
|
+
if (TailMatches(combined, ["VERBOSE|SKIP_LOCKED"])) return { candidates: filterAndCase(["ON", "OFF"], currentWord, ctx.settings) };
|
|
909
|
+
}
|
|
910
|
+
if (TailMatches(combined, [
|
|
911
|
+
"COMMENT",
|
|
912
|
+
"ON",
|
|
913
|
+
"CONSTRAINT",
|
|
914
|
+
null,
|
|
915
|
+
"ON"
|
|
916
|
+
])) {
|
|
917
|
+
if (!conn) return { candidates: [] };
|
|
918
|
+
const constraintNameRaw = combined[combined.length - 2];
|
|
919
|
+
const constraintName = stripIdentifierQuote(constraintNameRaw);
|
|
920
|
+
const split = splitSchemaPrefix(currentWord);
|
|
921
|
+
if (split) {
|
|
922
|
+
const rows = await runCatalogQuery(conn, Query_for_list_of_tables_for_constraint_in_schema, split.prefix, [constraintName, split.schema]);
|
|
923
|
+
const canonicalSchema = split.schemaWasQuoted ? split.schema : split.schema.toLowerCase();
|
|
924
|
+
return { candidates: rows.map((r) => canonicalSchema + "." + r) };
|
|
925
|
+
}
|
|
926
|
+
const [tables, schemas] = await Promise.all([runCatalogQuery(conn, Query_for_list_of_tables_for_constraint, currentWord, [constraintName]), runCatalogQuery(conn, Query_for_list_of_schemas, currentWord)]);
|
|
927
|
+
return { candidates: [...tables, ...schemas.map((s) => s + ".")] };
|
|
928
|
+
}
|
|
929
|
+
return null;
|
|
1164
930
|
};
|
|
1165
931
|
/**
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
932
|
+
* Return true when the tokens (after dropping a leading `ANALYZE` keyword)
|
|
933
|
+
* are inside an unclosed parenthesized form — i.e. there's a `(` somewhere
|
|
934
|
+
* and no matching `)` at the trailing position. Mirrors upstream's
|
|
935
|
+
* `HeadMatches("ANALYZE", "(*") && !HeadMatches("ANALYZE", "(*)")`
|
|
936
|
+
* pattern under our split-punctuation tokenizer.
|
|
937
|
+
*/
|
|
1172
938
|
const isInsideOpenParen = (tokens) => {
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
else if (t === ")") {
|
|
1181
|
-
depth--;
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
return sawOpen && depth > 0;
|
|
939
|
+
let depth = 0;
|
|
940
|
+
let sawOpen = false;
|
|
941
|
+
for (const t of tokens) if (t === "(") {
|
|
942
|
+
depth++;
|
|
943
|
+
sawOpen = true;
|
|
944
|
+
} else if (t === ")") depth--;
|
|
945
|
+
return sawOpen && depth > 0;
|
|
1185
946
|
};
|
|
1186
947
|
/** Strip surrounding `"..."` quoting from a constraint/identifier token. */
|
|
1187
948
|
const stripIdentifierQuote = (raw) => {
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
return raw.slice(1, -1).replace(/""/g, '"');
|
|
1192
|
-
}
|
|
1193
|
-
return raw;
|
|
949
|
+
if (raw === void 0) return "";
|
|
950
|
+
if (raw.length >= 2 && raw.startsWith("\"") && raw.endsWith("\"")) return raw.slice(1, -1).replace(/""/g, "\"");
|
|
951
|
+
return raw;
|
|
1194
952
|
};
|
|
1195
|
-
// ---------------------------------------------------------------------------
|
|
1196
|
-
// Backslash arg rules.
|
|
1197
|
-
// ---------------------------------------------------------------------------
|
|
1198
953
|
const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
return { candidates: [] };
|
|
1309
|
-
}
|
|
1310
|
-
if (cmd === "\\dm" || cmd === "\\dm+") {
|
|
1311
|
-
if (prevWords.length === 1 && conn) {
|
|
1312
|
-
return {
|
|
1313
|
-
candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_matviews),
|
|
1314
|
-
};
|
|
1315
|
-
}
|
|
1316
|
-
return { candidates: [] };
|
|
1317
|
-
}
|
|
1318
|
-
if (cmd === "\\di" || cmd === "\\di+") {
|
|
1319
|
-
if (prevWords.length === 1 && conn) {
|
|
1320
|
-
return {
|
|
1321
|
-
candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_indexes),
|
|
1322
|
-
};
|
|
1323
|
-
}
|
|
1324
|
-
return { candidates: [] };
|
|
1325
|
-
}
|
|
1326
|
-
if (cmd === "\\ds" || cmd === "\\ds+") {
|
|
1327
|
-
if (prevWords.length === 1 && conn) {
|
|
1328
|
-
return {
|
|
1329
|
-
candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_sequences),
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
return { candidates: [] };
|
|
1333
|
-
}
|
|
1334
|
-
// \l[+] / \list → databases.
|
|
1335
|
-
if (cmd === "\\l" ||
|
|
1336
|
-
cmd === "\\l+" ||
|
|
1337
|
-
cmd === "\\list" ||
|
|
1338
|
-
cmd === "\\list+") {
|
|
1339
|
-
if (prevWords.length === 1 && conn) {
|
|
1340
|
-
const rows = await runCatalogQuery(conn, Query_for_list_of_databases, currentWord);
|
|
1341
|
-
return { candidates: rows };
|
|
1342
|
-
}
|
|
1343
|
-
return { candidates: [] };
|
|
1344
|
-
}
|
|
1345
|
-
// \encoding NAME
|
|
1346
|
-
if (cmd === "\\encoding") {
|
|
1347
|
-
if (prevWords.length === 1) {
|
|
1348
|
-
return { candidates: filterCi(ENCODINGS, currentWord) };
|
|
1349
|
-
}
|
|
1350
|
-
return { candidates: [] };
|
|
1351
|
-
}
|
|
1352
|
-
// \pset OPT [value]
|
|
1353
|
-
if (cmd === "\\pset") {
|
|
1354
|
-
if (prevWords.length === 1) {
|
|
1355
|
-
return { candidates: filterCi(PSET_OPTIONS, currentWord) };
|
|
1356
|
-
}
|
|
1357
|
-
if (prevWords.length === 2) {
|
|
1358
|
-
const values = psetValuesFor(prevWords[1].toLowerCase());
|
|
1359
|
-
if (values)
|
|
1360
|
-
return { candidates: filterCi(values, currentWord) };
|
|
1361
|
-
return { candidates: [] };
|
|
1362
|
-
}
|
|
1363
|
-
return { candidates: [] };
|
|
1364
|
-
}
|
|
1365
|
-
// \set NAME [VALUE]
|
|
1366
|
-
if (cmd === "\\set") {
|
|
1367
|
-
if (prevWords.length === 1) {
|
|
1368
|
-
return {
|
|
1369
|
-
candidates: filterCi(listAllVarNames(ctx.settings), currentWord),
|
|
1370
|
-
};
|
|
1371
|
-
}
|
|
1372
|
-
if (prevWords.length === 2) {
|
|
1373
|
-
const values = variableValuesFor(prevWords[1].toUpperCase());
|
|
1374
|
-
if (values)
|
|
1375
|
-
return { candidates: filterCi(values, currentWord) };
|
|
1376
|
-
return { candidates: [] };
|
|
1377
|
-
}
|
|
1378
|
-
return { candidates: [] };
|
|
1379
|
-
}
|
|
1380
|
-
// \unset NAME — only existing variables.
|
|
1381
|
-
if (cmd === "\\unset") {
|
|
1382
|
-
if (prevWords.length === 1) {
|
|
1383
|
-
return {
|
|
1384
|
-
candidates: filterCi(listVarNames(ctx.settings), currentWord),
|
|
1385
|
-
};
|
|
1386
|
-
}
|
|
1387
|
-
return { candidates: [] };
|
|
1388
|
-
}
|
|
1389
|
-
// \echo / \warn / \qecho — variable expansion only (handled above).
|
|
1390
|
-
// \prompt — variable name argument is the 1st positional.
|
|
1391
|
-
if (cmd === "\\prompt") {
|
|
1392
|
-
if (prevWords.length === 2) {
|
|
1393
|
-
return {
|
|
1394
|
-
candidates: filterCi(listAllVarNames(ctx.settings), currentWord),
|
|
1395
|
-
};
|
|
1396
|
-
}
|
|
1397
|
-
return { candidates: [] };
|
|
1398
|
-
}
|
|
1399
|
-
// \lo_import / \lo_export → filesystem-driven filename completion.
|
|
1400
|
-
// psql parses the path as a backslash-argument literal — no SQL string
|
|
1401
|
-
// quoting required, so we use the unquoted candidate form.
|
|
1402
|
-
if (cmd === "\\lo_import" || cmd === "\\lo_export") {
|
|
1403
|
-
if (prevWords.length === 1) {
|
|
1404
|
-
return { candidates: completeFilenames(currentWord, "none") };
|
|
1405
|
-
}
|
|
1406
|
-
return { candidates: [] };
|
|
1407
|
-
}
|
|
1408
|
-
// \copy <table> [FROM|TO] <path> — once the FROM/TO keyword has been
|
|
1409
|
-
// typed, the next token is a filename (backslash-context, so bare paths
|
|
1410
|
-
// are fine).
|
|
1411
|
-
if (cmd === "\\copy") {
|
|
1412
|
-
// First arg: a table name.
|
|
1413
|
-
if (prevWords.length === 1 && conn) {
|
|
1414
|
-
return {
|
|
1415
|
-
candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_tables),
|
|
1416
|
-
};
|
|
1417
|
-
}
|
|
1418
|
-
// Second arg: the FROM/TO keyword.
|
|
1419
|
-
if (prevWords.length === 2) {
|
|
1420
|
-
return {
|
|
1421
|
-
candidates: filterAndCase(["FROM", "TO"], currentWord, ctx.settings),
|
|
1422
|
-
};
|
|
1423
|
-
}
|
|
1424
|
-
// Third arg (after FROM/TO): the filename.
|
|
1425
|
-
if (prevWords.length >= 3) {
|
|
1426
|
-
const last = prevWords[prevWords.length - 1].toUpperCase();
|
|
1427
|
-
if (last === "FROM" || last === "TO") {
|
|
1428
|
-
return { candidates: completeFilenames(currentWord, "none") };
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
return { candidates: [] };
|
|
1432
|
-
}
|
|
1433
|
-
// \drds, \drg → roles (for the first arg).
|
|
1434
|
-
if (cmd === "\\drds" || cmd === "\\drg") {
|
|
1435
|
-
if (prevWords.length === 1 && conn) {
|
|
1436
|
-
const rows = await runCatalogQuery(conn, Query_for_list_of_roles, currentWord);
|
|
1437
|
-
return { candidates: rows };
|
|
1438
|
-
}
|
|
1439
|
-
return { candidates: [] };
|
|
1440
|
-
}
|
|
1441
|
-
// Anything else: no completion.
|
|
1442
|
-
return { candidates: [] };
|
|
954
|
+
const cmd = prevWords[0];
|
|
955
|
+
if (cmd === "\\c" || cmd === "\\connect") {
|
|
956
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_databases, currentWord) };
|
|
957
|
+
return { candidates: [] };
|
|
958
|
+
}
|
|
959
|
+
if (cmd === "\\dn" || cmd === "\\dn+") {
|
|
960
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord) };
|
|
961
|
+
return { candidates: [] };
|
|
962
|
+
}
|
|
963
|
+
if (cmd === "\\df" || cmd === "\\df+" || cmd === "\\dfa" || cmd === "\\dfn" || cmd === "\\dfp" || cmd === "\\dft" || cmd === "\\dfw" || cmd === "\\ef" || cmd === "\\sf" || cmd === "\\sf+") {
|
|
964
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_functions, currentWord) };
|
|
965
|
+
return { candidates: [] };
|
|
966
|
+
}
|
|
967
|
+
if (cmd === "\\du" || cmd === "\\dg" || cmd === "\\du+" || cmd === "\\dg+") {
|
|
968
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord) };
|
|
969
|
+
return { candidates: [] };
|
|
970
|
+
}
|
|
971
|
+
if (cmd === "\\dx" || cmd === "\\dx+") {
|
|
972
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_extensions, currentWord) };
|
|
973
|
+
return { candidates: [] };
|
|
974
|
+
}
|
|
975
|
+
if (cmd === "\\dL" || cmd === "\\dL+") {
|
|
976
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_languages, currentWord) };
|
|
977
|
+
return { candidates: [] };
|
|
978
|
+
}
|
|
979
|
+
if (cmd === "\\dT" || cmd === "\\dT+") {
|
|
980
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_types, currentWord) };
|
|
981
|
+
return { candidates: [] };
|
|
982
|
+
}
|
|
983
|
+
if (cmd === "\\do" || cmd === "\\do+" || cmd === "\\doS" || cmd === "\\doS+") {
|
|
984
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_operators, currentWord) };
|
|
985
|
+
return { candidates: [] };
|
|
986
|
+
}
|
|
987
|
+
if (cmd === "\\dC" || cmd === "\\dC+") {
|
|
988
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_casts, currentWord) };
|
|
989
|
+
return { candidates: [] };
|
|
990
|
+
}
|
|
991
|
+
if (cmd === "\\dt" || cmd === "\\dt+" || cmd === "\\dtv" || cmd === "\\d" || cmd === "\\d+" || cmd === "\\dE" || cmd === "\\dE+") {
|
|
992
|
+
if (prevWords.length === 1 && conn) return { candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_tables) };
|
|
993
|
+
return { candidates: [] };
|
|
994
|
+
}
|
|
995
|
+
if (cmd === "\\dv" || cmd === "\\dv+") {
|
|
996
|
+
if (prevWords.length === 1 && conn) return { candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_views) };
|
|
997
|
+
return { candidates: [] };
|
|
998
|
+
}
|
|
999
|
+
if (cmd === "\\dm" || cmd === "\\dm+") {
|
|
1000
|
+
if (prevWords.length === 1 && conn) return { candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_matviews) };
|
|
1001
|
+
return { candidates: [] };
|
|
1002
|
+
}
|
|
1003
|
+
if (cmd === "\\di" || cmd === "\\di+") {
|
|
1004
|
+
if (prevWords.length === 1 && conn) return { candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_indexes) };
|
|
1005
|
+
return { candidates: [] };
|
|
1006
|
+
}
|
|
1007
|
+
if (cmd === "\\ds" || cmd === "\\ds+") {
|
|
1008
|
+
if (prevWords.length === 1 && conn) return { candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_sequences) };
|
|
1009
|
+
return { candidates: [] };
|
|
1010
|
+
}
|
|
1011
|
+
if (cmd === "\\l" || cmd === "\\l+" || cmd === "\\list" || cmd === "\\list+") {
|
|
1012
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_databases, currentWord) };
|
|
1013
|
+
return { candidates: [] };
|
|
1014
|
+
}
|
|
1015
|
+
if (cmd === "\\encoding") {
|
|
1016
|
+
if (prevWords.length === 1) return { candidates: filterCi(ENCODINGS, currentWord) };
|
|
1017
|
+
return { candidates: [] };
|
|
1018
|
+
}
|
|
1019
|
+
if (cmd === "\\pset") {
|
|
1020
|
+
if (prevWords.length === 1) return { candidates: filterCi(PSET_OPTIONS, currentWord) };
|
|
1021
|
+
if (prevWords.length === 2) {
|
|
1022
|
+
const values = psetValuesFor(prevWords[1].toLowerCase());
|
|
1023
|
+
if (values) return { candidates: filterCi(values, currentWord) };
|
|
1024
|
+
return { candidates: [] };
|
|
1025
|
+
}
|
|
1026
|
+
return { candidates: [] };
|
|
1027
|
+
}
|
|
1028
|
+
if (cmd === "\\set") {
|
|
1029
|
+
if (prevWords.length === 1) return { candidates: filterCi(listAllVarNames(ctx.settings), currentWord) };
|
|
1030
|
+
if (prevWords.length === 2) {
|
|
1031
|
+
const values = variableValuesFor(prevWords[1].toUpperCase());
|
|
1032
|
+
if (values) return { candidates: filterCi(values, currentWord) };
|
|
1033
|
+
return { candidates: [] };
|
|
1034
|
+
}
|
|
1035
|
+
return { candidates: [] };
|
|
1036
|
+
}
|
|
1037
|
+
if (cmd === "\\unset") {
|
|
1038
|
+
if (prevWords.length === 1) return { candidates: filterCi(listVarNames(ctx.settings), currentWord) };
|
|
1039
|
+
return { candidates: [] };
|
|
1040
|
+
}
|
|
1041
|
+
if (cmd === "\\prompt") {
|
|
1042
|
+
if (prevWords.length === 2) return { candidates: filterCi(listAllVarNames(ctx.settings), currentWord) };
|
|
1043
|
+
return { candidates: [] };
|
|
1044
|
+
}
|
|
1045
|
+
if (cmd === "\\lo_import" || cmd === "\\lo_export") {
|
|
1046
|
+
if (prevWords.length === 1) return { candidates: completeFilenames(currentWord, "none") };
|
|
1047
|
+
return { candidates: [] };
|
|
1048
|
+
}
|
|
1049
|
+
if (cmd === "\\copy") {
|
|
1050
|
+
if (prevWords.length === 1 && conn) return { candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_tables) };
|
|
1051
|
+
if (prevWords.length === 2) return { candidates: filterAndCase(["FROM", "TO"], currentWord, ctx.settings) };
|
|
1052
|
+
if (prevWords.length >= 3) {
|
|
1053
|
+
const last = prevWords[prevWords.length - 1].toUpperCase();
|
|
1054
|
+
if (last === "FROM" || last === "TO") return { candidates: completeFilenames(currentWord, "none") };
|
|
1055
|
+
}
|
|
1056
|
+
return { candidates: [] };
|
|
1057
|
+
}
|
|
1058
|
+
if (cmd === "\\drds" || cmd === "\\drg") {
|
|
1059
|
+
if (prevWords.length === 1 && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord) };
|
|
1060
|
+
return { candidates: [] };
|
|
1061
|
+
}
|
|
1062
|
+
return { candidates: [] };
|
|
1443
1063
|
};
|
|
1444
|
-
// ---------------------------------------------------------------------------
|
|
1445
|
-
// SQL rules.
|
|
1446
|
-
// ---------------------------------------------------------------------------
|
|
1447
1064
|
const sqlRules = async (prevWords, currentWord, ctx, conn) => {
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
}
|
|
1918
|
-
// CREATE INDEX ... ON <table> <TAB> → USING / (.
|
|
1919
|
-
if ((HeadMatches(prevWords, ["CREATE", "INDEX"]) ||
|
|
1920
|
-
HeadMatches(prevWords, ["CREATE", "UNIQUE", "INDEX"])) &&
|
|
1921
|
-
TailMatches(prevWords, ["ON", MatchAny])) {
|
|
1922
|
-
return {
|
|
1923
|
-
candidates: filterAndCase(["USING", "("], currentWord, ctx.settings),
|
|
1924
|
-
};
|
|
1925
|
-
}
|
|
1926
|
-
// CREATE INDEX ... USING <TAB> → access methods.
|
|
1927
|
-
if ((HeadMatches(prevWords, ["CREATE", "INDEX"]) ||
|
|
1928
|
-
HeadMatches(prevWords, ["CREATE", "UNIQUE", "INDEX"])) &&
|
|
1929
|
-
TailMatches(prevWords, ["USING"])) {
|
|
1930
|
-
if (!conn) {
|
|
1931
|
-
// Even without a connection, offer the built-in AMs as a fallback.
|
|
1932
|
-
return {
|
|
1933
|
-
candidates: filterAndCase(["btree", "hash", "gist", "gin", "spgist", "brin"], currentWord, ctx.settings),
|
|
1934
|
-
};
|
|
1935
|
-
}
|
|
1936
|
-
return {
|
|
1937
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_index_access_methods, currentWord),
|
|
1938
|
-
};
|
|
1939
|
-
}
|
|
1940
|
-
// CREATE ... — first sub-object keyword.
|
|
1941
|
-
if (TailMatches(prevWords, ["CREATE"])) {
|
|
1942
|
-
return {
|
|
1943
|
-
candidates: filterAndCase(CREATE_OBJECTS, currentWord, ctx.settings),
|
|
1944
|
-
};
|
|
1945
|
-
}
|
|
1946
|
-
if (TailMatches(prevWords, ["CREATE", "TABLE"])) {
|
|
1947
|
-
// Upstream's `words_after_create` fallback (tab-complete.in.c
|
|
1948
|
-
// ~lines 2062-2082) runs `Query_for_list_of_tables` when the
|
|
1949
|
-
// word immediately before the cursor is `TABLE`. The intent is to
|
|
1950
|
-
// surface existing table names as a HINT — the user can pick a
|
|
1951
|
-
// similar name as a starting point. The completion is non-binding;
|
|
1952
|
-
// psql doesn't actually insert one of these on a single Tab if
|
|
1953
|
-
// the prefix is ambiguous, but the listing on Tab-Tab matches
|
|
1954
|
-
// upstream's `qr/mytab123 +mytab246/`.
|
|
1955
|
-
return completeTables();
|
|
1956
|
-
}
|
|
1957
|
-
// Inside CREATE TABLE column-list parens: `<col_name> <TAB>` → types.
|
|
1958
|
-
if (HeadMatches(prevWords, ["CREATE", "TABLE"]) &&
|
|
1959
|
-
TailMatches(prevWords, ["(|,", MatchAny])) {
|
|
1960
|
-
if (!conn)
|
|
1961
|
-
return { candidates: [] };
|
|
1962
|
-
return {
|
|
1963
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_datatypes, currentWord),
|
|
1964
|
-
};
|
|
1965
|
-
}
|
|
1966
|
-
if (TailMatches(prevWords, ["CREATE", "OR", "REPLACE"])) {
|
|
1967
|
-
return {
|
|
1968
|
-
candidates: filterAndCase([
|
|
1969
|
-
"FUNCTION",
|
|
1970
|
-
"PROCEDURE",
|
|
1971
|
-
"VIEW",
|
|
1972
|
-
"TRIGGER",
|
|
1973
|
-
"AGGREGATE",
|
|
1974
|
-
"TRANSFORM",
|
|
1975
|
-
], currentWord, ctx.settings),
|
|
1976
|
-
};
|
|
1977
|
-
}
|
|
1978
|
-
// TRUNCATE [TABLE] x
|
|
1979
|
-
if (TailMatches(prevWords, ["TRUNCATE"])) {
|
|
1980
|
-
return {
|
|
1981
|
-
candidates: [
|
|
1982
|
-
...filterAndCase(["TABLE", "ONLY"], currentWord, ctx.settings),
|
|
1983
|
-
...(await tableCandidates(conn, currentWord)),
|
|
1984
|
-
],
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
if (TailMatches(prevWords, ["TRUNCATE", "TABLE"]))
|
|
1988
|
-
return completeTables();
|
|
1989
|
-
if (TailMatches(prevWords, ["TRUNCATE", "ONLY"]))
|
|
1990
|
-
return completeTables();
|
|
1991
|
-
// COPY ... FROM <sth> WITH ( — option keywords inside the WITH
|
|
1992
|
-
// parenthesised list. The tokenizer splits `(` and `,` into their
|
|
1993
|
-
// own tokens so the tail looks like `[... WITH (]` for the first
|
|
1994
|
-
// option and `[..., WITH, (, opt, ,]` for subsequent ones. Two
|
|
1995
|
-
// arms: one for FROM (which adds DEFAULT, FORCE_NOT_NULL, etc.)
|
|
1996
|
-
// and one for TO (which adds FORCE_QUOTE only). Mirrors upstream
|
|
1997
|
-
// tab-complete.in.c ~3309-3315 (`Copy_from_options` /
|
|
1998
|
-
// `Copy_to_options`). The `HeadMatches` guard restricts the rule
|
|
1999
|
-
// to a real COPY statement so the generic `(`/`,` pattern doesn't
|
|
2000
|
-
// fire inside CREATE TABLE / SELECT lists.
|
|
2001
|
-
if (HeadMatches(prevWords, ["COPY|\\copy"]) &&
|
|
2002
|
-
HeadMatches(prevWords, [MatchAny, MatchAny, "FROM"]) &&
|
|
2003
|
-
(TailMatches(prevWords, ["("]) || TailMatches(prevWords, [","]))) {
|
|
2004
|
-
return {
|
|
2005
|
-
candidates: filterAndCase(COPY_FROM_OPTIONS, currentWord, ctx.settings),
|
|
2006
|
-
};
|
|
2007
|
-
}
|
|
2008
|
-
if (HeadMatches(prevWords, ["COPY|\\copy"]) &&
|
|
2009
|
-
HeadMatches(prevWords, [MatchAny, MatchAny, "TO"]) &&
|
|
2010
|
-
(TailMatches(prevWords, ["("]) || TailMatches(prevWords, [","]))) {
|
|
2011
|
-
return {
|
|
2012
|
-
candidates: filterAndCase(COPY_TO_OPTIONS, currentWord, ctx.settings),
|
|
2013
|
-
};
|
|
2014
|
-
}
|
|
2015
|
-
// COPY x → tables. (The `COPY x FROM/TO <path>` filename completion is
|
|
2016
|
-
// handled by the early `isCopyFromOrTo` check at the top of this
|
|
2017
|
-
// function so it wins over the generic `FROM <prefix>` table rule.)
|
|
2018
|
-
if (TailMatches(prevWords, ["COPY"]))
|
|
2019
|
-
return completeTables();
|
|
2020
|
-
if (TailMatches(prevWords, ["COPY", MatchAny])) {
|
|
2021
|
-
return {
|
|
2022
|
-
candidates: filterAndCase(["FROM", "TO"], currentWord, ctx.settings),
|
|
2023
|
-
};
|
|
2024
|
-
}
|
|
2025
|
-
// ANALYZE x → tables (optional VERBOSE first).
|
|
2026
|
-
if (TailMatches(prevWords, ["ANALYZE"]) ||
|
|
2027
|
-
TailMatches(prevWords, ["ANALYZE", "VERBOSE"])) {
|
|
2028
|
-
return completeTables();
|
|
2029
|
-
}
|
|
2030
|
-
// VACUUM x → tables.
|
|
2031
|
-
if (TailMatches(prevWords, ["VACUUM"]) ||
|
|
2032
|
-
TailMatches(prevWords, ["VACUUM", "VERBOSE"])) {
|
|
2033
|
-
return completeTables();
|
|
2034
|
-
}
|
|
2035
|
-
if (TailMatches(prevWords, ["VACUUM", "FULL"]))
|
|
2036
|
-
return completeTables();
|
|
2037
|
-
if (TailMatches(prevWords, ["VACUUM", "ANALYZE"]))
|
|
2038
|
-
return completeTables();
|
|
2039
|
-
// REINDEX [TABLE|INDEX|SCHEMA|DATABASE] x
|
|
2040
|
-
if (TailMatches(prevWords, ["REINDEX"])) {
|
|
2041
|
-
return {
|
|
2042
|
-
candidates: filterAndCase([
|
|
2043
|
-
"TABLE",
|
|
2044
|
-
"INDEX",
|
|
2045
|
-
"SCHEMA",
|
|
2046
|
-
"DATABASE",
|
|
2047
|
-
"SYSTEM",
|
|
2048
|
-
"CONCURRENTLY",
|
|
2049
|
-
], currentWord, ctx.settings),
|
|
2050
|
-
};
|
|
2051
|
-
}
|
|
2052
|
-
if (TailMatches(prevWords, ["REINDEX", "TABLE"]))
|
|
2053
|
-
return completeTables();
|
|
2054
|
-
if (TailMatches(prevWords, ["REINDEX", "INDEX"])) {
|
|
2055
|
-
return completeTables(Query_for_list_of_indexes);
|
|
2056
|
-
}
|
|
2057
|
-
if (TailMatches(prevWords, ["REINDEX", "SCHEMA"])) {
|
|
2058
|
-
if (!conn)
|
|
2059
|
-
return { candidates: [] };
|
|
2060
|
-
return {
|
|
2061
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord),
|
|
2062
|
-
};
|
|
2063
|
-
}
|
|
2064
|
-
if (TailMatches(prevWords, ["REINDEX", "DATABASE"])) {
|
|
2065
|
-
if (!conn)
|
|
2066
|
-
return { candidates: [] };
|
|
2067
|
-
return {
|
|
2068
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_databases, currentWord),
|
|
2069
|
-
};
|
|
2070
|
-
}
|
|
2071
|
-
// GRANT … ON … TO …
|
|
2072
|
-
if (TailMatches(prevWords, ["GRANT"]) ||
|
|
2073
|
-
TailMatches(prevWords, ["REVOKE"])) {
|
|
2074
|
-
return {
|
|
2075
|
-
candidates: filterAndCase(PRIVILEGE_KEYWORDS, currentWord, ctx.settings),
|
|
2076
|
-
};
|
|
2077
|
-
}
|
|
2078
|
-
if (TailMatches(prevWords, ["ON"])) {
|
|
2079
|
-
// Could be either GRANT/REVOKE … ON or CREATE INDEX … ON. We try
|
|
2080
|
-
// tables; if the prior keyword set is CREATE INDEX the rule above
|
|
2081
|
-
// already short-circuited.
|
|
2082
|
-
return completeTables();
|
|
2083
|
-
}
|
|
2084
|
-
if (TailMatches(prevWords, ["TO"])) {
|
|
2085
|
-
if (HeadMatches(prevWords, ["GRANT"]) && conn) {
|
|
2086
|
-
return {
|
|
2087
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord),
|
|
2088
|
-
};
|
|
2089
|
-
}
|
|
2090
|
-
}
|
|
2091
|
-
if (TailMatches(prevWords, ["FROM"]) &&
|
|
2092
|
-
HeadMatches(prevWords, ["REVOKE"])) {
|
|
2093
|
-
if (!conn)
|
|
2094
|
-
return { candidates: [] };
|
|
2095
|
-
return {
|
|
2096
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord),
|
|
2097
|
-
};
|
|
2098
|
-
}
|
|
2099
|
-
// LOCK [TABLE] x
|
|
2100
|
-
if (TailMatches(prevWords, ["LOCK"])) {
|
|
2101
|
-
return {
|
|
2102
|
-
candidates: [
|
|
2103
|
-
...filterAndCase(["TABLE"], currentWord, ctx.settings),
|
|
2104
|
-
...(await tableCandidates(conn, currentWord)),
|
|
2105
|
-
],
|
|
2106
|
-
};
|
|
2107
|
-
}
|
|
2108
|
-
if (TailMatches(prevWords, ["LOCK", "TABLE"]))
|
|
2109
|
-
return completeTables();
|
|
2110
|
-
// SET search_path, SET ROLE, SET SCHEMA, etc.
|
|
2111
|
-
if (TailMatches(prevWords, ["SET", "ROLE"])) {
|
|
2112
|
-
if (!conn)
|
|
2113
|
-
return { candidates: [] };
|
|
2114
|
-
return {
|
|
2115
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord),
|
|
2116
|
-
};
|
|
2117
|
-
}
|
|
2118
|
-
if (TailMatches(prevWords, ["SET", "SCHEMA"])) {
|
|
2119
|
-
if (!conn)
|
|
2120
|
-
return { candidates: [] };
|
|
2121
|
-
return {
|
|
2122
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord),
|
|
2123
|
-
};
|
|
2124
|
-
}
|
|
2125
|
-
if (TailMatches(prevWords, ["SET", "SESSION"])) {
|
|
2126
|
-
return {
|
|
2127
|
-
candidates: filterAndCase(["AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION"], currentWord, ctx.settings),
|
|
2128
|
-
};
|
|
2129
|
-
}
|
|
2130
|
-
if (TailMatches(prevWords, ["SET", "TRANSACTION"])) {
|
|
2131
|
-
return {
|
|
2132
|
-
candidates: filterAndCase(["ISOLATION LEVEL", "READ ONLY", "READ WRITE", "DEFERRABLE"], currentWord, ctx.settings),
|
|
2133
|
-
};
|
|
2134
|
-
}
|
|
2135
|
-
// `SET <name> TO|= <TAB>` — for DateStyle we can suggest the formats.
|
|
2136
|
-
if (TailMatches(prevWords, ["SET", "DateStyle", "TO|="]) ||
|
|
2137
|
-
TailMatches(prevWords, ["SET", "DATESTYLE", "TO|="]) ||
|
|
2138
|
-
TailMatches(prevWords, ["SET", "datestyle", "TO|="])) {
|
|
2139
|
-
return {
|
|
2140
|
-
candidates: filterAndCase(DATESTYLE_VALUES, currentWord, ctx.settings),
|
|
2141
|
-
};
|
|
2142
|
-
}
|
|
2143
|
-
// `SET timezone TO <prefix>` — names from pg_timezone_names. Two
|
|
2144
|
-
// variants depending on whether the user has opened a single quote:
|
|
2145
|
-
// - `SET timezone TO am<TAB>` → user typed an unquoted prefix; we
|
|
2146
|
-
// respond with `'America/'`-style quoted candidates so the next
|
|
2147
|
-
// keystroke continues inside the string literal. The
|
|
2148
|
-
// `Query_for_list_of_timezone_names_quoted_out` template matches
|
|
2149
|
-
// LIKE against the unquoted name and returns `quote_literal(name)`.
|
|
2150
|
-
// - `SET timezone TO 'America/New_<TAB>` → user is mid-literal;
|
|
2151
|
-
// `Query_for_list_of_timezone_names_quoted_in` matches the LIKE
|
|
2152
|
-
// pattern against the quoted form so the partial `'America/New_`
|
|
2153
|
-
// resolves correctly.
|
|
2154
|
-
// Mirrors upstream tab-complete.in.c ~line 4530.
|
|
2155
|
-
if (TailMatches(prevWords, ["SET", "timezone", "TO|="]) ||
|
|
2156
|
-
TailMatches(prevWords, ["SET", "TIMEZONE", "TO|="]) ||
|
|
2157
|
-
TailMatches(prevWords, ["SET", "TimeZone", "TO|="])) {
|
|
2158
|
-
if (!conn)
|
|
2159
|
-
return { candidates: [] };
|
|
2160
|
-
const query = currentWord.startsWith("'")
|
|
2161
|
-
? Query_for_list_of_timezone_names_quoted_in
|
|
2162
|
-
: Query_for_list_of_timezone_names_quoted_out;
|
|
2163
|
-
const cands = await runCatalogQuery(conn, query, currentWord);
|
|
2164
|
-
return { candidates: cands };
|
|
2165
|
-
}
|
|
2166
|
-
// `SET <name> TO|= <prefix>` for any enum-typed GUC — emit the legal
|
|
2167
|
-
// values from `pg_settings.enumvals`. Mirrors upstream `tab-complete.in.c`
|
|
2168
|
-
// `Query_for_values_of_enum_GUC`. Enum-typed GUCs (intervalstyle,
|
|
2169
|
-
// bytea_output, synchronous_commit, plpgsql.variable_conflict, …) get
|
|
2170
|
-
// value completion; non-enum GUCs return an empty rowset (no candidates)
|
|
2171
|
-
// — matching upstream, which also emits nothing for unknown GUCs once a
|
|
2172
|
-
// value position is reached.
|
|
2173
|
-
if (TailMatches(prevWords, ["SET", MatchAny, "TO|="])) {
|
|
2174
|
-
if (!conn)
|
|
2175
|
-
return { candidates: [] };
|
|
2176
|
-
// Walk back to the GUC name (the word before TO/=).
|
|
2177
|
-
const gucName = prevWords[prevWords.length - 2];
|
|
2178
|
-
const cands = await runCatalogQuery(conn, Query_for_values_of_enum_GUC, currentWord, [gucName]);
|
|
2179
|
-
return { candidates: cands };
|
|
2180
|
-
}
|
|
2181
|
-
// `SET <name> <TAB>` (no operator yet) → TO.
|
|
2182
|
-
// Upstream tab-complete.in.c uses `COMPLETE_WITH("TO")` here even
|
|
2183
|
-
// though `SET <name> = <value>` is valid syntax — the goal is a
|
|
2184
|
-
// single unique completion so `set foo<tab><tab>` resolves to
|
|
2185
|
-
// `set foo TO ` rather than listing two near-synonymous separators.
|
|
2186
|
-
// Verified against vanilla psql 18 + upstream test line 366.
|
|
2187
|
-
if (TailMatches(prevWords, ["SET", MatchAny])) {
|
|
2188
|
-
return {
|
|
2189
|
-
candidates: filterAndCase(["TO"], currentWord, ctx.settings),
|
|
2190
|
-
};
|
|
2191
|
-
}
|
|
2192
|
-
// Bare SET <TAB>: GUC name OR top-level SET sub-keywords (ROLE, SCHEMA, …).
|
|
2193
|
-
if (TailMatches(prevWords, ["SET"])) {
|
|
2194
|
-
const staticKw = filterAndCase([
|
|
2195
|
-
"CONSTRAINTS",
|
|
2196
|
-
"LOCAL",
|
|
2197
|
-
"ROLE",
|
|
2198
|
-
"SCHEMA",
|
|
2199
|
-
"SESSION",
|
|
2200
|
-
"TIME ZONE",
|
|
2201
|
-
"TRANSACTION",
|
|
2202
|
-
], currentWord, ctx.settings);
|
|
2203
|
-
if (!conn)
|
|
2204
|
-
return { candidates: staticKw };
|
|
2205
|
-
const guc = await runCatalogQuery(conn, Query_for_list_of_set_vars, currentWord);
|
|
2206
|
-
return { candidates: [...staticKw, ...guc] };
|
|
2207
|
-
}
|
|
2208
|
-
// SHOW <TAB> — ALL keyword plus the live GUC list.
|
|
2209
|
-
if (TailMatches(prevWords, ["SHOW"])) {
|
|
2210
|
-
const staticKw = filterAndCase(["ALL"], currentWord, ctx.settings);
|
|
2211
|
-
if (!conn) {
|
|
2212
|
-
return {
|
|
2213
|
-
candidates: [
|
|
2214
|
-
...staticKw,
|
|
2215
|
-
...filterAndCase([
|
|
2216
|
-
"search_path",
|
|
2217
|
-
"role",
|
|
2218
|
-
"session_authorization",
|
|
2219
|
-
"transaction_isolation",
|
|
2220
|
-
"client_encoding",
|
|
2221
|
-
"server_encoding",
|
|
2222
|
-
"server_version",
|
|
2223
|
-
"timezone",
|
|
2224
|
-
], currentWord, ctx.settings),
|
|
2225
|
-
],
|
|
2226
|
-
};
|
|
2227
|
-
}
|
|
2228
|
-
const guc = await runCatalogQuery(conn, Query_for_list_of_set_vars, currentWord);
|
|
2229
|
-
return { candidates: [...staticKw, ...guc] };
|
|
2230
|
-
}
|
|
2231
|
-
// RESET <TAB> — ALL or the live GUC list.
|
|
2232
|
-
if (TailMatches(prevWords, ["RESET"])) {
|
|
2233
|
-
const staticKw = filterAndCase(["ALL", "SESSION AUTHORIZATION", "ROLE"], currentWord, ctx.settings);
|
|
2234
|
-
if (!conn)
|
|
2235
|
-
return { candidates: staticKw };
|
|
2236
|
-
const guc = await runCatalogQuery(conn, Query_for_list_of_set_vars, currentWord);
|
|
2237
|
-
return { candidates: [...staticKw, ...guc] };
|
|
2238
|
-
}
|
|
2239
|
-
// START / BEGIN [TRANSACTION] …
|
|
2240
|
-
if (TailMatches(prevWords, ["BEGIN"]) ||
|
|
2241
|
-
TailMatches(prevWords, ["START"])) {
|
|
2242
|
-
return {
|
|
2243
|
-
candidates: filterAndCase(TRANSACTION_KEYWORDS, currentWord, ctx.settings),
|
|
2244
|
-
};
|
|
2245
|
-
}
|
|
2246
|
-
// COMMIT / ROLLBACK / RELEASE / SAVEPOINT - small completions
|
|
2247
|
-
if (TailMatches(prevWords, ["ROLLBACK"])) {
|
|
2248
|
-
return {
|
|
2249
|
-
candidates: filterAndCase(["TO SAVEPOINT", "TRANSACTION", "AND CHAIN", "AND NO CHAIN"], currentWord, ctx.settings),
|
|
2250
|
-
};
|
|
2251
|
-
}
|
|
2252
|
-
// EXPLAIN … — pass through to SELECT-/INSERT-/UPDATE-style rules by
|
|
2253
|
-
// letting subsequent words drive completion. For the first word after
|
|
2254
|
-
// EXPLAIN, offer the options + statement keywords.
|
|
2255
|
-
if (TailMatches(prevWords, ["EXPLAIN"])) {
|
|
2256
|
-
return {
|
|
2257
|
-
candidates: filterAndCase([
|
|
2258
|
-
"ANALYZE",
|
|
2259
|
-
"VERBOSE",
|
|
2260
|
-
"SELECT",
|
|
2261
|
-
"INSERT INTO",
|
|
2262
|
-
"UPDATE",
|
|
2263
|
-
"DELETE FROM",
|
|
2264
|
-
"(",
|
|
2265
|
-
], currentWord, ctx.settings),
|
|
2266
|
-
};
|
|
2267
|
-
}
|
|
2268
|
-
// DECLARE … CURSOR FOR …
|
|
2269
|
-
if (TailMatches(prevWords, ["DECLARE"])) {
|
|
2270
|
-
return { candidates: [] };
|
|
2271
|
-
}
|
|
2272
|
-
// CALL / DO — no completion beyond keywords (procedure args / language).
|
|
2273
|
-
if (TailMatches(prevWords, ["CALL"])) {
|
|
2274
|
-
if (!conn)
|
|
2275
|
-
return { candidates: [] };
|
|
2276
|
-
return {
|
|
2277
|
-
candidates: await runCatalogQuery(conn, Query_for_list_of_functions, currentWord),
|
|
2278
|
-
};
|
|
2279
|
-
}
|
|
2280
|
-
// After SELECT — offer FROM / common functions.
|
|
2281
|
-
if (TailMatches(prevWords, ["SELECT"])) {
|
|
2282
|
-
// The next word can be anything (column list); offer DISTINCT/ALL/* as a
|
|
2283
|
-
// small hint set.
|
|
2284
|
-
return {
|
|
2285
|
-
candidates: filterAndCase([
|
|
2286
|
-
"DISTINCT",
|
|
2287
|
-
"ALL",
|
|
2288
|
-
"*",
|
|
2289
|
-
"CURRENT_DATE",
|
|
2290
|
-
"CURRENT_TIME",
|
|
2291
|
-
"CURRENT_TIMESTAMP",
|
|
2292
|
-
"CURRENT_USER",
|
|
2293
|
-
"NULL",
|
|
2294
|
-
"TRUE",
|
|
2295
|
-
"FALSE",
|
|
2296
|
-
], currentWord, ctx.settings),
|
|
2297
|
-
};
|
|
2298
|
-
}
|
|
2299
|
-
// Trailing-keyword fallthrough: WHERE, ORDER BY, GROUP BY, LIMIT etc.
|
|
2300
|
-
if (TailMatches(prevWords, ["SELECT", "*"])) {
|
|
2301
|
-
return {
|
|
2302
|
-
candidates: filterAndCase(["FROM"], currentWord, ctx.settings),
|
|
2303
|
-
};
|
|
2304
|
-
}
|
|
2305
|
-
// No specific rule fired.
|
|
2306
|
-
return { candidates: [] };
|
|
1065
|
+
const completeTables = async (query = Query_for_list_of_tables) => {
|
|
1066
|
+
if (!conn) return { candidates: [] };
|
|
1067
|
+
return { candidates: await completeSchemaOrRelations(conn, currentWord, query) };
|
|
1068
|
+
};
|
|
1069
|
+
if (isCopyFromOrTo(prevWords)) return { candidates: completeFilenames(currentWord, "sql") };
|
|
1070
|
+
if (TailMatches(prevWords, ["FROM"]) && !HeadMatches(prevWords, ["REVOKE"])) return completeTables(Query_for_list_of_tables_views);
|
|
1071
|
+
if (TailMatches(prevWords, ["UPDATE"])) return completeTables();
|
|
1072
|
+
if (TailMatches(prevWords, ["DELETE", "FROM"])) return completeTables();
|
|
1073
|
+
if (TailMatches(prevWords, ["INTO"])) return completeTables();
|
|
1074
|
+
if (TailMatches(prevWords, ["JOIN"])) return completeTables(Query_for_list_of_tables_views);
|
|
1075
|
+
if (TailMatches(prevWords, ["JOIN", null])) return { candidates: filterAndCase(["ON", "USING"], currentWord, ctx.settings) };
|
|
1076
|
+
const inSelectContext = HeadMatches(prevWords, ["SELECT"]) || HeadMatches(prevWords, ["INSERT"]) || HeadMatches(prevWords, ["UPDATE"]) || HeadMatches(prevWords, ["DELETE"]) || HeadMatches(prevWords, ["WITH"]) || HeadMatches(prevWords, ["EXPLAIN"]);
|
|
1077
|
+
if (inSelectContext && (TailMatches(prevWords, ["FROM", null]) || TailMatches(prevWords, [
|
|
1078
|
+
"FROM",
|
|
1079
|
+
null,
|
|
1080
|
+
null
|
|
1081
|
+
]))) return { candidates: filterAndCase(POST_FROM_KEYWORDS, currentWord, ctx.settings) };
|
|
1082
|
+
if (TailMatches(prevWords, ["OVER", "("])) return { candidates: filterAndCase(WINDOW_FRAME_KEYWORDS, currentWord, ctx.settings) };
|
|
1083
|
+
if (inSelectContext && TailMatches(prevWords, ["WHERE", null]) && !TailMatches(prevWords, ["WHERE"])) return { candidates: filterAndCase(WHERE_CONTINUATIONS, currentWord, ctx.settings) };
|
|
1084
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && TailMatches(prevWords, ["ADD"])) return { candidates: filterAndCase(ALTER_TABLE_ADD, currentWord, ctx.settings) };
|
|
1085
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && TailMatches(prevWords, ["DROP"])) return { candidates: filterAndCase(ALTER_TABLE_DROP, currentWord, ctx.settings) };
|
|
1086
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && TailMatches(prevWords, ["DROP", "CONSTRAINT"])) {
|
|
1087
|
+
if (!conn) return { candidates: [] };
|
|
1088
|
+
const refTokens = prevWords.slice(2, prevWords.length - 2);
|
|
1089
|
+
const ref = parseTableRef(refTokens);
|
|
1090
|
+
if (!ref) return { candidates: [] };
|
|
1091
|
+
return { candidates: ref.schema === null ? await runCatalogQuery(conn, Query_for_constraint_of_table, currentWord, [ref.table]) : await runCatalogQuery(conn, Query_for_constraint_of_table_in_schema, currentWord, [ref.schema, ref.table]) };
|
|
1092
|
+
}
|
|
1093
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && TailMatches(prevWords, ["RENAME"])) return { candidates: filterAndCase(ALTER_TABLE_RENAME, currentWord, ctx.settings) };
|
|
1094
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && (TailMatches(prevWords, ["ALTER"]) || TailMatches(prevWords, [
|
|
1095
|
+
"ALTER",
|
|
1096
|
+
"COLUMN",
|
|
1097
|
+
null
|
|
1098
|
+
]))) return { candidates: filterAndCase(ALTER_TABLE_ALTER_COLUMN, currentWord, ctx.settings) };
|
|
1099
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && TailMatches(prevWords, ["SET"])) return { candidates: filterAndCase(ALTER_TABLE_SET, currentWord, ctx.settings) };
|
|
1100
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && TailMatches(prevWords, ["ENABLE"])) return { candidates: filterAndCase(ALTER_TABLE_ENABLE, currentWord, ctx.settings) };
|
|
1101
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && TailMatches(prevWords, ["DISABLE"])) return { candidates: filterAndCase(ALTER_TABLE_DISABLE, currentWord, ctx.settings) };
|
|
1102
|
+
if (HeadMatches(prevWords, ["ALTER", "TABLE"]) && TailMatches(prevWords, ["REPLICA", "IDENTITY"])) return { candidates: filterAndCase(ALTER_TABLE_REPLICA_IDENTITY, currentWord, ctx.settings) };
|
|
1103
|
+
if (TailMatches(prevWords, [
|
|
1104
|
+
"ALTER",
|
|
1105
|
+
"TABLE",
|
|
1106
|
+
null
|
|
1107
|
+
])) return { candidates: filterAndCase(ALTER_TABLE_ACTIONS, currentWord, ctx.settings) };
|
|
1108
|
+
if (TailMatches(prevWords, ["ALTER", "TABLE"])) return completeTables();
|
|
1109
|
+
if (TailMatches(prevWords, [
|
|
1110
|
+
"ALTER",
|
|
1111
|
+
"VIEW",
|
|
1112
|
+
null
|
|
1113
|
+
])) return { candidates: filterAndCase(ALTER_VIEW_ACTIONS, currentWord, ctx.settings) };
|
|
1114
|
+
if (TailMatches(prevWords, ["ALTER", "VIEW"])) return completeTables(Query_for_list_of_views);
|
|
1115
|
+
if (TailMatches(prevWords, [
|
|
1116
|
+
"ALTER",
|
|
1117
|
+
"MATERIALIZED",
|
|
1118
|
+
"VIEW",
|
|
1119
|
+
null
|
|
1120
|
+
])) return { candidates: filterAndCase(ALTER_MATVIEW_ACTIONS, currentWord, ctx.settings) };
|
|
1121
|
+
if (TailMatches(prevWords, [
|
|
1122
|
+
"ALTER",
|
|
1123
|
+
"MATERIALIZED",
|
|
1124
|
+
"VIEW"
|
|
1125
|
+
])) return completeTables(Query_for_list_of_matviews);
|
|
1126
|
+
if (TailMatches(prevWords, [
|
|
1127
|
+
"ALTER",
|
|
1128
|
+
"INDEX",
|
|
1129
|
+
null
|
|
1130
|
+
])) return { candidates: filterAndCase(ALTER_INDEX_ACTIONS, currentWord, ctx.settings) };
|
|
1131
|
+
if (TailMatches(prevWords, ["ALTER", "INDEX"])) return completeTables(Query_for_list_of_indexes);
|
|
1132
|
+
if (TailMatches(prevWords, [
|
|
1133
|
+
"ALTER",
|
|
1134
|
+
"SEQUENCE",
|
|
1135
|
+
null
|
|
1136
|
+
])) return { candidates: filterAndCase(ALTER_SEQUENCE_ACTIONS, currentWord, ctx.settings) };
|
|
1137
|
+
if (TailMatches(prevWords, ["ALTER", "SEQUENCE"])) return completeTables(Query_for_list_of_sequences);
|
|
1138
|
+
if (TailMatches(prevWords, [
|
|
1139
|
+
"ALTER",
|
|
1140
|
+
"FUNCTION|PROCEDURE|ROUTINE",
|
|
1141
|
+
null
|
|
1142
|
+
])) return { candidates: filterAndCase(ALTER_FUNCTION_ACTIONS, currentWord, ctx.settings) };
|
|
1143
|
+
if (TailMatches(prevWords, ["ALTER", "FUNCTION|PROCEDURE|ROUTINE"])) {
|
|
1144
|
+
if (!conn) return { candidates: [] };
|
|
1145
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_functions, currentWord) };
|
|
1146
|
+
}
|
|
1147
|
+
if (TailMatches(prevWords, [
|
|
1148
|
+
"ALTER",
|
|
1149
|
+
"TYPE",
|
|
1150
|
+
null,
|
|
1151
|
+
"RENAME",
|
|
1152
|
+
"VALUE"
|
|
1153
|
+
]) && currentWord.startsWith("'")) {
|
|
1154
|
+
if (!conn) return { candidates: [] };
|
|
1155
|
+
const typeName = prevWords[prevWords.length - 3].toLowerCase();
|
|
1156
|
+
const labelPrefix = currentWord.slice(1);
|
|
1157
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_enum_values_quoted, labelPrefix, [typeName]) };
|
|
1158
|
+
}
|
|
1159
|
+
if (TailMatches(prevWords, [
|
|
1160
|
+
"ALTER",
|
|
1161
|
+
"TYPE",
|
|
1162
|
+
null
|
|
1163
|
+
])) return { candidates: filterAndCase(ALTER_TYPE_ACTIONS, currentWord, ctx.settings) };
|
|
1164
|
+
if (TailMatches(prevWords, ["ALTER", "TYPE"])) {
|
|
1165
|
+
if (!conn) return { candidates: [] };
|
|
1166
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_types, currentWord) };
|
|
1167
|
+
}
|
|
1168
|
+
if (TailMatches(prevWords, [
|
|
1169
|
+
"ALTER",
|
|
1170
|
+
"ROLE|USER|GROUP",
|
|
1171
|
+
null
|
|
1172
|
+
])) return { candidates: filterAndCase(ALTER_ROLE_ACTIONS, currentWord, ctx.settings) };
|
|
1173
|
+
if (TailMatches(prevWords, ["ALTER", "ROLE|USER|GROUP"])) {
|
|
1174
|
+
if (!conn) return { candidates: [] };
|
|
1175
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord) };
|
|
1176
|
+
}
|
|
1177
|
+
if (TailMatches(prevWords, [
|
|
1178
|
+
"ALTER",
|
|
1179
|
+
"DATABASE",
|
|
1180
|
+
null
|
|
1181
|
+
])) return { candidates: filterAndCase(ALTER_DATABASE_ACTIONS, currentWord, ctx.settings) };
|
|
1182
|
+
if (TailMatches(prevWords, ["ALTER", "DATABASE"])) {
|
|
1183
|
+
if (!conn) return { candidates: [] };
|
|
1184
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_databases, currentWord) };
|
|
1185
|
+
}
|
|
1186
|
+
if (TailMatches(prevWords, [
|
|
1187
|
+
"ALTER",
|
|
1188
|
+
"SCHEMA",
|
|
1189
|
+
null
|
|
1190
|
+
])) return { candidates: filterAndCase(ALTER_SCHEMA_ACTIONS, currentWord, ctx.settings) };
|
|
1191
|
+
if (TailMatches(prevWords, ["ALTER", "SCHEMA"])) {
|
|
1192
|
+
if (!conn) return { candidates: [] };
|
|
1193
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord) };
|
|
1194
|
+
}
|
|
1195
|
+
if (TailMatches(prevWords, [
|
|
1196
|
+
"ALTER",
|
|
1197
|
+
"EXTENSION",
|
|
1198
|
+
null
|
|
1199
|
+
])) return { candidates: filterAndCase(ALTER_EXTENSION_ACTIONS, currentWord, ctx.settings) };
|
|
1200
|
+
if (TailMatches(prevWords, ["ALTER", "EXTENSION"])) {
|
|
1201
|
+
if (!conn) return { candidates: [] };
|
|
1202
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_extensions, currentWord) };
|
|
1203
|
+
}
|
|
1204
|
+
if (TailMatches(prevWords, [
|
|
1205
|
+
"ALTER",
|
|
1206
|
+
"POLICY",
|
|
1207
|
+
null
|
|
1208
|
+
])) return { candidates: filterAndCase(ALTER_POLICY_ACTIONS, currentWord, ctx.settings) };
|
|
1209
|
+
if (HeadMatches(prevWords, ["ALTER", "POLICY"]) && TailMatches(prevWords, ["ON"])) return completeTables();
|
|
1210
|
+
if (TailMatches(prevWords, ["ALTER", "POLICY"])) return { candidates: [] };
|
|
1211
|
+
if (TailMatches(prevWords, [
|
|
1212
|
+
"ALTER",
|
|
1213
|
+
"PUBLICATION",
|
|
1214
|
+
null
|
|
1215
|
+
])) return { candidates: filterAndCase(ALTER_PUBLICATION_ACTIONS, currentWord, ctx.settings) };
|
|
1216
|
+
if (TailMatches(prevWords, ["ALTER", "PUBLICATION"])) {
|
|
1217
|
+
if (!conn) return { candidates: [] };
|
|
1218
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_publications, currentWord) };
|
|
1219
|
+
}
|
|
1220
|
+
if (TailMatches(prevWords, [
|
|
1221
|
+
"ALTER",
|
|
1222
|
+
"SUBSCRIPTION",
|
|
1223
|
+
null
|
|
1224
|
+
])) return { candidates: filterAndCase(ALTER_SUBSCRIPTION_ACTIONS, currentWord, ctx.settings) };
|
|
1225
|
+
if (TailMatches(prevWords, ["ALTER", "SUBSCRIPTION"])) {
|
|
1226
|
+
if (!conn) return { candidates: [] };
|
|
1227
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_subscriptions, currentWord) };
|
|
1228
|
+
}
|
|
1229
|
+
if (TailMatches(prevWords, ["ALTER"])) return { candidates: filterAndCase(ALTER_OBJECTS, currentWord, ctx.settings) };
|
|
1230
|
+
if (TailMatches(prevWords, ["DROP", "TABLE"])) return completeTables();
|
|
1231
|
+
if (TailMatches(prevWords, ["DROP", "VIEW"])) return completeTables(Query_for_list_of_views);
|
|
1232
|
+
if (TailMatches(prevWords, [
|
|
1233
|
+
"DROP",
|
|
1234
|
+
"MATERIALIZED",
|
|
1235
|
+
"VIEW"
|
|
1236
|
+
])) return completeTables(Query_for_list_of_matviews);
|
|
1237
|
+
if (TailMatches(prevWords, ["DROP", "INDEX"])) return completeTables(Query_for_list_of_indexes);
|
|
1238
|
+
if (TailMatches(prevWords, ["DROP", "SEQUENCE"])) return completeTables(Query_for_list_of_sequences);
|
|
1239
|
+
if (TailMatches(prevWords, ["DROP", "TYPE"])) {
|
|
1240
|
+
const keywords = filterAndCase(BUILTIN_DATATYPE_KEYWORDS, currentWord, ctx.settings);
|
|
1241
|
+
if (!conn) return { candidates: keywords };
|
|
1242
|
+
const types = await runCatalogQuery(conn, Query_for_list_of_types, currentWord);
|
|
1243
|
+
return { candidates: [...keywords, ...types] };
|
|
1244
|
+
}
|
|
1245
|
+
if (TailMatches(prevWords, ["DROP", "SCHEMA"])) {
|
|
1246
|
+
if (!conn) return { candidates: [] };
|
|
1247
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord) };
|
|
1248
|
+
}
|
|
1249
|
+
if (TailMatches(prevWords, ["DROP", "EXTENSION"])) {
|
|
1250
|
+
if (!conn) return { candidates: [] };
|
|
1251
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_extensions, currentWord) };
|
|
1252
|
+
}
|
|
1253
|
+
if (TailMatches(prevWords, ["DROP", "ROLE|USER|GROUP"])) {
|
|
1254
|
+
if (!conn) return { candidates: [] };
|
|
1255
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord) };
|
|
1256
|
+
}
|
|
1257
|
+
if (TailMatches(prevWords, ["DROP", "DATABASE"])) {
|
|
1258
|
+
if (!conn) return { candidates: [] };
|
|
1259
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_databases, currentWord) };
|
|
1260
|
+
}
|
|
1261
|
+
if (TailMatches(prevWords, ["DROP", "FUNCTION"])) {
|
|
1262
|
+
if (!conn) return { candidates: [] };
|
|
1263
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_functions, currentWord) };
|
|
1264
|
+
}
|
|
1265
|
+
if (TailMatches(prevWords, ["DROP", "LANGUAGE"])) {
|
|
1266
|
+
if (!conn) return { candidates: [] };
|
|
1267
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_languages, currentWord) };
|
|
1268
|
+
}
|
|
1269
|
+
if (TailMatches(prevWords, ["DROP", "TABLESPACE"])) {
|
|
1270
|
+
if (!conn) return { candidates: [] };
|
|
1271
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_tablespaces, currentWord) };
|
|
1272
|
+
}
|
|
1273
|
+
if (TailMatches(prevWords, ["DROP", "PUBLICATION"])) {
|
|
1274
|
+
if (!conn) return { candidates: [] };
|
|
1275
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_publications, currentWord) };
|
|
1276
|
+
}
|
|
1277
|
+
if (TailMatches(prevWords, ["DROP", "SUBSCRIPTION"])) {
|
|
1278
|
+
if (!conn) return { candidates: [] };
|
|
1279
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_subscriptions, currentWord) };
|
|
1280
|
+
}
|
|
1281
|
+
if (TailMatches(prevWords, ["DROP"])) return { candidates: filterAndCase(DROP_OBJECTS, currentWord, ctx.settings) };
|
|
1282
|
+
if (TailMatches(prevWords, ["CREATE", "INDEX"])) return { candidates: filterAndCase(CREATE_INDEX_OPTIONS, currentWord, ctx.settings) };
|
|
1283
|
+
if (TailMatches(prevWords, [
|
|
1284
|
+
"CREATE",
|
|
1285
|
+
"UNIQUE",
|
|
1286
|
+
"INDEX"
|
|
1287
|
+
])) return { candidates: filterAndCase(CREATE_INDEX_OPTIONS, currentWord, ctx.settings) };
|
|
1288
|
+
if (TailMatches(prevWords, [
|
|
1289
|
+
"CREATE",
|
|
1290
|
+
"INDEX",
|
|
1291
|
+
null
|
|
1292
|
+
]) || TailMatches(prevWords, [
|
|
1293
|
+
"CREATE",
|
|
1294
|
+
"UNIQUE",
|
|
1295
|
+
"INDEX",
|
|
1296
|
+
null
|
|
1297
|
+
])) return { candidates: filterAndCase(["ON"], currentWord, ctx.settings) };
|
|
1298
|
+
if (TailMatches(prevWords, [
|
|
1299
|
+
"CREATE",
|
|
1300
|
+
"INDEX",
|
|
1301
|
+
null,
|
|
1302
|
+
"ON"
|
|
1303
|
+
]) || TailMatches(prevWords, [
|
|
1304
|
+
"CREATE",
|
|
1305
|
+
"INDEX",
|
|
1306
|
+
"ON"
|
|
1307
|
+
]) || TailMatches(prevWords, [
|
|
1308
|
+
"CREATE",
|
|
1309
|
+
"UNIQUE",
|
|
1310
|
+
"INDEX",
|
|
1311
|
+
null,
|
|
1312
|
+
"ON"
|
|
1313
|
+
]) || TailMatches(prevWords, [
|
|
1314
|
+
"CREATE",
|
|
1315
|
+
"UNIQUE",
|
|
1316
|
+
"INDEX",
|
|
1317
|
+
"ON"
|
|
1318
|
+
])) return completeTables();
|
|
1319
|
+
if ((HeadMatches(prevWords, ["CREATE", "INDEX"]) || HeadMatches(prevWords, [
|
|
1320
|
+
"CREATE",
|
|
1321
|
+
"UNIQUE",
|
|
1322
|
+
"INDEX"
|
|
1323
|
+
])) && TailMatches(prevWords, ["ON", null])) return { candidates: filterAndCase(["USING", "("], currentWord, ctx.settings) };
|
|
1324
|
+
if ((HeadMatches(prevWords, ["CREATE", "INDEX"]) || HeadMatches(prevWords, [
|
|
1325
|
+
"CREATE",
|
|
1326
|
+
"UNIQUE",
|
|
1327
|
+
"INDEX"
|
|
1328
|
+
])) && TailMatches(prevWords, ["USING"])) {
|
|
1329
|
+
if (!conn) return { candidates: filterAndCase([
|
|
1330
|
+
"btree",
|
|
1331
|
+
"hash",
|
|
1332
|
+
"gist",
|
|
1333
|
+
"gin",
|
|
1334
|
+
"spgist",
|
|
1335
|
+
"brin"
|
|
1336
|
+
], currentWord, ctx.settings) };
|
|
1337
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_index_access_methods, currentWord) };
|
|
1338
|
+
}
|
|
1339
|
+
if (TailMatches(prevWords, ["CREATE"])) return { candidates: filterAndCase(CREATE_OBJECTS, currentWord, ctx.settings) };
|
|
1340
|
+
if (TailMatches(prevWords, ["CREATE", "TABLE"])) return completeTables();
|
|
1341
|
+
if (HeadMatches(prevWords, ["CREATE", "TABLE"]) && TailMatches(prevWords, ["(|,", null])) {
|
|
1342
|
+
if (!conn) return { candidates: [] };
|
|
1343
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_datatypes, currentWord) };
|
|
1344
|
+
}
|
|
1345
|
+
if (TailMatches(prevWords, [
|
|
1346
|
+
"CREATE",
|
|
1347
|
+
"OR",
|
|
1348
|
+
"REPLACE"
|
|
1349
|
+
])) return { candidates: filterAndCase([
|
|
1350
|
+
"FUNCTION",
|
|
1351
|
+
"PROCEDURE",
|
|
1352
|
+
"VIEW",
|
|
1353
|
+
"TRIGGER",
|
|
1354
|
+
"AGGREGATE",
|
|
1355
|
+
"TRANSFORM"
|
|
1356
|
+
], currentWord, ctx.settings) };
|
|
1357
|
+
if (TailMatches(prevWords, ["TRUNCATE"])) return { candidates: [...filterAndCase(["TABLE", "ONLY"], currentWord, ctx.settings), ...await tableCandidates(conn, currentWord)] };
|
|
1358
|
+
if (TailMatches(prevWords, ["TRUNCATE", "TABLE"])) return completeTables();
|
|
1359
|
+
if (TailMatches(prevWords, ["TRUNCATE", "ONLY"])) return completeTables();
|
|
1360
|
+
if (HeadMatches(prevWords, ["COPY|\\copy"]) && HeadMatches(prevWords, [
|
|
1361
|
+
null,
|
|
1362
|
+
null,
|
|
1363
|
+
"FROM"
|
|
1364
|
+
]) && (TailMatches(prevWords, ["("]) || TailMatches(prevWords, [","]))) return { candidates: filterAndCase(COPY_FROM_OPTIONS, currentWord, ctx.settings) };
|
|
1365
|
+
if (HeadMatches(prevWords, ["COPY|\\copy"]) && HeadMatches(prevWords, [
|
|
1366
|
+
null,
|
|
1367
|
+
null,
|
|
1368
|
+
"TO"
|
|
1369
|
+
]) && (TailMatches(prevWords, ["("]) || TailMatches(prevWords, [","]))) return { candidates: filterAndCase(COPY_TO_OPTIONS, currentWord, ctx.settings) };
|
|
1370
|
+
if (TailMatches(prevWords, ["COPY"])) return completeTables();
|
|
1371
|
+
if (TailMatches(prevWords, ["COPY", null])) return { candidates: filterAndCase(["FROM", "TO"], currentWord, ctx.settings) };
|
|
1372
|
+
if (TailMatches(prevWords, ["ANALYZE"]) || TailMatches(prevWords, ["ANALYZE", "VERBOSE"])) return completeTables();
|
|
1373
|
+
if (TailMatches(prevWords, ["VACUUM"]) || TailMatches(prevWords, ["VACUUM", "VERBOSE"])) return completeTables();
|
|
1374
|
+
if (TailMatches(prevWords, ["VACUUM", "FULL"])) return completeTables();
|
|
1375
|
+
if (TailMatches(prevWords, ["VACUUM", "ANALYZE"])) return completeTables();
|
|
1376
|
+
if (TailMatches(prevWords, ["REINDEX"])) return { candidates: filterAndCase([
|
|
1377
|
+
"TABLE",
|
|
1378
|
+
"INDEX",
|
|
1379
|
+
"SCHEMA",
|
|
1380
|
+
"DATABASE",
|
|
1381
|
+
"SYSTEM",
|
|
1382
|
+
"CONCURRENTLY"
|
|
1383
|
+
], currentWord, ctx.settings) };
|
|
1384
|
+
if (TailMatches(prevWords, ["REINDEX", "TABLE"])) return completeTables();
|
|
1385
|
+
if (TailMatches(prevWords, ["REINDEX", "INDEX"])) return completeTables(Query_for_list_of_indexes);
|
|
1386
|
+
if (TailMatches(prevWords, ["REINDEX", "SCHEMA"])) {
|
|
1387
|
+
if (!conn) return { candidates: [] };
|
|
1388
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord) };
|
|
1389
|
+
}
|
|
1390
|
+
if (TailMatches(prevWords, ["REINDEX", "DATABASE"])) {
|
|
1391
|
+
if (!conn) return { candidates: [] };
|
|
1392
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_databases, currentWord) };
|
|
1393
|
+
}
|
|
1394
|
+
if (TailMatches(prevWords, ["GRANT"]) || TailMatches(prevWords, ["REVOKE"])) return { candidates: filterAndCase(PRIVILEGE_KEYWORDS, currentWord, ctx.settings) };
|
|
1395
|
+
if (TailMatches(prevWords, ["ON"])) return completeTables();
|
|
1396
|
+
if (TailMatches(prevWords, ["TO"])) {
|
|
1397
|
+
if (HeadMatches(prevWords, ["GRANT"]) && conn) return { candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord) };
|
|
1398
|
+
}
|
|
1399
|
+
if (TailMatches(prevWords, ["FROM"]) && HeadMatches(prevWords, ["REVOKE"])) {
|
|
1400
|
+
if (!conn) return { candidates: [] };
|
|
1401
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord) };
|
|
1402
|
+
}
|
|
1403
|
+
if (TailMatches(prevWords, ["LOCK"])) return { candidates: [...filterAndCase(["TABLE"], currentWord, ctx.settings), ...await tableCandidates(conn, currentWord)] };
|
|
1404
|
+
if (TailMatches(prevWords, ["LOCK", "TABLE"])) return completeTables();
|
|
1405
|
+
if (TailMatches(prevWords, ["SET", "ROLE"])) {
|
|
1406
|
+
if (!conn) return { candidates: [] };
|
|
1407
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord) };
|
|
1408
|
+
}
|
|
1409
|
+
if (TailMatches(prevWords, ["SET", "SCHEMA"])) {
|
|
1410
|
+
if (!conn) return { candidates: [] };
|
|
1411
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord) };
|
|
1412
|
+
}
|
|
1413
|
+
if (TailMatches(prevWords, ["SET", "SESSION"])) return { candidates: filterAndCase(["AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION"], currentWord, ctx.settings) };
|
|
1414
|
+
if (TailMatches(prevWords, ["SET", "TRANSACTION"])) return { candidates: filterAndCase([
|
|
1415
|
+
"ISOLATION LEVEL",
|
|
1416
|
+
"READ ONLY",
|
|
1417
|
+
"READ WRITE",
|
|
1418
|
+
"DEFERRABLE"
|
|
1419
|
+
], currentWord, ctx.settings) };
|
|
1420
|
+
if (TailMatches(prevWords, [
|
|
1421
|
+
"SET",
|
|
1422
|
+
"DateStyle",
|
|
1423
|
+
"TO|="
|
|
1424
|
+
]) || TailMatches(prevWords, [
|
|
1425
|
+
"SET",
|
|
1426
|
+
"DATESTYLE",
|
|
1427
|
+
"TO|="
|
|
1428
|
+
]) || TailMatches(prevWords, [
|
|
1429
|
+
"SET",
|
|
1430
|
+
"datestyle",
|
|
1431
|
+
"TO|="
|
|
1432
|
+
])) return { candidates: filterAndCase(DATESTYLE_VALUES, currentWord, ctx.settings) };
|
|
1433
|
+
if (TailMatches(prevWords, [
|
|
1434
|
+
"SET",
|
|
1435
|
+
"timezone",
|
|
1436
|
+
"TO|="
|
|
1437
|
+
]) || TailMatches(prevWords, [
|
|
1438
|
+
"SET",
|
|
1439
|
+
"TIMEZONE",
|
|
1440
|
+
"TO|="
|
|
1441
|
+
]) || TailMatches(prevWords, [
|
|
1442
|
+
"SET",
|
|
1443
|
+
"TimeZone",
|
|
1444
|
+
"TO|="
|
|
1445
|
+
])) {
|
|
1446
|
+
if (!conn) return { candidates: [] };
|
|
1447
|
+
const query = currentWord.startsWith("'") ? Query_for_list_of_timezone_names_quoted_in : Query_for_list_of_timezone_names_quoted_out;
|
|
1448
|
+
return { candidates: await runCatalogQuery(conn, query, currentWord) };
|
|
1449
|
+
}
|
|
1450
|
+
if (TailMatches(prevWords, [
|
|
1451
|
+
"SET",
|
|
1452
|
+
null,
|
|
1453
|
+
"TO|="
|
|
1454
|
+
])) {
|
|
1455
|
+
if (!conn) return { candidates: [] };
|
|
1456
|
+
const gucName = prevWords[prevWords.length - 2];
|
|
1457
|
+
return { candidates: await runCatalogQuery(conn, Query_for_values_of_enum_GUC, currentWord, [gucName]) };
|
|
1458
|
+
}
|
|
1459
|
+
if (TailMatches(prevWords, ["SET", null])) return { candidates: filterAndCase(["TO"], currentWord, ctx.settings) };
|
|
1460
|
+
if (TailMatches(prevWords, ["SET"])) {
|
|
1461
|
+
const staticKw = filterAndCase([
|
|
1462
|
+
"CONSTRAINTS",
|
|
1463
|
+
"LOCAL",
|
|
1464
|
+
"ROLE",
|
|
1465
|
+
"SCHEMA",
|
|
1466
|
+
"SESSION",
|
|
1467
|
+
"TIME ZONE",
|
|
1468
|
+
"TRANSACTION"
|
|
1469
|
+
], currentWord, ctx.settings);
|
|
1470
|
+
if (!conn) return { candidates: staticKw };
|
|
1471
|
+
const guc = await runCatalogQuery(conn, Query_for_list_of_set_vars, currentWord);
|
|
1472
|
+
return { candidates: [...staticKw, ...guc] };
|
|
1473
|
+
}
|
|
1474
|
+
if (TailMatches(prevWords, ["SHOW"])) {
|
|
1475
|
+
const staticKw = filterAndCase(["ALL"], currentWord, ctx.settings);
|
|
1476
|
+
if (!conn) return { candidates: [...staticKw, ...filterAndCase([
|
|
1477
|
+
"search_path",
|
|
1478
|
+
"role",
|
|
1479
|
+
"session_authorization",
|
|
1480
|
+
"transaction_isolation",
|
|
1481
|
+
"client_encoding",
|
|
1482
|
+
"server_encoding",
|
|
1483
|
+
"server_version",
|
|
1484
|
+
"timezone"
|
|
1485
|
+
], currentWord, ctx.settings)] };
|
|
1486
|
+
const guc = await runCatalogQuery(conn, Query_for_list_of_set_vars, currentWord);
|
|
1487
|
+
return { candidates: [...staticKw, ...guc] };
|
|
1488
|
+
}
|
|
1489
|
+
if (TailMatches(prevWords, ["RESET"])) {
|
|
1490
|
+
const staticKw = filterAndCase([
|
|
1491
|
+
"ALL",
|
|
1492
|
+
"SESSION AUTHORIZATION",
|
|
1493
|
+
"ROLE"
|
|
1494
|
+
], currentWord, ctx.settings);
|
|
1495
|
+
if (!conn) return { candidates: staticKw };
|
|
1496
|
+
const guc = await runCatalogQuery(conn, Query_for_list_of_set_vars, currentWord);
|
|
1497
|
+
return { candidates: [...staticKw, ...guc] };
|
|
1498
|
+
}
|
|
1499
|
+
if (TailMatches(prevWords, ["BEGIN"]) || TailMatches(prevWords, ["START"])) return { candidates: filterAndCase(TRANSACTION_KEYWORDS, currentWord, ctx.settings) };
|
|
1500
|
+
if (TailMatches(prevWords, ["ROLLBACK"])) return { candidates: filterAndCase([
|
|
1501
|
+
"TO SAVEPOINT",
|
|
1502
|
+
"TRANSACTION",
|
|
1503
|
+
"AND CHAIN",
|
|
1504
|
+
"AND NO CHAIN"
|
|
1505
|
+
], currentWord, ctx.settings) };
|
|
1506
|
+
if (TailMatches(prevWords, ["EXPLAIN"])) return { candidates: filterAndCase([
|
|
1507
|
+
"ANALYZE",
|
|
1508
|
+
"VERBOSE",
|
|
1509
|
+
"SELECT",
|
|
1510
|
+
"INSERT INTO",
|
|
1511
|
+
"UPDATE",
|
|
1512
|
+
"DELETE FROM",
|
|
1513
|
+
"("
|
|
1514
|
+
], currentWord, ctx.settings) };
|
|
1515
|
+
if (TailMatches(prevWords, ["DECLARE"])) return { candidates: [] };
|
|
1516
|
+
if (TailMatches(prevWords, ["CALL"])) {
|
|
1517
|
+
if (!conn) return { candidates: [] };
|
|
1518
|
+
return { candidates: await runCatalogQuery(conn, Query_for_list_of_functions, currentWord) };
|
|
1519
|
+
}
|
|
1520
|
+
if (TailMatches(prevWords, ["SELECT"])) return { candidates: filterAndCase([
|
|
1521
|
+
"DISTINCT",
|
|
1522
|
+
"ALL",
|
|
1523
|
+
"*",
|
|
1524
|
+
"CURRENT_DATE",
|
|
1525
|
+
"CURRENT_TIME",
|
|
1526
|
+
"CURRENT_TIMESTAMP",
|
|
1527
|
+
"CURRENT_USER",
|
|
1528
|
+
"NULL",
|
|
1529
|
+
"TRUE",
|
|
1530
|
+
"FALSE"
|
|
1531
|
+
], currentWord, ctx.settings) };
|
|
1532
|
+
if (TailMatches(prevWords, ["SELECT", "*"])) return { candidates: filterAndCase(["FROM"], currentWord, ctx.settings) };
|
|
1533
|
+
return { candidates: [] };
|
|
2307
1534
|
};
|
|
2308
|
-
// ---------------------------------------------------------------------------
|
|
2309
|
-
// Helpers.
|
|
2310
|
-
// ---------------------------------------------------------------------------
|
|
2311
1535
|
/** Candidates for table-name completion, no schema-qualifier handling. */
|
|
2312
1536
|
const tableCandidates = async (conn, word) => {
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
return runCatalogQuery(conn, Query_for_list_of_tables, word);
|
|
1537
|
+
if (!conn) return [];
|
|
1538
|
+
return runCatalogQuery(conn, Query_for_list_of_tables, word);
|
|
2316
1539
|
};
|
|
2317
1540
|
/**
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
1541
|
+
* Schema-aware relation completion. If the user typed `schema.x`, fetch
|
|
1542
|
+
* relations in `schema` matching `x`. Otherwise fetch unqualified relations
|
|
1543
|
+
* AND a list of schemas (so the user can dot through to relations in any
|
|
1544
|
+
* schema, mirroring upstream's `complete_from_schema_query`).
|
|
1545
|
+
*
|
|
1546
|
+
* Schema names are returned with a trailing `.` so the completion engine
|
|
1547
|
+
* recognizes them as "in progress" and refrains from appending a space.
|
|
1548
|
+
* When a unique candidate is a schema (e.g. `pub<tab>` → `public.`) the
|
|
1549
|
+
* user can immediately Tab again to list relations within that schema.
|
|
1550
|
+
*
|
|
1551
|
+
* Quoted identifier handling: if the user's input starts with `"`, we
|
|
1552
|
+
* search the catalog case-sensitively (stripping the opening quote) and
|
|
1553
|
+
* return candidates pre-quoted with `"..."` so the line ends up in a
|
|
1554
|
+
* valid quoted form — matching upstream readline's behaviour for
|
|
1555
|
+
* `select * from "my<tab>` → `"mytab123 "mytab246`.
|
|
1556
|
+
*/
|
|
2334
1557
|
const completeSchemaOrRelations = async (conn, word, query) => {
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
// completes to `public.tab1` instead of preserving `PUBLIC` in the
|
|
2345
|
-
// returned candidate.
|
|
2346
|
-
const canonicalSchema = split.schemaWasQuoted
|
|
2347
|
-
? split.schema
|
|
2348
|
-
: split.schema.toLowerCase();
|
|
2349
|
-
return rows.map((r) => canonicalSchema + "." + r);
|
|
2350
|
-
}
|
|
2351
|
-
// Unqualified: combine relations + schemas (schemas suffixed with `.`).
|
|
2352
|
-
const [rels, schemas] = await Promise.all([
|
|
2353
|
-
runCatalogQuery(conn, query, word),
|
|
2354
|
-
runCatalogQuery(conn, Query_for_list_of_schemas, word),
|
|
2355
|
-
]);
|
|
2356
|
-
return [...rels, ...schemas.map((s) => s + ".")];
|
|
1558
|
+
if (word.startsWith("\"")) return completeQuotedRelations(conn, word, query);
|
|
1559
|
+
const split = splitSchemaPrefix(word);
|
|
1560
|
+
if (split) {
|
|
1561
|
+
const rows = await runCatalogQuery(conn, Query_for_list_of_relations_in_schema, split.prefix, [split.schema]);
|
|
1562
|
+
const canonicalSchema = split.schemaWasQuoted ? split.schema : split.schema.toLowerCase();
|
|
1563
|
+
return rows.map((r) => canonicalSchema + "." + r);
|
|
1564
|
+
}
|
|
1565
|
+
const [rels, schemas] = await Promise.all([runCatalogQuery(conn, query, word), runCatalogQuery(conn, Query_for_list_of_schemas, word)]);
|
|
1566
|
+
return [...rels, ...schemas.map((s) => s + ".")];
|
|
2357
1567
|
};
|
|
2358
1568
|
/**
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
1569
|
+
* Search the catalog for relations matching a user-supplied prefix that
|
|
1570
|
+
* begins with `"`. We strip the opening quote, search the RAW relname
|
|
1571
|
+
* case-sensitively (so `"mi` → `mixedName` rather than `mytab123`), and
|
|
1572
|
+
* emit results wrapped in `"..."` with a closing quote so the editor's
|
|
1573
|
+
* unique-completion handler appends the trailing space outside the
|
|
1574
|
+
* quoted region (e.g. `"mixedName" `).
|
|
1575
|
+
*/
|
|
2366
1576
|
const completeQuotedRelations = async (conn, word, query) => {
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
const sql = caseSensitiveRelnameVariant(query);
|
|
2372
|
-
if (!sql)
|
|
2373
|
-
return [];
|
|
2374
|
-
const rows = await runCatalogQuery(conn, sql, inside);
|
|
2375
|
-
return rows.map((name) => '"' + name + '"');
|
|
1577
|
+
const inside = word.slice(1).replace(/"$/, "");
|
|
1578
|
+
const sql = caseSensitiveRelnameVariant(query);
|
|
1579
|
+
if (!sql) return [];
|
|
1580
|
+
return (await runCatalogQuery(conn, sql, inside)).map((name) => "\"" + name + "\"");
|
|
2376
1581
|
};
|
|
2377
1582
|
/**
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
1583
|
+
* Build a case-sensitive variant of a relation-list query for quoted
|
|
1584
|
+
* input. The standard queries use `ILIKE` on `quote_ident(c.relname)`
|
|
1585
|
+
* (which obscures the original case for identifiers like `mixedName`);
|
|
1586
|
+
* we swap that for `LIKE` on the raw `c.relname` and return the raw
|
|
1587
|
+
* relname so we control the quoting.
|
|
1588
|
+
*
|
|
1589
|
+
* Returns null if the query isn't a recognised relation query
|
|
1590
|
+
* (defensive — keeps the quoted-completion code path bounded).
|
|
1591
|
+
*/
|
|
2387
1592
|
const caseSensitiveRelnameVariant = (sql) => {
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
if (!sql.includes("pg_catalog.pg_class c"))
|
|
2392
|
-
return null;
|
|
2393
|
-
if (!sql.includes("c.relname ILIKE $1"))
|
|
2394
|
-
return null;
|
|
2395
|
-
return sql
|
|
2396
|
-
.replace("SELECT pg_catalog.quote_ident(c.relname)", "SELECT c.relname")
|
|
2397
|
-
.replace("c.relname ILIKE $1", "c.relname LIKE $1");
|
|
1593
|
+
if (!sql.includes("pg_catalog.pg_class c")) return null;
|
|
1594
|
+
if (!sql.includes("c.relname ILIKE $1")) return null;
|
|
1595
|
+
return sql.replace("SELECT pg_catalog.quote_ident(c.relname)", "SELECT c.relname").replace("c.relname ILIKE $1", "c.relname LIKE $1");
|
|
2398
1596
|
};
|
|
2399
1597
|
/** Case-insensitive prefix filter; preserves the candidate's original casing. */
|
|
2400
1598
|
const filterCi = (candidates, prefix) => {
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
return candidates.filter((c) => c.toLowerCase().startsWith(lp));
|
|
1599
|
+
if (prefix.length === 0) return candidates.slice();
|
|
1600
|
+
const lp = prefix.toLowerCase();
|
|
1601
|
+
return candidates.filter((c) => c.toLowerCase().startsWith(lp));
|
|
2405
1602
|
};
|
|
2406
1603
|
/** Names of variables currently SET on the settings (for `\unset` etc). */
|
|
2407
1604
|
const listVarNames = (settings) => {
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
return out.sort();
|
|
1605
|
+
const out = [];
|
|
1606
|
+
for (const [name] of settings.vars.entries()) out.push(name);
|
|
1607
|
+
return out.sort();
|
|
2412
1608
|
};
|
|
2413
1609
|
/** Both currently-set variables AND special-variable names. */
|
|
2414
1610
|
const listAllVarNames = (settings) => {
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
set.add(n);
|
|
2420
|
-
return [...set].sort();
|
|
1611
|
+
const set = /* @__PURE__ */ new Set();
|
|
1612
|
+
for (const [name] of settings.vars.entries()) set.add(name);
|
|
1613
|
+
for (const n of SPECIAL_VARIABLES) set.add(n);
|
|
1614
|
+
return [...set].sort();
|
|
2421
1615
|
};
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
export
|
|
1616
|
+
const _internals = { splitSchemaPrefix };
|
|
1617
|
+
//#endregion
|
|
1618
|
+
export { ALTER_DATABASE_ACTIONS, ALTER_EXTENSION_ACTIONS, ALTER_FUNCTION_ACTIONS, ALTER_INDEX_ACTIONS, ALTER_MATVIEW_ACTIONS, ALTER_OBJECTS, ALTER_POLICY_ACTIONS, ALTER_PUBLICATION_ACTIONS, ALTER_ROLE_ACTIONS, ALTER_SCHEMA_ACTIONS, ALTER_SEQUENCE_ACTIONS, ALTER_SUBSCRIPTION_ACTIONS, ALTER_TABLE_ACTIONS, ALTER_TABLE_ADD, ALTER_TABLE_ALTER_COLUMN, ALTER_TABLE_DISABLE, ALTER_TABLE_DROP, ALTER_TABLE_ENABLE, ALTER_TABLE_RENAME, ALTER_TABLE_REPLICA_IDENTITY, ALTER_TABLE_SET, ALTER_TYPE_ACTIONS, ALTER_VIEW_ACTIONS, BACKSLASH_COMMANDS, BUILTIN_DATATYPE_KEYWORDS, COPY_FROM_OPTIONS, COPY_TO_OPTIONS, CREATE_INDEX_OPTIONS, CREATE_OBJECTS, DATESTYLE_VALUES, DROP_OBJECTS, POST_FROM_KEYWORDS, PRIVILEGE_KEYWORDS, SQL_TOP_KEYWORDS, TRANSACTION_KEYWORDS, WHERE_CONTINUATIONS, WINDOW_FRAME_KEYWORDS, _internals, findCompletions };
|