@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 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 collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
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 physicalTables) {
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 firstPhysicalTable = physicalTables[0] ?? null;
5353
- const subtableTable = physicalTables.find((t) => !!t.subtableCode) ?? null;
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 physicalTables) {
5389
+ for (const table of targetTables) {
5356
5390
  if (table.alias) aliasToTable.set(table.alias, table);
5357
- if (!table.subtableCode) {
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 markAllPhysicalTables = () => {
5370
- for (const t of physicalTables) markAll(t);
5405
+ const markAllTargetTables = () => {
5406
+ for (const t of targetTables) markAll(t);
5371
5407
  };
5372
5408
  const markAllSubtableTables = () => {
5373
- for (const t of physicalTables) {
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
- markAllPhysicalTables();
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?.cteName === null) {
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
- markAllPhysicalTables();
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.required === true || field.minValue !== void 0 || field.maxValue !== void 0 || field.minLength !== void 0 || field.maxLength !== void 0 || field.optionOrder !== void 0;
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 = resolveCacheContext(client, options.cacheContext);
15266
- const stmt = parseSql(sql, options.enableImport === true);
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
- metrics.elapsedMs = Date.now() - startedAt;
15282
- const finalResult = { ...attachSearchAbortWarning(result, collector), metrics };
15283
- if (result.type === "SELECT") {
15284
- const columnMeta = materializedMetaBySelectResult.get(result);
15285
- if (columnMeta) materializedMetaBySelectResult.set(finalResult, columnMeta);
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: { errorRecords: errorRecordIds.size, errorCount }
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 = resolveCacheContext(client, options.cacheContext);
15848
- const tempTables = /* @__PURE__ */ new Map();
15849
- const variables = /* @__PURE__ */ new Map();
15850
- const results = [];
15851
- const failed = /* @__PURE__ */ new Set();
15852
- let aborted = null;
15853
- for (let i = 0; i < statements.length; i++) {
15854
- const info = analysis.statements[i];
15855
- const base = { index: i, type: info.statementType };
15856
- if (aborted) {
15857
- results.push({ ...base, status: "skipped", skippedReason: aborted });
15858
- failed.add(i);
15859
- continue;
15860
- }
15861
- const brokenDep = info.dependsOn.find((d) => failed.has(d));
15862
- if (brokenDep !== void 0) {
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
- results.push({ ...base, status: "success", ...outcome });
15905
- } catch (e) {
15906
- results.push({
15907
- ...base,
15908
- status: "error",
15909
- error: toBatchStatementError(e),
15910
- ...e instanceof RejectLimitExceededError ? { result: e.diagnostic } : {}
15911
- });
15912
- failed.add(i);
15913
- if (e instanceof BatchTimeoutError) {
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
- } else if (e instanceof AssertError) {
15916
- aborted = "assertion";
15917
- } else if (info.statementType === "SET_VARIABLE" || info.statementType === "DECLARE_VARIABLE") {
15918
- aborted = "fail-fast";
15919
- } else if (!options.continueOnError) {
15920
- aborted = "fail-fast";
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) => resolveBatchVariableReferences(v, variables));
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]) => [key, resolveBatchVariableReferences(value, variables)])
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 statements = parseSqlBatch(sql, enableImport);
22033
- const analysis = analyzeBatch(statements);
22034
- validateDeclaredBatchVariables(statements, injectedVariables);
22035
- const variables = /* @__PURE__ */ new Map();
22036
- const plans = [];
22037
- for (let i = 0; i < statements.length; i++) {
22038
- const stmt = statements[i];
22039
- const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveBatchVariableReferences(stmt.expr, variables) } : stmt : resolveBatchVariableReferences(stmt, variables);
22040
- validateKlikeStatement(planStmt);
22041
- const relativeDatePlan = await resolveRelativeDateExecutionPlan(planStmt, client, cacheContext);
22042
- const whereAnalysis = await buildExplainWhereAnalysis(
22043
- planStmt,
22044
- client,
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
- analysis.statements[i],
22054
- whereAnalysis.capabilities,
22055
- whereAnalysis.orderPlans,
22056
- dmlMaxRows,
22057
- dmlMaxSubtableRows
22058
- ), cursorMaxActive)
22059
- ];
22060
- const metadataPlan = explainMetadataLines(whereAnalysis);
22061
- plans.push({
22062
- index: i,
22063
- type: analysis.statements[i].statementType,
22064
- plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
22065
- });
22066
- if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
22067
- 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}` });
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)})`;