@rex0220/kintone-sql-tools 3.71.0 → 3.73.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
@@ -4161,7 +4161,7 @@ var Parser = class {
4161
4161
  const values = [];
4162
4162
  do {
4163
4163
  this.expect("(" /* LPAREN */);
4164
- const row = this.parseInsertRow(fields.length);
4164
+ const row = this.parseInsertRow(fields.length, true);
4165
4165
  this.expect(")" /* RPAREN */);
4166
4166
  values.push(row);
4167
4167
  } while (this.consume("," /* COMMA */));
@@ -4222,7 +4222,7 @@ var Parser = class {
4222
4222
  const values = [];
4223
4223
  do {
4224
4224
  this.expect("(" /* LPAREN */);
4225
- values.push(this.parseInsertRow(fields.length));
4225
+ values.push(this.parseInsertRow(fields.length, false));
4226
4226
  this.expect(")" /* RPAREN */);
4227
4227
  } while (this.consume("," /* COMMA */));
4228
4228
  const keyFields = this.parseOnDuplicate();
@@ -4546,7 +4546,7 @@ var Parser = class {
4546
4546
  this.expect("]" /* RBRACKET */);
4547
4547
  return { type: "ARRAY", elements };
4548
4548
  }
4549
- parseInsertRow(expectedLen) {
4549
+ parseInsertRow(expectedLen, allowAsOf) {
4550
4550
  const row = [];
4551
4551
  do {
4552
4552
  if (this.peek().kind === "[" /* LBRACKET */) {
@@ -4567,8 +4567,11 @@ var Parser = class {
4567
4567
  row.push({ type: "STRING", value: tok.value });
4568
4568
  } else if (tok.kind === "NUMBER" /* NUMBER */) {
4569
4569
  row.push(makeNumberLiteral(tok.value));
4570
+ } else if (allowAsOf && this.isDialect1AsOfCall(tok)) {
4571
+ row.push(this.finishVariableReference(tok));
4570
4572
  } else {
4571
- throw new ParseError("INSERT \u306E\u5024\u306B\u306F\u6587\u5B57\u5217\u30FB\u6570\u5024\u30FB\u914D\u5217\u30EA\u30C6\u30E9\u30EB\u30FBCASE WHEN \u304C\u5FC5\u8981\u3067\u3059", tok);
4573
+ const hint = this.isDialect1AsOfCall(tok) ? " INSERT ... VALUES \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002\u3053\u306E\u6587\u578B\u3067\u306F INSERT ... SELECT \u3067\u6CE8\u5165\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : "";
4574
+ throw new ParseError(`INSERT \u306E\u5024\u306B\u306F\u6587\u5B57\u5217\u30FB\u6570\u5024\u30FB\u914D\u5217\u30EA\u30C6\u30E9\u30EB\u30FBCASE WHEN \u304C\u5FC5\u8981\u3067\u3059${hint}`, tok);
4572
4575
  }
4573
4576
  }
4574
4577
  } while (this.consume("," /* COMMA */));
@@ -4580,6 +4583,9 @@ var Parser = class {
4580
4583
  }
4581
4584
  return row;
4582
4585
  }
4586
+ isDialect1AsOfCall(tok) {
4587
+ return this.capabilities.dialect1 === true && tok.kind === "VARIABLE" /* VARIABLE */ && isAsOfFunctionName(tok.value.slice(1).toUpperCase()) && this.peek().kind === "(" /* LPAREN */ && this.peekAt(1).kind === ")" /* RPAREN */;
4588
+ }
4583
4589
  // ----------------------------------------------------------
4584
4590
  // UPDATE
4585
4591
  // ----------------------------------------------------------
@@ -4742,7 +4748,7 @@ var Parser = class {
4742
4748
  const values = [];
4743
4749
  do {
4744
4750
  this.expect("(" /* LPAREN */, "APPEND VALUES \u306E\u5404\u884C\u306F ( \u3067\u59CB\u3081\u3066\u304F\u3060\u3055\u3044");
4745
- values.push(this.parseInsertRow(fields.length));
4751
+ values.push(this.parseInsertRow(fields.length, false));
4746
4752
  this.expect(")" /* RPAREN */);
4747
4753
  } while (this.consume("," /* COMMA */));
4748
4754
  return { kind: "APPEND", fields, values };
@@ -18460,6 +18466,24 @@ var materializedMetaBySelectResult = /* @__PURE__ */ new WeakMap();
18460
18466
  var materializedMetaByValidationResult = /* @__PURE__ */ new WeakMap();
18461
18467
  var importSourceByDmlStatement = /* @__PURE__ */ new WeakMap();
18462
18468
  var statementEvaluationContextKey = /* @__PURE__ */ Symbol("statementEvaluationContext");
18469
+ var nativeUpsertExecutionKey = /* @__PURE__ */ Symbol("nativeUpsertExecution");
18470
+ var nativeUpsertExplainCapabilityKey = /* @__PURE__ */ Symbol("nativeUpsertExplainCapability");
18471
+ function withNativeUpsertExecutionOption(options, enabled, explainClientCapability) {
18472
+ return {
18473
+ ...options,
18474
+ [nativeUpsertExecutionKey]: enabled,
18475
+ ...explainClientCapability === void 0 ? {} : { [nativeUpsertExplainCapabilityKey]: explainClientCapability }
18476
+ };
18477
+ }
18478
+ function nativeUpsertExecutionEnabled(options) {
18479
+ return options[nativeUpsertExecutionKey] === true;
18480
+ }
18481
+ function hasNativeUpsertExecutionOption(options) {
18482
+ return nativeUpsertExecutionKey in options;
18483
+ }
18484
+ function nativeUpsertExplainClientCapability(options) {
18485
+ return options[nativeUpsertExplainCapabilityKey];
18486
+ }
18463
18487
  function bindStatementEvaluationContext(options) {
18464
18488
  const internal = options;
18465
18489
  if (internal[statementEvaluationContextKey]) return options;
@@ -18524,6 +18548,7 @@ function createEmptyMetrics() {
18524
18548
  getCalls: 0,
18525
18549
  postCalls: 0,
18526
18550
  putCalls: 0,
18551
+ nativeUpsertCalls: 0,
18527
18552
  deleteCalls: 0,
18528
18553
  fieldCalls: 0,
18529
18554
  numberPrecisionCalls: 0,
@@ -18552,7 +18577,7 @@ function markLimitReached(client, appId) {
18552
18577
  if (!metrics.limitReachedApps.includes(appId)) metrics.limitReachedApps.push(appId);
18553
18578
  }
18554
18579
  function wrapClientWithMetrics(client, metrics) {
18555
- return {
18580
+ const wrapped = {
18556
18581
  [LIMIT_METRICS_SINK]: metrics,
18557
18582
  getRecords: async (params) => {
18558
18583
  metrics.getCalls += 1;
@@ -18631,6 +18656,14 @@ function wrapClientWithMetrics(client, metrics) {
18631
18656
  return client.getProcessStatuses(appId);
18632
18657
  }
18633
18658
  };
18659
+ if (clientHasNativeUpsert(client)) {
18660
+ wrapped.upsertRecords = (params) => {
18661
+ metrics.putCalls += 1;
18662
+ metrics.nativeUpsertCalls += 1;
18663
+ return client.upsertRecords(params);
18664
+ };
18665
+ }
18666
+ return wrapped;
18634
18667
  }
18635
18668
  var SEARCH_ABORT_FAIL_CLOSED = /* @__PURE__ */ Symbol("searchAbortFailClosed");
18636
18669
  function wrapClientWithSearchAbort(client, collector, failClosed) {
@@ -18803,7 +18836,12 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
18803
18836
  relativeDatePlan,
18804
18837
  options.recursiveCteMaxDepth,
18805
18838
  options.recursiveCteMaxRows,
18806
- options.recursiveCteMaxExpansions
18839
+ options.recursiveCteMaxExpansions,
18840
+ hasNativeUpsertExecutionOption(options) ? {
18841
+ surface: "CLI",
18842
+ enableNativeUpsert: nativeUpsertExecutionEnabled(options),
18843
+ clientHasNativeUpsert: nativeUpsertExplainClientCapability(options) ?? clientHasNativeUpsert(client)
18844
+ } : { surface: "DOCUMENT_ONLY" }
18807
18845
  );
18808
18846
  // 一時テーブルはバッチスコープのため単文実行では拒否する(executeBatch を使う)
18809
18847
  case "CREATE_TEMP_TABLE":
@@ -19266,18 +19304,12 @@ async function executeBatchStatement(context) {
19266
19304
  cacheContext,
19267
19305
  tempTables
19268
19306
  );
19269
- const first = resolvedStmt2.expr.query.columns[0];
19270
- let numeric = first?.type === "ARITH_COL" || first?.type === "ARITH_AGG_COL" || first?.type === "WINDOW_COL" && (first.windowKind === void 0 || first.windowKind === "RANKING" || first.windowKind === "AGGREGATE" && (first.aggFunc === "COUNT" || first.aggFunc === "SUM" || first.aggFunc === "AVG")) || first?.type === "AGGREGATE" && (first.func === "COUNT" || first.func === "SUM" || first.func === "AVG" || first.func === "STDDEV_POP" || first.func === "STDDEV_SAMP" || first.func === "VAR_POP" || first.func === "VAR_SAMP" || first.func === "MEDIAN");
19271
- if (first?.type === "AGGREGATE" && first.func === "MODE" || first?.type === "WINDOW_COL" && first.windowKind === "VALUE" || first?.type === "WINDOW_COL" && first.windowKind === "AGGREGATE" && (first.aggFunc === "MIN" || first.aggFunc === "MAX")) {
19272
- const meta = (await inferSelectColumnMeta(
19273
- resolvedStmt2.expr.query,
19274
- ["__scalar__"],
19275
- client,
19276
- cacheContext,
19277
- tempTables
19278
- )).get("__scalar__");
19279
- numeric = meta?.semantics?.compareMode === "number" || meta?.sortKind === "number";
19280
- }
19307
+ const numeric = await scalarSubqueryHasNumericResult(
19308
+ resolvedStmt2.expr.query,
19309
+ client,
19310
+ cacheContext,
19311
+ tempTables
19312
+ );
19281
19313
  const numberValue = numeric ? Number(value) : Number.NaN;
19282
19314
  variables.set(stmt.name, numeric && Number.isFinite(numberValue) ? { type: "number", value: numberValue, raw: value } : { type: "string", value });
19283
19315
  } catch (e) {
@@ -19762,7 +19794,6 @@ async function executeExit(stmt, client, options, cacheContext, tempTables) {
19762
19794
  }
19763
19795
  async function evaluateAssertCondition(stmt, client, options, cacheContext, tempTables) {
19764
19796
  const left = await evalAssertOperand(stmt.left, client, options, cacheContext, tempTables);
19765
- const semantics = stmt.left.type === "NUMBER" || stmt.left.type === "ARITH" ? syntheticSemantics("number") : syntheticSemantics("string");
19766
19797
  if (stmt.op === "BETWEEN") {
19767
19798
  if (stmt.low === null || stmt.high === null) {
19768
19799
  throw new Error("ArgumentError: malformed ASSERT statement.");
@@ -19770,35 +19801,49 @@ async function evaluateAssertCondition(stmt, client, options, cacheContext, temp
19770
19801
  const low = await evalAssertOperand(stmt.low, client, options, cacheContext, tempTables);
19771
19802
  const high = await evalAssertOperand(stmt.high, client, options, cacheContext, tempTables);
19772
19803
  return {
19773
- passed: compareScalarValues(">=", left, low, semantics) && compareScalarValues("<=", left, high, semantics),
19774
- actual: left
19804
+ passed: compareScalarValues(">=", left.value, low.value, assertComparisonSemantics(left, low)) && compareScalarValues("<=", left.value, high.value, assertComparisonSemantics(left, high)),
19805
+ actual: left.value
19775
19806
  };
19776
19807
  }
19777
19808
  if (stmt.right === null) {
19778
19809
  throw new Error("ArgumentError: malformed ASSERT statement.");
19779
19810
  }
19780
19811
  const right = await evalAssertOperand(stmt.right, client, options, cacheContext, tempTables);
19781
- return { passed: compareScalarValues(stmt.op, left, right, semantics), actual: left };
19812
+ const semantics = stmt.op === "=" || stmt.op === "!=" || stmt.op === "<>" ? stmt.left.type === "NUMBER" || stmt.left.type === "ARITH" ? syntheticSemantics("number") : syntheticSemantics("string") : assertComparisonSemantics(left, right);
19813
+ return {
19814
+ passed: compareScalarValues(stmt.op, left.value, right.value, semantics),
19815
+ actual: left.value
19816
+ };
19817
+ }
19818
+ function assertComparisonSemantics(left, right) {
19819
+ return syntheticSemantics(left.semantics === "number" && right.semantics === "number" ? "number" : "string");
19782
19820
  }
19783
19821
  async function evalAssertOperand(operand, client, options, cacheContext, tempTables) {
19784
19822
  switch (operand.type) {
19785
19823
  case "VARIABLE":
19786
19824
  throw new Error(`ParseError: unresolved batch variable @${operand.name}.`);
19787
19825
  case "NUMBER":
19788
- return numberLiteralText(operand);
19826
+ return { value: numberLiteralText(operand), semantics: "number" };
19789
19827
  case "STRING":
19790
- return operand.value;
19828
+ return { value: operand.value, semantics: "string" };
19791
19829
  case "ARITH":
19792
- return String(evalAssertArith(operand));
19830
+ return { value: String(evalAssertArith(operand)), semantics: "number" };
19793
19831
  case "SCALAR_SUBQUERY": {
19794
19832
  try {
19795
- return await evaluateScalarSubquery(
19833
+ const value = await evaluateScalarSubquery(
19796
19834
  operand.query,
19797
19835
  client,
19798
19836
  options,
19799
19837
  cacheContext,
19800
19838
  tempTables
19801
19839
  );
19840
+ const numeric = await scalarSubqueryHasNumericResult(
19841
+ operand.query,
19842
+ client,
19843
+ cacheContext,
19844
+ tempTables
19845
+ );
19846
+ return { value, semantics: numeric ? "number" : "string" };
19802
19847
  } catch (e) {
19803
19848
  if (e instanceof ScalarSubqueryError) throw new AssertError(e.message);
19804
19849
  throw e;
@@ -19806,6 +19851,21 @@ async function evalAssertOperand(operand, client, options, cacheContext, tempTab
19806
19851
  }
19807
19852
  }
19808
19853
  }
19854
+ async function scalarSubqueryHasNumericResult(query, client, cacheContext, tempTables) {
19855
+ const first = query.columns[0];
19856
+ let numeric = first?.type === "ARITH_COL" || first?.type === "ARITH_AGG_COL" || first?.type === "WINDOW_COL" && (first.windowKind === void 0 || first.windowKind === "RANKING" || first.windowKind === "AGGREGATE" && (first.aggFunc === "COUNT" || first.aggFunc === "SUM" || first.aggFunc === "AVG")) || first?.type === "AGGREGATE" && (first.func === "COUNT" || first.func === "SUM" || first.func === "AVG" || first.func === "STDDEV_POP" || first.func === "STDDEV_SAMP" || first.func === "VAR_POP" || first.func === "VAR_SAMP" || first.func === "MEDIAN");
19857
+ if (first?.type === "AGGREGATE" && first.func === "MODE" || first?.type === "WINDOW_COL" && first.windowKind === "VALUE" || first?.type === "WINDOW_COL" && first.windowKind === "AGGREGATE" && (first.aggFunc === "MIN" || first.aggFunc === "MAX")) {
19858
+ const meta = (await inferSelectColumnMeta(
19859
+ query,
19860
+ ["__scalar__"],
19861
+ client,
19862
+ cacheContext,
19863
+ tempTables
19864
+ )).get("__scalar__");
19865
+ numeric = meta?.semantics?.compareMode === "number" || meta?.sortKind === "number";
19866
+ }
19867
+ return numeric;
19868
+ }
19809
19869
  async function evaluateScalarSubquery(sourceQuery, client, options, cacheContext, tempTables) {
19810
19870
  const { query, probed } = withScalarProbeLimit(sourceQuery);
19811
19871
  const result = await runSubquery(query, client, options, cacheContext, tempTables);
@@ -22785,6 +22845,206 @@ function upsertCompositeKey(parts) {
22785
22845
  function upsertNormalizedKey(parts, numericKey) {
22786
22846
  return JSON.stringify(parts.map((p, i) => numericKey[i] ? normalizeKeyPart(p) : p));
22787
22847
  }
22848
+ var NATIVE_UPSERT_CONDITION_NAMES = {
22849
+ 1: "CLIENT_CAPABILITY",
22850
+ 2: "OPT_IN",
22851
+ 3: "KEY_SCHEMA",
22852
+ 4: "PLAIN_UPSERT",
22853
+ 5: "EMPTY_KEY",
22854
+ 6: "SOURCE_DUPLICATE"
22855
+ };
22856
+ function nativeUpsertExplainReason(condition, unknown, surface, unknownConditions = []) {
22857
+ if (unknown) {
22858
+ if (condition === 1) return "\u901A\u5E38\u5B9F\u884C client \u306E native \u80FD\u529B\u304C\u4E0D\u660E";
22859
+ if (condition === 2) return "native \u8A2D\u5B9A\u304C\u4E0D\u660E";
22860
+ if (condition === 3) return "\u30D5\u30A9\u30FC\u30E0\u30E1\u30BF\u30C7\u30FC\u30BF\u672A\u53D6\u5F97";
22861
+ if (condition === 5 || unknownConditions.includes(5)) return "\u30BD\u30FC\u30B9\u884C\u672A materialize";
22862
+ if (condition === 6) return "\u30AD\u30FC\u578B\u60C5\u5831\u304C\u672A\u78BA\u5B9A\u306E\u305F\u3081\u91CD\u8907\u5224\u5B9A\u4E0D\u80FD";
22863
+ }
22864
+ if (condition === 1) return "client \u304C upsertRecords \u80FD\u529B\u3092\u6301\u305F\u306A\u3044";
22865
+ if (condition === 2) return surface === "CLI" ? "--native-upsert \u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u306A\u3044" : "enableNativeUpsert \u304C false";
22866
+ if (condition === 3) return "\u30AD\u30FC\u9805\u76EE\u306F\u91CD\u8907\u7981\u6B62\u306E SINGLE_LINE_TEXT \u307E\u305F\u306F NUMBER \u3067\u306F\u306A\u3044";
22867
+ if (condition === 4) return "CHECK / APPLY / IMPORT / VALIDATE ONLY / ON ERROR SKIP \u3092\u4F34\u3046\u7D20\u3067\u306A\u3044 UPSERT";
22868
+ if (condition === 5) return "\u30BD\u30FC\u30B9\u306B\u7A7A\u6587\u5B57\u30AD\u30FC\u304C\u3042\u308B";
22869
+ return "\u30BD\u30FC\u30B9\u5185\u306B\u540C\u4E00\u30AD\u30FC\u304C\u3042\u308B";
22870
+ }
22871
+ function renderNativeUpsertEligibilityResult(label, result, surface) {
22872
+ if (result.status === "ELIGIBLE") {
22873
+ return ` ${label}: ELIGIBLE\uFF08${label.includes("statement/data") ? "\u6761\u4EF6 3\u301C6 \u3092" : "6 \u6761\u4EF6\u3092\u3059\u3079\u3066"}\u6E80\u305F\u3059\uFF09`;
22874
+ }
22875
+ if (result.status === "INELIGIBLE") {
22876
+ return ` ${label}: INELIGIBLE\uFF08\u6761\u4EF6 ${result.condition}: ${NATIVE_UPSERT_CONDITION_NAMES[result.condition]} \u2014 ${nativeUpsertExplainReason(result.condition, false, surface)}\uFF09`;
22877
+ }
22878
+ const unknownConditionNumbers = result.unknownConditions.map(({ condition }) => condition);
22879
+ const details = result.unknownConditions.map(
22880
+ ({ condition }) => `\u6761\u4EF6 ${condition}: ${NATIVE_UPSERT_CONDITION_NAMES[condition]} \u2014 ${nativeUpsertExplainReason(condition, true, surface, unknownConditionNumbers)}`
22881
+ );
22882
+ return ` ${label}: UNKNOWN\uFF08${details.join("; ")}\uFF09`;
22883
+ }
22884
+ function renderNativeUpsertEligibility(evaluation, surface) {
22885
+ if (surface === "DOCUMENT_ONLY") {
22886
+ return [
22887
+ renderNativeUpsertEligibilityResult("native UPSERT statement/data eligibility", evaluation.statement, surface),
22888
+ ` native UPSERT execution surface: NOT_APPLICABLE\uFF08\u3053\u306E\u9762\u3067\u306F\u5B9F\u884C\u3057\u306A\u3044${evaluation.statement.status === "ELIGIBLE" ? "\u3002/flow \u307E\u305F\u306F CLI --native-upsert \u3067\u306F native \u5019\u88DC" : ""}\uFF09`
22889
+ ];
22890
+ }
22891
+ const lines = [renderNativeUpsertEligibilityResult("native UPSERT eligibility", evaluation.execution, surface)];
22892
+ if (evaluation.conditions[1].state === "FAIL" || evaluation.conditions[2].state === "FAIL") {
22893
+ lines.push(renderNativeUpsertEligibilityResult("native UPSERT statement/data eligibility", evaluation.statement, surface));
22894
+ }
22895
+ return lines;
22896
+ }
22897
+ function explainNativeUpsertStatement(statement) {
22898
+ const candidate = statement.type === "EXPLAIN" ? statement.query : statement;
22899
+ return candidate.type === "UPSERT" || candidate.type === "UPSERT_SELECT" ? candidate : null;
22900
+ }
22901
+ function nativeUpsertExplainEvaluation(statement, fieldInfos, options) {
22902
+ let rowKeyValues = null;
22903
+ if (statement.type === "UPSERT") {
22904
+ try {
22905
+ rowKeyValues = buildUpsertRowKeyValues(statement);
22906
+ } catch {
22907
+ }
22908
+ }
22909
+ return evaluateNativeUpsertEligibility({
22910
+ surface: options.surface === "DOCUMENT_ONLY" ? "DOCUMENT_ONLY" : "EXECUTION",
22911
+ clientCapability: options.surface === "DOCUMENT_ONLY" ? null : options.clientHasNativeUpsert ?? null,
22912
+ enabled: options.surface === "DOCUMENT_ONLY" ? null : options.surface === "FLOW" ? options.enableNativeUpsert !== false : options.enableNativeUpsert === true,
22913
+ statement: {
22914
+ kind: statement.type === "UPSERT" ? "VALUES" : "SELECT",
22915
+ keyFields: statement.keyFields,
22916
+ hasCheck: Boolean(statement.checkGroups?.length),
22917
+ hasApply: statement.type === "UPSERT" && Boolean(statement.onInsertApplyBlocks?.length || statement.onUpdateApplyBlocks?.length),
22918
+ validateOnly: statement.validateOnly === true,
22919
+ onErrorSkip: statement.onErrorSkip === true,
22920
+ importDerived: importSourceByDmlStatement.has(statement)
22921
+ },
22922
+ fieldInfos,
22923
+ rowKeyValues
22924
+ });
22925
+ }
22926
+ async function nativeUpsertExplainLines(statement, cacheContext, options) {
22927
+ const upsert = explainNativeUpsertStatement(statement);
22928
+ if (!upsert) return [];
22929
+ const fieldInfos = await getFieldsIfCached(upsert.appId, cacheContext);
22930
+ return renderNativeUpsertEligibility(
22931
+ nativeUpsertExplainEvaluation(upsert, fieldInfos, options),
22932
+ options.surface
22933
+ );
22934
+ }
22935
+ function evaluateNativeUpsertEligibility(input) {
22936
+ const keyField = input.statement.keyFields.length === 1 ? input.statement.keyFields[0] : void 0;
22937
+ const keyInfo = keyField === void 0 || input.fieldInfos === null ? void 0 : input.fieldInfos.find((field) => field.code === keyField);
22938
+ const supportedKeyType = keyInfo?.fieldType === "SINGLE_LINE_TEXT" || keyInfo?.fieldType === "NUMBER";
22939
+ const schemaPass = input.fieldInfos === null ? null : Boolean(
22940
+ keyField !== void 0 && keyInfo && supportedKeyType && keyInfo.isUnique === true
22941
+ );
22942
+ const plain = !input.statement.hasCheck && !input.statement.hasApply && !input.statement.validateOnly && !input.statement.onErrorSkip && !(input.statement.kind === "SELECT" && input.statement.importDerived);
22943
+ const rows = input.rowKeyValues;
22944
+ const noEmpty = rows === null ? null : rows.every((parts) => parts.every((part) => part !== ""));
22945
+ let noDuplicates = null;
22946
+ if (rows !== null && keyField !== void 0 && supportedKeyType) {
22947
+ const seen = /* @__PURE__ */ new Set();
22948
+ noDuplicates = true;
22949
+ for (const parts of rows) {
22950
+ const normalized = upsertNormalizedKey([...parts], [keyInfo.fieldType === "NUMBER"]);
22951
+ if (seen.has(normalized)) {
22952
+ noDuplicates = false;
22953
+ break;
22954
+ }
22955
+ seen.add(normalized);
22956
+ }
22957
+ }
22958
+ const state = (value, reason) => ({
22959
+ state: value === null ? "UNKNOWN" : value ? "PASS" : "FAIL",
22960
+ reason
22961
+ });
22962
+ const conditions = {
22963
+ 1: input.surface === "DOCUMENT_ONLY" ? { state: "NOT_APPLICABLE", reason: "client capability is not applicable on this surface" } : state(input.clientCapability, "client does not provide upsertRecords"),
22964
+ 2: input.surface === "DOCUMENT_ONLY" ? { state: "NOT_APPLICABLE", reason: "native setting is not applicable on this surface" } : state(input.enabled, "native UPSERT is disabled"),
22965
+ 3: state(schemaPass, "update key schema is not a single unique text or number field"),
22966
+ 4: state(plain, "statement is not a plain UPSERT"),
22967
+ 5: state(noEmpty, "source contains an empty update key"),
22968
+ 6: state(noDuplicates, "source contains duplicate update keys")
22969
+ };
22970
+ const summarize = (ordered) => {
22971
+ const failed = ordered.find((condition) => conditions[condition].state === "FAIL");
22972
+ if (failed !== void 0) return { status: "INELIGIBLE", condition: failed, reason: conditions[failed].reason };
22973
+ const unknownConditions = ordered.filter((condition) => conditions[condition].state === "UNKNOWN").map((condition) => ({ condition, reason: conditions[condition].reason }));
22974
+ return unknownConditions.length > 0 ? { status: "UNKNOWN", unknownConditions } : { status: "ELIGIBLE" };
22975
+ };
22976
+ return {
22977
+ conditions,
22978
+ execution: summarize([1, 2, 3, 4, 5, 6]),
22979
+ statement: summarize([3, 4, 5, 6])
22980
+ };
22981
+ }
22982
+ function clientHasNativeUpsert(client) {
22983
+ return "upsertRecords" in client && typeof client.upsertRecords === "function";
22984
+ }
22985
+ function nativeEligibilityInput(stmt, client, options, fieldInfos, rowKeyValues) {
22986
+ return {
22987
+ surface: "EXECUTION",
22988
+ clientCapability: clientHasNativeUpsert(client),
22989
+ enabled: nativeUpsertExecutionEnabled(options),
22990
+ statement: {
22991
+ kind: stmt.type === "UPSERT" ? "VALUES" : "SELECT",
22992
+ keyFields: stmt.keyFields,
22993
+ hasCheck: Boolean(stmt.checkGroups?.length),
22994
+ hasApply: stmt.type === "UPSERT" && Boolean(stmt.onInsertApplyBlocks?.length || stmt.onUpdateApplyBlocks?.length),
22995
+ validateOnly: stmt.validateOnly === true,
22996
+ onErrorSkip: stmt.onErrorSkip === true,
22997
+ importDerived: importSourceByDmlStatement.has(stmt)
22998
+ },
22999
+ fieldInfos,
23000
+ rowKeyValues
23001
+ };
23002
+ }
23003
+ var NativeUpsertResponseError = class extends Error {
23004
+ constructor() {
23005
+ super("NativeUpsertResponseError: upsertRecords returned an invalid response.");
23006
+ this.name = "NativeUpsertResponseError";
23007
+ }
23008
+ };
23009
+ function validateNativeUpsertResponse(response, expectedRecords) {
23010
+ if (!response || !Array.isArray(response.records) || response.records.length !== expectedRecords) {
23011
+ throw new NativeUpsertResponseError();
23012
+ }
23013
+ let insertedCount = 0;
23014
+ let updatedCount = 0;
23015
+ for (const record of response.records) {
23016
+ if (!record || typeof record.id !== "string" || typeof record.revision !== "string" || record.operation !== "INSERT" && record.operation !== "UPDATE") {
23017
+ throw new NativeUpsertResponseError();
23018
+ }
23019
+ if (record.operation === "INSERT") insertedCount += 1;
23020
+ else updatedCount += 1;
23021
+ }
23022
+ return { insertedCount, updatedCount };
23023
+ }
23024
+ async function executeNativeUpsertRecords(appId, keyField, records, rowKeyValues, client, options) {
23025
+ if (records.length === 0) return { type: "UPSERT", insertedCount: 0, updatedCount: 0 };
23026
+ if (options.confirm) {
23027
+ const ok = await options.confirm(records.length, "UPDATE");
23028
+ if (!ok) throw new OperationCancelledError("UPDATE", records.length);
23029
+ }
23030
+ let insertedCount = 0;
23031
+ let updatedCount = 0;
23032
+ for (let offset = 0; offset < records.length; offset += 100) {
23033
+ const nativeRecords = records.slice(offset, offset + 100).map((record, index) => {
23034
+ const payload = {};
23035
+ for (const [field, value] of Object.entries(record)) if (field !== keyField) payload[field] = value;
23036
+ return {
23037
+ updateKey: { field: keyField, value: rowKeyValues[offset + index][0] },
23038
+ record: payload
23039
+ };
23040
+ });
23041
+ const response = await client.upsertRecords({ app: appId, upsert: true, records: nativeRecords });
23042
+ const counts = validateNativeUpsertResponse(response, nativeRecords.length);
23043
+ insertedCount += counts.insertedCount;
23044
+ updatedCount += counts.updatedCount;
23045
+ }
23046
+ return { type: "UPSERT", insertedCount, updatedCount };
23047
+ }
22788
23048
  function lookupUpsertTarget(index, keyParts) {
22789
23049
  const exact = index.raw.get(upsertCompositeKey(keyParts));
22790
23050
  if (exact !== void 0) return exact;
@@ -23001,6 +23261,10 @@ async function getFieldsCached(appId, client, cacheContext) {
23001
23261
  setScopedCacheValue(fieldInfoCache, cacheContext, appId, loading);
23002
23262
  return loading;
23003
23263
  }
23264
+ async function getFieldsIfCached(appId, cacheContext) {
23265
+ const cached = getScopedCacheValue(fieldInfoCache, cacheContext, appId);
23266
+ return cached ? await cached : null;
23267
+ }
23004
23268
  async function getNumberPrecisionCached(appId, client, cacheContext) {
23005
23269
  const cached = getScopedCacheValue(numberPrecisionCache, cacheContext, appId);
23006
23270
  if (cached) return cached;
@@ -25568,6 +25832,16 @@ async function executeDelete(stmt, client, options, cacheContext) {
25568
25832
  }
25569
25833
  return { type: "DELETE", deletedCount: ids.length };
25570
25834
  }
25835
+ function materializeUpsertValueRecords(stmt, fieldTypes, options) {
25836
+ return stmt.values.map((row) => {
25837
+ const record = {};
25838
+ stmt.fields.forEach((field, index) => {
25839
+ const value = row[index];
25840
+ record[field] = { value: value.type === "CASE_VALUE" ? evalCaseWhenValue(value.expr, {}, fieldTypes.get(field), statementEvaluationContext(options)) : toKintoneValue(value, fieldTypes.get(field)) };
25841
+ });
25842
+ return record;
25843
+ });
25844
+ }
25571
25845
  async function executeUpsert(stmt, client, options, cacheContext) {
25572
25846
  if (stmt.onInsertApplyBlocks?.length || stmt.onUpdateApplyBlocks?.length) {
25573
25847
  return executeApplyUpsert(stmt, client, options, cacheContext);
@@ -25579,6 +25853,14 @@ async function executeUpsert(stmt, client, options, cacheContext) {
25579
25853
  const toUpdate = [];
25580
25854
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
25581
25855
  const rowKeyValues = buildUpsertRowKeyValues(stmt);
25856
+ const nativeEligibility = evaluateNativeUpsertEligibility(
25857
+ nativeEligibilityInput(stmt, client, options, fieldInfos, rowKeyValues)
25858
+ );
25859
+ if (nativeEligibility.execution.status === "ELIGIBLE") {
25860
+ const records = materializeUpsertValueRecords(stmt, fieldTypes, options);
25861
+ assertValidDmlRecords(records, stmt.fields, fieldInfos, numberPrecision);
25862
+ return executeNativeUpsertRecords(stmt.appId, stmt.keyFields[0], records, rowKeyValues, client, options);
25863
+ }
25582
25864
  const targetIndex = await resolveUpsertTargets(stmt.appId, stmt.keyFields, rowKeyValues, client, options, fieldTypes);
25583
25865
  stmt.values.forEach((row, rowIdx) => {
25584
25866
  const record = {};
@@ -25905,6 +26187,9 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
25905
26187
  };
25906
26188
  }
25907
26189
  function valueToString(value) {
26190
+ if (value.type === "VARIABLE") {
26191
+ throw new Error(`InternalError: unresolved variable @${value.name} reached INSERT evaluation.`);
26192
+ }
25908
26193
  if (value.type === "STRING") return value.value;
25909
26194
  if (value.type === "NUMBER") return numberLiteralText(value);
25910
26195
  if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, {});
@@ -26064,6 +26349,12 @@ async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache
26064
26349
  const rowKeyValues = records.map(
26065
26350
  (record) => stmt.keyFields.map((key) => String(record[key]?.value ?? ""))
26066
26351
  );
26352
+ const nativeEligibility = evaluateNativeUpsertEligibility(
26353
+ nativeEligibilityInput(stmt, client, options, fieldInfos, rowKeyValues)
26354
+ );
26355
+ if (nativeEligibility.execution.status === "ELIGIBLE") {
26356
+ return executeNativeUpsertRecords(stmt.appId, stmt.keyFields[0], records, rowKeyValues, client, options);
26357
+ }
26067
26358
  if (importSourceByDmlStatement.has(stmt)) {
26068
26359
  const numericKey = stmt.keyFields.map((key) => fieldTypes.get(key) === "NUMBER");
26069
26360
  const sourceKeys = /* @__PURE__ */ new Set();
@@ -27115,7 +27406,7 @@ var EXPLAIN_FETCH_PLAN = /* @__PURE__ */ Symbol("ksql.explainFetchPlan");
27115
27406
  function setExplainFetchPlan(result, plan) {
27116
27407
  result[EXPLAIN_FETCH_PLAN] = plan;
27117
27408
  }
27118
- async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, resolveMetadata = true, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions, asOf, timezone) {
27409
+ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, resolveMetadata = true, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions, asOf, timezone, nativeUpsertOptions = { surface: "DOCUMENT_ONLY" }) {
27119
27410
  const asOfClock = createAsOfClock(asOf ?? /* @__PURE__ */ new Date(), timezone);
27120
27411
  const recursiveLimits = resolveRecursiveCteLimits({
27121
27412
  recursiveCteMaxDepth,
@@ -27214,10 +27505,15 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
27214
27505
  maxRecords,
27215
27506
  dmlMaxRows
27216
27507
  ) : [];
27508
+ const nativeUpsertPlan = await nativeUpsertExplainLines(
27509
+ planStmt,
27510
+ invocationCacheContext,
27511
+ nativeUpsertOptions
27512
+ );
27217
27513
  plans.push({
27218
27514
  index: i,
27219
27515
  type: analysis.statements[i].statementType,
27220
- plan: statementPlan.length === 0 ? [...metadataPlan, ...dialect1Estimate] : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1), ...dialect1Estimate]
27516
+ plan: statementPlan.length === 0 ? [...metadataPlan, ...nativeUpsertPlan, ...dialect1Estimate] : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1), ...nativeUpsertPlan, ...dialect1Estimate]
27221
27517
  });
27222
27518
  fetchStatements.push({
27223
27519
  index: i,
@@ -27531,7 +27827,7 @@ var explainMaterializedTables = /* @__PURE__ */ new WeakMap();
27531
27827
  function defaultRecursiveExplainContext() {
27532
27828
  return { maxRecords: 1e4, recursiveLimits: resolveRecursiveCteLimits({}) };
27533
27829
  }
27534
- async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxActive, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, relativeDatePlan, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions) {
27830
+ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxActive, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, relativeDatePlan, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions, nativeUpsertOptions = { surface: "DOCUMENT_ONLY" }) {
27535
27831
  const recursiveLimits = resolveRecursiveCteLimits({
27536
27832
  recursiveCteMaxDepth,
27537
27833
  recursiveCteMaxRows,
@@ -27569,7 +27865,8 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
27569
27865
  cursorMaxActive
27570
27866
  )
27571
27867
  ];
27572
- const lines = addFetchSummary(planLines, fetchCollector.sources);
27868
+ const nativeUpsertPlan = await nativeUpsertExplainLines(stmt, cacheContext, nativeUpsertOptions);
27869
+ const lines = addFetchSummary([...planLines, ...nativeUpsertPlan], fetchCollector.sources);
27573
27870
  const result = {
27574
27871
  type: "SELECT",
27575
27872
  columns: ["plan"],
@@ -29492,7 +29789,7 @@ var RequestGate = class {
29492
29789
  }
29493
29790
  };
29494
29791
  function withRequestGate(client, gate) {
29495
- return {
29792
+ const wrapped = {
29496
29793
  getRecords: (params) => gate.runReadOnly(() => client.getRecords(params)),
29497
29794
  openCursor: async (params) => {
29498
29795
  const handle = await gate.runCursorStep(() => client.openCursor(params));
@@ -29510,6 +29807,10 @@ function withRequestGate(client, gate) {
29510
29807
  putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
29511
29808
  deleteRecords: (params) => gate.runMutation(() => client.deleteRecords(params))
29512
29809
  };
29810
+ if ("upsertRecords" in client && typeof client.upsertRecords === "function") {
29811
+ wrapped.upsertRecords = (params) => gate.runMutation(() => client.upsertRecords(params));
29812
+ }
29813
+ return wrapped;
29513
29814
  }
29514
29815
  var globalGate = null;
29515
29816
  function getGlobalRequestGate(options) {
@@ -30266,6 +30567,16 @@ function createNodeKintoneConnection(baseUrl, tokenResolver) {
30266
30567
  _params.app
30267
30568
  );
30268
30569
  },
30570
+ async upsertRecords(_params) {
30571
+ return requestJson(
30572
+ `${apiBasePath}/records.json`,
30573
+ {
30574
+ method: "PUT",
30575
+ body: JSON.stringify({ app: _params.app, upsert: true, records: _params.records })
30576
+ },
30577
+ _params.app
30578
+ );
30579
+ },
30269
30580
  async deleteRecords(_params) {
30270
30581
  await requestJson(
30271
30582
  `${apiBasePath}/records.json`,
@@ -30665,6 +30976,9 @@ var CLI_HELP_TEXT = HELP_TEXT.replace(
30665
30976
  " --max-records <n> Max records to fetch (default: 500)",
30666
30977
  ` --max-records <n> Max records to fetch (default: 500)
30667
30978
  ${RECURSIVE_CTE_HELP_LINES}`
30979
+ ).replace(
30980
+ " --allow-dml Enable UPDATE/DELETE/INSERT/UPSERT/REORDER execution",
30981
+ " --allow-dml Enable UPDATE/DELETE/INSERT/UPSERT/REORDER execution\n --native-upsert Allow eligible plain UPSERT to use kintone native UPSERT"
30668
30982
  );
30669
30983
  var CLI_IMPORT_SOURCE_REQUIRED_MESSAGE = "IMPORT \u306B\u306F\u30BD\u30FC\u30B9\u304C\u5FC5\u8981\u3067\u3059\u3002--import-csv <name=path> \u307E\u305F\u306F --import-json <name=path> \u3067\u30D5\u30A1\u30A4\u30EB\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
30670
30984
  function toCliImportError(error, importEnabled) {
@@ -30716,6 +31030,7 @@ function parseArgs(argv) {
30716
31030
  debugHeaders: false,
30717
31031
  exitOnEmpty: false,
30718
31032
  allowDml: false,
31033
+ nativeUpsert: false,
30719
31034
  yes: false,
30720
31035
  allowWithoutWhere: false,
30721
31036
  continueOnError: false,
@@ -30788,6 +31103,10 @@ function parseArgs(argv) {
30788
31103
  out.allowDml = true;
30789
31104
  continue;
30790
31105
  }
31106
+ if (a === "--native-upsert") {
31107
+ out.nativeUpsert = true;
31108
+ continue;
31109
+ }
30791
31110
  if (a === "--yes") {
30792
31111
  out.yes = true;
30793
31112
  continue;
@@ -31625,6 +31944,7 @@ function buildReplExecArgv(base, sql, dryRun, format) {
31625
31944
  if (base.exitOnEmpty) argv.push("--exit-on-empty");
31626
31945
  if (base.allowDml) argv.push("--yes");
31627
31946
  if (base.allowDml) argv.push("--allow-dml");
31947
+ if (base.nativeUpsert) argv.push("--native-upsert");
31628
31948
  if (base.allowWithoutWhere) argv.push("--allow-without-where");
31629
31949
  if (base.continueOnError) argv.push("--continue-on-error");
31630
31950
  return argv;
@@ -31801,7 +32121,8 @@ async function runConsole(base) {
31801
32121
  ` auth=${base.auth ?? "(auto)"}`,
31802
32122
  ` format=${format ?? "(default)"}`,
31803
32123
  ` dryrun=${dryRun ? "on" : "off"}`,
31804
- ` allow-dml=${base.allowDml ? "on" : "off"}`
32124
+ ` allow-dml=${base.allowDml ? "on" : "off"}`,
32125
+ ` native-upsert=${base.nativeUpsert ? "on" : "off"}`
31805
32126
  ].join("\n") + "\n"
31806
32127
  );
31807
32128
  try {
@@ -31932,6 +32253,7 @@ async function runConsole(base) {
31932
32253
  `app=${base.app ?? "(from SQL or config)"}`,
31933
32254
  `resolved-app-profiles=${lastResolvedProfiles}`,
31934
32255
  `allow-dml=${base.allowDml ? "on" : "off"}`,
32256
+ `native-upsert=${base.nativeUpsert ? "on" : "off"}`,
31935
32257
  `dml-max-rows=${base.dmlMaxRows ?? "(default)"}`,
31936
32258
  `dml-max-subtable-rows=${base.dmlMaxSubtableRows ?? "(default)"}`
31937
32259
  ];
@@ -32514,6 +32836,14 @@ async function run() {
32514
32836
  if (!routed) throw new Error(`AuthError: profile "${pName}" is not resolved for APP${params.app}.`);
32515
32837
  return routed.putRecords({ ...params, app: binding.appId });
32516
32838
  },
32839
+ upsertRecords: (params) => {
32840
+ const binding = appBindingByMappedApp.get(params.app) ?? { appId: params.app, profile: profileName.toLowerCase() };
32841
+ const routed = profileClientMap.get(binding.profile);
32842
+ if (!routed || typeof routed.upsertRecords !== "function") {
32843
+ throw new Error(`AuthError: native UPSERT client is not resolved for APP${params.app}.`);
32844
+ }
32845
+ return routed.upsertRecords({ ...params, app: binding.appId });
32846
+ },
32517
32847
  deleteRecords: (params) => {
32518
32848
  const binding = appBindingByMappedApp.get(params.app) ?? { appId: params.app, profile: profileName.toLowerCase() };
32519
32849
  const pName = binding.profile;
@@ -32567,7 +32897,14 @@ async function run() {
32567
32897
  !dryRunUsesStaticTypedPlan,
32568
32898
  recursiveCteMaxDepth,
32569
32899
  recursiveCteMaxRows,
32570
- recursiveCteMaxExpansions
32900
+ recursiveCteMaxExpansions,
32901
+ void 0,
32902
+ void 0,
32903
+ {
32904
+ surface: "CLI",
32905
+ enableNativeUpsert: args.nativeUpsert,
32906
+ clientHasNativeUpsert: true
32907
+ }
32571
32908
  );
32572
32909
  const out = [];
32573
32910
  const restoredStatements = sqlDiagnosticContext ? restoreSqlDiagnosticValue(plans.statements, sqlDiagnosticContext.appBindingByMappedApp) : plans.statements;
@@ -32648,7 +32985,7 @@ query=${label}`);
32648
32985
  return 2;
32649
32986
  }
32650
32987
  }
32651
- let batchResult = await executeBatch(sql, client, {
32988
+ let batchResult = await executeBatch(sql, client, withNativeUpsertExecutionOption({
32652
32989
  maxRecords,
32653
32990
  fetchParallel,
32654
32991
  onLimitReached: effectiveOnLimit,
@@ -32686,7 +33023,7 @@ query=${label}`);
32686
33023
  }
32687
33024
  return true;
32688
33025
  } : void 0
32689
- });
33026
+ }, args.nativeUpsert, true));
32690
33027
  if (sqlDiagnosticContext) {
32691
33028
  batchResult = {
32692
33029
  ...batchResult,
@@ -32703,7 +33040,7 @@ query=${label}`);
32703
33040
  }
32704
33041
  return writeBatchOutput(batchResult, { format, noHeader, pretty, displayOptions, outputPath, quiet });
32705
33042
  }
32706
- let result = args.dryRun ? await execute(`EXPLAIN ${sql}`, client, {
33043
+ let result = args.dryRun ? await execute(`EXPLAIN ${sql}`, client, withNativeUpsertExecutionOption({
32707
33044
  maxRecords,
32708
33045
  onLimitReached: onLimit,
32709
33046
  cacheContext,
@@ -32715,7 +33052,7 @@ query=${label}`);
32715
33052
  recursiveCteMaxDepth,
32716
33053
  recursiveCteMaxRows,
32717
33054
  recursiveCteMaxExpansions
32718
- }) : await execute(sql, client, {
33055
+ }, args.nativeUpsert, true)) : await execute(sql, client, withNativeUpsertExecutionOption({
32719
33056
  maxRecords,
32720
33057
  fetchParallel,
32721
33058
  onLimitReached: effectiveOnLimit,
@@ -32733,7 +33070,7 @@ query=${label}`);
32733
33070
  dmlMaxSubtableRows
32734
33071
  } : {},
32735
33072
  ...containsApplyMutation ? { allowApplyMutation: true } : {}
32736
- });
33073
+ }, args.nativeUpsert, true));
32737
33074
  if ((args.dryRun || parsedStatements[0]?.type === "EXPLAIN") && sqlDiagnosticContext) {
32738
33075
  result = restoreSqlDiagnosticValue(result, sqlDiagnosticContext.appBindingByMappedApp);
32739
33076
  }