@rex0220/kintone-sql-tools 3.29.0 → 3.31.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/dist-cli/ksql.js +558 -163
- package/dist-engine/errors.d.ts +3 -0
- package/dist-engine/index.cjs +10 -9
- package/dist-engine/index.d.ts +1 -1
- package/dist-engine/index.mjs +11 -10
- package/dist-engine/ksql-engine.umd.js +10 -9
- package/dist-engine/meta/bundle-baseline.json +10 -10
- package/dist-engine/meta/cjs.json +129 -111
- package/dist-engine/meta/esm.json +129 -111
- package/dist-engine/meta/umd.json +129 -111
- package/dist-engine/publicTypes.d.ts +25 -0
- package/dist-engine/query.d.ts +1 -2
- package/dist-mcp/ksql-mcp.js +565 -168
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -670,6 +670,9 @@ function quote(value) {
|
|
|
670
670
|
return `'${value.replace(/'/g, "''")}'`;
|
|
671
671
|
}
|
|
672
672
|
function arithLabel(node, topLevel = false) {
|
|
673
|
+
if (node.type === "VARIABLE") throw new Error(
|
|
674
|
+
`InternalError: unresolved arithmetic variable @${node.name} reached aggregate expression labeling.`
|
|
675
|
+
);
|
|
673
676
|
if (node.type === "FIELD_REF") return node.field;
|
|
674
677
|
if (node.type === "NUMBER") return numberLiteralText(node);
|
|
675
678
|
if (node.type === "STRING_FUNC") return stringFuncLabel(node);
|
|
@@ -1054,6 +1057,7 @@ var Parser = class {
|
|
|
1054
1057
|
this.cteNames = /* @__PURE__ */ new Set();
|
|
1055
1058
|
/** パース中に出現した一時テーブル参照(#name)のトークン。単文 API での拒否に使う */
|
|
1056
1059
|
this.tempTableRefs = [];
|
|
1060
|
+
this.allowSelectArithVariable = false;
|
|
1057
1061
|
}
|
|
1058
1062
|
// ----------------------------------------------------------
|
|
1059
1063
|
// 公開 API
|
|
@@ -1893,6 +1897,15 @@ var Parser = class {
|
|
|
1893
1897
|
} while (this.consume("," /* COMMA */));
|
|
1894
1898
|
return cols;
|
|
1895
1899
|
}
|
|
1900
|
+
parseSelectArith(parse) {
|
|
1901
|
+
const previous = this.allowSelectArithVariable;
|
|
1902
|
+
this.allowSelectArithVariable = true;
|
|
1903
|
+
try {
|
|
1904
|
+
return parse();
|
|
1905
|
+
} finally {
|
|
1906
|
+
this.allowSelectArithVariable = previous;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1896
1909
|
parseSelectColumn() {
|
|
1897
1910
|
if (this.consume("*" /* STAR */)) {
|
|
1898
1911
|
return { type: "WILDCARD" };
|
|
@@ -1938,7 +1951,7 @@ var Parser = class {
|
|
|
1938
1951
|
if (this.tryStringFuncName() !== null) {
|
|
1939
1952
|
const funcExpr = this.parseStringFuncExpr();
|
|
1940
1953
|
if (this.isArithOp(this.peek().kind)) {
|
|
1941
|
-
const node = this.continueArith(funcExpr);
|
|
1954
|
+
const node = this.parseSelectArith(() => this.continueArith(funcExpr));
|
|
1942
1955
|
const alias3 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
1943
1956
|
return { type: "ARITH_COL", expr: node, alias: alias3 };
|
|
1944
1957
|
}
|
|
@@ -1976,7 +1989,7 @@ var Parser = class {
|
|
|
1976
1989
|
return { type: "LITERAL_COL", value, alias: alias2 };
|
|
1977
1990
|
}
|
|
1978
1991
|
if (this.peek().kind === "(" /* LPAREN */ || this.peek().kind === "NUMBER" /* NUMBER */) {
|
|
1979
|
-
const node = this.parseArithAddSub();
|
|
1992
|
+
const node = this.parseSelectArith(() => this.parseArithAddSub());
|
|
1980
1993
|
const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
1981
1994
|
return { type: "ARITH_COL", expr: node, alias: alias2 };
|
|
1982
1995
|
}
|
|
@@ -1989,7 +2002,7 @@ var Parser = class {
|
|
|
1989
2002
|
}
|
|
1990
2003
|
if (this.isArithOp(this.peek().kind)) {
|
|
1991
2004
|
const left = { type: "FIELD_REF", field };
|
|
1992
|
-
const node = this.continueArith(left);
|
|
2005
|
+
const node = this.parseSelectArith(() => this.continueArith(left));
|
|
1993
2006
|
const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
1994
2007
|
return { type: "ARITH_COL", expr: node, alias: alias2 };
|
|
1995
2008
|
}
|
|
@@ -2269,6 +2282,10 @@ var Parser = class {
|
|
|
2269
2282
|
this.advance();
|
|
2270
2283
|
return makeNumberLiteral(tok.value);
|
|
2271
2284
|
}
|
|
2285
|
+
if (this.allowSelectArithVariable && tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
2286
|
+
this.advance();
|
|
2287
|
+
return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
|
|
2288
|
+
}
|
|
2272
2289
|
if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
|
|
2273
2290
|
this.advance();
|
|
2274
2291
|
let field = tok.value;
|
|
@@ -5258,6 +5275,9 @@ function collectArithFields(expr, out) {
|
|
|
5258
5275
|
collectArithNode(expr.right, out);
|
|
5259
5276
|
}
|
|
5260
5277
|
function collectArithNode(node, out) {
|
|
5278
|
+
if (node.type === "VARIABLE") throw new Error(
|
|
5279
|
+
`InternalError: unresolved arithmetic variable @${node.name} reached SELECT field collection.`
|
|
5280
|
+
);
|
|
5261
5281
|
if (node.type === "FIELD_REF") out.push(normalizeSimpleFieldRef(node.field));
|
|
5262
5282
|
else if (node.type === "ARITH") collectArithFields(node, out);
|
|
5263
5283
|
else if (node.type === "STRING_FUNC") collectStringFuncFields(node, out);
|
|
@@ -5341,20 +5361,36 @@ function caseResultHasAggregate(result) {
|
|
|
5341
5361
|
if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
|
|
5342
5362
|
return scalarValueHasAggregate(result);
|
|
5343
5363
|
}
|
|
5344
|
-
function
|
|
5364
|
+
function collectSelectFieldReferencesBySource(stmt, plainGroupByPlan) {
|
|
5365
|
+
const unqualified = /* @__PURE__ */ new Set();
|
|
5366
|
+
const states = collectRequiredFieldsByTable(stmt, plainGroupByPlan, {
|
|
5367
|
+
includeMaterialized: true,
|
|
5368
|
+
unqualified
|
|
5369
|
+
});
|
|
5370
|
+
return {
|
|
5371
|
+
bySource: new Map(
|
|
5372
|
+
[...states.entries()].map(([table, state]) => [table, new Set(state.fields)])
|
|
5373
|
+
),
|
|
5374
|
+
unqualified
|
|
5375
|
+
};
|
|
5376
|
+
}
|
|
5377
|
+
function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
|
|
5345
5378
|
const allTables = [stmt.from, ...stmt.joins.map((j) => j.table)];
|
|
5346
5379
|
const physicalTables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
|
|
5380
|
+
const targetTables = sourceAware ? allTables : physicalTables;
|
|
5347
5381
|
const states = /* @__PURE__ */ new Map();
|
|
5348
|
-
for (const table of
|
|
5382
|
+
for (const table of targetTables) {
|
|
5349
5383
|
states.set(table, { table, allFields: false, fields: /* @__PURE__ */ new Set() });
|
|
5350
5384
|
}
|
|
5351
5385
|
if (states.size === 0) return states;
|
|
5352
|
-
const
|
|
5353
|
-
const subtableTable =
|
|
5386
|
+
const firstTargetTable = targetTables[0] ?? null;
|
|
5387
|
+
const subtableTable = targetTables.find((t) => !!t.subtableCode) ?? null;
|
|
5354
5388
|
const aliasToTable = /* @__PURE__ */ new Map();
|
|
5355
|
-
for (const table of
|
|
5389
|
+
for (const table of targetTables) {
|
|
5356
5390
|
if (table.alias) aliasToTable.set(table.alias, table);
|
|
5357
|
-
if (
|
|
5391
|
+
if (table.cteName !== null) {
|
|
5392
|
+
aliasToTable.set(table.cteName, table);
|
|
5393
|
+
} else if (!table.subtableCode) {
|
|
5358
5394
|
aliasToTable.set(`APP${table.appId}`, table);
|
|
5359
5395
|
aliasToTable.set(`app${table.appId}`, table);
|
|
5360
5396
|
}
|
|
@@ -5366,11 +5402,11 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5366
5402
|
st.allFields = true;
|
|
5367
5403
|
st.fields.clear();
|
|
5368
5404
|
};
|
|
5369
|
-
const
|
|
5370
|
-
for (const t of
|
|
5405
|
+
const markAllTargetTables = () => {
|
|
5406
|
+
for (const t of targetTables) markAll(t);
|
|
5371
5407
|
};
|
|
5372
5408
|
const markAllSubtableTables = () => {
|
|
5373
|
-
for (const t of
|
|
5409
|
+
for (const t of targetTables) {
|
|
5374
5410
|
if (t.subtableCode) markAll(t);
|
|
5375
5411
|
}
|
|
5376
5412
|
};
|
|
@@ -5400,7 +5436,7 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5400
5436
|
if (rawName.endsWith(".*")) {
|
|
5401
5437
|
const qualifier = rawName.slice(0, -2);
|
|
5402
5438
|
if (!qualifier) {
|
|
5403
|
-
|
|
5439
|
+
markAllTargetTables();
|
|
5404
5440
|
return;
|
|
5405
5441
|
}
|
|
5406
5442
|
if (qualifier === "_p") {
|
|
@@ -5417,7 +5453,7 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5417
5453
|
if (phase === "groupBy" && groupResolution !== void 0) {
|
|
5418
5454
|
if (groupResolution.kind === "PHYSICAL") {
|
|
5419
5455
|
const source = allTables[groupResolution.sourceIndex];
|
|
5420
|
-
if (source
|
|
5456
|
+
if (source && (sourceAware || source.cteName === null)) {
|
|
5421
5457
|
addFieldToTable(source, groupResolution.fieldCode);
|
|
5422
5458
|
}
|
|
5423
5459
|
}
|
|
@@ -5442,8 +5478,13 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5442
5478
|
addFieldToTable(target, field);
|
|
5443
5479
|
return;
|
|
5444
5480
|
}
|
|
5481
|
+
if (sourceAware) return;
|
|
5482
|
+
}
|
|
5483
|
+
if (sourceAware) {
|
|
5484
|
+
sourceAware.unqualified.add(rawName);
|
|
5485
|
+
} else if (firstTargetTable) {
|
|
5486
|
+
addFieldToTable(firstTargetTable, rawName);
|
|
5445
5487
|
}
|
|
5446
|
-
if (firstPhysicalTable) addFieldToTable(firstPhysicalTable, rawName);
|
|
5447
5488
|
};
|
|
5448
5489
|
const addFieldRef = (field, tableAlias, phase = "select") => {
|
|
5449
5490
|
if (tableAlias) {
|
|
@@ -5456,10 +5497,16 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5456
5497
|
addFieldToTable(target, field);
|
|
5457
5498
|
return;
|
|
5458
5499
|
}
|
|
5500
|
+
if (sourceAware) return;
|
|
5459
5501
|
}
|
|
5460
5502
|
addFieldName(field, phase);
|
|
5461
5503
|
};
|
|
5462
5504
|
const walkArith = (node, phase = "select") => {
|
|
5505
|
+
if (node.type === "VARIABLE") {
|
|
5506
|
+
throw new Error(
|
|
5507
|
+
`InternalError: unresolved arithmetic variable @${node.name} reached source-aware field collection.`
|
|
5508
|
+
);
|
|
5509
|
+
}
|
|
5463
5510
|
if (node.type === "FIELD_REF") {
|
|
5464
5511
|
addFieldName(node.field, phase);
|
|
5465
5512
|
return;
|
|
@@ -5611,7 +5658,7 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5611
5658
|
for (const col of stmt.columns) {
|
|
5612
5659
|
switch (col.type) {
|
|
5613
5660
|
case "WILDCARD":
|
|
5614
|
-
|
|
5661
|
+
markAllTargetTables();
|
|
5615
5662
|
break;
|
|
5616
5663
|
case "PARENT_WILDCARD":
|
|
5617
5664
|
markAllSubtableTables();
|
|
@@ -7107,6 +7154,9 @@ function selectScalarExtreme(values, extreme) {
|
|
|
7107
7154
|
|
|
7108
7155
|
// src/engine/evalFunc.ts
|
|
7109
7156
|
function evalArithExpr(expr, row) {
|
|
7157
|
+
if (expr.type === "VARIABLE") throw new Error(
|
|
7158
|
+
`InternalError: unresolved arithmetic variable @${expr.name} reached arithmetic evaluation.`
|
|
7159
|
+
);
|
|
7110
7160
|
if (expr.type === "NUMBER") return expr.value;
|
|
7111
7161
|
if (expr.type === "FIELD_REF") return Number(resolveFieldRef(row, expr.field));
|
|
7112
7162
|
if (expr.type === "STRING_FUNC") return Number(evalStringFunc(expr, row));
|
|
@@ -8144,6 +8194,9 @@ function collectArithFields2(expr, out) {
|
|
|
8144
8194
|
collectArithNode2(expr.right, out);
|
|
8145
8195
|
}
|
|
8146
8196
|
function collectArithNode2(node, out) {
|
|
8197
|
+
if (node.type === "VARIABLE") throw new Error(
|
|
8198
|
+
`InternalError: unresolved arithmetic variable @${node.name} reached DML field collection.`
|
|
8199
|
+
);
|
|
8147
8200
|
if (node.type === "FIELD_REF") out.add(node.field);
|
|
8148
8201
|
else if (node.type === "ARITH") collectArithFields2(node, out);
|
|
8149
8202
|
else if (node.type === "STRING_FUNC") collectStringFuncFields2(node, out);
|
|
@@ -8341,6 +8394,9 @@ function evalArith(expr, raw) {
|
|
|
8341
8394
|
}
|
|
8342
8395
|
}
|
|
8343
8396
|
function resolveArithOperand(operand, raw) {
|
|
8397
|
+
if (operand.type === "VARIABLE") throw new Error(
|
|
8398
|
+
`InternalError: unresolved arithmetic variable @${operand.name} reached DML evaluation.`
|
|
8399
|
+
);
|
|
8344
8400
|
if (operand.type === "NUMBER") return operand.value;
|
|
8345
8401
|
if (operand.type === "ARITH") return evalArith(operand, raw);
|
|
8346
8402
|
if (operand.type === "STRING_FUNC") throw new DmlConvertError(
|
|
@@ -9490,6 +9546,20 @@ function renderValidationValue(value) {
|
|
|
9490
9546
|
}
|
|
9491
9547
|
|
|
9492
9548
|
// src/core/existingRecordValidation.ts
|
|
9549
|
+
var VALIDATE_CONSTRAINT_CATEGORIES = [
|
|
9550
|
+
"required",
|
|
9551
|
+
"length",
|
|
9552
|
+
"range",
|
|
9553
|
+
"choice"
|
|
9554
|
+
];
|
|
9555
|
+
function getAuditableConstraintCategories(field) {
|
|
9556
|
+
return [
|
|
9557
|
+
...field.required === true ? ["required"] : [],
|
|
9558
|
+
...field.minLength !== void 0 || field.maxLength !== void 0 ? ["length"] : [],
|
|
9559
|
+
...field.minValue !== void 0 || field.maxValue !== void 0 ? ["range"] : [],
|
|
9560
|
+
...field.optionOrder !== void 0 ? ["choice"] : []
|
|
9561
|
+
];
|
|
9562
|
+
}
|
|
9493
9563
|
function buildValidationFieldMetadataIndex(fieldInfos) {
|
|
9494
9564
|
const topLevel = fieldInfos.filter((field) => !field.inSubtable);
|
|
9495
9565
|
const childrenByTable = /* @__PURE__ */ new Map();
|
|
@@ -9506,7 +9576,7 @@ function buildValidationFieldMetadataIndex(fieldInfos) {
|
|
|
9506
9576
|
};
|
|
9507
9577
|
}
|
|
9508
9578
|
function hasAuditableConstraint(field) {
|
|
9509
|
-
return field.
|
|
9579
|
+
return getAuditableConstraintCategories(field).length > 0;
|
|
9510
9580
|
}
|
|
9511
9581
|
function isExistingValidationAuditable(field) {
|
|
9512
9582
|
return field.fieldType === "NUMBER" || hasAuditableConstraint(field);
|
|
@@ -12429,6 +12499,65 @@ function planPlainGroupByResolution(groupBy, columns, schemas) {
|
|
|
12429
12499
|
};
|
|
12430
12500
|
}
|
|
12431
12501
|
|
|
12502
|
+
// src/core/emptyWildcardSchema.ts
|
|
12503
|
+
var EMPTY_WILDCARD_FIELD_TYPE_POLICY = {
|
|
12504
|
+
CALC: "RECORD",
|
|
12505
|
+
CATEGORY: "NON_RECORD",
|
|
12506
|
+
CHECK_BOX: "RECORD",
|
|
12507
|
+
CREATED_TIME: "RECORD",
|
|
12508
|
+
CREATOR: "RECORD",
|
|
12509
|
+
DATE: "RECORD",
|
|
12510
|
+
DATETIME: "RECORD",
|
|
12511
|
+
DROP_DOWN: "RECORD",
|
|
12512
|
+
FILE: "RECORD",
|
|
12513
|
+
GROUP: "NON_RECORD",
|
|
12514
|
+
GROUP_SELECT: "RECORD",
|
|
12515
|
+
LINK: "RECORD",
|
|
12516
|
+
MODIFIER: "RECORD",
|
|
12517
|
+
MULTI_LINE_TEXT: "RECORD",
|
|
12518
|
+
MULTI_SELECT: "RECORD",
|
|
12519
|
+
NUMBER: "RECORD",
|
|
12520
|
+
ORGANIZATION_SELECT: "RECORD",
|
|
12521
|
+
RADIO_BUTTON: "RECORD",
|
|
12522
|
+
RECORD_NUMBER: "RECORD",
|
|
12523
|
+
REFERENCE_TABLE: "NON_RECORD",
|
|
12524
|
+
RICH_TEXT: "RECORD",
|
|
12525
|
+
SINGLE_LINE_TEXT: "RECORD",
|
|
12526
|
+
STATUS: "PROCESS",
|
|
12527
|
+
STATUS_ASSIGNEE: "PROCESS",
|
|
12528
|
+
SUBTABLE: "RECORD",
|
|
12529
|
+
TIME: "RECORD",
|
|
12530
|
+
UPDATED_TIME: "RECORD",
|
|
12531
|
+
USER_SELECT: "RECORD"
|
|
12532
|
+
};
|
|
12533
|
+
function fieldPolicy(fieldType) {
|
|
12534
|
+
const policy = EMPTY_WILDCARD_FIELD_TYPE_POLICY[fieldType];
|
|
12535
|
+
if (policy === void 0) {
|
|
12536
|
+
throw new Error(
|
|
12537
|
+
`InternalError: empty SELECT * schema policy is not defined for field type ${fieldType}.`
|
|
12538
|
+
);
|
|
12539
|
+
}
|
|
12540
|
+
return policy;
|
|
12541
|
+
}
|
|
12542
|
+
async function deriveEmptyWildcardColumns(fields, subtableCode, loadProcessStatuses) {
|
|
12543
|
+
if (subtableCode != null) {
|
|
12544
|
+
return [
|
|
12545
|
+
"_pid",
|
|
12546
|
+
"_rid",
|
|
12547
|
+
"_idx",
|
|
12548
|
+
...fields.filter((field) => field.inSubtable === true && field.subtableCode === subtableCode).map((field) => field.code)
|
|
12549
|
+
];
|
|
12550
|
+
}
|
|
12551
|
+
const topLevel = fields.filter((field) => !field.inSubtable);
|
|
12552
|
+
const needsProcessSettings = topLevel.some((field) => fieldPolicy(field.fieldType) === "PROCESS");
|
|
12553
|
+
const processEnabled = needsProcessSettings ? (await loadProcessStatuses()).enable : false;
|
|
12554
|
+
const columns = topLevel.filter((field) => {
|
|
12555
|
+
const policy = fieldPolicy(field.fieldType);
|
|
12556
|
+
return policy === "RECORD" || policy === "PROCESS" && processEnabled;
|
|
12557
|
+
}).map((field) => field.code);
|
|
12558
|
+
return [...columns, "$revision", "$id"];
|
|
12559
|
+
}
|
|
12560
|
+
|
|
12432
12561
|
// src/engine/process.ts
|
|
12433
12562
|
function flatten(record, alias) {
|
|
12434
12563
|
const row = {};
|
|
@@ -13312,6 +13441,9 @@ function stripParentShortcutColumns(row) {
|
|
|
13312
13441
|
}
|
|
13313
13442
|
function arithColDefaultKey(expr) {
|
|
13314
13443
|
const nodeLabel = (n) => {
|
|
13444
|
+
if (n.type === "VARIABLE") throw new Error(
|
|
13445
|
+
`InternalError: unresolved arithmetic variable @${n.name} reached arithmetic column labeling.`
|
|
13446
|
+
);
|
|
13315
13447
|
if (n.type === "FIELD_REF") return n.field;
|
|
13316
13448
|
if (n.type === "NUMBER") return numberLiteralText(n);
|
|
13317
13449
|
if (n.type === "STRING_FUNC") return stringFuncDefaultKey(n);
|
|
@@ -15251,6 +15383,7 @@ var materializedMetaByValidationResult = /* @__PURE__ */ new WeakMap();
|
|
|
15251
15383
|
var importSourceByDmlStatement = /* @__PURE__ */ new WeakMap();
|
|
15252
15384
|
var defaultCacheContextByClient = /* @__PURE__ */ new WeakMap();
|
|
15253
15385
|
var nextDefaultCacheContextId = 1;
|
|
15386
|
+
var nextCacheInvocationId = 1;
|
|
15254
15387
|
function resolveCacheContext(client, explicit) {
|
|
15255
15388
|
if (explicit) return explicit;
|
|
15256
15389
|
let context = defaultCacheContextByClient.get(client);
|
|
@@ -15260,31 +15393,40 @@ function resolveCacheContext(client, explicit) {
|
|
|
15260
15393
|
}
|
|
15261
15394
|
return context;
|
|
15262
15395
|
}
|
|
15396
|
+
function createInvocationCacheContext(cacheContext) {
|
|
15397
|
+
return `${cacheContext}\0inv:${nextCacheInvocationId++}`;
|
|
15398
|
+
}
|
|
15263
15399
|
async function execute(sql, client, options = {}) {
|
|
15264
15400
|
const startedAt = Date.now();
|
|
15265
|
-
const cacheContext =
|
|
15266
|
-
|
|
15267
|
-
const metrics = createEmptyMetrics();
|
|
15268
|
-
const countedClient = wrapClientWithMetrics(client, metrics);
|
|
15269
|
-
const collector = { aborted: false };
|
|
15270
|
-
const guardedClient = wrapClientWithSearchAbort(
|
|
15271
|
-
countedClient,
|
|
15272
|
-
collector,
|
|
15273
|
-
!isSelectLikeStatement(stmt) || statementContainsOuterJoin(stmt)
|
|
15274
|
-
);
|
|
15275
|
-
const result = await executeParsedStatement(
|
|
15276
|
-
stmt,
|
|
15277
|
-
guardedClient,
|
|
15278
|
-
options,
|
|
15279
|
-
cacheContext
|
|
15401
|
+
const cacheContext = createInvocationCacheContext(
|
|
15402
|
+
resolveCacheContext(client, options.cacheContext)
|
|
15280
15403
|
);
|
|
15281
|
-
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
const
|
|
15285
|
-
|
|
15404
|
+
try {
|
|
15405
|
+
const stmt = parseSql(sql, options.enableImport === true);
|
|
15406
|
+
const metrics = createEmptyMetrics();
|
|
15407
|
+
const countedClient = wrapClientWithMetrics(client, metrics);
|
|
15408
|
+
const collector = { aborted: false };
|
|
15409
|
+
const guardedClient = wrapClientWithSearchAbort(
|
|
15410
|
+
countedClient,
|
|
15411
|
+
collector,
|
|
15412
|
+
!isSelectLikeStatement(stmt) || statementContainsOuterJoin(stmt)
|
|
15413
|
+
);
|
|
15414
|
+
const result = await executeParsedStatement(
|
|
15415
|
+
stmt,
|
|
15416
|
+
guardedClient,
|
|
15417
|
+
options,
|
|
15418
|
+
cacheContext
|
|
15419
|
+
);
|
|
15420
|
+
metrics.elapsedMs = Date.now() - startedAt;
|
|
15421
|
+
const finalResult = { ...attachSearchAbortWarning(result, collector), metrics };
|
|
15422
|
+
if (result.type === "SELECT") {
|
|
15423
|
+
const columnMeta = materializedMetaBySelectResult.get(result);
|
|
15424
|
+
if (columnMeta) materializedMetaBySelectResult.set(finalResult, columnMeta);
|
|
15425
|
+
}
|
|
15426
|
+
return finalResult;
|
|
15427
|
+
} finally {
|
|
15428
|
+
releaseMetadataCacheScope(cacheContext);
|
|
15286
15429
|
}
|
|
15287
|
-
return finalResult;
|
|
15288
15430
|
}
|
|
15289
15431
|
function createEmptyMetrics() {
|
|
15290
15432
|
return {
|
|
@@ -15629,6 +15771,13 @@ async function executeExistingRecordValidationCore(stmt, client, options, cacheC
|
|
|
15629
15771
|
const infoByCode = new Map(fieldInfos.filter((field) => !field.inSubtable).map((field) => [field.code, field]));
|
|
15630
15772
|
const childCodes = new Set(fieldInfos.filter((field) => field.inSubtable).map((field) => field.code));
|
|
15631
15773
|
const targets = resolveExistingValidationTargets(stmt, fieldInfos);
|
|
15774
|
+
const presentConstraintCategories = new Set(
|
|
15775
|
+
targets.flatMap((target) => getAuditableConstraintCategories(target.field))
|
|
15776
|
+
);
|
|
15777
|
+
const constraintMetadata = {
|
|
15778
|
+
present: VALIDATE_CONSTRAINT_CATEGORIES.filter((category) => presentConstraintCategories.has(category)),
|
|
15779
|
+
absent: VALIDATE_CONSTRAINT_CATEGORIES.filter((category) => !presentConstraintCategories.has(category))
|
|
15780
|
+
};
|
|
15632
15781
|
const checkGroups = stmt.checkGroups ?? [];
|
|
15633
15782
|
const checkRefs2 = collectCheckFieldRefs(checkGroups);
|
|
15634
15783
|
for (const ref of checkRefs2) {
|
|
@@ -15785,7 +15934,11 @@ async function executeExistingRecordValidationCore(stmt, client, options, cacheC
|
|
|
15785
15934
|
columns: [...columns],
|
|
15786
15935
|
rows,
|
|
15787
15936
|
rowCount: rows.length,
|
|
15788
|
-
validateStats: {
|
|
15937
|
+
validateStats: {
|
|
15938
|
+
errorRecords: errorRecordIds.size,
|
|
15939
|
+
errorCount,
|
|
15940
|
+
constraintMetadata
|
|
15941
|
+
}
|
|
15789
15942
|
};
|
|
15790
15943
|
materializedMetaBySelectResult.set(result, existingValidationColumnMeta(stmt.summary === true));
|
|
15791
15944
|
return result;
|
|
@@ -15844,91 +15997,97 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
15844
15997
|
const countedClient = wrapClientWithMetrics(client, metrics);
|
|
15845
15998
|
const startedAt = Date.now();
|
|
15846
15999
|
const deadline = options.timeoutMs != null ? startedAt + options.timeoutMs : null;
|
|
15847
|
-
const cacheContext =
|
|
15848
|
-
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
const
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
15863
|
-
const depName = analysis.statements[brokenDep].tempTablesCreated[0] ?? `statement ${brokenDep}`;
|
|
15864
|
-
results.push({ ...base, status: "skipped", skippedReason: `dependency: ${depName}` });
|
|
15865
|
-
failed.add(i);
|
|
15866
|
-
continue;
|
|
15867
|
-
}
|
|
15868
|
-
if (deadline !== null && Date.now() >= deadline) {
|
|
15869
|
-
results.push({ ...base, status: "skipped", skippedReason: "timeout" });
|
|
15870
|
-
failed.add(i);
|
|
15871
|
-
aborted = "timeout";
|
|
15872
|
-
continue;
|
|
15873
|
-
}
|
|
15874
|
-
try {
|
|
15875
|
-
const remaining = deadline !== null ? deadline - Date.now() : null;
|
|
15876
|
-
const userConfirm = batchOptions.confirm;
|
|
15877
|
-
const stmtOptions = userConfirm ? {
|
|
15878
|
-
...batchOptions,
|
|
15879
|
-
confirm: (count, operation, detailContext) => userConfirm(count, operation, {
|
|
15880
|
-
statementIndex: i,
|
|
15881
|
-
statementCount: statements.length,
|
|
15882
|
-
statementType: info.statementType,
|
|
15883
|
-
targetAppId: info.targetAppId,
|
|
15884
|
-
...detailContext?.importDetail ? { importDetail: detailContext.importDetail } : {},
|
|
15885
|
-
...detailContext?.applyDetail ? { applyDetail: detailContext.applyDetail } : {},
|
|
15886
|
-
...detailContext?.applyDiagnostic ? { applyDiagnostic: detailContext.applyDiagnostic } : {}
|
|
15887
|
-
})
|
|
15888
|
-
} : batchOptions;
|
|
15889
|
-
const searchAbortCollector = { aborted: false };
|
|
15890
|
-
const statementClient = wrapClientWithSearchAbort(
|
|
15891
|
-
countedClient,
|
|
15892
|
-
searchAbortCollector,
|
|
15893
|
-
info.statementType !== "SELECT" && info.statementType !== "UNION" && info.statementType !== "WITH" || statementContainsOuterJoin(statements[i])
|
|
15894
|
-
);
|
|
15895
|
-
const cursorScope = wrapClientWithCursorScope(statementClient);
|
|
15896
|
-
const outcome = await runWithDeadline(
|
|
15897
|
-
executeBatchStatement(statements[i], info, cursorScope.client, stmtOptions, cacheContext, tempTables, variables),
|
|
15898
|
-
remaining,
|
|
15899
|
-
cursorScope.closeActive
|
|
15900
|
-
);
|
|
15901
|
-
if (outcome.result) {
|
|
15902
|
-
outcome.result = attachSearchAbortWarning(outcome.result, searchAbortCollector);
|
|
16000
|
+
const cacheContext = createInvocationCacheContext(
|
|
16001
|
+
resolveCacheContext(client, options.cacheContext)
|
|
16002
|
+
);
|
|
16003
|
+
try {
|
|
16004
|
+
const tempTables = /* @__PURE__ */ new Map();
|
|
16005
|
+
const variables = /* @__PURE__ */ new Map();
|
|
16006
|
+
const results = [];
|
|
16007
|
+
const failed = /* @__PURE__ */ new Set();
|
|
16008
|
+
let aborted = null;
|
|
16009
|
+
for (let i = 0; i < statements.length; i++) {
|
|
16010
|
+
const info = analysis.statements[i];
|
|
16011
|
+
const base = { index: i, type: info.statementType };
|
|
16012
|
+
if (aborted) {
|
|
16013
|
+
results.push({ ...base, status: "skipped", skippedReason: aborted });
|
|
16014
|
+
failed.add(i);
|
|
16015
|
+
continue;
|
|
15903
16016
|
}
|
|
15904
|
-
|
|
15905
|
-
|
|
15906
|
-
|
|
15907
|
-
...base,
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
|
|
15911
|
-
|
|
15912
|
-
|
|
15913
|
-
|
|
16017
|
+
const brokenDep = info.dependsOn.find((d) => failed.has(d));
|
|
16018
|
+
if (brokenDep !== void 0) {
|
|
16019
|
+
const depName = analysis.statements[brokenDep].tempTablesCreated[0] ?? `statement ${brokenDep}`;
|
|
16020
|
+
results.push({ ...base, status: "skipped", skippedReason: `dependency: ${depName}` });
|
|
16021
|
+
failed.add(i);
|
|
16022
|
+
continue;
|
|
16023
|
+
}
|
|
16024
|
+
if (deadline !== null && Date.now() >= deadline) {
|
|
16025
|
+
results.push({ ...base, status: "skipped", skippedReason: "timeout" });
|
|
16026
|
+
failed.add(i);
|
|
15914
16027
|
aborted = "timeout";
|
|
15915
|
-
|
|
15916
|
-
|
|
15917
|
-
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
|
|
16028
|
+
continue;
|
|
16029
|
+
}
|
|
16030
|
+
try {
|
|
16031
|
+
const remaining = deadline !== null ? deadline - Date.now() : null;
|
|
16032
|
+
const userConfirm = batchOptions.confirm;
|
|
16033
|
+
const stmtOptions = userConfirm ? {
|
|
16034
|
+
...batchOptions,
|
|
16035
|
+
confirm: (count, operation, detailContext) => userConfirm(count, operation, {
|
|
16036
|
+
statementIndex: i,
|
|
16037
|
+
statementCount: statements.length,
|
|
16038
|
+
statementType: info.statementType,
|
|
16039
|
+
targetAppId: info.targetAppId,
|
|
16040
|
+
...detailContext?.importDetail ? { importDetail: detailContext.importDetail } : {},
|
|
16041
|
+
...detailContext?.applyDetail ? { applyDetail: detailContext.applyDetail } : {},
|
|
16042
|
+
...detailContext?.applyDiagnostic ? { applyDiagnostic: detailContext.applyDiagnostic } : {}
|
|
16043
|
+
})
|
|
16044
|
+
} : batchOptions;
|
|
16045
|
+
const searchAbortCollector = { aborted: false };
|
|
16046
|
+
const statementClient = wrapClientWithSearchAbort(
|
|
16047
|
+
countedClient,
|
|
16048
|
+
searchAbortCollector,
|
|
16049
|
+
info.statementType !== "SELECT" && info.statementType !== "UNION" && info.statementType !== "WITH" || statementContainsOuterJoin(statements[i])
|
|
16050
|
+
);
|
|
16051
|
+
const cursorScope = wrapClientWithCursorScope(statementClient);
|
|
16052
|
+
const outcome = await runWithDeadline(
|
|
16053
|
+
executeBatchStatement(statements[i], info, cursorScope.client, stmtOptions, cacheContext, tempTables, variables),
|
|
16054
|
+
remaining,
|
|
16055
|
+
cursorScope.closeActive
|
|
16056
|
+
);
|
|
16057
|
+
if (outcome.result) {
|
|
16058
|
+
outcome.result = attachSearchAbortWarning(outcome.result, searchAbortCollector);
|
|
16059
|
+
}
|
|
16060
|
+
results.push({ ...base, status: "success", ...outcome });
|
|
16061
|
+
} catch (e) {
|
|
16062
|
+
results.push({
|
|
16063
|
+
...base,
|
|
16064
|
+
status: "error",
|
|
16065
|
+
error: toBatchStatementError(e),
|
|
16066
|
+
...e instanceof RejectLimitExceededError ? { result: e.diagnostic } : {}
|
|
16067
|
+
});
|
|
16068
|
+
failed.add(i);
|
|
16069
|
+
if (e instanceof BatchTimeoutError) {
|
|
16070
|
+
aborted = "timeout";
|
|
16071
|
+
} else if (e instanceof AssertError) {
|
|
16072
|
+
aborted = "assertion";
|
|
16073
|
+
} else if (info.statementType === "SET_VARIABLE" || info.statementType === "DECLARE_VARIABLE") {
|
|
16074
|
+
aborted = "fail-fast";
|
|
16075
|
+
} else if (!options.continueOnError) {
|
|
16076
|
+
aborted = "fail-fast";
|
|
16077
|
+
}
|
|
15921
16078
|
}
|
|
15922
16079
|
}
|
|
16080
|
+
metrics.elapsedMs = Date.now() - startedAt;
|
|
16081
|
+
return {
|
|
16082
|
+
ok: results.every((r) => r.status === "success"),
|
|
16083
|
+
statementCount: statements.length,
|
|
16084
|
+
statements: results,
|
|
16085
|
+
analysis,
|
|
16086
|
+
metrics
|
|
16087
|
+
};
|
|
16088
|
+
} finally {
|
|
16089
|
+
releaseMetadataCacheScope(cacheContext);
|
|
15923
16090
|
}
|
|
15924
|
-
metrics.elapsedMs = Date.now() - startedAt;
|
|
15925
|
-
return {
|
|
15926
|
-
ok: results.every((r) => r.status === "success"),
|
|
15927
|
-
statementCount: statements.length,
|
|
15928
|
-
statements: results,
|
|
15929
|
-
analysis,
|
|
15930
|
-
metrics
|
|
15931
|
-
};
|
|
15932
16091
|
}
|
|
15933
16092
|
function statementHasApplyMutation(statement) {
|
|
15934
16093
|
if (statement.type === "UPDATE" || statement.type === "INSERT") {
|
|
@@ -16215,8 +16374,11 @@ function evaluateScalarExpr(expr) {
|
|
|
16215
16374
|
}
|
|
16216
16375
|
}
|
|
16217
16376
|
function resolveBatchVariableReferences(node, variables) {
|
|
16377
|
+
return resolveBatchVariableReferencesInternal(node, variables, false);
|
|
16378
|
+
}
|
|
16379
|
+
function resolveBatchVariableReferencesInternal(node, variables, numericArithmeticOperand) {
|
|
16218
16380
|
if (Array.isArray(node)) {
|
|
16219
|
-
return node.map((v) =>
|
|
16381
|
+
return node.map((v) => resolveBatchVariableReferencesInternal(v, variables, false));
|
|
16220
16382
|
}
|
|
16221
16383
|
if (node !== null && typeof node === "object") {
|
|
16222
16384
|
const obj = node;
|
|
@@ -16228,6 +16390,11 @@ function resolveBatchVariableReferences(node, variables) {
|
|
|
16228
16390
|
if (value.type === "array") {
|
|
16229
16391
|
throw new Error(`ParseError: array variable @${obj["name"]} can only be used as IN @${obj["name"]}.`);
|
|
16230
16392
|
}
|
|
16393
|
+
if (numericArithmeticOperand && value.type !== "number") {
|
|
16394
|
+
throw new Error(
|
|
16395
|
+
`ArgumentError: variable @${obj["name"]} is not numeric and cannot be used in arithmetic.`
|
|
16396
|
+
);
|
|
16397
|
+
}
|
|
16231
16398
|
return value.type === "number" ? { type: "NUMBER", value: value.value, raw: value.raw ?? String(value.value) } : { type: "STRING", value: value.value };
|
|
16232
16399
|
}
|
|
16233
16400
|
if (obj["type"] === "VARIABLE_COL" && typeof obj["name"] === "string" && typeof obj["alias"] === "string") {
|
|
@@ -16238,7 +16405,14 @@ function resolveBatchVariableReferences(node, variables) {
|
|
|
16238
16405
|
}
|
|
16239
16406
|
if (obj["type"] === "VARIABLE_IN_LIST") return obj;
|
|
16240
16407
|
const resolved = Object.fromEntries(
|
|
16241
|
-
Object.entries(obj).map(([key, value]) => [
|
|
16408
|
+
Object.entries(obj).map(([key, value]) => [
|
|
16409
|
+
key,
|
|
16410
|
+
resolveBatchVariableReferencesInternal(
|
|
16411
|
+
value,
|
|
16412
|
+
variables,
|
|
16413
|
+
(obj["type"] === "ARITH" || obj["type"] === "SCALAR_ARITH" || obj["type"] === "AGG_ARITH") && (key === "left" || key === "right")
|
|
16414
|
+
)
|
|
16415
|
+
])
|
|
16242
16416
|
);
|
|
16243
16417
|
if (resolved["type"] === "BINARY") {
|
|
16244
16418
|
const right = resolved["right"];
|
|
@@ -16393,6 +16567,11 @@ function withScalarProbeLimit(query) {
|
|
|
16393
16567
|
return { query: { ...query, limit: 2 }, probed: true };
|
|
16394
16568
|
}
|
|
16395
16569
|
function evalAssertArith(node) {
|
|
16570
|
+
if (node.type === "VARIABLE") {
|
|
16571
|
+
throw new Error(
|
|
16572
|
+
`InternalError: unresolved arithmetic variable @${node.name} reached ASSERT evaluation.`
|
|
16573
|
+
);
|
|
16574
|
+
}
|
|
16396
16575
|
if (node.type === "NUMBER") return node.value;
|
|
16397
16576
|
if (node.type === "ARITH") {
|
|
16398
16577
|
const left = evalAssertArith(node.left);
|
|
@@ -16909,6 +17088,11 @@ function isNoFromSelect(stmt) {
|
|
|
16909
17088
|
return stmt.from.appId === 0 && stmt.from.cteName === NO_FROM_CTE_NAME;
|
|
16910
17089
|
}
|
|
16911
17090
|
function arithHasFieldRef(node) {
|
|
17091
|
+
if (node.type === "VARIABLE") {
|
|
17092
|
+
throw new Error(
|
|
17093
|
+
`InternalError: unresolved arithmetic variable @${node.name} reached SELECT planning.`
|
|
17094
|
+
);
|
|
17095
|
+
}
|
|
16912
17096
|
if (node.type === "FIELD_REF") return true;
|
|
16913
17097
|
if (node.type === "ARITH") return arithHasFieldRef(node.left) || arithHasFieldRef(node.right);
|
|
16914
17098
|
if (node.type === "STRING_FUNC") return stringFuncHasFieldRef(node);
|
|
@@ -17051,7 +17235,7 @@ async function executeSimpleSelect(stmt, client, options, cacheContext, orderPla
|
|
|
17051
17235
|
);
|
|
17052
17236
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
17053
17237
|
}
|
|
17054
|
-
const { rows: projected, columns } = project(
|
|
17238
|
+
const { rows: projected, columns: projectedColumns } = project(
|
|
17055
17239
|
rows,
|
|
17056
17240
|
stmt.columns,
|
|
17057
17241
|
void 0,
|
|
@@ -17059,6 +17243,13 @@ async function executeSimpleSelect(stmt, client, options, cacheContext, orderPla
|
|
|
17059
17243
|
void 0,
|
|
17060
17244
|
projectionSemanticsResolver
|
|
17061
17245
|
);
|
|
17246
|
+
const columns = await restoreEmptyWildcardColumns(
|
|
17247
|
+
stmt,
|
|
17248
|
+
projected,
|
|
17249
|
+
projectedColumns,
|
|
17250
|
+
client,
|
|
17251
|
+
cacheContext
|
|
17252
|
+
);
|
|
17062
17253
|
return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
|
|
17063
17254
|
}
|
|
17064
17255
|
async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
@@ -17093,6 +17284,159 @@ async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
|
17093
17284
|
}
|
|
17094
17285
|
}
|
|
17095
17286
|
}
|
|
17287
|
+
function b86SourceLabel(table) {
|
|
17288
|
+
return table.cteName ?? `APP${table.appId}`;
|
|
17289
|
+
}
|
|
17290
|
+
function b86SourceAliases(table) {
|
|
17291
|
+
if (table.alias) return [table.alias];
|
|
17292
|
+
if (table.cteName !== null) return [table.cteName];
|
|
17293
|
+
return [`APP${table.appId}`, `app${table.appId}`];
|
|
17294
|
+
}
|
|
17295
|
+
function b86PhysicalFieldExists(schema, field) {
|
|
17296
|
+
return isSystemLikeFieldCode(field) || schema.validCodes.has(field);
|
|
17297
|
+
}
|
|
17298
|
+
function b86FieldExists(schema, field) {
|
|
17299
|
+
if (schema.table.cteName !== null) return schema.validCodes.has(field);
|
|
17300
|
+
return b86PhysicalFieldExists(schema, field);
|
|
17301
|
+
}
|
|
17302
|
+
function collectB86Subqueries(stmt) {
|
|
17303
|
+
const queries = [];
|
|
17304
|
+
const visitWhere = (where) => {
|
|
17305
|
+
if (where === null) return;
|
|
17306
|
+
switch (where.type) {
|
|
17307
|
+
case "BINARY":
|
|
17308
|
+
if (where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY") {
|
|
17309
|
+
queries.push(where.right.query);
|
|
17310
|
+
}
|
|
17311
|
+
return;
|
|
17312
|
+
case "EXISTS":
|
|
17313
|
+
queries.push(where.query);
|
|
17314
|
+
return;
|
|
17315
|
+
case "LOGICAL":
|
|
17316
|
+
visitWhere(where.left);
|
|
17317
|
+
visitWhere(where.right);
|
|
17318
|
+
return;
|
|
17319
|
+
case "NOT":
|
|
17320
|
+
case "GROUP":
|
|
17321
|
+
visitWhere(where.expr);
|
|
17322
|
+
return;
|
|
17323
|
+
case "NULL_CHECK":
|
|
17324
|
+
case "BOOLEAN":
|
|
17325
|
+
return;
|
|
17326
|
+
}
|
|
17327
|
+
};
|
|
17328
|
+
visitWhere(stmt.where);
|
|
17329
|
+
visitWhere(stmt.having);
|
|
17330
|
+
for (const column of stmt.columns) {
|
|
17331
|
+
if (column.type === "SCALAR_SUBQUERY_COL") {
|
|
17332
|
+
queries.push(column.query);
|
|
17333
|
+
} else if (column.type === "CASE_COL") {
|
|
17334
|
+
for (const branch of column.expr.branches) visitWhere(branch.condition);
|
|
17335
|
+
}
|
|
17336
|
+
}
|
|
17337
|
+
return queries;
|
|
17338
|
+
}
|
|
17339
|
+
async function validateB86SelectFieldCodes(stmt, client, cteCache, cacheContext) {
|
|
17340
|
+
const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
17341
|
+
const materializedByTable = /* @__PURE__ */ new Map();
|
|
17342
|
+
const effectiveAliases = /* @__PURE__ */ new Set();
|
|
17343
|
+
for (const table of tables) {
|
|
17344
|
+
const alias = effectiveTableAlias(table);
|
|
17345
|
+
if (alias === null) continue;
|
|
17346
|
+
if (effectiveAliases.has(alias)) {
|
|
17347
|
+
throw new Error(`ArgumentError: effective alias ${alias} is used by multiple tables.`);
|
|
17348
|
+
}
|
|
17349
|
+
effectiveAliases.add(alias);
|
|
17350
|
+
}
|
|
17351
|
+
for (const table of tables) {
|
|
17352
|
+
if (table.cteName === null || table.cteName === NO_FROM_CTE_NAME) continue;
|
|
17353
|
+
const materialized = cteCache.get(table.cteName);
|
|
17354
|
+
if (!materialized) {
|
|
17355
|
+
throw new Error(`ArgumentError: materialized source ${table.cteName} is not available.`);
|
|
17356
|
+
}
|
|
17357
|
+
if (materialized.rows.length > 0 && materialized.columns.length === 0) {
|
|
17358
|
+
throw new Error(
|
|
17359
|
+
`InternalError: materialized source ${table.cteName} has rows but no column schema.`
|
|
17360
|
+
);
|
|
17361
|
+
}
|
|
17362
|
+
if (stmt.joins.length > 0 && materialized.rows.length === 0 && materialized.columns.length === 0) {
|
|
17363
|
+
throw new Error(
|
|
17364
|
+
`ArgumentError: column schema is unavailable for materialized JOIN source ${table.cteName}.`
|
|
17365
|
+
);
|
|
17366
|
+
}
|
|
17367
|
+
materializedByTable.set(table, materialized);
|
|
17368
|
+
}
|
|
17369
|
+
const schemas = /* @__PURE__ */ new Map();
|
|
17370
|
+
await Promise.all(tables.map(async (table) => {
|
|
17371
|
+
const materialized = materializedByTable.get(table);
|
|
17372
|
+
if (materialized) {
|
|
17373
|
+
schemas.set(table, {
|
|
17374
|
+
table,
|
|
17375
|
+
label: b86SourceLabel(table),
|
|
17376
|
+
validCodes: new Set(materialized.columns),
|
|
17377
|
+
authoritative: true,
|
|
17378
|
+
schemaUnavailable: materialized.rows.length === 0 && materialized.columns.length === 0
|
|
17379
|
+
});
|
|
17380
|
+
return;
|
|
17381
|
+
}
|
|
17382
|
+
if (table.cteName === NO_FROM_CTE_NAME) return;
|
|
17383
|
+
const defs = await getFieldsCached(table.appId, client, cacheContext);
|
|
17384
|
+
schemas.set(table, {
|
|
17385
|
+
table,
|
|
17386
|
+
label: b86SourceLabel(table),
|
|
17387
|
+
validCodes: new Set(defs.map((def) => def.code)),
|
|
17388
|
+
authoritative: defs.length > 0,
|
|
17389
|
+
schemaUnavailable: false
|
|
17390
|
+
});
|
|
17391
|
+
}));
|
|
17392
|
+
const sourceByAlias = /* @__PURE__ */ new Map();
|
|
17393
|
+
for (const schema of schemas.values()) {
|
|
17394
|
+
for (const alias of b86SourceAliases(schema.table)) sourceByAlias.set(alias, schema);
|
|
17395
|
+
}
|
|
17396
|
+
for (const join2 of stmt.joins) {
|
|
17397
|
+
for (const ref of [join2.on.left, join2.on.right]) {
|
|
17398
|
+
if (!ref.tableAlias) continue;
|
|
17399
|
+
const schema = sourceByAlias.get(ref.tableAlias);
|
|
17400
|
+
if (schema && schema.table.cteName !== null && !schema.schemaUnavailable && !b86FieldExists(schema, ref.field)) {
|
|
17401
|
+
throw new Error(
|
|
17402
|
+
`ArgumentError: JOIN key ${ref.tableAlias}.${ref.field} is not available in the materialized table.`
|
|
17403
|
+
);
|
|
17404
|
+
}
|
|
17405
|
+
}
|
|
17406
|
+
}
|
|
17407
|
+
const references = collectSelectFieldReferencesBySource(stmt);
|
|
17408
|
+
for (const [table, fields] of references.bySource) {
|
|
17409
|
+
const schema = schemas.get(table);
|
|
17410
|
+
if (!schema || schema.schemaUnavailable || !schema.authoritative) continue;
|
|
17411
|
+
const unknown = [...fields].filter((field) => !b86FieldExists(schema, field));
|
|
17412
|
+
if (unknown.length > 0) {
|
|
17413
|
+
throw new Error(
|
|
17414
|
+
`ArgumentError: unknown field code(s): ${unknown.join(", ")} (${schema.label})`
|
|
17415
|
+
);
|
|
17416
|
+
}
|
|
17417
|
+
}
|
|
17418
|
+
for (const field of references.unqualified) {
|
|
17419
|
+
const candidates = [...schemas.values()].filter((schema) => !schema.schemaUnavailable);
|
|
17420
|
+
if (candidates.some((schema) => b86FieldExists(schema, field))) continue;
|
|
17421
|
+
if ([...schemas.values()].some((schema) => schema.schemaUnavailable)) continue;
|
|
17422
|
+
if (candidates.some((schema) => schema.table.cteName === null && !schema.authoritative)) continue;
|
|
17423
|
+
const labels = candidates.map((schema) => schema.label).join(", ");
|
|
17424
|
+
throw new Error(`ArgumentError: unknown field code(s): ${field} (${labels})`);
|
|
17425
|
+
}
|
|
17426
|
+
}
|
|
17427
|
+
async function preflightB86QueryWithCte(query, client, cteCache, cacheContext, seen = /* @__PURE__ */ new Set()) {
|
|
17428
|
+
if (seen.has(query)) return;
|
|
17429
|
+
seen.add(query);
|
|
17430
|
+
if (query.type === "UNION") {
|
|
17431
|
+
await preflightB86QueryWithCte(query.left, client, cteCache, cacheContext, seen);
|
|
17432
|
+
await preflightB86QueryWithCte(query.right, client, cteCache, cacheContext, seen);
|
|
17433
|
+
return;
|
|
17434
|
+
}
|
|
17435
|
+
await validateB86SelectFieldCodes(query, client, cteCache, cacheContext);
|
|
17436
|
+
for (const subquery of collectB86Subqueries(query)) {
|
|
17437
|
+
await preflightB86QueryWithCte(subquery, client, cteCache, cacheContext, seen);
|
|
17438
|
+
}
|
|
17439
|
+
}
|
|
17096
17440
|
function extractMainTypedPushdownCandidate(stmt) {
|
|
17097
17441
|
if (stmt.where === null || stmt.from.subtableCode || stmt.from.cteName !== null) return null;
|
|
17098
17442
|
if (stmt.joins.length === 0) {
|
|
@@ -17882,7 +18226,7 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
17882
18226
|
tables.set(join2.table.alias, joinRecords);
|
|
17883
18227
|
}));
|
|
17884
18228
|
const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
|
|
17885
|
-
const { rows, columns } = runFullScan({
|
|
18229
|
+
const { rows, columns: projectedColumns } = runFullScan({
|
|
17886
18230
|
tables,
|
|
17887
18231
|
stmt,
|
|
17888
18232
|
scalarCache,
|
|
@@ -17899,6 +18243,13 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
17899
18243
|
resolvedGroupingSpec: resolvedGroupingSpecs.get(stmt),
|
|
17900
18244
|
plainGroupByPlan
|
|
17901
18245
|
});
|
|
18246
|
+
const columns = await restoreEmptyWildcardColumns(
|
|
18247
|
+
stmt,
|
|
18248
|
+
rows,
|
|
18249
|
+
projectedColumns,
|
|
18250
|
+
client,
|
|
18251
|
+
cacheContext
|
|
18252
|
+
);
|
|
17902
18253
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
17903
18254
|
}
|
|
17904
18255
|
async function executeUnion(stmt, client, options, cacheContext, captureColumnMeta = false, forLibraryCapture = false) {
|
|
@@ -17954,11 +18305,14 @@ async function executeWith(stmt, client, options, cacheContext, seed, captureCol
|
|
|
17954
18305
|
}
|
|
17955
18306
|
return executeQueryWithCte(stmt.query, client, options, cteCache, cacheContext, captureColumnMeta);
|
|
17956
18307
|
}
|
|
17957
|
-
async function executeQueryWithCte(query, client, options, cteCache, cacheContext, captureColumnMeta = false) {
|
|
18308
|
+
async function executeQueryWithCte(query, client, options, cteCache, cacheContext, captureColumnMeta = false, b86PreflightComplete = false) {
|
|
18309
|
+
if (!b86PreflightComplete) {
|
|
18310
|
+
await preflightB86QueryWithCte(query, client, cteCache, cacheContext);
|
|
18311
|
+
}
|
|
17958
18312
|
if (query.type === "UNION") {
|
|
17959
18313
|
const [leftResult, rightResult] = await Promise.all([
|
|
17960
|
-
executeQueryWithCte(query.left, client, options, cteCache, cacheContext, captureColumnMeta),
|
|
17961
|
-
executeQueryWithCte(query.right, client, options, cteCache, cacheContext, captureColumnMeta)
|
|
18314
|
+
executeQueryWithCte(query.left, client, options, cteCache, cacheContext, captureColumnMeta, true),
|
|
18315
|
+
executeQueryWithCte(query.right, client, options, cteCache, cacheContext, captureColumnMeta, true)
|
|
17962
18316
|
]);
|
|
17963
18317
|
const leftCols = leftResult.columns;
|
|
17964
18318
|
const rightCols = rightResult.columns;
|
|
@@ -18138,7 +18492,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
18138
18492
|
await Promise.all(joinFetches);
|
|
18139
18493
|
const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
|
|
18140
18494
|
const sourceColumns2 = stmt.joins.length === 0 && stmt.from.cteName != null ? requireMaterializedTable(stmt.from.cteName).columns : void 0;
|
|
18141
|
-
const { rows, columns } = runFullScan({
|
|
18495
|
+
const { rows, columns: projectedColumns } = runFullScan({
|
|
18142
18496
|
tables,
|
|
18143
18497
|
stmt,
|
|
18144
18498
|
scalarCache,
|
|
@@ -18157,8 +18511,26 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
18157
18511
|
resolvedGroupingSpec,
|
|
18158
18512
|
plainGroupByPlan
|
|
18159
18513
|
});
|
|
18514
|
+
const columns = await restoreEmptyWildcardColumns(
|
|
18515
|
+
stmt,
|
|
18516
|
+
rows,
|
|
18517
|
+
projectedColumns,
|
|
18518
|
+
client,
|
|
18519
|
+
cacheContext
|
|
18520
|
+
);
|
|
18160
18521
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
18161
18522
|
}
|
|
18523
|
+
async function restoreEmptyWildcardColumns(stmt, rows, columns, client, cacheContext) {
|
|
18524
|
+
if (rows.length !== 0 || columns.length !== 0 || stmt.columns.length !== 1 || stmt.columns[0].type !== "WILDCARD" || stmt.joins.length !== 0 || stmt.from.cteName !== null) {
|
|
18525
|
+
return [...columns];
|
|
18526
|
+
}
|
|
18527
|
+
const fields = await getFieldsCached(stmt.from.appId, client, cacheContext);
|
|
18528
|
+
return deriveEmptyWildcardColumns(
|
|
18529
|
+
fields,
|
|
18530
|
+
stmt.from.subtableCode,
|
|
18531
|
+
() => getProcessStatusesCached(stmt.from.appId, client, cacheContext)
|
|
18532
|
+
);
|
|
18533
|
+
}
|
|
18162
18534
|
function processRowToKintoneRecord(row) {
|
|
18163
18535
|
return Object.fromEntries(
|
|
18164
18536
|
Object.entries(row).map(([k, v]) => [k, { value: v ?? "" }])
|
|
@@ -18358,6 +18730,14 @@ var sortKindCache = /* @__PURE__ */ new Map();
|
|
|
18358
18730
|
var fieldInfoCache = /* @__PURE__ */ new Map();
|
|
18359
18731
|
var processStatusCache = /* @__PURE__ */ new Map();
|
|
18360
18732
|
var numberPrecisionCache = /* @__PURE__ */ new Map();
|
|
18733
|
+
function releaseMetadataCacheScope(cacheContext) {
|
|
18734
|
+
fieldTypeCache.delete(cacheContext);
|
|
18735
|
+
optionOrderCache.delete(cacheContext);
|
|
18736
|
+
sortKindCache.delete(cacheContext);
|
|
18737
|
+
fieldInfoCache.delete(cacheContext);
|
|
18738
|
+
processStatusCache.delete(cacheContext);
|
|
18739
|
+
numberPrecisionCache.delete(cacheContext);
|
|
18740
|
+
}
|
|
18361
18741
|
function getScopedCacheValue(root, cacheContext, appId) {
|
|
18362
18742
|
return root.get(cacheContext)?.get(appId);
|
|
18363
18743
|
}
|
|
@@ -22029,45 +22409,50 @@ function serverFunctionClientEvaluationLabel(leaves) {
|
|
|
22029
22409
|
) ? "relative date client evaluations" : "kintone function client evaluations";
|
|
22030
22410
|
}
|
|
22031
22411
|
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS) {
|
|
22032
|
-
const
|
|
22033
|
-
|
|
22034
|
-
|
|
22035
|
-
|
|
22036
|
-
|
|
22037
|
-
|
|
22038
|
-
const
|
|
22039
|
-
|
|
22040
|
-
|
|
22041
|
-
|
|
22042
|
-
|
|
22043
|
-
planStmt,
|
|
22044
|
-
|
|
22045
|
-
cacheContext,
|
|
22046
|
-
maxRecords,
|
|
22047
|
-
relativeDatePlan
|
|
22048
|
-
);
|
|
22049
|
-
const statementPlan = relativeDatePlan.hasServerOnlyWhereFunction && !relativeDatePlan.allowed ? relativeDateExplainLines(relativeDatePlan) : [
|
|
22050
|
-
...relativeDateExplainLines(relativeDatePlan),
|
|
22051
|
-
...addCursorConcurrency(buildBatchStatementPlan(
|
|
22412
|
+
const invocationCacheContext = createInvocationCacheContext(cacheContext);
|
|
22413
|
+
try {
|
|
22414
|
+
const statements = parseSqlBatch(sql, enableImport);
|
|
22415
|
+
const analysis = analyzeBatch(statements);
|
|
22416
|
+
validateDeclaredBatchVariables(statements, injectedVariables);
|
|
22417
|
+
const variables = /* @__PURE__ */ new Map();
|
|
22418
|
+
const plans = [];
|
|
22419
|
+
for (let i = 0; i < statements.length; i++) {
|
|
22420
|
+
const stmt = statements[i];
|
|
22421
|
+
const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveBatchVariableReferences(stmt.expr, variables) } : stmt : resolveBatchVariableReferences(stmt, variables);
|
|
22422
|
+
validateKlikeStatement(planStmt);
|
|
22423
|
+
const relativeDatePlan = await resolveRelativeDateExecutionPlan(planStmt, client, invocationCacheContext);
|
|
22424
|
+
const whereAnalysis = await buildExplainWhereAnalysis(
|
|
22052
22425
|
planStmt,
|
|
22053
|
-
|
|
22054
|
-
|
|
22055
|
-
|
|
22056
|
-
|
|
22057
|
-
|
|
22058
|
-
)
|
|
22059
|
-
|
|
22060
|
-
|
|
22061
|
-
|
|
22062
|
-
|
|
22063
|
-
|
|
22064
|
-
|
|
22065
|
-
|
|
22066
|
-
|
|
22067
|
-
|
|
22426
|
+
client,
|
|
22427
|
+
invocationCacheContext,
|
|
22428
|
+
maxRecords,
|
|
22429
|
+
relativeDatePlan
|
|
22430
|
+
);
|
|
22431
|
+
const statementPlan = relativeDatePlan.hasServerOnlyWhereFunction && !relativeDatePlan.allowed ? relativeDateExplainLines(relativeDatePlan) : [
|
|
22432
|
+
...relativeDateExplainLines(relativeDatePlan),
|
|
22433
|
+
...addCursorConcurrency(buildBatchStatementPlan(
|
|
22434
|
+
planStmt,
|
|
22435
|
+
analysis.statements[i],
|
|
22436
|
+
whereAnalysis.capabilities,
|
|
22437
|
+
whereAnalysis.orderPlans,
|
|
22438
|
+
dmlMaxRows,
|
|
22439
|
+
dmlMaxSubtableRows
|
|
22440
|
+
), cursorMaxActive)
|
|
22441
|
+
];
|
|
22442
|
+
const metadataPlan = explainMetadataLines(whereAnalysis);
|
|
22443
|
+
plans.push({
|
|
22444
|
+
index: i,
|
|
22445
|
+
type: analysis.statements[i].statementType,
|
|
22446
|
+
plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
|
|
22447
|
+
});
|
|
22448
|
+
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
22449
|
+
variables.set(stmt.name, stmt.type === "SET_VARIABLE" && stmt.expr.type === "ARRAY" ? { type: "array", elements: stmt.expr.elements.map((element) => ({ type: "string", value: element.value })) } : { type: "string", value: `@${stmt.name}` });
|
|
22450
|
+
}
|
|
22068
22451
|
}
|
|
22452
|
+
return { statementCount: statements.length, statements: plans };
|
|
22453
|
+
} finally {
|
|
22454
|
+
releaseMetadataCacheScope(invocationCacheContext);
|
|
22069
22455
|
}
|
|
22070
|
-
return { statementCount: statements.length, statements: plans };
|
|
22071
22456
|
}
|
|
22072
22457
|
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS) {
|
|
22073
22458
|
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
@@ -22847,6 +23232,11 @@ function collectArithRefFields(stmt) {
|
|
|
22847
23232
|
return [...refs];
|
|
22848
23233
|
}
|
|
22849
23234
|
function collectArithNodeRefs(node, out) {
|
|
23235
|
+
if (node.type === "VARIABLE") {
|
|
23236
|
+
throw new Error(
|
|
23237
|
+
`InternalError: unresolved arithmetic variable @${node.name} reached CHECK field collection.`
|
|
23238
|
+
);
|
|
23239
|
+
}
|
|
22850
23240
|
if (node.type === "FIELD_REF") {
|
|
22851
23241
|
out.add(node.field);
|
|
22852
23242
|
return;
|
|
@@ -22942,6 +23332,11 @@ function formatArithExprStr(expr) {
|
|
|
22942
23332
|
return `${formatArithNodeStr(expr.left)} ${expr.op} ${formatArithNodeStr(expr.right)}`;
|
|
22943
23333
|
}
|
|
22944
23334
|
function formatArithNodeStr(node) {
|
|
23335
|
+
if (node.type === "VARIABLE") {
|
|
23336
|
+
throw new Error(
|
|
23337
|
+
`InternalError: unresolved arithmetic variable @${node.name} reached arithmetic formatting.`
|
|
23338
|
+
);
|
|
23339
|
+
}
|
|
22945
23340
|
if (node.type === "FIELD_REF") return node.field;
|
|
22946
23341
|
if (node.type === "NUMBER") return numberLiteralText(node);
|
|
22947
23342
|
if (node.type === "ARITH") return `(${formatArithExprStr(node)})`;
|