@rex0220/kintone-sql-tools 2.3.0 → 2.5.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 +47 -46
- package/dist-cli/ksql.js +433 -102
- package/dist-mcp/ksql-mcp.js +424 -105
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -599,13 +599,14 @@ var Parser = class {
|
|
|
599
599
|
const upper = tok.value.toUpperCase();
|
|
600
600
|
if (upper === "CREATE") return this.parseCreateTempTable();
|
|
601
601
|
if (upper === "DROP") return this.parseDropTempTable();
|
|
602
|
+
if (upper === "DECLARE") return this.parseDeclareVariable();
|
|
602
603
|
break;
|
|
603
604
|
}
|
|
604
605
|
default:
|
|
605
606
|
break;
|
|
606
607
|
}
|
|
607
608
|
throw new ParseError(
|
|
608
|
-
"SELECT / INSERT / UPDATE / DELETE / REORDER / WITH / SHOW / DESCRIBE / EXPLAIN / CREATE TEMP TABLE / DROP TEMP TABLE / SET / ASSERT \u306E\u3044\u305A\u308C\u304B\u3067\u59CB\u307E\u308B SQL \u6587\u304C\u5FC5\u8981\u3067\u3059",
|
|
609
|
+
"SELECT / INSERT / UPDATE / DELETE / REORDER / WITH / SHOW / DESCRIBE / EXPLAIN / CREATE TEMP TABLE / DROP TEMP TABLE / SET / DECLARE / ASSERT \u306E\u3044\u305A\u308C\u304B\u3067\u59CB\u307E\u308B SQL \u6587\u304C\u5FC5\u8981\u3067\u3059",
|
|
609
610
|
tok
|
|
610
611
|
);
|
|
611
612
|
}
|
|
@@ -616,19 +617,32 @@ var Parser = class {
|
|
|
616
617
|
this.expect("SET" /* SET */);
|
|
617
618
|
const variable = this.expect("VARIABLE" /* VARIABLE */, "SET \u306E\u5F8C\u306B\u306F\u5909\u6570\u540D\uFF08\u4F8B: @name\uFF09\u304C\u5FC5\u8981\u3067\u3059");
|
|
618
619
|
this.expect("=" /* EQ */);
|
|
619
|
-
const expr = this.parseScalarExpr();
|
|
620
|
+
const expr = this.parseScalarExpr("SET", true);
|
|
620
621
|
return { type: "SET_VARIABLE", name: variable.value.slice(1).toLowerCase(), expr };
|
|
621
622
|
}
|
|
622
|
-
|
|
623
|
-
|
|
623
|
+
parseDeclareVariable() {
|
|
624
|
+
this.advance();
|
|
625
|
+
const variable = this.expect("VARIABLE" /* VARIABLE */, "DECLARE \u306E\u5F8C\u306B\u306F\u5909\u6570\u540D\uFF08\u4F8B: @name\uFF09\u304C\u5FC5\u8981\u3067\u3059");
|
|
626
|
+
this.expect("=" /* EQ */);
|
|
627
|
+
const expr = this.parseScalarExpr("DECLARE", false);
|
|
628
|
+
if (expr.type === "SCALAR_SUBQUERY") {
|
|
629
|
+
throw new ParseError("DECLARE \u306E\u65E2\u5B9A\u5024\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
630
|
+
}
|
|
631
|
+
return { type: "DECLARE_VARIABLE", name: variable.value.slice(1).toLowerCase(), default: expr };
|
|
632
|
+
}
|
|
633
|
+
/** SET / DECLARE RHS 専用。既存式パーサーで構文を読み、フィールド参照を明示的に拒否する。 */
|
|
634
|
+
parseScalarExpr(context, allowScalarSubquery) {
|
|
624
635
|
const tok = this.peek();
|
|
625
636
|
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
626
|
-
throw new ParseError(
|
|
637
|
+
throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F\u4ED6\u306E\u5909\u6570\u3092\u53C2\u7167\u3067\u304D\u307E\u305B\u3093`, tok);
|
|
627
638
|
}
|
|
628
639
|
if (tok.kind === "NULL" /* NULL */) {
|
|
629
|
-
throw new ParseError(
|
|
640
|
+
throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067 NULL \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`, tok);
|
|
630
641
|
}
|
|
631
642
|
if (tok.kind === "(" /* LPAREN */ && this.peekAt(1).kind === "SELECT" /* SELECT */) {
|
|
643
|
+
if (!allowScalarSubquery) {
|
|
644
|
+
throw new ParseError("DECLARE \u306E\u65E2\u5B9A\u5024\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
|
|
645
|
+
}
|
|
632
646
|
this.advance();
|
|
633
647
|
const query = this.parseSelect();
|
|
634
648
|
this.expect(")" /* RPAREN */);
|
|
@@ -652,7 +666,7 @@ var Parser = class {
|
|
|
652
666
|
}
|
|
653
667
|
if (tok.kind === "LOGINUSER" /* LOGINUSER */) {
|
|
654
668
|
throw new ParseError(
|
|
655
|
-
|
|
669
|
+
`${context} \u306E\u53F3\u8FBA\u3067 LOGINUSER() \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\uFF08\u5B9F\u884C\u74B0\u5883\u5171\u901A\u306E\u30ED\u30B0\u30A4\u30F3\u30E6\u30FC\u30B6\u30FC\u89E3\u6C7A\u306F\u672A\u5BFE\u5FDC\u3067\u3059\uFF09`,
|
|
656
670
|
tok
|
|
657
671
|
);
|
|
658
672
|
}
|
|
@@ -660,22 +674,22 @@ var Parser = class {
|
|
|
660
674
|
return this.parseSqlValue();
|
|
661
675
|
}
|
|
662
676
|
const expr = this.parseArithAddSub();
|
|
663
|
-
this.rejectNonScalarExpr(expr, tok);
|
|
677
|
+
this.rejectNonScalarExpr(expr, tok, context);
|
|
664
678
|
if (expr.type === "NUMBER" || expr.type === "STRING_FUNC" || expr.type === "ARITH") return expr;
|
|
665
|
-
throw new ParseError(
|
|
679
|
+
throw new ParseError(`${context} \u306E\u53F3\u8FBA\u306B\u306F\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u3092\u542B\u307E\u306A\u3044\u30B9\u30AB\u30E9\u30FC\u5F0F\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044`, tok);
|
|
666
680
|
}
|
|
667
|
-
rejectNonScalarExpr(node, tok) {
|
|
681
|
+
rejectNonScalarExpr(node, tok, context) {
|
|
668
682
|
if (node.type === "STRING" || node.type === "NUMBER") return;
|
|
669
683
|
if (node.type === "FIELD_REF" || node.type === "AGG_REF") {
|
|
670
|
-
throw new ParseError(
|
|
684
|
+
throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u30FB\u96C6\u8A08\u95A2\u6570\u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`, tok);
|
|
671
685
|
}
|
|
672
686
|
if (node.type === "ARITH" || node.type === "AGG_ARITH") {
|
|
673
|
-
this.rejectNonScalarExpr(node.left, tok);
|
|
674
|
-
this.rejectNonScalarExpr(node.right, tok);
|
|
687
|
+
this.rejectNonScalarExpr(node.left, tok, context);
|
|
688
|
+
this.rejectNonScalarExpr(node.right, tok, context);
|
|
675
689
|
return;
|
|
676
690
|
}
|
|
677
691
|
if (node.type === "STRING_FUNC") {
|
|
678
|
-
for (const arg of node.args) this.rejectNonScalarExpr(arg, tok);
|
|
692
|
+
for (const arg of node.args) this.rejectNonScalarExpr(arg, tok, context);
|
|
679
693
|
}
|
|
680
694
|
}
|
|
681
695
|
// ----------------------------------------------------------
|
|
@@ -2301,7 +2315,7 @@ function isDmlType(type) {
|
|
|
2301
2315
|
return type === "INSERT" || type === "INSERT_SELECT" || type === "UPDATE" || type === "DELETE" || type === "UPSERT" || type === "UPSERT_SELECT" || type === "REORDER";
|
|
2302
2316
|
}
|
|
2303
2317
|
function isReadOnlyType(type) {
|
|
2304
|
-
return type === "SELECT" || type === "UNION" || type === "WITH" || type === "EXPLAIN" || type === "SHOW_APPS" || type === "DESCRIBE" || type === "CREATE_TEMP_TABLE" || type === "DROP_TEMP_TABLE" || type === "SET_VARIABLE" || type === "ASSERT";
|
|
2318
|
+
return type === "SELECT" || type === "UNION" || type === "WITH" || type === "EXPLAIN" || type === "SHOW_APPS" || type === "DESCRIBE" || type === "CREATE_TEMP_TABLE" || type === "DROP_TEMP_TABLE" || type === "SET_VARIABLE" || type === "DECLARE_VARIABLE" || type === "ASSERT";
|
|
2305
2319
|
}
|
|
2306
2320
|
function hasWhereClause(stmt) {
|
|
2307
2321
|
if (!stmt || typeof stmt !== "object") return false;
|
|
@@ -2375,8 +2389,9 @@ function analyzeBatch(statements) {
|
|
|
2375
2389
|
}
|
|
2376
2390
|
if (statements.length === 1) {
|
|
2377
2391
|
const t = statements[0].type;
|
|
2378
|
-
if (t === "SET_VARIABLE") {
|
|
2379
|
-
|
|
2392
|
+
if (t === "SET_VARIABLE" || t === "DECLARE_VARIABLE") {
|
|
2393
|
+
const verb = t === "SET_VARIABLE" ? "SET" : "DECLARE";
|
|
2394
|
+
throw new BatchAnalysisError(`ArgumentError: ${verb} variable requires a batch.`, 0);
|
|
2380
2395
|
}
|
|
2381
2396
|
if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
|
|
2382
2397
|
const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
|
|
@@ -2410,7 +2425,7 @@ function analyzeBatch(statements) {
|
|
|
2410
2425
|
}
|
|
2411
2426
|
def.referencedBy.push(index);
|
|
2412
2427
|
}
|
|
2413
|
-
if (stmt.type === "SET_VARIABLE") {
|
|
2428
|
+
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
2414
2429
|
if (variableDefs.has(stmt.name)) {
|
|
2415
2430
|
throw new BatchAnalysisError(`ParseError: variable @${stmt.name} is already defined.`, index);
|
|
2416
2431
|
}
|
|
@@ -2507,6 +2522,40 @@ function analyzeBatch(statements) {
|
|
|
2507
2522
|
};
|
|
2508
2523
|
}
|
|
2509
2524
|
|
|
2525
|
+
// src/core/batchVariables.ts
|
|
2526
|
+
var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
2527
|
+
function normalizeBatchVariableName(name) {
|
|
2528
|
+
if (!VARIABLE_NAME_RE.test(name)) {
|
|
2529
|
+
throw new Error(
|
|
2530
|
+
`ArgumentError: invalid variable name "${name}". Use a name without @ matching [A-Za-z_][A-Za-z0-9_]{0,63}.`
|
|
2531
|
+
);
|
|
2532
|
+
}
|
|
2533
|
+
return name.toLowerCase();
|
|
2534
|
+
}
|
|
2535
|
+
function normalizeBatchVariables(input) {
|
|
2536
|
+
const normalized = /* @__PURE__ */ Object.create(null);
|
|
2537
|
+
for (const [rawName, value] of Object.entries(input ?? {})) {
|
|
2538
|
+
const name = normalizeBatchVariableName(rawName);
|
|
2539
|
+
if (Object.prototype.hasOwnProperty.call(normalized, name)) {
|
|
2540
|
+
throw new Error(`ArgumentError: variable "${rawName}" is specified more than once.`);
|
|
2541
|
+
}
|
|
2542
|
+
normalized[name] = value;
|
|
2543
|
+
}
|
|
2544
|
+
return normalized;
|
|
2545
|
+
}
|
|
2546
|
+
function validateDeclaredBatchVariables(statements, input) {
|
|
2547
|
+
const normalized = normalizeBatchVariables(input);
|
|
2548
|
+
const declared = new Set(
|
|
2549
|
+
statements.filter((stmt) => stmt.type === "DECLARE_VARIABLE").map((stmt) => stmt.name)
|
|
2550
|
+
);
|
|
2551
|
+
for (const name of Object.keys(normalized)) {
|
|
2552
|
+
if (!declared.has(name)) {
|
|
2553
|
+
throw new Error(`ArgumentError: injected variable @${name} is not declared.`);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
return normalized;
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2510
2559
|
// src/core/scalarCompare.ts
|
|
2511
2560
|
function compareScalarValues(op, leftStr, rightStr) {
|
|
2512
2561
|
if (op === "=") return leftStr === rightStr;
|
|
@@ -3459,52 +3508,91 @@ function resolveFieldRef(row, field) {
|
|
|
3459
3508
|
}
|
|
3460
3509
|
|
|
3461
3510
|
// src/engine/evalWhere.ts
|
|
3462
|
-
function evalWhere(expr, row) {
|
|
3511
|
+
function evalWhere(expr, row, resolveFieldType) {
|
|
3463
3512
|
switch (expr.type) {
|
|
3464
3513
|
case "BINARY":
|
|
3465
|
-
return evalBinary(expr, row);
|
|
3514
|
+
return evalBinary(expr, row, resolveFieldType);
|
|
3466
3515
|
case "NULL_CHECK":
|
|
3467
3516
|
return evalNullCheck(expr, row);
|
|
3468
3517
|
case "LOGICAL":
|
|
3469
|
-
return evalLogical(expr, row);
|
|
3518
|
+
return evalLogical(expr, row, resolveFieldType);
|
|
3470
3519
|
case "NOT":
|
|
3471
|
-
return !evalWhere(expr.expr, row);
|
|
3520
|
+
return !evalWhere(expr.expr, row, resolveFieldType);
|
|
3472
3521
|
case "GROUP":
|
|
3473
|
-
return evalWhere(expr.expr, row);
|
|
3522
|
+
return evalWhere(expr.expr, row, resolveFieldType);
|
|
3474
3523
|
case "EXISTS": {
|
|
3475
3524
|
const exists = expr.resolved;
|
|
3476
3525
|
return expr.not ? !exists : exists;
|
|
3477
3526
|
}
|
|
3478
3527
|
}
|
|
3479
3528
|
}
|
|
3480
|
-
function evalBinary(expr, row) {
|
|
3481
|
-
const left = resolveField(expr.left, row);
|
|
3482
|
-
|
|
3529
|
+
function evalBinary(expr, row, resolveFieldType) {
|
|
3530
|
+
const left = resolveField(expr.left, row, resolveFieldType);
|
|
3531
|
+
const fieldType = expr.left.type === "FIELD" ? resolveFieldType?.(expr.left) : void 0;
|
|
3532
|
+
return evalOp(expr.op, left, expr.right, row, fieldType, resolveFieldType);
|
|
3483
3533
|
}
|
|
3484
|
-
function evalOp(op, leftStr, right, row) {
|
|
3534
|
+
function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
|
|
3485
3535
|
if (op === "IN" || op === "NOT_IN") {
|
|
3536
|
+
let values = null;
|
|
3486
3537
|
if (right.type === "IN_LIST") {
|
|
3487
3538
|
assertResolvedInListValues2(right.values);
|
|
3488
|
-
|
|
3489
|
-
return op === "IN" ? contains : !contains;
|
|
3539
|
+
values = new Set(right.values.map((v) => String(v.value)));
|
|
3490
3540
|
}
|
|
3491
3541
|
if (right.type === "SUBQUERY_IN_LIST") {
|
|
3492
|
-
|
|
3493
|
-
return op === "IN" ? contains : !contains;
|
|
3542
|
+
values = right.resolved;
|
|
3494
3543
|
}
|
|
3495
|
-
return op === "NOT_IN";
|
|
3544
|
+
if (values === null) return op === "NOT_IN";
|
|
3545
|
+
const contains = typedInContains(leftStr, values, fieldType);
|
|
3546
|
+
return op === "IN" ? contains : !contains;
|
|
3496
3547
|
}
|
|
3497
3548
|
if (op === "LIKE") {
|
|
3498
|
-
const pattern = resolveValue(right, row);
|
|
3549
|
+
const pattern = resolveValue(right, row, resolveFieldType);
|
|
3499
3550
|
return matchLike(leftStr, pattern);
|
|
3500
3551
|
}
|
|
3501
3552
|
if (op === "NOT_LIKE") {
|
|
3502
|
-
const pattern = resolveValue(right, row);
|
|
3553
|
+
const pattern = resolveValue(right, row, resolveFieldType);
|
|
3503
3554
|
return !matchLike(leftStr, pattern);
|
|
3504
3555
|
}
|
|
3505
|
-
const rightStr = resolveValue(right, row);
|
|
3556
|
+
const rightStr = resolveValue(right, row, resolveFieldType);
|
|
3506
3557
|
return compareScalarValues(op, leftStr, rightStr);
|
|
3507
3558
|
}
|
|
3559
|
+
var STRING_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
|
|
3560
|
+
var OBJECT_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
3561
|
+
"USER_SELECT",
|
|
3562
|
+
"ORGANIZATION_SELECT",
|
|
3563
|
+
"GROUP_SELECT",
|
|
3564
|
+
"STATUS_ASSIGNEE"
|
|
3565
|
+
]);
|
|
3566
|
+
var SINGLE_OBJECT_FIELD_TYPES = /* @__PURE__ */ new Set(["CREATOR", "MODIFIER"]);
|
|
3567
|
+
function typedInContains(leftStr, values, fieldType) {
|
|
3568
|
+
const fallback = () => values.has(leftStr);
|
|
3569
|
+
if (fieldType === void 0) return fallback();
|
|
3570
|
+
let parsed;
|
|
3571
|
+
if (STRING_ARRAY_FIELD_TYPES.has(fieldType) || OBJECT_ARRAY_FIELD_TYPES.has(fieldType) || SINGLE_OBJECT_FIELD_TYPES.has(fieldType)) {
|
|
3572
|
+
try {
|
|
3573
|
+
parsed = JSON.parse(leftStr);
|
|
3574
|
+
} catch {
|
|
3575
|
+
return fallback();
|
|
3576
|
+
}
|
|
3577
|
+
} else {
|
|
3578
|
+
return fallback();
|
|
3579
|
+
}
|
|
3580
|
+
if (STRING_ARRAY_FIELD_TYPES.has(fieldType)) {
|
|
3581
|
+
if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === "string")) {
|
|
3582
|
+
return fallback();
|
|
3583
|
+
}
|
|
3584
|
+
return parsed.some((item) => values.has(item));
|
|
3585
|
+
}
|
|
3586
|
+
if (OBJECT_ARRAY_FIELD_TYPES.has(fieldType)) {
|
|
3587
|
+
if (!Array.isArray(parsed) || !parsed.every(hasStringCode)) return fallback();
|
|
3588
|
+
return parsed.some((item) => values.has(item.code));
|
|
3589
|
+
}
|
|
3590
|
+
if (!hasStringCode(parsed)) return fallback();
|
|
3591
|
+
return values.has(parsed.code);
|
|
3592
|
+
}
|
|
3593
|
+
function hasStringCode(value) {
|
|
3594
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.code === "string";
|
|
3595
|
+
}
|
|
3508
3596
|
function assertResolvedInListValues2(values) {
|
|
3509
3597
|
const unresolved = values.find((item) => item.type === "VARIABLE");
|
|
3510
3598
|
if (unresolved?.type === "VARIABLE") {
|
|
@@ -3515,20 +3603,20 @@ function evalNullCheck(expr, row) {
|
|
|
3515
3603
|
const val = resolveField(expr.field, row);
|
|
3516
3604
|
return expr.not ? val !== "" : val === "";
|
|
3517
3605
|
}
|
|
3518
|
-
function evalLogical(expr, row) {
|
|
3606
|
+
function evalLogical(expr, row, resolveFieldType) {
|
|
3519
3607
|
if (expr.op === "AND") {
|
|
3520
|
-
return evalWhere(expr.left, row) && evalWhere(expr.right, row);
|
|
3608
|
+
return evalWhere(expr.left, row, resolveFieldType) && evalWhere(expr.right, row, resolveFieldType);
|
|
3521
3609
|
}
|
|
3522
|
-
return evalWhere(expr.left, row) || evalWhere(expr.right, row);
|
|
3610
|
+
return evalWhere(expr.left, row, resolveFieldType) || evalWhere(expr.right, row, resolveFieldType);
|
|
3523
3611
|
}
|
|
3524
|
-
function resolveField(field, row) {
|
|
3612
|
+
function resolveField(field, row, resolveFieldType) {
|
|
3525
3613
|
if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
|
|
3526
3614
|
if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
|
|
3527
|
-
if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row);
|
|
3615
|
+
if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType);
|
|
3528
3616
|
const key = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
|
|
3529
3617
|
return resolveFieldRef(row, key);
|
|
3530
3618
|
}
|
|
3531
|
-
function resolveValue(value, row) {
|
|
3619
|
+
function resolveValue(value, row, resolveFieldType) {
|
|
3532
3620
|
switch (value.type) {
|
|
3533
3621
|
case "VARIABLE":
|
|
3534
3622
|
throw new Error(`ParseError: unresolved batch variable @${value.name}.`);
|
|
@@ -3551,14 +3639,14 @@ function resolveValue(value, row) {
|
|
|
3551
3639
|
if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
|
|
3552
3640
|
return String(evalArithExpr(value.expr, row));
|
|
3553
3641
|
case "CASE_VALUE":
|
|
3554
|
-
return evalCaseWhen(value.expr, row);
|
|
3642
|
+
return evalCaseWhen(value.expr, row, resolveFieldType);
|
|
3555
3643
|
case "ARRAY":
|
|
3556
3644
|
return value.elements.map((e) => e.value).join(",");
|
|
3557
3645
|
}
|
|
3558
3646
|
}
|
|
3559
|
-
function evalCaseWhen(expr, row) {
|
|
3647
|
+
function evalCaseWhen(expr, row, resolveFieldType) {
|
|
3560
3648
|
for (const branch of expr.branches) {
|
|
3561
|
-
if (evalWhere(branch.condition, row)) {
|
|
3649
|
+
if (evalWhere(branch.condition, row, resolveFieldType)) {
|
|
3562
3650
|
return evalCaseResult(branch.result, row);
|
|
3563
3651
|
}
|
|
3564
3652
|
}
|
|
@@ -4225,9 +4313,9 @@ function applyJoin(leftRows, rightRows, join2) {
|
|
|
4225
4313
|
}
|
|
4226
4314
|
return result;
|
|
4227
4315
|
}
|
|
4228
|
-
function applyFilter(rows, where) {
|
|
4316
|
+
function applyFilter(rows, where, resolveFieldType) {
|
|
4229
4317
|
if (where === null) return rows;
|
|
4230
|
-
return rows.filter((row) => evalWhere(where, row));
|
|
4318
|
+
return rows.filter((row) => evalWhere(where, row, resolveFieldType));
|
|
4231
4319
|
}
|
|
4232
4320
|
function hasAggregateColumns(columns) {
|
|
4233
4321
|
return columns.some(
|
|
@@ -4353,9 +4441,9 @@ function aggregateSyntheticName2(func, distinct, arg) {
|
|
|
4353
4441
|
const argStr = aggregateArgLabel(arg);
|
|
4354
4442
|
return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
|
|
4355
4443
|
}
|
|
4356
|
-
function applyHaving(rows, having) {
|
|
4444
|
+
function applyHaving(rows, having, resolveFieldType) {
|
|
4357
4445
|
if (having === null) return rows;
|
|
4358
|
-
return rows.filter((row) => evalWhere(having, row));
|
|
4446
|
+
return rows.filter((row) => evalWhere(having, row, resolveFieldType));
|
|
4359
4447
|
}
|
|
4360
4448
|
function applyDistinct(rows, columns) {
|
|
4361
4449
|
if (rows.length === 0) return rows;
|
|
@@ -4480,7 +4568,7 @@ function applyLimit(rows, limit, offset) {
|
|
|
4480
4568
|
if (limit === null) return rows.slice(start);
|
|
4481
4569
|
return rows.slice(start, start + limit);
|
|
4482
4570
|
}
|
|
4483
|
-
function project(rows, columns, scalarCache) {
|
|
4571
|
+
function project(rows, columns, scalarCache, resolveFieldType) {
|
|
4484
4572
|
if (columns.length === 1 && columns[0].type === "WILDCARD") {
|
|
4485
4573
|
const projected2 = rows.map((row) => stripParentShortcutColumns(row));
|
|
4486
4574
|
const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [];
|
|
@@ -4541,7 +4629,7 @@ function project(rows, columns, scalarCache) {
|
|
|
4541
4629
|
}
|
|
4542
4630
|
case "CASE_COL": {
|
|
4543
4631
|
const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
|
|
4544
|
-
out[key] = evalCaseWhen(col.expr, row);
|
|
4632
|
+
out[key] = evalCaseWhen(col.expr, row, resolveFieldType);
|
|
4545
4633
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
4546
4634
|
break;
|
|
4547
4635
|
}
|
|
@@ -4677,7 +4765,15 @@ function resolveAggInStringFuncExpr(expr, rows) {
|
|
|
4677
4765
|
};
|
|
4678
4766
|
}
|
|
4679
4767
|
function runFullScan(input) {
|
|
4680
|
-
const {
|
|
4768
|
+
const {
|
|
4769
|
+
stmt,
|
|
4770
|
+
tables,
|
|
4771
|
+
scalarCache,
|
|
4772
|
+
optionOrders,
|
|
4773
|
+
sortKinds,
|
|
4774
|
+
fieldTypeResolver,
|
|
4775
|
+
havingFieldTypeResolver
|
|
4776
|
+
} = input;
|
|
4681
4777
|
let rows = [];
|
|
4682
4778
|
const mainAlias = stmt.from.alias;
|
|
4683
4779
|
const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
|
|
@@ -4688,17 +4784,17 @@ function runFullScan(input) {
|
|
|
4688
4784
|
const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
|
|
4689
4785
|
rows = applyJoin(rows, rightRows, join2);
|
|
4690
4786
|
}
|
|
4691
|
-
rows = applyFilter(rows, stmt.where);
|
|
4787
|
+
rows = applyFilter(rows, stmt.where, fieldTypeResolver);
|
|
4692
4788
|
if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
|
|
4693
4789
|
rows = applyGroupBy(rows, stmt.groupBy, stmt.columns);
|
|
4694
4790
|
}
|
|
4695
|
-
rows = applyHaving(rows, stmt.having);
|
|
4791
|
+
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
|
|
4696
4792
|
if (stmt.distinct) {
|
|
4697
4793
|
rows = applyDistinct(rows, stmt.columns);
|
|
4698
4794
|
}
|
|
4699
4795
|
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
|
|
4700
4796
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
4701
|
-
return project(rows, stmt.columns, scalarCache);
|
|
4797
|
+
return project(rows, stmt.columns, scalarCache, fieldTypeResolver);
|
|
4702
4798
|
}
|
|
4703
4799
|
|
|
4704
4800
|
// src/converter/subtableAdapter.ts
|
|
@@ -4838,6 +4934,8 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
4838
4934
|
throw new Error("ArgumentError: DROP TEMP TABLE requires a batch (temp tables are batch-scoped).");
|
|
4839
4935
|
case "SET_VARIABLE":
|
|
4840
4936
|
throw new Error("ArgumentError: SET variable requires a batch.");
|
|
4937
|
+
case "DECLARE_VARIABLE":
|
|
4938
|
+
throw new Error("ArgumentError: DECLARE variable requires a batch.");
|
|
4841
4939
|
case "ASSERT":
|
|
4842
4940
|
return executeAssert(stmt, client, options, cacheContext);
|
|
4843
4941
|
}
|
|
@@ -4851,6 +4949,8 @@ var BatchTimeoutError = class extends Error {
|
|
|
4851
4949
|
async function executeBatch(sql, client, options = {}) {
|
|
4852
4950
|
const statements = parseSqlBatch(sql);
|
|
4853
4951
|
const analysis = analyzeBatch(statements);
|
|
4952
|
+
const injectedVariables = validateDeclaredBatchVariables(statements, options.variables);
|
|
4953
|
+
const batchOptions = { ...options, variables: injectedVariables };
|
|
4854
4954
|
if (options.continueOnError && analysis.containsDml) {
|
|
4855
4955
|
throw new Error("ArgumentError: continueOnError is not allowed for batches containing DML.");
|
|
4856
4956
|
}
|
|
@@ -4895,16 +4995,16 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
4895
4995
|
}
|
|
4896
4996
|
try {
|
|
4897
4997
|
const remaining = deadline !== null ? deadline - Date.now() : null;
|
|
4898
|
-
const userConfirm =
|
|
4998
|
+
const userConfirm = batchOptions.confirm;
|
|
4899
4999
|
const stmtOptions = userConfirm ? {
|
|
4900
|
-
...
|
|
5000
|
+
...batchOptions,
|
|
4901
5001
|
confirm: (count, operation) => userConfirm(count, operation, {
|
|
4902
5002
|
statementIndex: i,
|
|
4903
5003
|
statementCount: statements.length,
|
|
4904
5004
|
statementType: info.statementType,
|
|
4905
5005
|
targetAppId: info.targetAppId
|
|
4906
5006
|
})
|
|
4907
|
-
} :
|
|
5007
|
+
} : batchOptions;
|
|
4908
5008
|
const outcome = await runWithDeadline(
|
|
4909
5009
|
executeBatchStatement(statements[i], info, countedClient, stmtOptions, cacheContext, tempTables, variables),
|
|
4910
5010
|
remaining
|
|
@@ -4917,7 +5017,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
4917
5017
|
aborted = "timeout";
|
|
4918
5018
|
} else if (e instanceof AssertError) {
|
|
4919
5019
|
aborted = "assertion";
|
|
4920
|
-
} else if (info.statementType === "SET_VARIABLE") {
|
|
5020
|
+
} else if (info.statementType === "SET_VARIABLE" || info.statementType === "DECLARE_VARIABLE") {
|
|
4921
5021
|
aborted = "fail-fast";
|
|
4922
5022
|
} else if (!options.continueOnError) {
|
|
4923
5023
|
aborted = "fail-fast";
|
|
@@ -4957,6 +5057,16 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
4957
5057
|
}
|
|
4958
5058
|
return {};
|
|
4959
5059
|
}
|
|
5060
|
+
if (stmt.type === "DECLARE_VARIABLE") {
|
|
5061
|
+
const injected = options.variables ?? {};
|
|
5062
|
+
if (Object.prototype.hasOwnProperty.call(injected, stmt.name)) {
|
|
5063
|
+
variables.set(stmt.name, { type: "string", value: injected[stmt.name] });
|
|
5064
|
+
} else {
|
|
5065
|
+
const value = evaluateScalarExpr(stmt.default);
|
|
5066
|
+
variables.set(stmt.name, { type: "string", value: String(value.value) });
|
|
5067
|
+
}
|
|
5068
|
+
return {};
|
|
5069
|
+
}
|
|
4960
5070
|
const resolvedStmt = resolveVariableRefs(stmt, variables);
|
|
4961
5071
|
if (resolvedStmt.type === "CREATE_TEMP_TABLE") {
|
|
4962
5072
|
const materializeOptions = {
|
|
@@ -5217,6 +5327,7 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache) {
|
|
|
5217
5327
|
if (isNoFromSelect(stmt)) {
|
|
5218
5328
|
return executeNoFromSelect(stmt);
|
|
5219
5329
|
}
|
|
5330
|
+
await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
|
|
5220
5331
|
const mode = resolveSelectMode(stmt);
|
|
5221
5332
|
await validateSelectFieldCodes(stmt, mode, client, cacheContext);
|
|
5222
5333
|
if (mode === "SIMPLE") {
|
|
@@ -5275,6 +5386,8 @@ function executeNoFromSelect(stmt) {
|
|
|
5275
5386
|
}
|
|
5276
5387
|
async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
5277
5388
|
const params = selectToKintoneParams(stmt);
|
|
5389
|
+
const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
|
|
5390
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
5278
5391
|
const maxRecords = options.maxRecords ?? 1e4;
|
|
5279
5392
|
const warnings = /* @__PURE__ */ new Set();
|
|
5280
5393
|
const onLimit = options.onLimitReached ?? "error";
|
|
@@ -5311,7 +5424,12 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
|
5311
5424
|
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
|
|
5312
5425
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
5313
5426
|
}
|
|
5314
|
-
const { rows: projected, columns } = project(
|
|
5427
|
+
const { rows: projected, columns } = project(
|
|
5428
|
+
rows,
|
|
5429
|
+
stmt.columns,
|
|
5430
|
+
void 0,
|
|
5431
|
+
fieldTypeResolvers.row
|
|
5432
|
+
);
|
|
5315
5433
|
return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
|
|
5316
5434
|
}
|
|
5317
5435
|
async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
@@ -5384,6 +5502,108 @@ async function loadNumericPushdownFieldTypes(stmt, client, cacheContext) {
|
|
|
5384
5502
|
const entries = await Promise.all([...appIds].map(async (appId) => [appId, await getFieldTypeMap(appId, client, cacheContext)]));
|
|
5385
5503
|
return new Map(entries);
|
|
5386
5504
|
}
|
|
5505
|
+
function collectTypedInFieldRefs(expr, out) {
|
|
5506
|
+
if (expr === null) return;
|
|
5507
|
+
switch (expr.type) {
|
|
5508
|
+
case "BINARY":
|
|
5509
|
+
if ((expr.op === "IN" || expr.op === "NOT_IN") && expr.left.type === "FIELD") {
|
|
5510
|
+
out.push(expr.left);
|
|
5511
|
+
}
|
|
5512
|
+
if (expr.left.type === "CASE_FIELD") collectCaseTypedInFieldRefs(expr.left.expr, out);
|
|
5513
|
+
if (expr.right.type === "CASE_VALUE") collectCaseTypedInFieldRefs(expr.right.expr, out);
|
|
5514
|
+
return;
|
|
5515
|
+
case "LOGICAL":
|
|
5516
|
+
collectTypedInFieldRefs(expr.left, out);
|
|
5517
|
+
collectTypedInFieldRefs(expr.right, out);
|
|
5518
|
+
return;
|
|
5519
|
+
case "NOT":
|
|
5520
|
+
case "GROUP":
|
|
5521
|
+
collectTypedInFieldRefs(expr.expr, out);
|
|
5522
|
+
return;
|
|
5523
|
+
case "NULL_CHECK":
|
|
5524
|
+
case "EXISTS":
|
|
5525
|
+
return;
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5528
|
+
function collectCaseTypedInFieldRefs(expr, out) {
|
|
5529
|
+
for (const branch of expr.branches) collectTypedInFieldRefs(branch.condition, out);
|
|
5530
|
+
}
|
|
5531
|
+
function collectSelectTypedInFieldRefs(stmt) {
|
|
5532
|
+
const refs = [];
|
|
5533
|
+
collectTypedInFieldRefs(stmt.where, refs);
|
|
5534
|
+
collectTypedInFieldRefs(stmt.having, refs);
|
|
5535
|
+
for (const column of stmt.columns) {
|
|
5536
|
+
if (column.type === "CASE_COL") collectCaseTypedInFieldRefs(column.expr, refs);
|
|
5537
|
+
}
|
|
5538
|
+
return refs;
|
|
5539
|
+
}
|
|
5540
|
+
function findTableForAlias(stmt, alias) {
|
|
5541
|
+
return [stmt.from, ...stmt.joins.map((join2) => join2.table)].find((table) => table.alias === alias);
|
|
5542
|
+
}
|
|
5543
|
+
function physicalSelectTables(stmt) {
|
|
5544
|
+
return [stmt.from, ...stmt.joins.map((join2) => join2.table)].filter((table) => table.cteName === null);
|
|
5545
|
+
}
|
|
5546
|
+
async function loadTypedInFieldTypes(stmt, client, cacheContext) {
|
|
5547
|
+
const refs = collectSelectTypedInFieldRefs(stmt);
|
|
5548
|
+
if (refs.length === 0) return /* @__PURE__ */ new Map();
|
|
5549
|
+
const appIds = /* @__PURE__ */ new Set();
|
|
5550
|
+
const physicalTables = physicalSelectTables(stmt);
|
|
5551
|
+
for (const ref of refs) {
|
|
5552
|
+
if (ref.tableAlias !== null) {
|
|
5553
|
+
if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
5554
|
+
appIds.add(stmt.from.appId);
|
|
5555
|
+
continue;
|
|
5556
|
+
}
|
|
5557
|
+
const table = findTableForAlias(stmt, ref.tableAlias);
|
|
5558
|
+
if (table && table.cteName === null) appIds.add(table.appId);
|
|
5559
|
+
continue;
|
|
5560
|
+
}
|
|
5561
|
+
if (stmt.joins.length === 0) {
|
|
5562
|
+
if (stmt.from.cteName === null) appIds.add(stmt.from.appId);
|
|
5563
|
+
continue;
|
|
5564
|
+
}
|
|
5565
|
+
for (const table of physicalTables) appIds.add(table.appId);
|
|
5566
|
+
}
|
|
5567
|
+
const entries = await Promise.all([...appIds].map(async (appId) => [appId, await getFieldTypeMap(appId, client, cacheContext)]));
|
|
5568
|
+
return new Map(entries);
|
|
5569
|
+
}
|
|
5570
|
+
function fieldCodeForTypeLookup(table, field) {
|
|
5571
|
+
if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
|
|
5572
|
+
return field;
|
|
5573
|
+
}
|
|
5574
|
+
function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
|
|
5575
|
+
const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
5576
|
+
const physicalTables = tables.filter((table) => table.cteName === null);
|
|
5577
|
+
const outputAliases = new Set(
|
|
5578
|
+
stmt.columns.map((column) => "alias" in column ? column.alias : null).filter((alias) => alias !== null)
|
|
5579
|
+
);
|
|
5580
|
+
const row = (field) => {
|
|
5581
|
+
if (field.tableAlias !== null) {
|
|
5582
|
+
if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
5583
|
+
return fieldTypesByApp.get(stmt.from.appId)?.get(field.field);
|
|
5584
|
+
}
|
|
5585
|
+
const table2 = tables.find((candidate) => candidate.alias === field.tableAlias);
|
|
5586
|
+
if (!table2 || table2.cteName !== null) return void 0;
|
|
5587
|
+
return fieldTypesByApp.get(table2.appId)?.get(fieldCodeForTypeLookup(table2, field.field));
|
|
5588
|
+
}
|
|
5589
|
+
if (stmt.joins.length === 0) {
|
|
5590
|
+
if (stmt.from.cteName !== null) return void 0;
|
|
5591
|
+
return fieldTypesByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, field.field));
|
|
5592
|
+
}
|
|
5593
|
+
if (tables.some((table2) => table2.cteName !== null)) return void 0;
|
|
5594
|
+
const matches = physicalTables.filter(
|
|
5595
|
+
(table2) => fieldTypesByApp.get(table2.appId)?.has(fieldCodeForTypeLookup(table2, field.field))
|
|
5596
|
+
);
|
|
5597
|
+
if (matches.length !== 1) return void 0;
|
|
5598
|
+
const table = matches[0];
|
|
5599
|
+
return fieldTypesByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field.field));
|
|
5600
|
+
};
|
|
5601
|
+
const having = (field) => {
|
|
5602
|
+
if (field.tableAlias === null && outputAliases.has(field.field)) return void 0;
|
|
5603
|
+
return row(field);
|
|
5604
|
+
};
|
|
5605
|
+
return { row, having };
|
|
5606
|
+
}
|
|
5387
5607
|
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
|
|
5388
5608
|
const maxRecords = options.maxRecords ?? 1e4;
|
|
5389
5609
|
const warnings = /* @__PURE__ */ new Set();
|
|
@@ -5392,7 +5612,11 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
5392
5612
|
resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
|
|
5393
5613
|
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
|
|
5394
5614
|
]);
|
|
5395
|
-
const pushdownFieldTypes = await
|
|
5615
|
+
const [pushdownFieldTypes, typedInFieldTypes] = await Promise.all([
|
|
5616
|
+
loadNumericPushdownFieldTypes(stmt, client, cacheContext),
|
|
5617
|
+
loadTypedInFieldTypes(stmt, client, cacheContext)
|
|
5618
|
+
]);
|
|
5619
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
5396
5620
|
const mainPushDown = extractMainSafePushdown(
|
|
5397
5621
|
stmt,
|
|
5398
5622
|
pushdownFieldTypes.get(stmt.from.appId)
|
|
@@ -5481,7 +5705,15 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
5481
5705
|
}));
|
|
5482
5706
|
const scalarCache = await scalarCachePromise;
|
|
5483
5707
|
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
5484
|
-
const { rows, columns } = runFullScan({
|
|
5708
|
+
const { rows, columns } = runFullScan({
|
|
5709
|
+
tables,
|
|
5710
|
+
stmt,
|
|
5711
|
+
scalarCache,
|
|
5712
|
+
optionOrders,
|
|
5713
|
+
sortKinds,
|
|
5714
|
+
fieldTypeResolver: fieldTypeResolvers.row,
|
|
5715
|
+
havingFieldTypeResolver: fieldTypeResolvers.having
|
|
5716
|
+
});
|
|
5485
5717
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
5486
5718
|
}
|
|
5487
5719
|
async function executeUnion(stmt, client, options, cacheContext) {
|
|
@@ -5637,8 +5869,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
5637
5869
|
const parallel = options.fetchParallel ?? 1;
|
|
5638
5870
|
await Promise.all([
|
|
5639
5871
|
resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
|
|
5640
|
-
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
|
|
5872
|
+
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache),
|
|
5873
|
+
resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache)
|
|
5641
5874
|
]);
|
|
5875
|
+
const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
|
|
5876
|
+
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
5642
5877
|
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
5643
5878
|
const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
|
|
5644
5879
|
scalarCachePromise.catch(() => {
|
|
@@ -5693,7 +5928,15 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
5693
5928
|
await Promise.all(joinFetches);
|
|
5694
5929
|
const scalarCache = await scalarCachePromise;
|
|
5695
5930
|
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
5696
|
-
const { rows, columns } = runFullScan({
|
|
5931
|
+
const { rows, columns } = runFullScan({
|
|
5932
|
+
tables,
|
|
5933
|
+
stmt,
|
|
5934
|
+
scalarCache,
|
|
5935
|
+
optionOrders,
|
|
5936
|
+
sortKinds,
|
|
5937
|
+
fieldTypeResolver: fieldTypeResolvers.row,
|
|
5938
|
+
havingFieldTypeResolver: fieldTypeResolvers.having
|
|
5939
|
+
});
|
|
5697
5940
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
5698
5941
|
}
|
|
5699
5942
|
function processRowToKintoneRecord(row) {
|
|
@@ -6190,6 +6433,16 @@ async function executeUpsert(stmt, client, options, cacheContext) {
|
|
|
6190
6433
|
updatedCount: toUpdate.length
|
|
6191
6434
|
};
|
|
6192
6435
|
}
|
|
6436
|
+
async function buildSubtableFieldTypeResolver(appId, typedInRefs, client, cacheContext) {
|
|
6437
|
+
if (typedInRefs.length === 0) return void 0;
|
|
6438
|
+
const fieldTypes = await getFieldTypeMap(appId, client, cacheContext);
|
|
6439
|
+
return (field) => {
|
|
6440
|
+
if (field.tableAlias !== null && field.tableAlias !== "_p") return void 0;
|
|
6441
|
+
if (field.tableAlias === "_p") return fieldTypes.get(field.field);
|
|
6442
|
+
const code = field.field.startsWith("_p.") ? field.field.slice(3) : field.field;
|
|
6443
|
+
return fieldTypes.get(code);
|
|
6444
|
+
};
|
|
6445
|
+
}
|
|
6193
6446
|
async function executeInsertSubtable(stmt, client, options, _cacheContext) {
|
|
6194
6447
|
const subtableCode = stmt.subtableCode;
|
|
6195
6448
|
const pidIndex = stmt.fields.indexOf("_pid");
|
|
@@ -6230,11 +6483,24 @@ async function executeInsertSubtable(stmt, client, options, _cacheContext) {
|
|
|
6230
6483
|
}
|
|
6231
6484
|
return { type: "INSERT", createdIds: [], insertedCount: stmt.values.length };
|
|
6232
6485
|
}
|
|
6233
|
-
async function executeUpdateSubtable(stmt, client, options,
|
|
6486
|
+
async function executeUpdateSubtable(stmt, client, options, cacheContext) {
|
|
6234
6487
|
const subtableCode = stmt.subtableCode;
|
|
6235
6488
|
if (!hasRidCondition(stmt.where)) {
|
|
6236
6489
|
throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
|
|
6237
6490
|
}
|
|
6491
|
+
const typedInRefs = [];
|
|
6492
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
6493
|
+
for (const assignment of stmt.assignments) {
|
|
6494
|
+
if (assignment.value.type === "CASE_VALUE") {
|
|
6495
|
+
collectCaseTypedInFieldRefs(assignment.value.expr, typedInRefs);
|
|
6496
|
+
}
|
|
6497
|
+
}
|
|
6498
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
6499
|
+
stmt.appId,
|
|
6500
|
+
typedInRefs,
|
|
6501
|
+
client,
|
|
6502
|
+
cacheContext
|
|
6503
|
+
);
|
|
6238
6504
|
const parents = await fetchAll(
|
|
6239
6505
|
client.getRecords,
|
|
6240
6506
|
stmt.appId,
|
|
@@ -6243,7 +6509,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
6243
6509
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
6244
6510
|
);
|
|
6245
6511
|
const expanded = expandRowsForSubtableDml(parents, subtableCode);
|
|
6246
|
-
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
|
|
6512
|
+
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
|
|
6247
6513
|
if (options.confirm) {
|
|
6248
6514
|
const ok = await options.confirm(targets.length, "UPDATE");
|
|
6249
6515
|
if (!ok) throw new OperationCancelledError("UPDATE", targets.length);
|
|
@@ -6263,7 +6529,7 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
6263
6529
|
if (a.field.startsWith("_")) {
|
|
6264
6530
|
throw new Error(`\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u3067\u30B7\u30B9\u30C6\u30E0\u5217\u300C${a.field}\u300D\u306F\u66F4\u65B0\u3067\u304D\u307E\u305B\u3093`);
|
|
6265
6531
|
}
|
|
6266
|
-
updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat) };
|
|
6532
|
+
updates[a.field] = { value: evalAssignmentValueForSubtable(a.value, t.flat, resolveFieldType) };
|
|
6267
6533
|
}
|
|
6268
6534
|
byRid.set(t.rowId, updates);
|
|
6269
6535
|
}
|
|
@@ -6285,11 +6551,19 @@ async function executeUpdateSubtable(stmt, client, options, _cacheContext) {
|
|
|
6285
6551
|
}
|
|
6286
6552
|
return { type: "UPDATE", updatedCount: targets.length };
|
|
6287
6553
|
}
|
|
6288
|
-
async function executeDeleteSubtable(stmt, client, options,
|
|
6554
|
+
async function executeDeleteSubtable(stmt, client, options, cacheContext) {
|
|
6289
6555
|
const subtableCode = stmt.subtableCode;
|
|
6290
6556
|
if (!hasRidCondition(stmt.where)) {
|
|
6291
6557
|
throw new Error("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB DELETE \u306B\u306F _rid \u6761\u4EF6\u304C\u5FC5\u9808\u3067\u3059");
|
|
6292
6558
|
}
|
|
6559
|
+
const typedInRefs = [];
|
|
6560
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
6561
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
6562
|
+
stmt.appId,
|
|
6563
|
+
typedInRefs,
|
|
6564
|
+
client,
|
|
6565
|
+
cacheContext
|
|
6566
|
+
);
|
|
6293
6567
|
const parents = await fetchAll(
|
|
6294
6568
|
client.getRecords,
|
|
6295
6569
|
stmt.appId,
|
|
@@ -6298,7 +6572,7 @@ async function executeDeleteSubtable(stmt, client, options, _cacheContext) {
|
|
|
6298
6572
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
6299
6573
|
);
|
|
6300
6574
|
const expanded = expandRowsForSubtableDml(parents, subtableCode);
|
|
6301
|
-
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat));
|
|
6575
|
+
const targets = expanded.filter((r) => evalWhere(stmt.where, r.flat, resolveFieldType));
|
|
6302
6576
|
if (options.confirm) {
|
|
6303
6577
|
const ok = await options.confirm(targets.length, "DELETE");
|
|
6304
6578
|
if (!ok) throw new OperationCancelledError("DELETE", targets.length);
|
|
@@ -6413,11 +6687,11 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
|
|
|
6413
6687
|
]
|
|
6414
6688
|
};
|
|
6415
6689
|
}
|
|
6416
|
-
function evalAssignmentValueForSubtable(value, row) {
|
|
6690
|
+
function evalAssignmentValueForSubtable(value, row, resolveFieldType) {
|
|
6417
6691
|
if (value.type === "STRING") return value.value;
|
|
6418
6692
|
if (value.type === "NUMBER") return String(value.value);
|
|
6419
6693
|
if (value.type === "ARITH") return String(evalArithExpr(value, row));
|
|
6420
|
-
if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row);
|
|
6694
|
+
if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row, resolveFieldType);
|
|
6421
6695
|
throw new Error(`${value.type} \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306E\u5024\u3068\u3057\u3066\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);
|
|
6422
6696
|
}
|
|
6423
6697
|
function valueToString(value) {
|
|
@@ -6449,7 +6723,15 @@ function hasRidCondition(where) {
|
|
|
6449
6723
|
return false;
|
|
6450
6724
|
}
|
|
6451
6725
|
}
|
|
6452
|
-
async function executeReorder(stmt, client, options,
|
|
6726
|
+
async function executeReorder(stmt, client, options, cacheContext) {
|
|
6727
|
+
const typedInRefs = [];
|
|
6728
|
+
collectTypedInFieldRefs(stmt.where, typedInRefs);
|
|
6729
|
+
const resolveFieldType = await buildSubtableFieldTypeResolver(
|
|
6730
|
+
stmt.appId,
|
|
6731
|
+
typedInRefs,
|
|
6732
|
+
client,
|
|
6733
|
+
cacheContext
|
|
6734
|
+
);
|
|
6453
6735
|
const parents = await fetchAll(
|
|
6454
6736
|
client.getRecords,
|
|
6455
6737
|
stmt.appId,
|
|
@@ -6458,7 +6740,7 @@ async function executeReorder(stmt, client, options, _cacheContext) {
|
|
|
6458
6740
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
6459
6741
|
);
|
|
6460
6742
|
const expanded = expandRowsForSubtableDml(parents, stmt.subtableCode);
|
|
6461
|
-
const targetParentIds = stmt.all ? new Set(parents.map((p) => String(p["$id"]?.value ?? "")).filter((id) => id !== "")) : new Set(expanded.filter((r) => stmt.where && evalWhere(stmt.where, r.flat)).map((r) => r.parentId));
|
|
6743
|
+
const targetParentIds = stmt.all ? new Set(parents.map((p) => String(p["$id"]?.value ?? "")).filter((id) => id !== "")) : new Set(expanded.filter((r) => stmt.where && evalWhere(stmt.where, r.flat, resolveFieldType)).map((r) => r.parentId));
|
|
6462
6744
|
if (options.confirm) {
|
|
6463
6745
|
const ok = await options.confirm(targetParentIds.size, "UPDATE");
|
|
6464
6746
|
if (!ok) throw new OperationCancelledError("UPDATE", targetParentIds.size);
|
|
@@ -6603,6 +6885,16 @@ async function resolveSubqueries(where, client, options, cacheContext, cteCache)
|
|
|
6603
6885
|
collectSubqueryTasks(where, client, options, cacheContext, tasks, cteCache);
|
|
6604
6886
|
await Promise.all(tasks);
|
|
6605
6887
|
}
|
|
6888
|
+
async function resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache) {
|
|
6889
|
+
const tasks = [];
|
|
6890
|
+
for (const column of stmt.columns) {
|
|
6891
|
+
if (column.type !== "CASE_COL") continue;
|
|
6892
|
+
for (const branch of column.expr.branches) {
|
|
6893
|
+
tasks.push(resolveSubqueries(branch.condition, client, options, cacheContext, cteCache));
|
|
6894
|
+
}
|
|
6895
|
+
}
|
|
6896
|
+
await Promise.all(tasks);
|
|
6897
|
+
}
|
|
6606
6898
|
function runSubquery(query, client, options, cacheContext, cteCache) {
|
|
6607
6899
|
if (cteCache !== void 0 && cteCache.size > 0) {
|
|
6608
6900
|
return executeQueryWithCte(query, client, options, cteCache, cacheContext);
|
|
@@ -6682,9 +6974,10 @@ async function resolveScalarColumns(columns, client, options, cacheContext, cteC
|
|
|
6682
6974
|
pending.forEach(([i], idx) => cache.set(i, values[idx]));
|
|
6683
6975
|
return cache;
|
|
6684
6976
|
}
|
|
6685
|
-
function buildBatchExplainPlans(sql) {
|
|
6977
|
+
function buildBatchExplainPlans(sql, injectedVariables) {
|
|
6686
6978
|
const statements = parseSqlBatch(sql);
|
|
6687
6979
|
const analysis = analyzeBatch(statements);
|
|
6980
|
+
validateDeclaredBatchVariables(statements, injectedVariables);
|
|
6688
6981
|
const variables = /* @__PURE__ */ new Map();
|
|
6689
6982
|
return {
|
|
6690
6983
|
statementCount: statements.length,
|
|
@@ -6695,7 +6988,7 @@ function buildBatchExplainPlans(sql) {
|
|
|
6695
6988
|
type: analysis.statements[i].statementType,
|
|
6696
6989
|
plan: buildBatchStatementPlan(planStmt, analysis.statements[i])
|
|
6697
6990
|
};
|
|
6698
|
-
if (stmt.type === "SET_VARIABLE") {
|
|
6991
|
+
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
6699
6992
|
variables.set(stmt.name, { type: "string", value: `@${stmt.name}` });
|
|
6700
6993
|
}
|
|
6701
6994
|
return result;
|
|
@@ -6732,6 +7025,12 @@ function buildBatchStatementPlan(stmt, info) {
|
|
|
6732
7025
|
" value: \u5B9F\u884C\u6642\u306B1\u56DE\u8A55\u4FA1\uFF08\u30D0\u30C3\u30C1\u5185\u5B9A\u6570\u30FB\u7D50\u679C\u30E1\u30BF\u30C7\u30FC\u30BF\u306B\u306F\u975E\u516C\u958B\uFF09"
|
|
6733
7026
|
];
|
|
6734
7027
|
}
|
|
7028
|
+
if (stmt.type === "DECLARE_VARIABLE") {
|
|
7029
|
+
return [
|
|
7030
|
+
`DECLARE @${stmt.name} = <default scalar expression>`,
|
|
7031
|
+
" value: \u5916\u90E8\u6CE8\u5165\u304C\u3042\u308C\u3070\u63A1\u7528\u3001\u306A\u3051\u308C\u3070\u65E2\u5B9A\u5024\u3092\u5B9F\u884C\u6642\u306B1\u56DE\u8A55\u4FA1\uFF08\u5024\u306F\u975E\u516C\u958B\uFF09"
|
|
7032
|
+
];
|
|
7033
|
+
}
|
|
6735
7034
|
if (stmt.type === "SHOW_APPS") return ["SHOW APPS\uFF08\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\uFF09"];
|
|
6736
7035
|
if (stmt.type === "DESCRIBE") return [`DESCRIBE APP${stmt.appId}\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\uFF09`];
|
|
6737
7036
|
if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info);
|
|
@@ -7525,6 +7824,42 @@ function clampInt(v, min, max) {
|
|
|
7525
7824
|
return Math.max(min, Math.min(max, Math.trunc(v)));
|
|
7526
7825
|
}
|
|
7527
7826
|
|
|
7827
|
+
// src/core/formFieldInfo.ts
|
|
7828
|
+
function flattenFormFieldProperties(properties) {
|
|
7829
|
+
const out = [];
|
|
7830
|
+
for (const field of Object.values(properties)) {
|
|
7831
|
+
out.push({
|
|
7832
|
+
code: field.code,
|
|
7833
|
+
label: field.label,
|
|
7834
|
+
fieldType: field.type,
|
|
7835
|
+
optionOrder: toOptionOrderMap(field.options),
|
|
7836
|
+
sortKind: detectSortKind(field.type, field.format)
|
|
7837
|
+
});
|
|
7838
|
+
if (field.fields) out.push(...flattenFormFieldProperties(field.fields));
|
|
7839
|
+
}
|
|
7840
|
+
return out;
|
|
7841
|
+
}
|
|
7842
|
+
function toOptionOrderMap(options) {
|
|
7843
|
+
if (!options || typeof options !== "object") return void 0;
|
|
7844
|
+
const order = {};
|
|
7845
|
+
let hasAny = false;
|
|
7846
|
+
for (const [label, meta] of Object.entries(options)) {
|
|
7847
|
+
const n = Number(meta?.index);
|
|
7848
|
+
if (!Number.isFinite(n)) continue;
|
|
7849
|
+
order[label] = n;
|
|
7850
|
+
hasAny = true;
|
|
7851
|
+
}
|
|
7852
|
+
return hasAny ? order : void 0;
|
|
7853
|
+
}
|
|
7854
|
+
function detectSortKind(fieldType, calcFormat) {
|
|
7855
|
+
if (fieldType === "NUMBER" || fieldType === "RECORD_NUMBER") return "number";
|
|
7856
|
+
if (fieldType === "CALC") {
|
|
7857
|
+
if (calcFormat === "NUMBER" || calcFormat === "NUMBER_DIGIT") return "number";
|
|
7858
|
+
return "string";
|
|
7859
|
+
}
|
|
7860
|
+
return void 0;
|
|
7861
|
+
}
|
|
7862
|
+
|
|
7528
7863
|
// src/cli/nodeKintoneClient.ts
|
|
7529
7864
|
function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
7530
7865
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
@@ -7703,36 +8038,10 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
7703
8038
|
{ method: "GET" },
|
|
7704
8039
|
appId
|
|
7705
8040
|
);
|
|
7706
|
-
return
|
|
7707
|
-
code: f.code,
|
|
7708
|
-
label: f.label,
|
|
7709
|
-
fieldType: f.type,
|
|
7710
|
-
optionOrder: toOptionOrderMap(f.options),
|
|
7711
|
-
sortKind: detectSortKind(f.type, f.format)
|
|
7712
|
-
}));
|
|
8041
|
+
return flattenFormFieldProperties(res.properties);
|
|
7713
8042
|
}
|
|
7714
8043
|
};
|
|
7715
8044
|
}
|
|
7716
|
-
function toOptionOrderMap(options) {
|
|
7717
|
-
if (!options || typeof options !== "object") return void 0;
|
|
7718
|
-
const order = {};
|
|
7719
|
-
let hasAny = false;
|
|
7720
|
-
for (const [label, meta] of Object.entries(options)) {
|
|
7721
|
-
const n = Number(meta?.index);
|
|
7722
|
-
if (!Number.isFinite(n)) continue;
|
|
7723
|
-
order[label] = n;
|
|
7724
|
-
hasAny = true;
|
|
7725
|
-
}
|
|
7726
|
-
return hasAny ? order : void 0;
|
|
7727
|
-
}
|
|
7728
|
-
function detectSortKind(fieldType, calcFormat) {
|
|
7729
|
-
if (fieldType === "NUMBER" || fieldType === "RECORD_NUMBER") return "number";
|
|
7730
|
-
if (fieldType === "CALC") {
|
|
7731
|
-
if (calcFormat === "NUMBER" || calcFormat === "NUMBER_DIGIT") return "number";
|
|
7732
|
-
return "string";
|
|
7733
|
-
}
|
|
7734
|
-
return void 0;
|
|
7735
|
-
}
|
|
7736
8045
|
|
|
7737
8046
|
// src/node/appProfiles.ts
|
|
7738
8047
|
var import_fs = require("fs");
|
|
@@ -8193,6 +8502,7 @@ Options:
|
|
|
8193
8502
|
-f, --file <path> Execute SQL file
|
|
8194
8503
|
--console Start interactive console mode
|
|
8195
8504
|
--dry-run Parse and show execution plan only
|
|
8505
|
+
--var <name=value> Override a DECLARE variable (repeatable; not for secrets)
|
|
8196
8506
|
--format <type> Output format: table | json | jsonl | csv | markdown | md
|
|
8197
8507
|
(batch + json: prints one JSON envelope for the whole batch)
|
|
8198
8508
|
--max-records <n> Max records to fetch (default: 500)
|
|
@@ -8262,6 +8572,8 @@ function parseArgs(argv) {
|
|
|
8262
8572
|
password: null,
|
|
8263
8573
|
token: null,
|
|
8264
8574
|
tokenMap: {},
|
|
8575
|
+
// `__proto__` も有効な変数名なので prototype のない辞書で保持する。
|
|
8576
|
+
variables: /* @__PURE__ */ Object.create(null),
|
|
8265
8577
|
tokenFile: null,
|
|
8266
8578
|
app: null,
|
|
8267
8579
|
diagRecordId: null,
|
|
@@ -8356,6 +8668,19 @@ function parseArgs(argv) {
|
|
|
8356
8668
|
continue;
|
|
8357
8669
|
}
|
|
8358
8670
|
const v = argv[i + 1];
|
|
8671
|
+
if (a === "--var") {
|
|
8672
|
+
const raw = v ?? "";
|
|
8673
|
+
const eq = raw.indexOf("=");
|
|
8674
|
+
if (eq < 0) throw new Error("ArgumentError: --var must use name=value.");
|
|
8675
|
+
const rawName = raw.slice(0, eq);
|
|
8676
|
+
const name = normalizeBatchVariableName(rawName);
|
|
8677
|
+
if (Object.prototype.hasOwnProperty.call(out.variables, name)) {
|
|
8678
|
+
throw new Error(`ArgumentError: variable "${rawName}" is specified more than once.`);
|
|
8679
|
+
}
|
|
8680
|
+
out.variables[name] = raw.slice(eq + 1);
|
|
8681
|
+
i++;
|
|
8682
|
+
continue;
|
|
8683
|
+
}
|
|
8359
8684
|
if (a === "-e" || a === "--execute") {
|
|
8360
8685
|
out.executeSql = v ?? "";
|
|
8361
8686
|
i++;
|
|
@@ -8912,6 +9237,7 @@ function buildReplExecArgv(base, sql, dryRun, format) {
|
|
|
8912
9237
|
const argv = ["-e", sql];
|
|
8913
9238
|
if (dryRun) argv.push("--dry-run");
|
|
8914
9239
|
if (format) argv.push("--format", format);
|
|
9240
|
+
for (const [name, value] of Object.entries(base.variables)) argv.push("--var", `${name}=${value}`);
|
|
8915
9241
|
pushOpt(argv, "--config", base.configPath);
|
|
8916
9242
|
pushOpt(argv, "--profile", base.profile);
|
|
8917
9243
|
pushOpt(argv, "--base-url", base.baseUrl);
|
|
@@ -9535,6 +9861,10 @@ async function run() {
|
|
|
9535
9861
|
attachmentFormat: args.attachmentFormat ?? profile.output?.attachmentFormat ?? "full"
|
|
9536
9862
|
};
|
|
9537
9863
|
const appIds = sql ? extractAppIds(sql) : [];
|
|
9864
|
+
if (!isBatchSql && Object.keys(args.variables).length > 0) {
|
|
9865
|
+
process.stderr.write("ArgumentError: --var requires a batch containing DECLARE.\n");
|
|
9866
|
+
return 2;
|
|
9867
|
+
}
|
|
9538
9868
|
const defaultApp = args.app ?? envInt2("KSQL_APP") ?? profile.app ?? null;
|
|
9539
9869
|
if (appIds.length === 0 && defaultApp !== null) appIds.push(defaultApp);
|
|
9540
9870
|
const allowNoFromSelect = isNoFromSelectStatement(parsedStmt) || stmtType === "SHOW_APPS";
|
|
@@ -9550,7 +9880,7 @@ async function run() {
|
|
|
9550
9880
|
if (args.dryRun) {
|
|
9551
9881
|
let plans;
|
|
9552
9882
|
try {
|
|
9553
|
-
plans = buildBatchExplainPlans(sql);
|
|
9883
|
+
plans = buildBatchExplainPlans(sql, args.variables);
|
|
9554
9884
|
} catch (err) {
|
|
9555
9885
|
const restored = sourceSql && sqlDiagnosticContext ? restoreSqlContextError(err, sourceSql, {
|
|
9556
9886
|
bindings: sqlDiagnosticContext.appBindingByMappedApp,
|
|
@@ -9867,6 +10197,7 @@ query=${label}`);
|
|
|
9867
10197
|
continueOnError: args.continueOnError,
|
|
9868
10198
|
tempTableMaxRows,
|
|
9869
10199
|
timeoutMs: timeout,
|
|
10200
|
+
variables: args.variables,
|
|
9870
10201
|
confirm: batchContainsDml ? async (count, operation) => {
|
|
9871
10202
|
if (count > dmlMaxRows) {
|
|
9872
10203
|
throw new Error(`ArgumentError: ${operation} affected rows (${count}) exceed --dml-max-rows (${dmlMaxRows}).`);
|