neonctl 2.22.0 → 2.23.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.
Files changed (116) hide show
  1. package/README.md +242 -16
  2. package/analytics.js +5 -2
  3. package/commands/branches.js +9 -1
  4. package/commands/checkout.js +249 -0
  5. package/commands/connection_string.js +15 -2
  6. package/commands/data_api.js +286 -0
  7. package/commands/functions.js +277 -0
  8. package/commands/index.js +12 -0
  9. package/commands/link.js +667 -0
  10. package/commands/neon_auth.js +1013 -0
  11. package/commands/projects.js +9 -1
  12. package/commands/psql.js +62 -0
  13. package/commands/set_context.js +7 -2
  14. package/context.js +86 -14
  15. package/functions_api.js +44 -0
  16. package/index.js +3 -0
  17. package/package.json +60 -51
  18. package/psql/cli.js +51 -0
  19. package/psql/command/cmd_cond.js +437 -0
  20. package/psql/command/cmd_connect.js +815 -0
  21. package/psql/command/cmd_copy.js +1025 -0
  22. package/psql/command/cmd_describe.js +1810 -0
  23. package/psql/command/cmd_format.js +909 -0
  24. package/psql/command/cmd_io.js +2187 -0
  25. package/psql/command/cmd_lo.js +385 -0
  26. package/psql/command/cmd_meta.js +970 -0
  27. package/psql/command/cmd_misc.js +187 -0
  28. package/psql/command/cmd_pipeline.js +1141 -0
  29. package/psql/command/cmd_restrict.js +171 -0
  30. package/psql/command/cmd_show.js +751 -0
  31. package/psql/command/dispatch.js +343 -0
  32. package/psql/command/inputQueue.js +42 -0
  33. package/psql/command/shared.js +71 -0
  34. package/psql/complete/filenames.js +139 -0
  35. package/psql/complete/index.js +104 -0
  36. package/psql/complete/matcher.js +314 -0
  37. package/psql/complete/psqlVars.js +247 -0
  38. package/psql/complete/queries.js +491 -0
  39. package/psql/complete/rules.js +2387 -0
  40. package/psql/core/common.js +1250 -0
  41. package/psql/core/help.js +576 -0
  42. package/psql/core/mainloop.js +1353 -0
  43. package/psql/core/prompt.js +437 -0
  44. package/psql/core/settings.js +684 -0
  45. package/psql/core/sqlHelp.js +1066 -0
  46. package/psql/core/startup.js +840 -0
  47. package/psql/core/syncVars.js +116 -0
  48. package/psql/core/variables.js +287 -0
  49. package/psql/describe/formatters.js +1277 -0
  50. package/psql/describe/processNamePattern.js +270 -0
  51. package/psql/describe/queries.js +2373 -0
  52. package/psql/describe/versionGate.js +43 -0
  53. package/psql/index.js +2005 -0
  54. package/psql/io/history.js +299 -0
  55. package/psql/io/input.js +120 -0
  56. package/psql/io/lineEditor/buffer.js +323 -0
  57. package/psql/io/lineEditor/complete.js +227 -0
  58. package/psql/io/lineEditor/filename.js +159 -0
  59. package/psql/io/lineEditor/index.js +891 -0
  60. package/psql/io/lineEditor/keymap.js +738 -0
  61. package/psql/io/lineEditor/vt100.js +363 -0
  62. package/psql/io/pgpass.js +202 -0
  63. package/psql/io/pgservice.js +194 -0
  64. package/psql/io/psqlrc.js +422 -0
  65. package/psql/print/aligned.js +1756 -0
  66. package/psql/print/asciidoc.js +248 -0
  67. package/psql/print/crosstab.js +460 -0
  68. package/psql/print/csv.js +92 -0
  69. package/psql/print/html.js +258 -0
  70. package/psql/print/json.js +96 -0
  71. package/psql/print/latex.js +396 -0
  72. package/psql/print/pager.js +265 -0
  73. package/psql/print/troff.js +258 -0
  74. package/psql/print/unaligned.js +118 -0
  75. package/psql/print/units.js +135 -0
  76. package/psql/scanner/slash.js +513 -0
  77. package/psql/scanner/sql.js +910 -0
  78. package/psql/scanner/stringutils.js +390 -0
  79. package/psql/types/backslash.js +1 -0
  80. package/psql/types/connection.js +1 -0
  81. package/psql/types/index.js +7 -0
  82. package/psql/types/printer.js +1 -0
  83. package/psql/types/repl.js +1 -0
  84. package/psql/types/scanner.js +24 -0
  85. package/psql/types/settings.js +1 -0
  86. package/psql/types/variables.js +1 -0
  87. package/psql/wire/connection.js +2844 -0
  88. package/psql/wire/copy.js +108 -0
  89. package/psql/wire/notify.js +59 -0
  90. package/psql/wire/pipeline.js +519 -0
  91. package/psql/wire/protocol.js +466 -0
  92. package/psql/wire/sasl.js +296 -0
  93. package/psql/wire/tls.js +596 -0
  94. package/test_utils/fixtures.js +1 -0
  95. package/utils/enrichers.js +18 -1
  96. package/utils/esbuild.js +147 -0
  97. package/utils/middlewares.js +1 -1
  98. package/utils/psql.js +107 -11
  99. package/utils/zip.js +4 -0
  100. package/writer.js +1 -1
  101. package/commands/auth.test.js +0 -211
  102. package/commands/branches.test.js +0 -460
  103. package/commands/connection_string.test.js +0 -196
  104. package/commands/databases.test.js +0 -39
  105. package/commands/help.test.js +0 -9
  106. package/commands/init.test.js +0 -56
  107. package/commands/ip_allow.test.js +0 -59
  108. package/commands/operations.test.js +0 -7
  109. package/commands/orgs.test.js +0 -7
  110. package/commands/projects.test.js +0 -144
  111. package/commands/roles.test.js +0 -37
  112. package/commands/set_context.test.js +0 -159
  113. package/commands/vpc_endpoints.test.js +0 -69
  114. package/env.test.js +0 -55
  115. package/utils/formats.test.js +0 -32
  116. package/writer.test.js +0 -104
@@ -0,0 +1,491 @@
1
+ /**
2
+ * Catalog-query templates for tab completion.
3
+ *
4
+ * Each template returns a single column of completion candidates and takes
5
+ * one parameter — the LIKE pattern (i.e. the user's partial prefix with a
6
+ * trailing `%`). We use `pg_catalog.quote_ident()` so identifiers that need
7
+ * quoting come back already wrapped in `"..."`.
8
+ *
9
+ * The templates are intentionally narrow: psql's upstream tab-complete uses
10
+ * elaborate `SchemaQuery` structs that synthesize visibility predicates
11
+ * (search-path awareness) at runtime. We trade that nuance for portability
12
+ * — these queries just `LIKE` against the system catalogs and let the user
13
+ * see everything they have access to, sorted alphabetically.
14
+ *
15
+ * Every query takes a single `$1` parameter (the LIKE pattern) and is
16
+ * capped at 1000 rows so a wildcard `%` doesn't dump entire databases.
17
+ */
18
+ const LIMIT = 1000;
19
+ /** Tables (incl. partitioned tables). */
20
+ export const Query_for_list_of_tables = `
21
+ SELECT pg_catalog.quote_ident(c.relname)
22
+ FROM pg_catalog.pg_class c
23
+ WHERE c.relkind IN ('r','p')
24
+ AND c.relname ILIKE $1
25
+ AND pg_catalog.pg_table_is_visible(c.oid)
26
+ ORDER BY 1
27
+ LIMIT ${LIMIT}
28
+ `;
29
+ /** Views. */
30
+ export const Query_for_list_of_views = `
31
+ SELECT pg_catalog.quote_ident(c.relname)
32
+ FROM pg_catalog.pg_class c
33
+ WHERE c.relkind = 'v'
34
+ AND c.relname ILIKE $1
35
+ AND pg_catalog.pg_table_is_visible(c.oid)
36
+ ORDER BY 1
37
+ LIMIT ${LIMIT}
38
+ `;
39
+ /** Materialized views. */
40
+ export const Query_for_list_of_matviews = `
41
+ SELECT pg_catalog.quote_ident(c.relname)
42
+ FROM pg_catalog.pg_class c
43
+ WHERE c.relkind = 'm'
44
+ AND c.relname ILIKE $1
45
+ AND pg_catalog.pg_table_is_visible(c.oid)
46
+ ORDER BY 1
47
+ LIMIT ${LIMIT}
48
+ `;
49
+ /** Sequences. */
50
+ export const Query_for_list_of_sequences = `
51
+ SELECT pg_catalog.quote_ident(c.relname)
52
+ FROM pg_catalog.pg_class c
53
+ WHERE c.relkind = 'S'
54
+ AND c.relname ILIKE $1
55
+ AND pg_catalog.pg_table_is_visible(c.oid)
56
+ ORDER BY 1
57
+ LIMIT ${LIMIT}
58
+ `;
59
+ /** Indexes. */
60
+ export const Query_for_list_of_indexes = `
61
+ SELECT pg_catalog.quote_ident(c.relname)
62
+ FROM pg_catalog.pg_class c
63
+ WHERE c.relkind IN ('i','I')
64
+ AND c.relname ILIKE $1
65
+ AND pg_catalog.pg_table_is_visible(c.oid)
66
+ ORDER BY 1
67
+ LIMIT ${LIMIT}
68
+ `;
69
+ /** Foreign tables. */
70
+ export const Query_for_list_of_foreign_tables = `
71
+ SELECT pg_catalog.quote_ident(c.relname)
72
+ FROM pg_catalog.pg_class c
73
+ WHERE c.relkind = 'f'
74
+ AND c.relname ILIKE $1
75
+ AND pg_catalog.pg_table_is_visible(c.oid)
76
+ ORDER BY 1
77
+ LIMIT ${LIMIT}
78
+ `;
79
+ /** Any relation (tables, views, mviews, indexes, sequences, foreign tables). */
80
+ export const Query_for_list_of_relations = `
81
+ SELECT pg_catalog.quote_ident(c.relname)
82
+ FROM pg_catalog.pg_class c
83
+ WHERE c.relkind IN ('r','v','m','S','f','p')
84
+ AND c.relname ILIKE $1
85
+ AND pg_catalog.pg_table_is_visible(c.oid)
86
+ ORDER BY 1
87
+ LIMIT ${LIMIT}
88
+ `;
89
+ /** Tables + views + matviews (what FROM/UPDATE/INSERT INTO accept). */
90
+ export const Query_for_list_of_tables_views = `
91
+ SELECT pg_catalog.quote_ident(c.relname)
92
+ FROM pg_catalog.pg_class c
93
+ WHERE c.relkind IN ('r','v','m','p','f')
94
+ AND c.relname ILIKE $1
95
+ AND pg_catalog.pg_table_is_visible(c.oid)
96
+ ORDER BY 1
97
+ LIMIT ${LIMIT}
98
+ `;
99
+ /** Schemas. */
100
+ export const Query_for_list_of_schemas = `
101
+ SELECT pg_catalog.quote_ident(nspname)
102
+ FROM pg_catalog.pg_namespace
103
+ WHERE nspname ILIKE $1
104
+ ORDER BY 1
105
+ LIMIT ${LIMIT}
106
+ `;
107
+ /** Functions (not procedures). */
108
+ export const Query_for_list_of_functions = `
109
+ SELECT pg_catalog.quote_ident(p.proname)
110
+ FROM pg_catalog.pg_proc p
111
+ WHERE p.proname ILIKE $1
112
+ AND pg_catalog.pg_function_is_visible(p.oid)
113
+ ORDER BY 1
114
+ LIMIT ${LIMIT}
115
+ `;
116
+ /** Roles. */
117
+ export const Query_for_list_of_roles = `
118
+ SELECT pg_catalog.quote_ident(rolname)
119
+ FROM pg_catalog.pg_roles
120
+ WHERE rolname ILIKE $1
121
+ ORDER BY 1
122
+ LIMIT ${LIMIT}
123
+ `;
124
+ /** Extensions. */
125
+ export const Query_for_list_of_extensions = `
126
+ SELECT pg_catalog.quote_ident(extname)
127
+ FROM pg_catalog.pg_extension
128
+ WHERE extname ILIKE $1
129
+ ORDER BY 1
130
+ LIMIT ${LIMIT}
131
+ `;
132
+ /** Available extensions (installable). */
133
+ export const Query_for_list_of_available_extensions = `
134
+ SELECT pg_catalog.quote_ident(name)
135
+ FROM pg_catalog.pg_available_extensions
136
+ WHERE name ILIKE $1
137
+ ORDER BY 1
138
+ LIMIT ${LIMIT}
139
+ `;
140
+ /** Databases. */
141
+ export const Query_for_list_of_databases = `
142
+ SELECT pg_catalog.quote_ident(datname)
143
+ FROM pg_catalog.pg_database
144
+ WHERE datname ILIKE $1
145
+ ORDER BY 1
146
+ LIMIT ${LIMIT}
147
+ `;
148
+ /** Types. */
149
+ export const Query_for_list_of_types = `
150
+ SELECT pg_catalog.quote_ident(t.typname)
151
+ FROM pg_catalog.pg_type t
152
+ WHERE (t.typrelid = 0 OR
153
+ (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))
154
+ AND t.typname NOT LIKE E'\\\\_%'
155
+ AND t.typname ILIKE $1
156
+ AND pg_catalog.pg_type_is_visible(t.oid)
157
+ ORDER BY 1
158
+ LIMIT ${LIMIT}
159
+ `;
160
+ /** Languages. */
161
+ export const Query_for_list_of_languages = `
162
+ SELECT pg_catalog.quote_ident(lanname)
163
+ FROM pg_catalog.pg_language
164
+ WHERE lanname != 'internal'
165
+ AND lanname ILIKE $1
166
+ ORDER BY 1
167
+ LIMIT ${LIMIT}
168
+ `;
169
+ /** Tablespaces. */
170
+ export const Query_for_list_of_tablespaces = `
171
+ SELECT pg_catalog.quote_ident(spcname)
172
+ FROM pg_catalog.pg_tablespace
173
+ WHERE spcname ILIKE $1
174
+ ORDER BY 1
175
+ LIMIT ${LIMIT}
176
+ `;
177
+ /** Operators. */
178
+ export const Query_for_list_of_operators = `
179
+ SELECT pg_catalog.quote_ident(o.oprname)
180
+ FROM pg_catalog.pg_operator o
181
+ WHERE o.oprname ILIKE $1
182
+ AND pg_catalog.pg_operator_is_visible(o.oid)
183
+ ORDER BY 1
184
+ LIMIT ${LIMIT}
185
+ `;
186
+ /** Casts (no quoting; format is "type AS type" — used rarely). */
187
+ export const Query_for_list_of_casts = `
188
+ SELECT pg_catalog.format_type(castsource, NULL)
189
+ || ' AS '
190
+ || pg_catalog.format_type(casttarget, NULL) AS cast
191
+ FROM pg_catalog.pg_cast
192
+ WHERE pg_catalog.format_type(castsource, NULL)
193
+ || ' AS '
194
+ || pg_catalog.format_type(casttarget, NULL) ILIKE $1
195
+ ORDER BY 1
196
+ LIMIT ${LIMIT}
197
+ `;
198
+ /** Configuration parameter (GUC) names — `pg_settings`. */
199
+ export const Query_for_list_of_set_vars = `
200
+ SELECT pg_catalog.lower(name)
201
+ FROM pg_catalog.pg_settings
202
+ WHERE name ILIKE $1
203
+ ORDER BY 1
204
+ LIMIT ${LIMIT}
205
+ `;
206
+ /**
207
+ * Allowed values of an enum-typed GUC — `pg_settings.enumvals`.
208
+ *
209
+ * The GUC name is the first parameter (matched case-insensitively against
210
+ * `pg_settings.name`, since names like `IntervalStyle` appear mixed-case in
211
+ * the catalog but are addressed in lowercase from user input). The ILIKE
212
+ * prefix on the unnested values is the trailing parameter.
213
+ *
214
+ * Mirrors upstream `tab-complete.in.c`'s `Query_for_values_of_enum_GUC`. The
215
+ * catalog stores enum values in lowercase (e.g. `iso_8601`, `use_column`),
216
+ * which matches how `SET <name> TO <value>` expects them.
217
+ */
218
+ export const Query_for_values_of_enum_GUC = `
219
+ SELECT val
220
+ FROM (
221
+ SELECT pg_catalog.unnest(enumvals) AS val
222
+ FROM pg_catalog.pg_settings
223
+ WHERE pg_catalog.lower(name) = pg_catalog.lower($1)
224
+ AND enumvals IS NOT NULL
225
+ ) sub
226
+ WHERE val ILIKE $2
227
+ ORDER BY 1
228
+ LIMIT ${LIMIT}
229
+ `;
230
+ /** Access methods (index AMs primarily). */
231
+ export const Query_for_list_of_access_methods = `
232
+ SELECT pg_catalog.quote_ident(amname)
233
+ FROM pg_catalog.pg_am
234
+ WHERE amname ILIKE $1
235
+ ORDER BY 1
236
+ LIMIT ${LIMIT}
237
+ `;
238
+ /** Index access methods only (`amtype = 'i'`). */
239
+ export const Query_for_list_of_index_access_methods = `
240
+ SELECT pg_catalog.quote_ident(amname)
241
+ FROM pg_catalog.pg_am
242
+ WHERE amname ILIKE $1
243
+ AND amtype = 'i'
244
+ ORDER BY 1
245
+ LIMIT ${LIMIT}
246
+ `;
247
+ /** Built-in type names — for CREATE TABLE column-type completion. */
248
+ export const Query_for_list_of_datatypes = `
249
+ SELECT pg_catalog.format_type(t.oid, NULL)
250
+ FROM pg_catalog.pg_type t
251
+ WHERE (t.typrelid = 0 OR
252
+ (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))
253
+ AND NOT EXISTS (
254
+ SELECT 1 FROM pg_catalog.pg_type el
255
+ WHERE el.typarray = t.oid
256
+ )
257
+ AND pg_catalog.format_type(t.oid, NULL) ILIKE $1
258
+ AND pg_catalog.pg_type_is_visible(t.oid)
259
+ ORDER BY 1
260
+ LIMIT ${LIMIT}
261
+ `;
262
+ /** Publications. */
263
+ export const Query_for_list_of_publications = `
264
+ SELECT pg_catalog.quote_ident(pubname)
265
+ FROM pg_catalog.pg_publication
266
+ WHERE pubname ILIKE $1
267
+ ORDER BY 1
268
+ LIMIT ${LIMIT}
269
+ `;
270
+ /** Subscriptions. */
271
+ export const Query_for_list_of_subscriptions = `
272
+ SELECT pg_catalog.quote_ident(subname)
273
+ FROM pg_catalog.pg_subscription
274
+ WHERE subname ILIKE $1
275
+ ORDER BY 1
276
+ LIMIT ${LIMIT}
277
+ `;
278
+ /**
279
+ * Relations qualified by an explicit schema. The caller passes the schema
280
+ * name as $1 and the ILIKE prefix as $2 — this lets `SELECT * FROM pg_catalog.x`
281
+ * complete to `pg_catalog.xxxx`. The schema name is matched
282
+ * case-insensitively so `PUBLIC.t` resolves to relations in `public`.
283
+ *
284
+ * Note: deliberately excludes `relkind = 'i'` (indexes) so that
285
+ * `SELECT * FROM public.tab<tab>` doesn't include `tab1_pkey` alongside
286
+ * `tab1`. Index-qualifying completions (REINDEX, DROP INDEX, ALTER INDEX)
287
+ * have their own table-kind queries and don't route through this helper.
288
+ */
289
+ export const Query_for_list_of_relations_in_schema = `
290
+ SELECT pg_catalog.quote_ident(c.relname)
291
+ FROM pg_catalog.pg_class c
292
+ JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
293
+ WHERE c.relkind IN ('r','v','m','S','f','p')
294
+ AND pg_catalog.lower(n.nspname) = pg_catalog.lower($1)
295
+ AND c.relname ILIKE $2
296
+ ORDER BY 1
297
+ LIMIT ${LIMIT}
298
+ `;
299
+ /**
300
+ * Constraint names attached to a referenced table. Mirrors upstream's
301
+ * `Query_for_constraint_of_table` (tab-complete.in.c ~line 453), which
302
+ * joins `pg_constraint` to `pg_class` via `conrelid` and filters by the
303
+ * referenced table name.
304
+ *
305
+ * Caller passes `[refName]` (the table the user typed between
306
+ * `ALTER TABLE` and `DROP CONSTRAINT`, already case-folded for unquoted
307
+ * input — see `parseTableRef` in rules.ts) and the ILIKE prefix.
308
+ *
309
+ * Visibility is checked via `pg_table_is_visible(c.oid)` so the user's
310
+ * `search_path` controls which schema's `tab1` is matched when the user
311
+ * gives an unqualified reference.
312
+ */
313
+ export const Query_for_constraint_of_table = `
314
+ SELECT pg_catalog.quote_ident(con.conname)
315
+ FROM pg_catalog.pg_constraint con, pg_catalog.pg_class c
316
+ WHERE con.conrelid = c.oid
317
+ AND c.relname = $1
318
+ AND pg_catalog.pg_table_is_visible(c.oid)
319
+ AND con.conname ILIKE $2
320
+ ORDER BY 1
321
+ LIMIT ${LIMIT}
322
+ `;
323
+ /**
324
+ * Constraint names attached to a referenced table within a specific
325
+ * schema. Used when the user qualified the reference, e.g.
326
+ * `ALTER TABLE public."tab1" DROP CONSTRAINT t<TAB>`. The schema name is
327
+ * matched case-insensitively against `pg_namespace.nspname` so
328
+ * `PUBLIC.tab1` still resolves to constraints in the `public` schema.
329
+ *
330
+ * Caller passes `[schema, refName]` (with `refName` already case-folded
331
+ * for the unquoted form), and the ILIKE prefix as the trailing parameter.
332
+ */
333
+ export const Query_for_constraint_of_table_in_schema = `
334
+ SELECT pg_catalog.quote_ident(con.conname)
335
+ FROM pg_catalog.pg_constraint con
336
+ JOIN pg_catalog.pg_class c ON con.conrelid = c.oid
337
+ JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
338
+ WHERE pg_catalog.lower(n.nspname) = pg_catalog.lower($1)
339
+ AND c.relname = $2
340
+ AND con.conname ILIKE $3
341
+ ORDER BY 1
342
+ LIMIT ${LIMIT}
343
+ `;
344
+ /**
345
+ * Tables (regular + partitioned) that have a constraint with the given
346
+ * name. The reverse direction of `Query_for_constraint_of_table` — used by
347
+ * the `COMMENT ON CONSTRAINT <name> ON <prefix>` completion to resolve the
348
+ * relation that owns the named constraint.
349
+ *
350
+ * Caller passes `[constraintName]`, then the ILIKE prefix on the relname.
351
+ * Mirrors upstream's `Query_for_list_of_tables_for_constraint` SchemaQuery
352
+ * (tab-complete.in.c ~line 694), which uses
353
+ * `selcondition = "c.oid=con.conrelid and c.relkind IN ('r','p')"` and
354
+ * `refname = "con.conname"`. The `quote_ident()` wrapper ensures
355
+ * names that need quoting (mixed case, reserved words) come back in a
356
+ * paste-safe form.
357
+ */
358
+ export const Query_for_list_of_tables_for_constraint = `
359
+ SELECT DISTINCT pg_catalog.quote_ident(c.relname)
360
+ FROM pg_catalog.pg_class c, pg_catalog.pg_constraint con
361
+ WHERE c.oid = con.conrelid
362
+ AND c.relkind IN ('r', 'p')
363
+ AND pg_catalog.pg_table_is_visible(c.oid)
364
+ AND con.conname = $1
365
+ AND c.relname ILIKE $2
366
+ ORDER BY 1
367
+ LIMIT ${LIMIT}
368
+ `;
369
+ /**
370
+ * Same as `Query_for_list_of_tables_for_constraint` but scoped to a
371
+ * specific schema (so `COMMENT ON CONSTRAINT foo ON public.<TAB>` only
372
+ * shows relations in `public`).
373
+ *
374
+ * Caller passes `[constraintName, schema]`, then the ILIKE prefix. Schema
375
+ * is matched case-insensitively to handle `PUBLIC.<TAB>` → `public.*`.
376
+ */
377
+ export const Query_for_list_of_tables_for_constraint_in_schema = `
378
+ SELECT DISTINCT pg_catalog.quote_ident(c.relname)
379
+ FROM pg_catalog.pg_class c
380
+ JOIN pg_catalog.pg_constraint con ON c.oid = con.conrelid
381
+ JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
382
+ WHERE c.relkind IN ('r', 'p')
383
+ AND pg_catalog.lower(n.nspname) = pg_catalog.lower($2)
384
+ AND con.conname = $1
385
+ AND c.relname ILIKE $3
386
+ ORDER BY 1
387
+ LIMIT ${LIMIT}
388
+ `;
389
+ /**
390
+ * Enum label values for the named enum type. Mirrors upstream's
391
+ * `Query_for_list_of_enum_values_quoted` / `…_unquoted` (tab-complete.in.c
392
+ * ~line 602-618), with a parameter-bound type name in place of upstream's
393
+ * `set_completion_reference()` macro state.
394
+ *
395
+ * The caller picks the variant based on whether the user is mid-string-
396
+ * literal (current word starts with `'`), and passes `[typeName]` along
397
+ * with the ILIKE prefix as the trailing parameter. The quoted variant
398
+ * uses `quote_literal` so candidates come back as `'BLACK'` rather than
399
+ * bare `BLACK`, and the case-sensitive `enumlabel LIKE` ensures upstream
400
+ * parity for tests like `RENAME VALUE 'B<TAB>` → `'BLACK'`.
401
+ */
402
+ export const Query_for_list_of_enum_values_quoted = `
403
+ SELECT pg_catalog.quote_literal(e.enumlabel)
404
+ FROM pg_catalog.pg_enum e, pg_catalog.pg_type t
405
+ WHERE t.oid = e.enumtypid
406
+ AND t.typname = $1
407
+ AND pg_catalog.pg_type_is_visible(t.oid)
408
+ AND e.enumlabel LIKE $2
409
+ ORDER BY 1
410
+ LIMIT ${LIMIT}
411
+ `;
412
+ export const Query_for_list_of_enum_values_unquoted = `
413
+ SELECT e.enumlabel
414
+ FROM pg_catalog.pg_enum e, pg_catalog.pg_type t
415
+ WHERE t.oid = e.enumtypid
416
+ AND t.typname = $1
417
+ AND pg_catalog.pg_type_is_visible(t.oid)
418
+ AND e.enumlabel LIKE $2
419
+ ORDER BY 1
420
+ LIMIT ${LIMIT}
421
+ `;
422
+ /**
423
+ * Timezone names from `pg_timezone_names()`. Three variants mirror
424
+ * upstream's `COMPLETE_WITH_TIMEZONE_NAME()` macro (tab-complete.in.c
425
+ * ~line 1160-1173) — different result shapes for the three contexts:
426
+ *
427
+ * - `…_unquoted` emits the bare name `America/New_York`. Used when
428
+ * the cursor is already inside an opened single-
429
+ * quoted string (`SET timezone TO 'America/New_<TAB>`),
430
+ * so the editor inserts the rest of the name and the
431
+ * closing quote.
432
+ * - `…_quoted_out` emits the candidate wrapped in single quotes —
433
+ * `'America/New_York'`. Used when the user hasn't
434
+ * typed any quote yet (`SET timezone TO am<TAB>` →
435
+ * `'America/`).
436
+ * - `…_quoted_in` emits the quoted form AND matches the quoted form
437
+ * against the LIKE pattern. Used when the user's
438
+ * partial word itself starts with `'` (so we feed
439
+ * `'am%` to the LIKE), so the editor can complete
440
+ * from inside the literal.
441
+ *
442
+ * All three are case-insensitive on the name (lower(name) LIKE lower(pat))
443
+ * because IANA names like `America/New_York` mix case but should still
444
+ * match a lowercase prefix.
445
+ */
446
+ export const Query_for_list_of_timezone_names_unquoted = `
447
+ SELECT name
448
+ FROM pg_catalog.pg_timezone_names()
449
+ WHERE pg_catalog.lower(name) LIKE pg_catalog.lower($1)
450
+ ORDER BY 1
451
+ LIMIT ${LIMIT}
452
+ `;
453
+ export const Query_for_list_of_timezone_names_quoted_out = `
454
+ SELECT pg_catalog.quote_literal(name) AS name
455
+ FROM pg_catalog.pg_timezone_names()
456
+ WHERE pg_catalog.lower(name) LIKE pg_catalog.lower($1)
457
+ ORDER BY 1
458
+ LIMIT ${LIMIT}
459
+ `;
460
+ export const Query_for_list_of_timezone_names_quoted_in = `
461
+ SELECT pg_catalog.quote_literal(name) AS name
462
+ FROM pg_catalog.pg_timezone_names()
463
+ WHERE pg_catalog.quote_literal(pg_catalog.lower(name)) LIKE pg_catalog.lower($1)
464
+ ORDER BY 1
465
+ LIMIT ${LIMIT}
466
+ `;
467
+ /**
468
+ * Run one of the templates above against a connection and return the
469
+ * single-column results as a string array. Empty array on any error so the
470
+ * completer degrades gracefully — a flaky catalog query shouldn't crash the
471
+ * REPL.
472
+ *
473
+ * `pattern` is the user's partial input; we append `%` automatically.
474
+ */
475
+ export const runCatalogQuery = async (conn, sql, pattern, extraParams = []) => {
476
+ try {
477
+ const likePattern = pattern + '%';
478
+ const params = extraParams.length > 0 ? [...extraParams, likePattern] : [likePattern];
479
+ const rs = await conn.query(sql, params);
480
+ const out = [];
481
+ for (const row of rs.rows) {
482
+ const v = row[0];
483
+ if (typeof v === 'string')
484
+ out.push(v);
485
+ }
486
+ return out;
487
+ }
488
+ catch {
489
+ return [];
490
+ }
491
+ };