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,846 +1,657 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* psql startup-args parser + applier.
|
|
3
|
-
*
|
|
4
|
-
* TypeScript port of `parse_psql_options()` / the top of `main()` in
|
|
5
|
-
* `src/bin/psql/startup.c`. Two responsibilities:
|
|
6
|
-
*
|
|
7
|
-
* 1. `parseStartupArgs(argv)` — hand-written getopt_long-equivalent that
|
|
8
|
-
* walks the argv array once, decoding short (`-c`) and long (`--command`)
|
|
9
|
-
* options, and accumulates an ordered list of `-c`/`-f` actions plus a
|
|
10
|
-
* bag of settings flags. Positional arguments follow the upstream
|
|
11
|
-
* `[DBNAME [USERNAME]]` rule.
|
|
12
|
-
*
|
|
13
|
-
* We hand-roll the parser instead of pulling in `yargs` (or similar)
|
|
14
|
-
* because upstream psql has subtle precedence rules — actions are
|
|
15
|
-
* ordered, `-v NAME` without `=` deletes the variable, `-X` interacts
|
|
16
|
-
* with `.psqlrc` discovery, etc. The parser stays under ~250 LOC and is
|
|
17
|
-
* fully covered by unit tests.
|
|
18
|
-
*
|
|
19
|
-
* 2. `applyStartupArgs(args, settings, baseConnect)` — mutates `settings`
|
|
20
|
-
* (and its var store) in-place to reflect parsed flags, then returns
|
|
21
|
-
* the connect options the caller should use plus the ordered list of
|
|
22
|
-
* pre-REPL actions to execute (currently just `-c` / `-f`).
|
|
23
|
-
*
|
|
24
|
-
* Out-of-scope for WP-26 but the table mentions them so they're listed below:
|
|
25
|
-
* - `-1` / `--single-transaction` — we accept and record on the args but
|
|
26
|
-
* do not wire its semantics in the caller. Tracked for a follow-up.
|
|
27
|
-
* - `-C` — accepted as a no-op (since-PG17 connection-check skip).
|
|
28
|
-
* - `-l` / `--list` — recorded; the caller may use it later to short-circuit
|
|
29
|
-
* the REPL with a `\l` and exit. Not wired here.
|
|
30
|
-
* - `-L logfile`, `-o output` — recorded on args. Routing into the printer
|
|
31
|
-
* is owned by other WPs (logfile streaming and output redirection).
|
|
32
|
-
* - `--help[=topic]` — returns a ParseError with `kind: 'help'` and the
|
|
33
|
-
* help text already rendered as `message`. Caller writes and exits 0.
|
|
34
|
-
* - `-V` / `--version` — returns `kind: 'version'` with the version string.
|
|
35
|
-
* Caller writes and exits 0.
|
|
36
|
-
*
|
|
37
|
-
* Help/version text is rendered through `./help.ts` so the formatting stays
|
|
38
|
-
* in lock-step with `\?` output (WP-18). The version string mirrors upstream
|
|
39
|
-
* `psql (PostgreSQL) PG_VERSION` and is currently hard-coded — the embedded
|
|
40
|
-
* psql doesn't have a build-system PG_VERSION constant. A follow-up could
|
|
41
|
-
* surface the real PG version from a const, but for now we expose the
|
|
42
|
-
* embedded build's version label.
|
|
43
|
-
*/
|
|
44
|
-
import { envConnectionDefaults, libpqConnectionDefaults, looksLikeConnectionString, mergeConnectOptions, parseConnectionUriPartial, parseConninfo, serviceEntryToConnectOptions, } from "../index.js";
|
|
45
|
-
import { lookupPgPass } from "../io/pgpass.js";
|
|
46
|
-
import { helpVariables, slashUsage, usage } from "./help.js";
|
|
47
1
|
import { setStartupVars } from "./syncVars.js";
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
2
|
+
import { helpVariables, slashUsage, usage } from "./help.js";
|
|
3
|
+
import { lookupPgPass } from "../io/pgpass.js";
|
|
4
|
+
import { envConnectionDefaults, libpqConnectionDefaults, looksLikeConnectionString, mergeConnectOptions, parseConnectionUriPartial, parseConninfo, serviceEntryToConnectOptions } from "../index.js";
|
|
5
|
+
//#region src/psql/core/startup.ts
|
|
6
|
+
/**
|
|
7
|
+
* psql startup-args parser + applier.
|
|
8
|
+
*
|
|
9
|
+
* TypeScript port of `parse_psql_options()` / the top of `main()` in
|
|
10
|
+
* `src/bin/psql/startup.c`. Two responsibilities:
|
|
11
|
+
*
|
|
12
|
+
* 1. `parseStartupArgs(argv)` — hand-written getopt_long-equivalent that
|
|
13
|
+
* walks the argv array once, decoding short (`-c`) and long (`--command`)
|
|
14
|
+
* options, and accumulates an ordered list of `-c`/`-f` actions plus a
|
|
15
|
+
* bag of settings flags. Positional arguments follow the upstream
|
|
16
|
+
* `[DBNAME [USERNAME]]` rule.
|
|
17
|
+
*
|
|
18
|
+
* We hand-roll the parser instead of pulling in `yargs` (or similar)
|
|
19
|
+
* because upstream psql has subtle precedence rules — actions are
|
|
20
|
+
* ordered, `-v NAME` without `=` deletes the variable, `-X` interacts
|
|
21
|
+
* with `.psqlrc` discovery, etc. The parser stays under ~250 LOC and is
|
|
22
|
+
* fully covered by unit tests.
|
|
23
|
+
*
|
|
24
|
+
* 2. `applyStartupArgs(args, settings, baseConnect)` — mutates `settings`
|
|
25
|
+
* (and its var store) in-place to reflect parsed flags, then returns
|
|
26
|
+
* the connect options the caller should use plus the ordered list of
|
|
27
|
+
* pre-REPL actions to execute (currently just `-c` / `-f`).
|
|
28
|
+
*
|
|
29
|
+
* Out-of-scope for WP-26 but the table mentions them so they're listed below:
|
|
30
|
+
* - `-1` / `--single-transaction` — we accept and record on the args but
|
|
31
|
+
* do not wire its semantics in the caller. Tracked for a follow-up.
|
|
32
|
+
* - `-C` — accepted as a no-op (since-PG17 connection-check skip).
|
|
33
|
+
* - `-l` / `--list` — recorded; the caller may use it later to short-circuit
|
|
34
|
+
* the REPL with a `\l` and exit. Not wired here.
|
|
35
|
+
* - `-L logfile`, `-o output` — recorded on args. Routing into the printer
|
|
36
|
+
* is owned by other WPs (logfile streaming and output redirection).
|
|
37
|
+
* - `--help[=topic]` — returns a ParseError with `kind: 'help'` and the
|
|
38
|
+
* help text already rendered as `message`. Caller writes and exits 0.
|
|
39
|
+
* - `-V` / `--version` — returns `kind: 'version'` with the version string.
|
|
40
|
+
* Caller writes and exits 0.
|
|
41
|
+
*
|
|
42
|
+
* Help/version text is rendered through `./help.ts` so the formatting stays
|
|
43
|
+
* in lock-step with `\?` output (WP-18). The version string mirrors upstream
|
|
44
|
+
* `psql (PostgreSQL) PG_VERSION` and is currently hard-coded — the embedded
|
|
45
|
+
* psql doesn't have a build-system PG_VERSION constant. A follow-up could
|
|
46
|
+
* surface the real PG version from a const, but for now we expose the
|
|
47
|
+
* embedded build's version label.
|
|
48
|
+
*/
|
|
51
49
|
/** Short options that consume the next argv slot (or attached value). */
|
|
52
|
-
const SHORT_WITH_ARG = new Set([
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
const SHORT_WITH_ARG = /* @__PURE__ */ new Set([
|
|
51
|
+
"c",
|
|
52
|
+
"d",
|
|
53
|
+
"f",
|
|
54
|
+
"F",
|
|
55
|
+
"h",
|
|
56
|
+
"L",
|
|
57
|
+
"o",
|
|
58
|
+
"p",
|
|
59
|
+
"P",
|
|
60
|
+
"R",
|
|
61
|
+
"T",
|
|
62
|
+
"U",
|
|
63
|
+
"v"
|
|
66
64
|
]);
|
|
67
65
|
/** Short flags (no argument). */
|
|
68
|
-
const SHORT_NO_ARG = new Set([
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
66
|
+
const SHORT_NO_ARG = /* @__PURE__ */ new Set([
|
|
67
|
+
"a",
|
|
68
|
+
"A",
|
|
69
|
+
"b",
|
|
70
|
+
"C",
|
|
71
|
+
"e",
|
|
72
|
+
"E",
|
|
73
|
+
"H",
|
|
74
|
+
"l",
|
|
75
|
+
"n",
|
|
76
|
+
"q",
|
|
77
|
+
"s",
|
|
78
|
+
"S",
|
|
79
|
+
"t",
|
|
80
|
+
"V",
|
|
81
|
+
"w",
|
|
82
|
+
"W",
|
|
83
|
+
"x",
|
|
84
|
+
"X",
|
|
85
|
+
"z",
|
|
86
|
+
"0",
|
|
87
|
+
"1",
|
|
88
|
+
"?"
|
|
91
89
|
]);
|
|
92
90
|
/** Long option → canonical short equivalent (or sentinel string). */
|
|
93
91
|
const LONG_MAP = {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
92
|
+
"echo-all": "a",
|
|
93
|
+
"no-align": "A",
|
|
94
|
+
command: "c",
|
|
95
|
+
dbname: "d",
|
|
96
|
+
"echo-queries": "e",
|
|
97
|
+
"echo-errors": "b",
|
|
98
|
+
"echo-hidden": "E",
|
|
99
|
+
file: "f",
|
|
100
|
+
"field-separator": "F",
|
|
101
|
+
"field-separator-zero": "z",
|
|
102
|
+
host: "h",
|
|
103
|
+
html: "H",
|
|
104
|
+
list: "l",
|
|
105
|
+
"log-file": "L",
|
|
106
|
+
"no-readline": "n",
|
|
107
|
+
"single-transaction": "1",
|
|
108
|
+
output: "o",
|
|
109
|
+
port: "p",
|
|
110
|
+
pset: "P",
|
|
111
|
+
quiet: "q",
|
|
112
|
+
"record-separator": "R",
|
|
113
|
+
"record-separator-zero": "0",
|
|
114
|
+
"single-step": "s",
|
|
115
|
+
"single-line": "S",
|
|
116
|
+
"tuples-only": "t",
|
|
117
|
+
"table-attr": "T",
|
|
118
|
+
username: "U",
|
|
119
|
+
set: "v",
|
|
120
|
+
variable: "v",
|
|
121
|
+
version: "V",
|
|
122
|
+
"no-password": "w",
|
|
123
|
+
password: "W",
|
|
124
|
+
expanded: "x",
|
|
125
|
+
"no-psqlrc": "X",
|
|
126
|
+
"no-pager": "__no_pager__",
|
|
127
|
+
"on-error-stop": "__on_error_stop__",
|
|
128
|
+
help: "__help__",
|
|
129
|
+
csv: "__csv__"
|
|
132
130
|
};
|
|
133
131
|
/** Long options that REQUIRE an attached value (or one in the next argv). */
|
|
134
|
-
const LONG_WITH_ARG = new Set([
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
132
|
+
const LONG_WITH_ARG = /* @__PURE__ */ new Set([
|
|
133
|
+
"command",
|
|
134
|
+
"dbname",
|
|
135
|
+
"file",
|
|
136
|
+
"field-separator",
|
|
137
|
+
"host",
|
|
138
|
+
"log-file",
|
|
139
|
+
"output",
|
|
140
|
+
"port",
|
|
141
|
+
"pset",
|
|
142
|
+
"record-separator",
|
|
143
|
+
"table-attr",
|
|
144
|
+
"username",
|
|
145
|
+
"set",
|
|
146
|
+
"variable"
|
|
149
147
|
]);
|
|
150
148
|
/** Long options whose value is optional (only attached with `=`). */
|
|
151
|
-
const LONG_OPTIONAL_ARG = new Set(["help", "echo-hidden"]);
|
|
149
|
+
const LONG_OPTIONAL_ARG = /* @__PURE__ */ new Set(["help", "echo-hidden"]);
|
|
152
150
|
const blankArgs = () => ({
|
|
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
|
-
|
|
151
|
+
actions: [],
|
|
152
|
+
variables: [],
|
|
153
|
+
noPsqlrc: false,
|
|
154
|
+
noReadline: false,
|
|
155
|
+
echoAll: false,
|
|
156
|
+
echoHidden: "off",
|
|
157
|
+
echoErrors: false,
|
|
158
|
+
echoQueries: false,
|
|
159
|
+
quiet: false,
|
|
160
|
+
singleline: false,
|
|
161
|
+
singlestep: false,
|
|
162
|
+
noAlign: false,
|
|
163
|
+
noPager: false,
|
|
164
|
+
htmlMode: false,
|
|
165
|
+
tuplesOnly: false,
|
|
166
|
+
expanded: false,
|
|
167
|
+
csvOutput: false,
|
|
168
|
+
onErrorStop: false,
|
|
169
|
+
fieldSepZero: false,
|
|
170
|
+
recordSepZero: false,
|
|
171
|
+
pset: [],
|
|
172
|
+
list: false,
|
|
173
|
+
singleTransaction: false,
|
|
174
|
+
help: false,
|
|
175
|
+
version: false,
|
|
176
|
+
positional: []
|
|
179
177
|
});
|
|
180
178
|
const renderToString = (fn) => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return true;
|
|
188
|
-
},
|
|
189
|
-
};
|
|
190
|
-
fn(sink);
|
|
191
|
-
return chunks.join("");
|
|
179
|
+
const chunks = [];
|
|
180
|
+
fn({ write(chunk) {
|
|
181
|
+
chunks.push(typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8"));
|
|
182
|
+
return true;
|
|
183
|
+
} });
|
|
184
|
+
return chunks.join("");
|
|
192
185
|
};
|
|
193
186
|
const renderHelp = (topic) => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (topic === "variables") {
|
|
205
|
-
return renderToString((out) => {
|
|
206
|
-
helpVariables(out);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
return "";
|
|
187
|
+
if (topic === void 0 || topic === "options") return renderToString((out) => {
|
|
188
|
+
usage(out);
|
|
189
|
+
});
|
|
190
|
+
if (topic === "commands") return renderToString((out) => {
|
|
191
|
+
slashUsage(out, false);
|
|
192
|
+
});
|
|
193
|
+
if (topic === "variables") return renderToString((out) => {
|
|
194
|
+
helpVariables(out);
|
|
195
|
+
});
|
|
196
|
+
return "";
|
|
210
197
|
};
|
|
211
198
|
/**
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// `psql --version` / `-V` output. Mirrors upstream's `psql (PostgreSQL)
|
|
222
|
-
// <PG_VERSION>` SHAPE (tools parse the leading `psql (PostgreSQL)`), with an
|
|
223
|
-
// `embedded-ts` label in place of a real PG build number since this is a
|
|
224
|
-
// reimplementation, not a compiled psql. Distinct from the `:VERSION` psql
|
|
225
|
-
// variable (the client-identity string seeded from CLIENT_VERSION).
|
|
199
|
+
* Version label for the embedded TypeScript psql. This is the "client"
|
|
200
|
+
* identifier — the analogue of upstream psql's compiled-in `PG_VERSION`.
|
|
201
|
+
* The embedded psql is not a real PostgreSQL build, so we track our own
|
|
202
|
+
* implementation version here. It seeds the `VERSION_NAME` psql var (and,
|
|
203
|
+
* via {@link setStartupVars}, the numeric `VERSION_NUM`); keep it as a
|
|
204
|
+
* `MAJOR.MINOR.PATCH` string so the numeric mapping stays meaningful. Bump
|
|
205
|
+
* alongside meaningful behaviour changes to the embedded psql.
|
|
206
|
+
*/
|
|
207
|
+
const CLIENT_VERSION = "1.0.0";
|
|
226
208
|
const VERSION_STRING = `psql (PostgreSQL) embedded-ts (neon ${CLIENT_VERSION})`;
|
|
227
209
|
const pushAction = (acts, a) => {
|
|
228
|
-
|
|
210
|
+
acts.push(a);
|
|
229
211
|
};
|
|
230
212
|
const pushVariable = (vars, raw) => {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
213
|
+
const eq = raw.indexOf("=");
|
|
214
|
+
if (eq < 0) {
|
|
215
|
+
vars.push({
|
|
216
|
+
name: raw,
|
|
217
|
+
value: ""
|
|
218
|
+
});
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
vars.push({
|
|
222
|
+
name: raw.slice(0, eq),
|
|
223
|
+
value: raw.slice(eq + 1)
|
|
224
|
+
});
|
|
240
225
|
};
|
|
241
226
|
/**
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
227
|
+
* `-d VALUE` resolution. libpq accepts three shapes for the value:
|
|
228
|
+
*
|
|
229
|
+
* 1. Bare database name (no `=`, no `postgres[ql]://` prefix) — set
|
|
230
|
+
* `args.database` directly. This is by far the common case.
|
|
231
|
+
* 2. Connection URI (`postgresql://…` / `postgres://…`) — parse it and
|
|
232
|
+
* lift the fields it specifies onto `args` (host, port, user, etc.).
|
|
233
|
+
* 3. Conninfo key=value pairs separated by whitespace — same, but parsed
|
|
234
|
+
* via `parseConninfo`.
|
|
235
|
+
*
|
|
236
|
+
* The test corpus for upstream `001_basic.pl` uses shape (3) to open a
|
|
237
|
+
* walsender connection: `-d "dbname=postgres replication=database"`. We
|
|
238
|
+
* fold any conninfo-only fields (currently only `replication`) onto a
|
|
239
|
+
* dedicated `args.replication` slot that `applyStartupArgs` threads into
|
|
240
|
+
* `ConnectOptions.replication`.
|
|
241
|
+
*/
|
|
257
242
|
const applyDashD = (args, value) => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// Continue to mirror the core target fields onto the flag slots so the
|
|
274
|
-
// positional-arg / dbname-username precedence logic below sees them. Only
|
|
275
|
-
// when not already set by an explicit flag (flags win over -d).
|
|
276
|
-
if (parsed.host !== undefined && args.host === undefined) {
|
|
277
|
-
args.host = parsed.host;
|
|
278
|
-
}
|
|
279
|
-
if (parsed.port !== undefined && args.port === undefined) {
|
|
280
|
-
args.port = parsed.port;
|
|
281
|
-
}
|
|
282
|
-
if (parsed.user !== undefined && args.user === undefined) {
|
|
283
|
-
args.user = parsed.user;
|
|
284
|
-
}
|
|
285
|
-
if (parsed.password !== undefined && args.password === undefined) {
|
|
286
|
-
args.password = parsed.password;
|
|
287
|
-
}
|
|
288
|
-
if (parsed.database !== undefined && args.database === undefined) {
|
|
289
|
-
args.database = parsed.database;
|
|
290
|
-
}
|
|
291
|
-
if (parsed.replication !== undefined) {
|
|
292
|
-
args.replication = parsed.replication;
|
|
293
|
-
}
|
|
243
|
+
if (!looksLikeConnectionString(value)) {
|
|
244
|
+
args.database = value;
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const parsed = value.startsWith("postgresql://") || value.startsWith("postgres://") ? parseConnectionUriPartial(value) : parseConninfo(value);
|
|
248
|
+
args.dashD = {
|
|
249
|
+
...args.dashD ?? {},
|
|
250
|
+
...parsed
|
|
251
|
+
};
|
|
252
|
+
if (parsed.host !== void 0 && args.host === void 0) args.host = parsed.host;
|
|
253
|
+
if (parsed.port !== void 0 && args.port === void 0) args.port = parsed.port;
|
|
254
|
+
if (parsed.user !== void 0 && args.user === void 0) args.user = parsed.user;
|
|
255
|
+
if (parsed.password !== void 0 && args.password === void 0) args.password = parsed.password;
|
|
256
|
+
if (parsed.database !== void 0 && args.database === void 0) args.database = parsed.database;
|
|
257
|
+
if (parsed.replication !== void 0) args.replication = parsed.replication;
|
|
294
258
|
};
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
}
|
|
572
|
-
i += 1;
|
|
573
|
-
value = argv[i];
|
|
574
|
-
}
|
|
575
|
-
else if (!requiresArg && !optionalArg && value !== undefined) {
|
|
576
|
-
return {
|
|
577
|
-
kind: "invalid-option",
|
|
578
|
-
message: `option does not take an argument: --${name}`,
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
const err = applyShort(short, value, `--${name}`);
|
|
582
|
-
if (err)
|
|
583
|
-
return err;
|
|
584
|
-
i += 1;
|
|
585
|
-
continue;
|
|
586
|
-
}
|
|
587
|
-
if (tok.startsWith("-") && tok.length > 1) {
|
|
588
|
-
// Short option cluster. Each char might consume the rest of the token
|
|
589
|
-
// (or the next argv) as its value.
|
|
590
|
-
let k = 1;
|
|
591
|
-
while (k < tok.length) {
|
|
592
|
-
const letter = tok[k];
|
|
593
|
-
if (!SHORT_WITH_ARG.has(letter) && !SHORT_NO_ARG.has(letter)) {
|
|
594
|
-
return {
|
|
595
|
-
kind: "invalid-option",
|
|
596
|
-
message: `invalid option -- ${letter}`,
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
if (SHORT_WITH_ARG.has(letter)) {
|
|
600
|
-
// Consume the rest of this token as the value if anything remains,
|
|
601
|
-
// otherwise pull from the next argv.
|
|
602
|
-
const remainder = tok.slice(k + 1);
|
|
603
|
-
const value = remainder.length > 0 ? remainder : undefined;
|
|
604
|
-
const err = applyShort(letter, value, letter);
|
|
605
|
-
if (err)
|
|
606
|
-
return err;
|
|
607
|
-
k = tok.length; // Consumed the rest.
|
|
608
|
-
break;
|
|
609
|
-
}
|
|
610
|
-
const err = applyShort(letter, undefined, letter);
|
|
611
|
-
if (err)
|
|
612
|
-
return err;
|
|
613
|
-
k += 1;
|
|
614
|
-
}
|
|
615
|
-
i += 1;
|
|
616
|
-
continue;
|
|
617
|
-
}
|
|
618
|
-
// Positional.
|
|
619
|
-
args.positional.push(tok);
|
|
620
|
-
i += 1;
|
|
621
|
-
}
|
|
622
|
-
// Upstream consumes only DBNAME and USERNAME from positionals; extras are
|
|
623
|
-
// warned about and ignored. We surface them all on `positional` so the
|
|
624
|
-
// caller can warn/log; applyStartupArgs takes care of the first two.
|
|
625
|
-
return {
|
|
626
|
-
...args,
|
|
627
|
-
actions,
|
|
628
|
-
variables,
|
|
629
|
-
pset,
|
|
630
|
-
};
|
|
259
|
+
const parseStartupArgs = (argv) => {
|
|
260
|
+
const args = blankArgs();
|
|
261
|
+
const actions = [];
|
|
262
|
+
const variables = [];
|
|
263
|
+
const pset = [];
|
|
264
|
+
let i = 0;
|
|
265
|
+
const n = argv.length;
|
|
266
|
+
const needValue = (flagDisplay) => {
|
|
267
|
+
if (i + 1 >= n) return {
|
|
268
|
+
kind: "missing-arg",
|
|
269
|
+
message: `option requires an argument -- ${flagDisplay}`
|
|
270
|
+
};
|
|
271
|
+
i += 1;
|
|
272
|
+
return argv[i];
|
|
273
|
+
};
|
|
274
|
+
const applyShort = (letter, attachedValue, flagDisplay) => {
|
|
275
|
+
const takesArg = SHORT_WITH_ARG.has(letter);
|
|
276
|
+
let value;
|
|
277
|
+
if (takesArg) if (attachedValue !== void 0) value = attachedValue;
|
|
278
|
+
else {
|
|
279
|
+
const v = needValue(flagDisplay);
|
|
280
|
+
if (typeof v !== "string") return v;
|
|
281
|
+
value = v;
|
|
282
|
+
}
|
|
283
|
+
else if (attachedValue !== void 0) return {
|
|
284
|
+
kind: "invalid-option",
|
|
285
|
+
message: `option does not take an argument -- ${letter}`
|
|
286
|
+
};
|
|
287
|
+
switch (letter) {
|
|
288
|
+
case "a":
|
|
289
|
+
args.echoAll = true;
|
|
290
|
+
return null;
|
|
291
|
+
case "A":
|
|
292
|
+
args.noAlign = true;
|
|
293
|
+
return null;
|
|
294
|
+
case "b":
|
|
295
|
+
args.echoErrors = true;
|
|
296
|
+
return null;
|
|
297
|
+
case "C": return null;
|
|
298
|
+
case "c":
|
|
299
|
+
pushAction(actions, {
|
|
300
|
+
kind: "command",
|
|
301
|
+
sql: value
|
|
302
|
+
});
|
|
303
|
+
return null;
|
|
304
|
+
case "d":
|
|
305
|
+
applyDashD(args, value);
|
|
306
|
+
return null;
|
|
307
|
+
case "e":
|
|
308
|
+
args.echoQueries = true;
|
|
309
|
+
return null;
|
|
310
|
+
case "E":
|
|
311
|
+
args.echoHidden = "on";
|
|
312
|
+
return null;
|
|
313
|
+
case "f":
|
|
314
|
+
pushAction(actions, {
|
|
315
|
+
kind: "file",
|
|
316
|
+
path: value
|
|
317
|
+
});
|
|
318
|
+
return null;
|
|
319
|
+
case "F":
|
|
320
|
+
args.fieldSep = value;
|
|
321
|
+
args.fieldSepZero = false;
|
|
322
|
+
return null;
|
|
323
|
+
case "h":
|
|
324
|
+
args.host = value;
|
|
325
|
+
return null;
|
|
326
|
+
case "H":
|
|
327
|
+
args.htmlMode = true;
|
|
328
|
+
return null;
|
|
329
|
+
case "l":
|
|
330
|
+
args.list = true;
|
|
331
|
+
return null;
|
|
332
|
+
case "L":
|
|
333
|
+
args.log = value;
|
|
334
|
+
return null;
|
|
335
|
+
case "n":
|
|
336
|
+
args.noReadline = true;
|
|
337
|
+
return null;
|
|
338
|
+
case "o":
|
|
339
|
+
args.output = value;
|
|
340
|
+
return null;
|
|
341
|
+
case "p": {
|
|
342
|
+
const p = Number.parseInt(value, 10);
|
|
343
|
+
if (!Number.isFinite(p) || p <= 0 || p > 65535) return {
|
|
344
|
+
kind: "invalid-value",
|
|
345
|
+
message: `invalid port number: "${value}"`
|
|
346
|
+
};
|
|
347
|
+
args.port = p;
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
case "P":
|
|
351
|
+
pset.push(value);
|
|
352
|
+
return null;
|
|
353
|
+
case "q":
|
|
354
|
+
args.quiet = true;
|
|
355
|
+
return null;
|
|
356
|
+
case "R":
|
|
357
|
+
args.recordSep = value;
|
|
358
|
+
args.recordSepZero = false;
|
|
359
|
+
return null;
|
|
360
|
+
case "s":
|
|
361
|
+
args.singlestep = true;
|
|
362
|
+
return null;
|
|
363
|
+
case "S":
|
|
364
|
+
args.singleline = true;
|
|
365
|
+
return null;
|
|
366
|
+
case "t":
|
|
367
|
+
args.tuplesOnly = true;
|
|
368
|
+
return null;
|
|
369
|
+
case "T":
|
|
370
|
+
pset.push(`tableattr=${value}`);
|
|
371
|
+
return null;
|
|
372
|
+
case "U":
|
|
373
|
+
args.user = value;
|
|
374
|
+
return null;
|
|
375
|
+
case "v":
|
|
376
|
+
pushVariable(variables, value);
|
|
377
|
+
return null;
|
|
378
|
+
case "V": return {
|
|
379
|
+
kind: "version",
|
|
380
|
+
message: VERSION_STRING
|
|
381
|
+
};
|
|
382
|
+
case "w":
|
|
383
|
+
args.promptPassword = false;
|
|
384
|
+
return null;
|
|
385
|
+
case "W":
|
|
386
|
+
args.promptPassword = true;
|
|
387
|
+
return null;
|
|
388
|
+
case "x":
|
|
389
|
+
args.expanded = true;
|
|
390
|
+
return null;
|
|
391
|
+
case "X":
|
|
392
|
+
args.noPsqlrc = true;
|
|
393
|
+
return null;
|
|
394
|
+
case "z":
|
|
395
|
+
args.fieldSepZero = true;
|
|
396
|
+
return null;
|
|
397
|
+
case "0":
|
|
398
|
+
args.recordSepZero = true;
|
|
399
|
+
return null;
|
|
400
|
+
case "1":
|
|
401
|
+
args.singleTransaction = true;
|
|
402
|
+
return null;
|
|
403
|
+
case "?": return {
|
|
404
|
+
kind: "help",
|
|
405
|
+
message: renderHelp(void 0)
|
|
406
|
+
};
|
|
407
|
+
default: return {
|
|
408
|
+
kind: "invalid-option",
|
|
409
|
+
message: `invalid option -- ${letter}`
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
while (i < n) {
|
|
414
|
+
const tok = argv[i];
|
|
415
|
+
if (tok === "--") {
|
|
416
|
+
i += 1;
|
|
417
|
+
while (i < n) {
|
|
418
|
+
args.positional.push(argv[i]);
|
|
419
|
+
i += 1;
|
|
420
|
+
}
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
if (tok.startsWith("--")) {
|
|
424
|
+
const eq = tok.indexOf("=");
|
|
425
|
+
const name = eq < 0 ? tok.slice(2) : tok.slice(2, eq);
|
|
426
|
+
const attached = eq < 0 ? void 0 : tok.slice(eq + 1);
|
|
427
|
+
if (name === "csv") {
|
|
428
|
+
if (attached !== void 0) return {
|
|
429
|
+
kind: "invalid-option",
|
|
430
|
+
message: `option does not take an argument: --${name}`
|
|
431
|
+
};
|
|
432
|
+
args.csvOutput = true;
|
|
433
|
+
i += 1;
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
if (name === "no-pager") {
|
|
437
|
+
if (attached !== void 0) return {
|
|
438
|
+
kind: "invalid-option",
|
|
439
|
+
message: `option does not take an argument: --${name}`
|
|
440
|
+
};
|
|
441
|
+
args.noPager = true;
|
|
442
|
+
i += 1;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (name === "on-error-stop") {
|
|
446
|
+
if (attached !== void 0) return {
|
|
447
|
+
kind: "invalid-option",
|
|
448
|
+
message: `option does not take an argument: --${name}`
|
|
449
|
+
};
|
|
450
|
+
args.onErrorStop = true;
|
|
451
|
+
variables.push({
|
|
452
|
+
name: "ON_ERROR_STOP",
|
|
453
|
+
value: "on"
|
|
454
|
+
});
|
|
455
|
+
i += 1;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (name === "help") {
|
|
459
|
+
const topic = attached;
|
|
460
|
+
if (topic !== void 0 && topic !== "options" && topic !== "commands" && topic !== "variables") return {
|
|
461
|
+
kind: "invalid-option",
|
|
462
|
+
message: `unrecognized help topic: ${topic}`
|
|
463
|
+
};
|
|
464
|
+
return {
|
|
465
|
+
kind: "help",
|
|
466
|
+
message: renderHelp(topic)
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
if (name === "echo-hidden") {
|
|
470
|
+
if (attached === void 0) args.echoHidden = "on";
|
|
471
|
+
else if (attached === "noexec") args.echoHidden = "noexec";
|
|
472
|
+
else if (attached === "" || attached === "on") args.echoHidden = "on";
|
|
473
|
+
else return {
|
|
474
|
+
kind: "invalid-value",
|
|
475
|
+
message: `invalid value for --echo-hidden: "${attached}"`
|
|
476
|
+
};
|
|
477
|
+
i += 1;
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const short = LONG_MAP[name];
|
|
481
|
+
if (short === void 0) return {
|
|
482
|
+
kind: "invalid-option",
|
|
483
|
+
message: `unrecognized option: --${name}`
|
|
484
|
+
};
|
|
485
|
+
const requiresArg = LONG_WITH_ARG.has(name);
|
|
486
|
+
const optionalArg = LONG_OPTIONAL_ARG.has(name);
|
|
487
|
+
let value = attached;
|
|
488
|
+
if (requiresArg && value === void 0) {
|
|
489
|
+
if (i + 1 >= n) return {
|
|
490
|
+
kind: "missing-arg",
|
|
491
|
+
message: `option requires an argument: --${name}`
|
|
492
|
+
};
|
|
493
|
+
i += 1;
|
|
494
|
+
value = argv[i];
|
|
495
|
+
} else if (!requiresArg && !optionalArg && value !== void 0) return {
|
|
496
|
+
kind: "invalid-option",
|
|
497
|
+
message: `option does not take an argument: --${name}`
|
|
498
|
+
};
|
|
499
|
+
const err = applyShort(short, value, `--${name}`);
|
|
500
|
+
if (err) return err;
|
|
501
|
+
i += 1;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (tok.startsWith("-") && tok.length > 1) {
|
|
505
|
+
let k = 1;
|
|
506
|
+
while (k < tok.length) {
|
|
507
|
+
const letter = tok[k];
|
|
508
|
+
if (!SHORT_WITH_ARG.has(letter) && !SHORT_NO_ARG.has(letter)) return {
|
|
509
|
+
kind: "invalid-option",
|
|
510
|
+
message: `invalid option -- ${letter}`
|
|
511
|
+
};
|
|
512
|
+
if (SHORT_WITH_ARG.has(letter)) {
|
|
513
|
+
const remainder = tok.slice(k + 1);
|
|
514
|
+
const err = applyShort(letter, remainder.length > 0 ? remainder : void 0, letter);
|
|
515
|
+
if (err) return err;
|
|
516
|
+
k = tok.length;
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
const err = applyShort(letter, void 0, letter);
|
|
520
|
+
if (err) return err;
|
|
521
|
+
k += 1;
|
|
522
|
+
}
|
|
523
|
+
i += 1;
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
args.positional.push(tok);
|
|
527
|
+
i += 1;
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
...args,
|
|
531
|
+
actions,
|
|
532
|
+
variables,
|
|
533
|
+
pset
|
|
534
|
+
};
|
|
631
535
|
};
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
// We don't have a parsed `do_pset` here yet (lives in command/cmd_format),
|
|
708
|
-
// so we surface them as raw strings and let the integration layer feed
|
|
709
|
-
// them through once parsed. For tableattr (the most common -T use), apply
|
|
710
|
-
// directly.
|
|
711
|
-
for (const directive of args.pset) {
|
|
712
|
-
const eq = directive.indexOf("=");
|
|
713
|
-
if (eq >= 0) {
|
|
714
|
-
const key = directive.slice(0, eq);
|
|
715
|
-
const val = directive.slice(eq + 1);
|
|
716
|
-
if (key === "tableattr" || key === "T") {
|
|
717
|
-
settings.popt.topt.tableAttr = val.length > 0 ? val : null;
|
|
718
|
-
}
|
|
719
|
-
else if (key === "pager") {
|
|
720
|
-
if (val === "on" || val === "off" || val === "always") {
|
|
721
|
-
settings.popt.topt.pager = val;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
// Other directives left to the broader -P plumbing.
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
// -------- 5) Connection overrides. -------------------------------------
|
|
728
|
-
// Positional args follow upstream: positional[0] → dbname, positional[1] →
|
|
729
|
-
// username (if not already set by a flag).
|
|
730
|
-
let dbname = args.database;
|
|
731
|
-
let username = args.user;
|
|
732
|
-
if (args.positional[0] && !dbname)
|
|
733
|
-
dbname = args.positional[0];
|
|
734
|
-
if (args.positional[1] && !username)
|
|
735
|
-
username = args.positional[1];
|
|
736
|
-
// The argv flag layer mirrors the highest-priority CLI inputs (`-h`/`-p`
|
|
737
|
-
// / positional DBNAME / etc). Only populated entries end up in the layer
|
|
738
|
-
// so they don't accidentally clobber URI/env values.
|
|
739
|
-
// Seed with the full `-d` partial (carries ssl*/channelBinding/hostaddr/
|
|
740
|
-
// requireAuth — review #6), then overlay the explicit flag/positional
|
|
741
|
-
// values so `-h`/`-p`/`-U`/`-W`/positional still take precedence over `-d`.
|
|
742
|
-
const argvLayer = { ...(args.dashD ?? {}) };
|
|
743
|
-
if (args.host !== undefined)
|
|
744
|
-
argvLayer.host = args.host;
|
|
745
|
-
if (args.port !== undefined)
|
|
746
|
-
argvLayer.port = args.port;
|
|
747
|
-
if (username !== undefined)
|
|
748
|
-
argvLayer.user = username;
|
|
749
|
-
if (dbname !== undefined)
|
|
750
|
-
argvLayer.database = dbname;
|
|
751
|
-
if (args.password !== undefined)
|
|
752
|
-
argvLayer.password = args.password;
|
|
753
|
-
if (args.replication !== undefined)
|
|
754
|
-
argvLayer.replication = args.replication;
|
|
755
|
-
// Two modes:
|
|
756
|
-
// - LEGACY: no `resolution` provided → behave exactly like before, with
|
|
757
|
-
// `baseConnectOpts` supplying every default and argv overriding it.
|
|
758
|
-
// - LAYERED: `resolution` provided → run the full vanilla-psql chain.
|
|
759
|
-
let connect;
|
|
760
|
-
if (resolution === undefined) {
|
|
761
|
-
const base = baseConnectOpts ?? {
|
|
762
|
-
host: "localhost",
|
|
763
|
-
port: 5432,
|
|
764
|
-
user: "",
|
|
765
|
-
database: "",
|
|
766
|
-
ssl: "prefer",
|
|
767
|
-
};
|
|
768
|
-
connect = { ...base, ...argvLayer };
|
|
769
|
-
}
|
|
770
|
-
else {
|
|
771
|
-
connect = resolveLayeredConnect(argvLayer, resolution, baseConnectOpts);
|
|
772
|
-
}
|
|
773
|
-
return { connect, preActions: args.actions };
|
|
536
|
+
const applyStartupArgs = (args, settings, baseConnectOpts, resolution) => {
|
|
537
|
+
setStartupVars(settings.vars, CLIENT_VERSION);
|
|
538
|
+
for (const v of args.variables) if (v.value === "") settings.vars.unset(v.name);
|
|
539
|
+
else settings.vars.set(v.name, v.value);
|
|
540
|
+
if (args.echoAll) settings.vars.set("ECHO", "all");
|
|
541
|
+
if (args.echoErrors) settings.vars.set("ECHO", "errors");
|
|
542
|
+
if (args.echoQueries) settings.vars.set("ECHO", "queries");
|
|
543
|
+
if (args.echoHidden !== "off") {
|
|
544
|
+
settings.echoHidden = args.echoHidden;
|
|
545
|
+
settings.vars.set("ECHO_HIDDEN", args.echoHidden === "noexec" ? "noexec" : "on");
|
|
546
|
+
}
|
|
547
|
+
if (args.quiet) {
|
|
548
|
+
settings.quiet = true;
|
|
549
|
+
settings.vars.set("QUIET", "on");
|
|
550
|
+
}
|
|
551
|
+
if (args.singleline) {
|
|
552
|
+
settings.singleline = true;
|
|
553
|
+
settings.vars.set("SINGLELINE", "on");
|
|
554
|
+
}
|
|
555
|
+
if (args.singlestep) {
|
|
556
|
+
settings.singlestep = true;
|
|
557
|
+
settings.vars.set("SINGLESTEP", "on");
|
|
558
|
+
}
|
|
559
|
+
if (args.onErrorStop) {
|
|
560
|
+
settings.onErrorStop = true;
|
|
561
|
+
settings.vars.set("ON_ERROR_STOP", "on");
|
|
562
|
+
}
|
|
563
|
+
if (args.noAlign) settings.popt.topt.format = "unaligned";
|
|
564
|
+
if (args.htmlMode) settings.popt.topt.format = "html";
|
|
565
|
+
if (args.csvOutput) settings.popt.topt.format = "csv";
|
|
566
|
+
if (args.tuplesOnly) settings.popt.topt.tuplesOnly = true;
|
|
567
|
+
if (args.expanded) settings.popt.topt.expanded = "on";
|
|
568
|
+
if (args.fieldSepZero) settings.popt.topt.fieldSep = "\0";
|
|
569
|
+
else if (args.fieldSep !== void 0) settings.popt.topt.fieldSep = args.fieldSep;
|
|
570
|
+
if (args.recordSepZero) settings.popt.topt.recordSep = "\0";
|
|
571
|
+
else if (args.recordSep !== void 0) settings.popt.topt.recordSep = args.recordSep;
|
|
572
|
+
if (args.noPager) settings.popt.topt.pager = "off";
|
|
573
|
+
for (const directive of args.pset) {
|
|
574
|
+
const eq = directive.indexOf("=");
|
|
575
|
+
if (eq >= 0) {
|
|
576
|
+
const key = directive.slice(0, eq);
|
|
577
|
+
const val = directive.slice(eq + 1);
|
|
578
|
+
if (key === "tableattr" || key === "T") settings.popt.topt.tableAttr = val.length > 0 ? val : null;
|
|
579
|
+
else if (key === "pager") {
|
|
580
|
+
if (val === "on" || val === "off" || val === "always") settings.popt.topt.pager = val;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
let dbname = args.database;
|
|
585
|
+
let username = args.user;
|
|
586
|
+
if (args.positional[0] && !dbname) dbname = args.positional[0];
|
|
587
|
+
if (args.positional[1] && !username) username = args.positional[1];
|
|
588
|
+
const argvLayer = { ...args.dashD ?? {} };
|
|
589
|
+
if (args.host !== void 0) argvLayer.host = args.host;
|
|
590
|
+
if (args.port !== void 0) argvLayer.port = args.port;
|
|
591
|
+
if (username !== void 0) argvLayer.user = username;
|
|
592
|
+
if (dbname !== void 0) argvLayer.database = dbname;
|
|
593
|
+
if (args.password !== void 0) argvLayer.password = args.password;
|
|
594
|
+
if (args.replication !== void 0) argvLayer.replication = args.replication;
|
|
595
|
+
let connect;
|
|
596
|
+
if (resolution === void 0) connect = {
|
|
597
|
+
...baseConnectOpts ?? {
|
|
598
|
+
host: "localhost",
|
|
599
|
+
port: 5432,
|
|
600
|
+
user: "",
|
|
601
|
+
database: "",
|
|
602
|
+
ssl: "prefer"
|
|
603
|
+
},
|
|
604
|
+
...argvLayer
|
|
605
|
+
};
|
|
606
|
+
else connect = resolveLayeredConnect(argvLayer, resolution, baseConnectOpts);
|
|
607
|
+
return {
|
|
608
|
+
connect,
|
|
609
|
+
preActions: args.actions
|
|
610
|
+
};
|
|
774
611
|
};
|
|
775
612
|
/**
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
613
|
+
* Run the layered connection-parameter merge.
|
|
614
|
+
*
|
|
615
|
+
* argv > URI partial > PG* env > .pgpass (password only) > service > libpq defaults
|
|
616
|
+
*
|
|
617
|
+
* `baseConnectOpts` (the legacy `ConnectOptions` argument) is treated as a
|
|
618
|
+
* pre-baked URI partial when the resolution path is used WITHOUT an explicit
|
|
619
|
+
* `uriPartial`. This keeps the door open for callers that still want to
|
|
620
|
+
* pass a fully-defaulted URI shape from `parseConnectionUri`.
|
|
621
|
+
*/
|
|
785
622
|
const resolveLayeredConnect = (argvLayer, resolution, legacyBase) => {
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
uriPartial,
|
|
818
|
-
envLayer,
|
|
819
|
-
serviceLayer,
|
|
820
|
-
];
|
|
821
|
-
// First-pass merge (without pgpass) so we know what host/port/db/user
|
|
822
|
-
// ended up as. pgpass is a password-only layer that depends on the
|
|
823
|
-
// resolved target.
|
|
824
|
-
let merged = mergeConnectOptions(layers, defaults);
|
|
825
|
-
if (merged.password === undefined) {
|
|
826
|
-
const pgpassPwd = lookupPgPass(resolution.pgpassEntries ?? [], {
|
|
827
|
-
host: merged.host,
|
|
828
|
-
port: merged.port,
|
|
829
|
-
database: merged.database !== "" ? merged.database : merged.user,
|
|
830
|
-
user: merged.user,
|
|
831
|
-
});
|
|
832
|
-
if (pgpassPwd !== undefined) {
|
|
833
|
-
// Re-merge with pgpass slotted in just above libpq defaults so any
|
|
834
|
-
// explicit `password=` in env / service still wins.
|
|
835
|
-
const pgpassLayer = {
|
|
836
|
-
password: pgpassPwd,
|
|
837
|
-
};
|
|
838
|
-
merged = mergeConnectOptions([...layers, pgpassLayer], defaults);
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
return merged;
|
|
623
|
+
const env = resolution.env ?? {};
|
|
624
|
+
const uriPartial = resolution.uriPartial ?? (legacyBase !== void 0 ? legacyBase : {});
|
|
625
|
+
const serviceName = resolution.serviceName ?? env.PGSERVICE;
|
|
626
|
+
let serviceEntry;
|
|
627
|
+
if (serviceName !== void 0 && serviceName !== "") {
|
|
628
|
+
serviceEntry = resolution.services?.get(serviceName);
|
|
629
|
+
if (serviceEntry === void 0) throw new Error(`definition of service "${serviceName}" not found`);
|
|
630
|
+
}
|
|
631
|
+
const serviceLayer = serviceEntry !== void 0 ? serviceEntryToConnectOptions(serviceEntry) : {};
|
|
632
|
+
const envLayer = envConnectionDefaults(env);
|
|
633
|
+
const defaults = libpqConnectionDefaults(env);
|
|
634
|
+
const layers = [
|
|
635
|
+
argvLayer,
|
|
636
|
+
uriPartial,
|
|
637
|
+
envLayer,
|
|
638
|
+
serviceLayer
|
|
639
|
+
];
|
|
640
|
+
let merged = mergeConnectOptions(layers, defaults);
|
|
641
|
+
if (merged.password === void 0) {
|
|
642
|
+
const pgpassPwd = lookupPgPass(resolution.pgpassEntries ?? [], {
|
|
643
|
+
host: merged.host,
|
|
644
|
+
port: merged.port,
|
|
645
|
+
database: merged.database !== "" ? merged.database : merged.user,
|
|
646
|
+
user: merged.user
|
|
647
|
+
});
|
|
648
|
+
if (pgpassPwd !== void 0) {
|
|
649
|
+
const pgpassLayer = { password: pgpassPwd };
|
|
650
|
+
merged = mergeConnectOptions([...layers, pgpassLayer], defaults);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return merged;
|
|
842
654
|
};
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
export const formatParseError = (err) => err.message;
|
|
655
|
+
const formatParseError = (err) => err.message;
|
|
656
|
+
//#endregion
|
|
657
|
+
export { CLIENT_VERSION, applyStartupArgs, formatParseError, parseStartupArgs };
|