neonctl 2.28.0 → 2.29.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 +2 -2
- package/dist/analytics.js +35 -33
- package/dist/api.js +34 -34
- package/dist/auth.js +50 -44
- package/dist/cli.js +2 -2
- package/dist/commands/auth.js +58 -52
- package/dist/commands/bootstrap.js +115 -157
- package/dist/commands/branches.js +154 -147
- package/dist/commands/bucket.js +124 -118
- package/dist/commands/checkout.js +49 -49
- package/dist/commands/config.js +212 -88
- package/dist/commands/connection_string.js +62 -62
- package/dist/commands/data_api.js +96 -96
- package/dist/commands/databases.js +23 -23
- package/dist/commands/deploy.js +12 -12
- package/dist/commands/dev.js +114 -114
- package/dist/commands/env.js +43 -43
- package/dist/commands/functions.js +97 -98
- package/dist/commands/index.js +26 -26
- package/dist/commands/init.js +23 -22
- package/dist/commands/ip_allow.js +29 -29
- package/dist/commands/link.js +223 -166
- package/dist/commands/neon_auth.js +381 -363
- package/dist/commands/operations.js +11 -11
- package/dist/commands/orgs.js +8 -8
- package/dist/commands/projects.js +101 -99
- package/dist/commands/psql.js +31 -31
- package/dist/commands/roles.js +21 -21
- package/dist/commands/schema_diff.js +23 -23
- package/dist/commands/set_context.js +17 -17
- package/dist/commands/status.js +17 -17
- package/dist/commands/user.js +5 -5
- package/dist/commands/vpc_endpoints.js +50 -50
- package/dist/config.js +7 -7
- package/dist/config_format.js +5 -5
- package/dist/context.js +23 -16
- package/dist/current_branch_fast_path.js +6 -6
- package/dist/dev/env.js +33 -33
- package/dist/dev/functions.js +4 -4
- package/dist/dev/inputs.js +6 -6
- package/dist/dev/runtime.js +25 -25
- package/dist/env.js +14 -14
- package/dist/env_file.js +13 -13
- package/dist/errors.js +19 -19
- package/dist/functions_api.js +10 -10
- package/dist/help.js +15 -15
- package/dist/index.js +94 -92
- package/dist/log.js +2 -2
- package/dist/pkg.js +5 -5
- package/dist/psql/cli.js +4 -2
- package/dist/psql/command/cmd_cond.js +61 -61
- package/dist/psql/command/cmd_connect.js +159 -154
- package/dist/psql/command/cmd_copy.js +107 -97
- package/dist/psql/command/cmd_describe.js +368 -363
- package/dist/psql/command/cmd_format.js +276 -263
- package/dist/psql/command/cmd_io.js +269 -263
- package/dist/psql/command/cmd_lo.js +74 -66
- package/dist/psql/command/cmd_meta.js +148 -148
- package/dist/psql/command/cmd_misc.js +17 -17
- package/dist/psql/command/cmd_pipeline.js +142 -135
- package/dist/psql/command/cmd_restrict.js +25 -25
- package/dist/psql/command/cmd_show.js +183 -168
- package/dist/psql/command/dispatch.js +26 -26
- package/dist/psql/command/shared.js +14 -14
- package/dist/psql/complete/filenames.js +16 -16
- package/dist/psql/complete/index.js +4 -4
- package/dist/psql/complete/matcher.js +33 -32
- package/dist/psql/complete/psqlVars.js +173 -173
- package/dist/psql/complete/queries.js +5 -3
- package/dist/psql/complete/rules.js +900 -863
- package/dist/psql/core/common.js +136 -133
- package/dist/psql/core/help.js +343 -343
- package/dist/psql/core/mainloop.js +160 -153
- package/dist/psql/core/prompt.js +126 -123
- package/dist/psql/core/settings.js +111 -111
- package/dist/psql/core/sqlHelp.js +150 -150
- package/dist/psql/core/startup.js +211 -205
- package/dist/psql/core/syncVars.js +14 -14
- package/dist/psql/core/variables.js +24 -24
- package/dist/psql/describe/formatters.js +302 -289
- package/dist/psql/describe/processNamePattern.js +28 -28
- package/dist/psql/describe/queries.js +656 -651
- package/dist/psql/index.js +436 -411
- package/dist/psql/io/history.js +36 -36
- package/dist/psql/io/input.js +15 -15
- package/dist/psql/io/lineEditor/buffer.js +27 -25
- package/dist/psql/io/lineEditor/complete.js +15 -15
- package/dist/psql/io/lineEditor/filename.js +22 -22
- package/dist/psql/io/lineEditor/index.js +65 -62
- package/dist/psql/io/lineEditor/keymap.js +325 -318
- package/dist/psql/io/lineEditor/vt100.js +60 -60
- package/dist/psql/io/pgpass.js +18 -18
- package/dist/psql/io/pgservice.js +14 -14
- package/dist/psql/io/psqlrc.js +46 -46
- package/dist/psql/print/aligned.js +175 -166
- package/dist/psql/print/asciidoc.js +51 -51
- package/dist/psql/print/crosstab.js +34 -31
- package/dist/psql/print/csv.js +25 -22
- package/dist/psql/print/html.js +54 -54
- package/dist/psql/print/json.js +12 -12
- package/dist/psql/print/latex.js +118 -118
- package/dist/psql/print/pager.js +28 -26
- package/dist/psql/print/troff.js +48 -48
- package/dist/psql/print/unaligned.js +15 -14
- package/dist/psql/print/units.js +17 -17
- package/dist/psql/scanner/slash.js +48 -46
- package/dist/psql/scanner/sql.js +88 -84
- package/dist/psql/scanner/stringutils.js +21 -17
- package/dist/psql/types/index.js +7 -7
- package/dist/psql/types/scanner.js +8 -8
- package/dist/psql/wire/connection.js +341 -327
- package/dist/psql/wire/copy.js +7 -7
- package/dist/psql/wire/pipeline.js +26 -24
- package/dist/psql/wire/protocol.js +102 -102
- package/dist/psql/wire/sasl.js +62 -62
- package/dist/psql/wire/tls.js +79 -73
- package/dist/storage_api.js +15 -15
- package/dist/test_utils/fixtures.js +34 -31
- package/dist/test_utils/oauth_server.js +5 -5
- package/dist/utils/api_enums.js +13 -13
- package/dist/utils/branch_notice.js +5 -5
- package/dist/utils/branch_picker.js +26 -26
- package/dist/utils/compute_units.js +4 -4
- package/dist/utils/enrichers.js +20 -15
- package/dist/utils/esbuild.js +28 -28
- package/dist/utils/formats.js +1 -1
- package/dist/utils/middlewares.js +3 -3
- package/dist/utils/package_manager.js +68 -0
- package/dist/utils/point_in_time.js +12 -12
- package/dist/utils/psql.js +30 -30
- package/dist/utils/string.js +2 -2
- package/dist/utils/ui.js +9 -9
- package/dist/utils/zip.js +1 -1
- package/dist/writer.js +17 -17
- package/package.json +6 -7
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
*
|
|
33
33
|
* The set is registered in bulk via {@link registerPipelineCommands}.
|
|
34
34
|
*/
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
35
|
+
import { alignedPrinter } from "../print/aligned.js";
|
|
36
|
+
import { clearPipelineGateErrors } from "./cmd_io.js";
|
|
37
|
+
import { writeErr } from "./shared.js";
|
|
38
38
|
// ---------------------------------------------------------------------------
|
|
39
39
|
// Settings stash. We can't add new fields to PsqlSettings (frozen WP-00) so
|
|
40
40
|
// we attach Symbol-keyed state.
|
|
41
41
|
// ---------------------------------------------------------------------------
|
|
42
|
-
const BIND_STATE_KEY = Symbol.for(
|
|
43
|
-
const PIPELINE_KEY = Symbol.for(
|
|
44
|
-
const PREPARED_BY_NAME_KEY = Symbol.for(
|
|
42
|
+
const BIND_STATE_KEY = Symbol.for("neonctl.psql.bindState");
|
|
43
|
+
const PIPELINE_KEY = Symbol.for("neonctl.psql.pipeline");
|
|
44
|
+
const PREPARED_BY_NAME_KEY = Symbol.for("neonctl.psql.preparedByName");
|
|
45
45
|
const stashOf = (settings) => settings;
|
|
46
46
|
/** Read (and clear) the pending bind params, if any. */
|
|
47
47
|
export const consumeBindState = (settings) => {
|
|
@@ -128,9 +128,9 @@ const bumpCounter = (settings, name, delta) => {
|
|
|
128
128
|
setCounter(settings, name, readCounter(settings, name) + delta);
|
|
129
129
|
};
|
|
130
130
|
const resetPipelineCounters = (settings) => {
|
|
131
|
-
setCounter(settings,
|
|
132
|
-
setCounter(settings,
|
|
133
|
-
setCounter(settings,
|
|
131
|
+
setCounter(settings, "PIPELINE_COMMAND_COUNT", 0);
|
|
132
|
+
setCounter(settings, "PIPELINE_SYNC_COUNT", 0);
|
|
133
|
+
setCounter(settings, "PIPELINE_RESULT_COUNT", 0);
|
|
134
134
|
};
|
|
135
135
|
/**
|
|
136
136
|
* Wrap `Pipeline.execute` so each enqueued Execute message bumps
|
|
@@ -146,7 +146,7 @@ const resetPipelineCounters = (settings) => {
|
|
|
146
146
|
const wrapSessionForCounters = (session, settings) => {
|
|
147
147
|
const origExecute = session.execute.bind(session);
|
|
148
148
|
session.execute = (name, maxRows) => {
|
|
149
|
-
bumpCounter(settings,
|
|
149
|
+
bumpCounter(settings, "PIPELINE_COMMAND_COUNT", 1);
|
|
150
150
|
return origExecute(name, maxRows);
|
|
151
151
|
};
|
|
152
152
|
return session;
|
|
@@ -159,7 +159,7 @@ const errResult = (ctx, message) => {
|
|
|
159
159
|
writeErr(`\\${ctx.cmdName}: ${message}\n`);
|
|
160
160
|
// Tell mainloop the diagnostic is already on stderr so it doesn't add
|
|
161
161
|
// a `psql: ERROR: <msg>` fallback line.
|
|
162
|
-
return { status:
|
|
162
|
+
return { status: "error", errorWritten: true };
|
|
163
163
|
};
|
|
164
164
|
/**
|
|
165
165
|
* Coerce any thrown / rejected value into a printable string. The
|
|
@@ -175,9 +175,9 @@ const errorToMessage = (err) => {
|
|
|
175
175
|
if (err instanceof Error)
|
|
176
176
|
return err.message;
|
|
177
177
|
if (err !== null &&
|
|
178
|
-
typeof err ===
|
|
179
|
-
|
|
180
|
-
typeof err.message ===
|
|
178
|
+
typeof err === "object" &&
|
|
179
|
+
"message" in err &&
|
|
180
|
+
typeof err.message === "string") {
|
|
181
181
|
return err.message;
|
|
182
182
|
}
|
|
183
183
|
try {
|
|
@@ -200,7 +200,7 @@ const errorToMessage = (err) => {
|
|
|
200
200
|
* the originating SQL position through `session.lastError`.
|
|
201
201
|
*/
|
|
202
202
|
const renderPipelineError = (err) => {
|
|
203
|
-
if (err === null || typeof err !==
|
|
203
|
+
if (err === null || typeof err !== "object") {
|
|
204
204
|
writeErr(`ERROR: ${errorToMessage(err)}\n`);
|
|
205
205
|
return;
|
|
206
206
|
}
|
|
@@ -211,11 +211,11 @@ const renderPipelineError = (err) => {
|
|
|
211
211
|
// wording the regress baseline asserts for cascaded skips after a
|
|
212
212
|
// preceding ErrorResponse.
|
|
213
213
|
if (e.pipelineAborted) {
|
|
214
|
-
writeErr(`${e.message ??
|
|
214
|
+
writeErr(`${e.message ?? "Pipeline aborted, command did not run"}\n`);
|
|
215
215
|
return;
|
|
216
216
|
}
|
|
217
|
-
const severity = e.severity ??
|
|
218
|
-
const message = e.message ??
|
|
217
|
+
const severity = e.severity ?? "ERROR";
|
|
218
|
+
const message = e.message ?? "";
|
|
219
219
|
writeErr(`${severity}: ${message}\n`);
|
|
220
220
|
if (e.detail)
|
|
221
221
|
writeErr(`DETAIL: ${e.detail}\n`);
|
|
@@ -227,7 +227,7 @@ const renderPipelineError = (err) => {
|
|
|
227
227
|
const readAllArgs = (ctx) => {
|
|
228
228
|
const out = [];
|
|
229
229
|
for (;;) {
|
|
230
|
-
const arg = ctx.nextArg(
|
|
230
|
+
const arg = ctx.nextArg("normal");
|
|
231
231
|
if (arg === null)
|
|
232
232
|
break;
|
|
233
233
|
out.push(arg);
|
|
@@ -238,26 +238,26 @@ const readAllArgs = (ctx) => {
|
|
|
238
238
|
// \bind [VALUE ...]
|
|
239
239
|
// ---------------------------------------------------------------------------
|
|
240
240
|
export const cmdBind = {
|
|
241
|
-
name:
|
|
242
|
-
helpKey:
|
|
241
|
+
name: "bind",
|
|
242
|
+
helpKey: "bind",
|
|
243
243
|
run(ctx) {
|
|
244
244
|
const values = readAllArgs(ctx);
|
|
245
245
|
stashOf(ctx.settings)[BIND_STATE_KEY] = {
|
|
246
|
-
name:
|
|
246
|
+
name: "",
|
|
247
247
|
values,
|
|
248
248
|
byName: false,
|
|
249
249
|
};
|
|
250
|
-
return Promise.resolve({ status:
|
|
250
|
+
return Promise.resolve({ status: "ok" });
|
|
251
251
|
},
|
|
252
252
|
};
|
|
253
253
|
// ---------------------------------------------------------------------------
|
|
254
254
|
// \bind_named NAME [VALUE ...]
|
|
255
255
|
// ---------------------------------------------------------------------------
|
|
256
256
|
export const cmdBindNamed = {
|
|
257
|
-
name:
|
|
258
|
-
helpKey:
|
|
257
|
+
name: "bind_named",
|
|
258
|
+
helpKey: "bind_named",
|
|
259
259
|
run(ctx) {
|
|
260
|
-
const name = ctx.nextArg(
|
|
260
|
+
const name = ctx.nextArg("normal");
|
|
261
261
|
// Upstream `exec_command_bind_named` rejects only the missing-arg
|
|
262
262
|
// case. `''` IS valid — it addresses the unnamed prepared statement
|
|
263
263
|
// slot (set via `\parse ''`).
|
|
@@ -266,27 +266,27 @@ export const cmdBindNamed = {
|
|
|
266
266
|
// follow-on `\g` falls back to `pset.last_query` (the previous
|
|
267
267
|
// successful query) instead of executing against a stale handle.
|
|
268
268
|
stashOf(ctx.settings)[BIND_STATE_KEY] = undefined;
|
|
269
|
-
return Promise.resolve(errResult(ctx,
|
|
269
|
+
return Promise.resolve(errResult(ctx, "missing required argument"));
|
|
270
270
|
}
|
|
271
271
|
const values = readAllArgs(ctx);
|
|
272
272
|
stashOf(ctx.settings)[BIND_STATE_KEY] = { name, values, byName: true };
|
|
273
|
-
return Promise.resolve({ status:
|
|
273
|
+
return Promise.resolve({ status: "ok" });
|
|
274
274
|
},
|
|
275
275
|
};
|
|
276
276
|
// ---------------------------------------------------------------------------
|
|
277
277
|
// \parse NAME — prepare current queryBuf as NAME.
|
|
278
278
|
// ---------------------------------------------------------------------------
|
|
279
279
|
export const cmdParse = {
|
|
280
|
-
name:
|
|
281
|
-
helpKey:
|
|
280
|
+
name: "parse",
|
|
281
|
+
helpKey: "parse",
|
|
282
282
|
async run(ctx) {
|
|
283
|
-
const name = ctx.nextArg(
|
|
283
|
+
const name = ctx.nextArg("normal");
|
|
284
284
|
// Upstream `exec_command_parse` rejects only the missing-arg case
|
|
285
285
|
// with `missing required argument`. An explicit empty string `''`
|
|
286
286
|
// IS valid — it's the "unnamed" prepared statement slot, addressable
|
|
287
287
|
// later via `\bind_named ''`.
|
|
288
288
|
if (name === null) {
|
|
289
|
-
return errResult(ctx,
|
|
289
|
+
return errResult(ctx, "missing required argument");
|
|
290
290
|
}
|
|
291
291
|
// Upstream `exec_command_parse` passes the query buffer verbatim to
|
|
292
292
|
// `PQsendPrepare`, with no trim — the server then stores the bytes
|
|
@@ -297,10 +297,10 @@ export const cmdParse = {
|
|
|
297
297
|
// only buffer reports `no query buffer` like upstream does.
|
|
298
298
|
const sql = ctx.queryBuf;
|
|
299
299
|
if (sql.trim().length === 0) {
|
|
300
|
-
return errResult(ctx,
|
|
300
|
+
return errResult(ctx, "no query buffer");
|
|
301
301
|
}
|
|
302
302
|
if (!ctx.settings.db) {
|
|
303
|
-
return errResult(ctx,
|
|
303
|
+
return errResult(ctx, "no connection to the server");
|
|
304
304
|
}
|
|
305
305
|
// In pipeline mode, route the Parse through the active session so
|
|
306
306
|
// it gets queued behind the in-flight P/B/E ops (and the server
|
|
@@ -321,7 +321,7 @@ export const cmdParse = {
|
|
|
321
321
|
// accounting. Test mocks that don't implement `parseSlot` fall
|
|
322
322
|
// through to the plain `parse()` method.
|
|
323
323
|
const session = pipelineActive.session;
|
|
324
|
-
if (typeof session.parseSlot ===
|
|
324
|
+
if (typeof session.parseSlot === "function") {
|
|
325
325
|
await session.parseSlot(name, sql, []);
|
|
326
326
|
}
|
|
327
327
|
else {
|
|
@@ -330,8 +330,8 @@ export const cmdParse = {
|
|
|
330
330
|
ctx.settings.lastQuery = sql;
|
|
331
331
|
// Upstream `exec_command_parse` bumps `pset.piped_commands` after
|
|
332
332
|
// PQsendPrepare succeeds — the Parse is one queued command.
|
|
333
|
-
bumpCounter(ctx.settings,
|
|
334
|
-
return { status:
|
|
333
|
+
bumpCounter(ctx.settings, "PIPELINE_COMMAND_COUNT", 1);
|
|
334
|
+
return { status: "reset-buf", newBuf: "" };
|
|
335
335
|
}
|
|
336
336
|
catch (err) {
|
|
337
337
|
return errResult(ctx, errorToMessage(err));
|
|
@@ -352,7 +352,7 @@ export const cmdParse = {
|
|
|
352
352
|
// "ERROR: there is no parameter $1" the conformance corpus
|
|
353
353
|
// expects from `SELECT $1, $2` executed without bind params.
|
|
354
354
|
ctx.settings.lastQuery = sql;
|
|
355
|
-
return { status:
|
|
355
|
+
return { status: "reset-buf", newBuf: "" };
|
|
356
356
|
}
|
|
357
357
|
catch (err) {
|
|
358
358
|
return errResult(ctx, errorToMessage(err));
|
|
@@ -363,17 +363,17 @@ export const cmdParse = {
|
|
|
363
363
|
// \close_prepared NAME
|
|
364
364
|
// ---------------------------------------------------------------------------
|
|
365
365
|
export const cmdClosePrepared = {
|
|
366
|
-
name:
|
|
367
|
-
helpKey:
|
|
366
|
+
name: "close_prepared",
|
|
367
|
+
helpKey: "close_prepared",
|
|
368
368
|
async run(ctx) {
|
|
369
|
-
const name = ctx.nextArg(
|
|
369
|
+
const name = ctx.nextArg("normal");
|
|
370
370
|
// Empty string `''` is the valid unnamed prepared statement.
|
|
371
371
|
if (name === null) {
|
|
372
|
-
return errResult(ctx,
|
|
372
|
+
return errResult(ctx, "missing required argument");
|
|
373
373
|
}
|
|
374
374
|
const db = ctx.settings.db;
|
|
375
375
|
if (!db) {
|
|
376
|
-
return errResult(ctx,
|
|
376
|
+
return errResult(ctx, "no connection to the server");
|
|
377
377
|
}
|
|
378
378
|
// Inside an open pipeline, upstream routes through
|
|
379
379
|
// `PQsendClosePrepared` (queues a `Close('S', name)` behind the
|
|
@@ -391,7 +391,7 @@ export const cmdClosePrepared = {
|
|
|
391
391
|
// that don't implement `closeSlot` fall through to plain
|
|
392
392
|
// `close()`.
|
|
393
393
|
const session = ps.session;
|
|
394
|
-
if (typeof session.closeSlot ===
|
|
394
|
+
if (typeof session.closeSlot === "function") {
|
|
395
395
|
await session.closeSlot(name);
|
|
396
396
|
}
|
|
397
397
|
else {
|
|
@@ -399,11 +399,11 @@ export const cmdClosePrepared = {
|
|
|
399
399
|
}
|
|
400
400
|
// Upstream `exec_command_close_prepared` bumps `piped_commands`
|
|
401
401
|
// (PIPELINE_COMMAND_COUNT) after a successful PQsendClosePrepared.
|
|
402
|
-
bumpCounter(ctx.settings,
|
|
402
|
+
bumpCounter(ctx.settings, "PIPELINE_COMMAND_COUNT", 1);
|
|
403
403
|
// Drop any cached binding so a later `\bind_named NAME \g`
|
|
404
404
|
// errors cleanly instead of using a stale handle.
|
|
405
405
|
dropPrepared(ctx.settings, name);
|
|
406
|
-
return { status:
|
|
406
|
+
return { status: "ok" };
|
|
407
407
|
}
|
|
408
408
|
catch (err) {
|
|
409
409
|
return errResult(ctx, errorToMessage(err));
|
|
@@ -425,13 +425,13 @@ export const cmdClosePrepared = {
|
|
|
425
425
|
// implement the dedicated entry point. The real PgConnection
|
|
426
426
|
// always provides closePreparedStatement; this branch only
|
|
427
427
|
// fires under unit tests with bespoke Connection mocks.
|
|
428
|
-
const stmt = await db.prepare(name,
|
|
428
|
+
const stmt = await db.prepare(name, "SELECT 1");
|
|
429
429
|
await stmt.close();
|
|
430
430
|
}
|
|
431
431
|
// Drop any cached binding so a later `\bind_named NAME \g` errors
|
|
432
432
|
// cleanly instead of using a stale handle.
|
|
433
433
|
dropPrepared(ctx.settings, name);
|
|
434
|
-
return { status:
|
|
434
|
+
return { status: "ok" };
|
|
435
435
|
}
|
|
436
436
|
catch (err) {
|
|
437
437
|
return errResult(ctx, errorToMessage(err));
|
|
@@ -442,11 +442,11 @@ export const cmdClosePrepared = {
|
|
|
442
442
|
// \startpipeline / \endpipeline
|
|
443
443
|
// ---------------------------------------------------------------------------
|
|
444
444
|
export const cmdStartPipeline = {
|
|
445
|
-
name:
|
|
446
|
-
helpKey:
|
|
445
|
+
name: "startpipeline",
|
|
446
|
+
helpKey: "startpipeline",
|
|
447
447
|
run(ctx) {
|
|
448
448
|
if (!ctx.settings.db) {
|
|
449
|
-
return Promise.resolve(errResult(ctx,
|
|
449
|
+
return Promise.resolve(errResult(ctx, "no connection to the server"));
|
|
450
450
|
}
|
|
451
451
|
// Vanilla psql 18.4 treats a duplicate `\startpipeline` as a silent
|
|
452
452
|
// no-op (no warning on stdout OR stderr) — verified empirically:
|
|
@@ -455,7 +455,7 @@ export const cmdStartPipeline = {
|
|
|
455
455
|
// lines. Our prior `errResult('pipeline already active')` was a
|
|
456
456
|
// divergence; match upstream's quiet path.
|
|
457
457
|
if (getPipelineState(ctx.settings) !== null) {
|
|
458
|
-
return Promise.resolve({ status:
|
|
458
|
+
return Promise.resolve({ status: "ok" });
|
|
459
459
|
}
|
|
460
460
|
try {
|
|
461
461
|
const session = wrapSessionForCounters(ctx.settings.db.pipeline(), ctx.settings);
|
|
@@ -464,11 +464,11 @@ export const cmdStartPipeline = {
|
|
|
464
464
|
pending: [],
|
|
465
465
|
drainedCount: 0,
|
|
466
466
|
};
|
|
467
|
-
ctx.settings.sendMode =
|
|
467
|
+
ctx.settings.sendMode = "extended-pipeline";
|
|
468
468
|
// Upstream `exec_command_startpipeline` calls SetVariable for the three
|
|
469
469
|
// counter vars (zeroing whatever the prior pipeline left behind).
|
|
470
470
|
resetPipelineCounters(ctx.settings);
|
|
471
|
-
return Promise.resolve({ status:
|
|
471
|
+
return Promise.resolve({ status: "ok" });
|
|
472
472
|
}
|
|
473
473
|
catch (err) {
|
|
474
474
|
return Promise.resolve(errResult(ctx, errorToMessage(err)));
|
|
@@ -476,8 +476,8 @@ export const cmdStartPipeline = {
|
|
|
476
476
|
},
|
|
477
477
|
};
|
|
478
478
|
export const cmdEndPipeline = {
|
|
479
|
-
name:
|
|
480
|
-
helpKey:
|
|
479
|
+
name: "endpipeline",
|
|
480
|
+
helpKey: "endpipeline",
|
|
481
481
|
async run(ctx) {
|
|
482
482
|
const ps = getPipelineState(ctx.settings);
|
|
483
483
|
if (!ps) {
|
|
@@ -490,10 +490,10 @@ export const cmdEndPipeline = {
|
|
|
490
490
|
// `errResult` (which would inject `\endpipeline: `) and write
|
|
491
491
|
// the line directly.
|
|
492
492
|
ctx.settings.lastErrorResult = {
|
|
493
|
-
message:
|
|
493
|
+
message: "cannot send pipeline when not in pipeline mode",
|
|
494
494
|
};
|
|
495
|
-
writeErr(
|
|
496
|
-
return { status:
|
|
495
|
+
writeErr("cannot send pipeline when not in pipeline mode\n");
|
|
496
|
+
return { status: "error", errorWritten: true };
|
|
497
497
|
}
|
|
498
498
|
try {
|
|
499
499
|
// Snapshot how many slots were already surfaced by prior
|
|
@@ -522,10 +522,10 @@ export const cmdEndPipeline = {
|
|
|
522
522
|
// "fetching results in chunked mode failed" wording in lieu of
|
|
523
523
|
// (or in addition to) the regular Pipeline aborted line. Read
|
|
524
524
|
// BEFORE end() resets the counters.
|
|
525
|
-
const fetchCountActive = (ctx.settings.vars.get(
|
|
525
|
+
const fetchCountActive = (ctx.settings.vars.get("FETCH_COUNT") ?? "0") !== "0";
|
|
526
526
|
const sets = await ps.session.end();
|
|
527
527
|
stashOf(ctx.settings)[PIPELINE_KEY] = undefined;
|
|
528
|
-
ctx.settings.sendMode =
|
|
528
|
+
ctx.settings.sendMode = "extended-query";
|
|
529
529
|
// Upstream `exec_command_endpipeline` zeroes the counters once the
|
|
530
530
|
// pipeline has drained — mirrors the empirical behaviour of vanilla
|
|
531
531
|
// psql 18.4 where `\echo :PIPELINE_*` reads "0" after `\endpipeline`.
|
|
@@ -554,7 +554,7 @@ export const cmdEndPipeline = {
|
|
|
554
554
|
const entries = settled.length > 0
|
|
555
555
|
? settled
|
|
556
556
|
: sets.map((rs) => ({
|
|
557
|
-
status:
|
|
557
|
+
status: "fulfilled",
|
|
558
558
|
value: rs,
|
|
559
559
|
}));
|
|
560
560
|
// Pre-scan THIS slice (entries from `alreadyDrained` onward) for
|
|
@@ -570,12 +570,13 @@ export const cmdEndPipeline = {
|
|
|
570
570
|
const sliceForError = entries.slice(alreadyDrained);
|
|
571
571
|
const realFromSlice = (() => {
|
|
572
572
|
for (const r of sliceForError) {
|
|
573
|
-
if (r.status !==
|
|
573
|
+
if (r.status !== "rejected")
|
|
574
574
|
continue;
|
|
575
575
|
const reason = r.reason;
|
|
576
|
-
const isAborted = typeof reason ===
|
|
576
|
+
const isAborted = typeof reason === "object" &&
|
|
577
577
|
reason !== null &&
|
|
578
|
-
reason
|
|
578
|
+
reason
|
|
579
|
+
.pipelineAborted === true;
|
|
579
580
|
if (!isAborted)
|
|
580
581
|
return reason;
|
|
581
582
|
}
|
|
@@ -586,7 +587,7 @@ export const cmdEndPipeline = {
|
|
|
586
587
|
const le = session.lastError;
|
|
587
588
|
if (le === null || le === undefined)
|
|
588
589
|
return null;
|
|
589
|
-
if (typeof le ===
|
|
590
|
+
if (typeof le === "object" &&
|
|
590
591
|
le.pipelineAborted) {
|
|
591
592
|
return null;
|
|
592
593
|
}
|
|
@@ -594,7 +595,7 @@ export const cmdEndPipeline = {
|
|
|
594
595
|
})();
|
|
595
596
|
for (let i = alreadyDrained; i < entries.length; i++) {
|
|
596
597
|
const r = entries[i];
|
|
597
|
-
if (r.status ===
|
|
598
|
+
if (r.status === "fulfilled") {
|
|
598
599
|
const rs = r.value;
|
|
599
600
|
// Emit any NoticeResponse messages attached to this result
|
|
600
601
|
// to stderr in the upstream libpq shape
|
|
@@ -622,8 +623,12 @@ export const cmdEndPipeline = {
|
|
|
622
623
|
// Skip our internal Sync marker (empty `command`, see
|
|
623
624
|
// wire/pipeline.ts) and DDL-style CommandComplete-only sets
|
|
624
625
|
// (non-empty `command` but no fields and no rows).
|
|
625
|
-
const isSyncOrPlaceholder = rs.fields.length === 0 &&
|
|
626
|
-
|
|
626
|
+
const isSyncOrPlaceholder = rs.fields.length === 0 &&
|
|
627
|
+
rs.command === "" &&
|
|
628
|
+
rs.rows.length === 0;
|
|
629
|
+
const isCommandOnly = rs.fields.length === 0 &&
|
|
630
|
+
rs.rows.length === 0 &&
|
|
631
|
+
rs.command !== "";
|
|
627
632
|
if (!isSyncOrPlaceholder && !isCommandOnly) {
|
|
628
633
|
if (rs.fields.length === 0 && rs.rows.length > 0) {
|
|
629
634
|
// 0-column tuples result: the aligned printer's
|
|
@@ -634,8 +639,8 @@ export const cmdEndPipeline = {
|
|
|
634
639
|
// `\watch`-rejected SELECT output byte-for-byte.
|
|
635
640
|
const tuplesOnly = ctx.settings.popt.topt.tuplesOnly;
|
|
636
641
|
if (!tuplesOnly) {
|
|
637
|
-
process.stdout.write(
|
|
638
|
-
process.stdout.write(`(${rs.rows.length} ${rs.rows.length === 1 ?
|
|
642
|
+
process.stdout.write("--\n");
|
|
643
|
+
process.stdout.write(`(${rs.rows.length} ${rs.rows.length === 1 ? "row" : "rows"})\n\n`);
|
|
639
644
|
}
|
|
640
645
|
}
|
|
641
646
|
else {
|
|
@@ -653,9 +658,10 @@ export const cmdEndPipeline = {
|
|
|
653
658
|
// `session.lastError` / `peekRealError` for the original
|
|
654
659
|
// ERROR.
|
|
655
660
|
const reason = r.reason;
|
|
656
|
-
const isAborted = typeof reason ===
|
|
661
|
+
const isAborted = typeof reason === "object" &&
|
|
657
662
|
reason !== null &&
|
|
658
|
-
reason
|
|
663
|
+
reason
|
|
664
|
+
.pipelineAborted === true;
|
|
659
665
|
// FETCH_COUNT-in-pipeline: upstream emits the chunked-mode
|
|
660
666
|
// diagnostic in addition to the per-op line. Both go to
|
|
661
667
|
// stderr; the chunked-mode line comes FIRST and addresses the
|
|
@@ -669,13 +675,13 @@ export const cmdEndPipeline = {
|
|
|
669
675
|
// aborted, command did not run" is shown ONLY for the synthetic
|
|
670
676
|
// queue-skip marker (no real error behind it).
|
|
671
677
|
if (fetchCountActive) {
|
|
672
|
-
writeErr(
|
|
678
|
+
writeErr("fetching results in chunked mode failed\n");
|
|
673
679
|
}
|
|
674
680
|
if (isAborted && realLastError !== null) {
|
|
675
681
|
renderPipelineError(realLastError);
|
|
676
682
|
}
|
|
677
683
|
else if (isAborted) {
|
|
678
|
-
writeErr(
|
|
684
|
+
writeErr("Pipeline aborted, command did not run\n");
|
|
679
685
|
}
|
|
680
686
|
else {
|
|
681
687
|
renderPipelineError(reason);
|
|
@@ -694,16 +700,16 @@ export const cmdEndPipeline = {
|
|
|
694
700
|
// FETCH_COUNT was active, but still render the actual ERROR rather
|
|
695
701
|
// than the synthetic "Pipeline aborted" line (review: minor).
|
|
696
702
|
if (fetchCountActive) {
|
|
697
|
-
writeErr(
|
|
703
|
+
writeErr("fetching results in chunked mode failed\n");
|
|
698
704
|
}
|
|
699
705
|
renderPipelineError(lastErr);
|
|
700
706
|
}
|
|
701
707
|
}
|
|
702
|
-
return { status:
|
|
708
|
+
return { status: "ok" };
|
|
703
709
|
}
|
|
704
710
|
catch (err) {
|
|
705
711
|
stashOf(ctx.settings)[PIPELINE_KEY] = undefined;
|
|
706
|
-
ctx.settings.sendMode =
|
|
712
|
+
ctx.settings.sendMode = "extended-query";
|
|
707
713
|
// Even on a failed `\endpipeline` (e.g. server hung up mid-drain),
|
|
708
714
|
// mirror upstream and clear the counters — the pipeline state is
|
|
709
715
|
// gone, so any non-zero value would be misleading. Same for the
|
|
@@ -718,12 +724,12 @@ export const cmdEndPipeline = {
|
|
|
718
724
|
// \syncpipeline / \flushrequest / \flush
|
|
719
725
|
// ---------------------------------------------------------------------------
|
|
720
726
|
export const cmdSyncPipeline = {
|
|
721
|
-
name:
|
|
722
|
-
helpKey:
|
|
727
|
+
name: "syncpipeline",
|
|
728
|
+
helpKey: "syncpipeline",
|
|
723
729
|
async run(ctx) {
|
|
724
730
|
const ps = getPipelineState(ctx.settings);
|
|
725
731
|
if (!ps)
|
|
726
|
-
return errResult(ctx,
|
|
732
|
+
return errResult(ctx, "no pipeline active");
|
|
727
733
|
try {
|
|
728
734
|
await ps.session.sync();
|
|
729
735
|
// Upstream `exec_command_syncpipeline`:
|
|
@@ -732,11 +738,11 @@ export const cmdSyncPipeline = {
|
|
|
732
738
|
// piped_syncs++;
|
|
733
739
|
// The pending commands have transitioned to "queued results" on the
|
|
734
740
|
// server, and Sync is itself counted as a piped command boundary.
|
|
735
|
-
const queued = readCounter(ctx.settings,
|
|
736
|
-
setCounter(ctx.settings,
|
|
737
|
-
bumpCounter(ctx.settings,
|
|
738
|
-
bumpCounter(ctx.settings,
|
|
739
|
-
return { status:
|
|
741
|
+
const queued = readCounter(ctx.settings, "PIPELINE_COMMAND_COUNT");
|
|
742
|
+
setCounter(ctx.settings, "PIPELINE_COMMAND_COUNT", 0);
|
|
743
|
+
bumpCounter(ctx.settings, "PIPELINE_RESULT_COUNT", queued);
|
|
744
|
+
bumpCounter(ctx.settings, "PIPELINE_SYNC_COUNT", 1);
|
|
745
|
+
return { status: "ok" };
|
|
740
746
|
}
|
|
741
747
|
catch (err) {
|
|
742
748
|
return errResult(ctx, errorToMessage(err));
|
|
@@ -744,22 +750,22 @@ export const cmdSyncPipeline = {
|
|
|
744
750
|
},
|
|
745
751
|
};
|
|
746
752
|
export const cmdFlushRequest = {
|
|
747
|
-
name:
|
|
748
|
-
helpKey:
|
|
753
|
+
name: "flushrequest",
|
|
754
|
+
helpKey: "flushrequest",
|
|
749
755
|
async run(ctx) {
|
|
750
756
|
const ps = getPipelineState(ctx.settings);
|
|
751
757
|
if (!ps)
|
|
752
|
-
return errResult(ctx,
|
|
758
|
+
return errResult(ctx, "no pipeline active");
|
|
753
759
|
try {
|
|
754
760
|
await ps.session.flush();
|
|
755
761
|
// Upstream `exec_command_flushrequest`:
|
|
756
762
|
// piped_results += piped_commands;
|
|
757
763
|
// piped_commands = 0;
|
|
758
764
|
// The pending commands move to "queued results" but SYNC isn't issued.
|
|
759
|
-
const queued = readCounter(ctx.settings,
|
|
760
|
-
setCounter(ctx.settings,
|
|
761
|
-
bumpCounter(ctx.settings,
|
|
762
|
-
return { status:
|
|
765
|
+
const queued = readCounter(ctx.settings, "PIPELINE_COMMAND_COUNT");
|
|
766
|
+
setCounter(ctx.settings, "PIPELINE_COMMAND_COUNT", 0);
|
|
767
|
+
bumpCounter(ctx.settings, "PIPELINE_RESULT_COUNT", queued);
|
|
768
|
+
return { status: "ok" };
|
|
763
769
|
}
|
|
764
770
|
catch (err) {
|
|
765
771
|
return errResult(ctx, errorToMessage(err));
|
|
@@ -767,8 +773,8 @@ export const cmdFlushRequest = {
|
|
|
767
773
|
},
|
|
768
774
|
};
|
|
769
775
|
export const cmdFlush = {
|
|
770
|
-
name:
|
|
771
|
-
helpKey:
|
|
776
|
+
name: "flush",
|
|
777
|
+
helpKey: "flush",
|
|
772
778
|
run(ctx) {
|
|
773
779
|
return cmdFlushRequest.run(ctx);
|
|
774
780
|
},
|
|
@@ -777,8 +783,8 @@ export const cmdFlush = {
|
|
|
777
783
|
// \sendpipeline — submit current buffer with stashed bind params.
|
|
778
784
|
// ---------------------------------------------------------------------------
|
|
779
785
|
export const cmdSendPipeline = {
|
|
780
|
-
name:
|
|
781
|
-
helpKey:
|
|
786
|
+
name: "sendpipeline",
|
|
787
|
+
helpKey: "sendpipeline",
|
|
782
788
|
async run(ctx) {
|
|
783
789
|
const ps = getPipelineState(ctx.settings);
|
|
784
790
|
if (!ps) {
|
|
@@ -794,10 +800,10 @@ export const cmdSendPipeline = {
|
|
|
794
800
|
// parameters from before the failed-outside-pipeline send.
|
|
795
801
|
consumeBindState(ctx.settings);
|
|
796
802
|
ctx.settings.lastErrorResult = {
|
|
797
|
-
message:
|
|
803
|
+
message: "\\sendpipeline not allowed outside of pipeline mode",
|
|
798
804
|
};
|
|
799
|
-
writeErr(
|
|
800
|
-
return { status:
|
|
805
|
+
writeErr("\\sendpipeline not allowed outside of pipeline mode\n");
|
|
806
|
+
return { status: "error", errorWritten: true };
|
|
801
807
|
}
|
|
802
808
|
const bind = consumeBindState(ctx.settings);
|
|
803
809
|
// Upstream `exec_command_sendpipeline` (in pipeline mode) requires
|
|
@@ -809,10 +815,10 @@ export const cmdSendPipeline = {
|
|
|
809
815
|
// same diagnostic, so order matters here.
|
|
810
816
|
if (bind === null) {
|
|
811
817
|
ctx.settings.lastErrorResult = {
|
|
812
|
-
message:
|
|
818
|
+
message: "\\sendpipeline must be used after \\bind or \\bind_named",
|
|
813
819
|
};
|
|
814
|
-
writeErr(
|
|
815
|
-
return { status:
|
|
820
|
+
writeErr("\\sendpipeline must be used after \\bind or \\bind_named\n");
|
|
821
|
+
return { status: "error", errorWritten: true };
|
|
816
822
|
}
|
|
817
823
|
const sql = ctx.queryBuf.trim();
|
|
818
824
|
const stmtName = bind.name;
|
|
@@ -822,7 +828,7 @@ export const cmdSendPipeline = {
|
|
|
822
828
|
// anonymous-`\bind` path still needs a buffer because we must
|
|
823
829
|
// Parse the SQL first.
|
|
824
830
|
if (!bind.byName && sql.length === 0) {
|
|
825
|
-
return errResult(ctx,
|
|
831
|
+
return errResult(ctx, "no query buffer");
|
|
826
832
|
}
|
|
827
833
|
try {
|
|
828
834
|
// We send the full P/B/E sequence without an intervening Sync — the
|
|
@@ -832,15 +838,15 @@ export const cmdSendPipeline = {
|
|
|
832
838
|
// an unnamed Parse so the SQL is parsed on the server in this
|
|
833
839
|
// batch.
|
|
834
840
|
if (!bind.byName) {
|
|
835
|
-
await ps.session.parse(
|
|
841
|
+
await ps.session.parse("", sql, []);
|
|
836
842
|
}
|
|
837
843
|
await ps.session.bind(stmtName, params);
|
|
838
844
|
const exec = (async () => {
|
|
839
|
-
await ps.session.execute(
|
|
845
|
+
await ps.session.execute("", 0);
|
|
840
846
|
// PipelineSession.execute resolves with void on the public API; the
|
|
841
847
|
// session internally tracks the ResultSet and surfaces it in end().
|
|
842
848
|
return {
|
|
843
|
-
command:
|
|
849
|
+
command: "",
|
|
844
850
|
rowCount: null,
|
|
845
851
|
oid: null,
|
|
846
852
|
fields: [],
|
|
@@ -849,7 +855,7 @@ export const cmdSendPipeline = {
|
|
|
849
855
|
};
|
|
850
856
|
})();
|
|
851
857
|
ps.pending.push(exec);
|
|
852
|
-
return { status:
|
|
858
|
+
return { status: "reset-buf", newBuf: "" };
|
|
853
859
|
}
|
|
854
860
|
catch (err) {
|
|
855
861
|
return errResult(ctx, errorToMessage(err));
|
|
@@ -860,11 +866,11 @@ export const cmdSendPipeline = {
|
|
|
860
866
|
// \getresults [N] — drain N pending results (or all if N omitted).
|
|
861
867
|
// ---------------------------------------------------------------------------
|
|
862
868
|
export const cmdGetResults = {
|
|
863
|
-
name:
|
|
864
|
-
helpKey:
|
|
869
|
+
name: "getresults",
|
|
870
|
+
helpKey: "getresults",
|
|
865
871
|
async run(ctx) {
|
|
866
872
|
const ps = getPipelineState(ctx.settings);
|
|
867
|
-
const arg = ctx.nextArg(
|
|
873
|
+
const arg = ctx.nextArg("normal");
|
|
868
874
|
// Upstream `exec_command_getresults` parses the optional count BEFORE
|
|
869
875
|
// checking pipeline state, so an invalid count surfaces even when
|
|
870
876
|
// there's no pipeline active. The wording matches upstream verbatim
|
|
@@ -873,7 +879,7 @@ export const cmdGetResults = {
|
|
|
873
879
|
if (arg !== null && arg.length > 0) {
|
|
874
880
|
const parsed = parseInt(arg, 10);
|
|
875
881
|
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
876
|
-
return errResult(ctx,
|
|
882
|
+
return errResult(ctx, "invalid number of requested results");
|
|
877
883
|
}
|
|
878
884
|
requested = parsed;
|
|
879
885
|
}
|
|
@@ -883,8 +889,8 @@ export const cmdGetResults = {
|
|
|
883
889
|
// outside of `\startpipeline / \endpipeline` brackets and right
|
|
884
890
|
// after `\endpipeline`.
|
|
885
891
|
if (!ps) {
|
|
886
|
-
process.stdout.write(
|
|
887
|
-
return { status:
|
|
892
|
+
process.stdout.write("No pending results to get\n");
|
|
893
|
+
return { status: "ok" };
|
|
888
894
|
}
|
|
889
895
|
// Available items to drain = PIPELINE_SYNC_COUNT + PIPELINE_RESULT_COUNT.
|
|
890
896
|
// Sync markers and data-result entries both occupy slots in libpq's
|
|
@@ -899,12 +905,12 @@ export const cmdGetResults = {
|
|
|
899
905
|
// prints nothing on the first \getresults 1 (SyncMarker drained,
|
|
900
906
|
// SYNC_COUNT: 2 → 1), the second prints nothing (SYNC_COUNT: 1 →
|
|
901
907
|
// 0), and the third prints the SELECT result.
|
|
902
|
-
const syncAvailable = readCounter(ctx.settings,
|
|
903
|
-
const resultAvailable = readCounter(ctx.settings,
|
|
908
|
+
const syncAvailable = readCounter(ctx.settings, "PIPELINE_SYNC_COUNT");
|
|
909
|
+
const resultAvailable = readCounter(ctx.settings, "PIPELINE_RESULT_COUNT");
|
|
904
910
|
const available = syncAvailable + resultAvailable;
|
|
905
911
|
if (available === 0) {
|
|
906
|
-
process.stdout.write(
|
|
907
|
-
return { status:
|
|
912
|
+
process.stdout.write("No pending results to get\n");
|
|
913
|
+
return { status: "ok" };
|
|
908
914
|
}
|
|
909
915
|
// `\getresults 0` and bare `\getresults` mean "all pending"
|
|
910
916
|
// (upstream semantics).
|
|
@@ -953,12 +959,13 @@ export const cmdGetResults = {
|
|
|
953
959
|
// one that should surface.
|
|
954
960
|
const sliceErr = (() => {
|
|
955
961
|
for (const r of settled) {
|
|
956
|
-
if (r.status !==
|
|
962
|
+
if (r.status !== "rejected")
|
|
957
963
|
continue;
|
|
958
964
|
const reason = r.reason;
|
|
959
|
-
const isAborted = typeof reason ===
|
|
965
|
+
const isAborted = typeof reason === "object" &&
|
|
960
966
|
reason !== null &&
|
|
961
|
-
reason
|
|
967
|
+
reason
|
|
968
|
+
.pipelineAborted === true;
|
|
962
969
|
if (!isAborted)
|
|
963
970
|
return reason;
|
|
964
971
|
}
|
|
@@ -966,7 +973,7 @@ export const cmdGetResults = {
|
|
|
966
973
|
})();
|
|
967
974
|
const sessPeek = session;
|
|
968
975
|
const realErr = sliceErr ??
|
|
969
|
-
(typeof sessPeek.peekRealError ===
|
|
976
|
+
(typeof sessPeek.peekRealError === "function"
|
|
970
977
|
? await sessPeek.peekRealError()
|
|
971
978
|
: null);
|
|
972
979
|
// Per upstream `\getresults`: emit AT MOST ONE error / aborted
|
|
@@ -986,7 +993,7 @@ export const cmdGetResults = {
|
|
|
986
993
|
// the remainder to RESULT_COUNT post-walk.
|
|
987
994
|
for (const r of settled) {
|
|
988
995
|
walkedItems++;
|
|
989
|
-
if (r.status !==
|
|
996
|
+
if (r.status !== "fulfilled") {
|
|
990
997
|
// Rejected promise — Parse / Bind / Execute / Close that the
|
|
991
998
|
// server responded to with ErrorResponse, or a cascaded
|
|
992
999
|
// pipelineAborted marker. Upstream `\getresults` walks
|
|
@@ -1000,10 +1007,10 @@ export const cmdGetResults = {
|
|
|
1000
1007
|
resultsDrained++;
|
|
1001
1008
|
if (!errorRenderedHere) {
|
|
1002
1009
|
const reason = r.reason;
|
|
1003
|
-
const isAborted = typeof reason ===
|
|
1010
|
+
const isAborted = typeof reason === "object" &&
|
|
1004
1011
|
reason !== null &&
|
|
1005
|
-
reason
|
|
1006
|
-
true;
|
|
1012
|
+
reason
|
|
1013
|
+
.pipelineAborted === true;
|
|
1007
1014
|
if (isAborted && realErr !== null) {
|
|
1008
1015
|
renderPipelineError(realErr);
|
|
1009
1016
|
}
|
|
@@ -1033,7 +1040,7 @@ export const cmdGetResults = {
|
|
|
1033
1040
|
// attribution is fixed up at the tail of this function based
|
|
1034
1041
|
// on `syncAvailable`.
|
|
1035
1042
|
if (rs.fields.length === 0 &&
|
|
1036
|
-
rs.command ===
|
|
1043
|
+
rs.command === "" &&
|
|
1037
1044
|
rs.rows.length === 0) {
|
|
1038
1045
|
syncsDrained++;
|
|
1039
1046
|
continue;
|
|
@@ -1044,8 +1051,8 @@ export const cmdGetResults = {
|
|
|
1044
1051
|
// `\endpipeline` (see comment there).
|
|
1045
1052
|
const tuplesOnly = ctx.settings.popt.topt.tuplesOnly;
|
|
1046
1053
|
if (!tuplesOnly) {
|
|
1047
|
-
process.stdout.write(
|
|
1048
|
-
process.stdout.write(`(${rs.rows.length} ${rs.rows.length === 1 ?
|
|
1054
|
+
process.stdout.write("--\n");
|
|
1055
|
+
process.stdout.write(`(${rs.rows.length} ${rs.rows.length === 1 ? "row" : "rows"})\n\n`);
|
|
1049
1056
|
}
|
|
1050
1057
|
}
|
|
1051
1058
|
else if (rs.fields.length > 0) {
|
|
@@ -1063,7 +1070,7 @@ export const cmdGetResults = {
|
|
|
1063
1070
|
// `_externalDrained` check, which is only consulted by `end()`
|
|
1064
1071
|
// to skip ALREADY-INSPECTED rejections).
|
|
1065
1072
|
const sessMark = session;
|
|
1066
|
-
if (typeof sessMark.markDrained ===
|
|
1073
|
+
if (typeof sessMark.markDrained === "function") {
|
|
1067
1074
|
sessMark.markDrained(end);
|
|
1068
1075
|
}
|
|
1069
1076
|
// Once we surface a rejection inline here, also clear any sticky
|
|
@@ -1071,7 +1078,7 @@ export const cmdGetResults = {
|
|
|
1071
1078
|
// `\endpipeline`'s fallback doesn't re-emit the same diagnostic.
|
|
1072
1079
|
if (errorRenderedHere) {
|
|
1073
1080
|
const sessAny = session;
|
|
1074
|
-
if (typeof sessAny.clearLastError ===
|
|
1081
|
+
if (typeof sessAny.clearLastError === "function") {
|
|
1075
1082
|
sessAny.clearLastError();
|
|
1076
1083
|
}
|
|
1077
1084
|
}
|
|
@@ -1104,9 +1111,9 @@ export const cmdGetResults = {
|
|
|
1104
1111
|
// `\getresults 1` x5 after 4 commands + 1 sync drains the 5th
|
|
1105
1112
|
// call silently against the SyncMarker; a 6th call would emit
|
|
1106
1113
|
// "No pending results to get".
|
|
1107
|
-
bumpCounter(ctx.settings,
|
|
1108
|
-
bumpCounter(ctx.settings,
|
|
1109
|
-
return { status:
|
|
1114
|
+
bumpCounter(ctx.settings, "PIPELINE_SYNC_COUNT", -syncsDrained);
|
|
1115
|
+
bumpCounter(ctx.settings, "PIPELINE_RESULT_COUNT", -resultsDrained);
|
|
1116
|
+
return { status: "ok" };
|
|
1110
1117
|
}
|
|
1111
1118
|
catch (err) {
|
|
1112
1119
|
return errResult(ctx, errorToMessage(err));
|
|
@@ -1122,7 +1129,7 @@ export const cmdGetResults = {
|
|
|
1122
1129
|
// module) continues to compile. Registration is left to `cmd_io.ts`'s
|
|
1123
1130
|
// `registerIoCommands` so we don't double-register.
|
|
1124
1131
|
// ---------------------------------------------------------------------------
|
|
1125
|
-
export { cmdGdesc } from
|
|
1132
|
+
export { cmdGdesc } from "./cmd_io.js";
|
|
1126
1133
|
// ---------------------------------------------------------------------------
|
|
1127
1134
|
// Registration entry point.
|
|
1128
1135
|
// ---------------------------------------------------------------------------
|