@rex0220/kintone-sql-tools 2.17.0 → 3.0.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.
@@ -30990,6 +30990,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
30990
30990
  ["BY", "BY" /* BY */],
30991
30991
  ["HAVING", "HAVING" /* HAVING */],
30992
30992
  ["ORDER", "ORDER" /* ORDER */],
30993
+ ["KORDER", "KORDER" /* KORDER */],
30993
30994
  ["ASC", "ASC" /* ASC */],
30994
30995
  ["DESC", "DESC" /* DESC */],
30995
30996
  ["LIMIT", "LIMIT" /* LIMIT */],
@@ -31515,7 +31516,7 @@ var Parser = class {
31515
31516
  case "WITH" /* WITH */:
31516
31517
  return this.parseWith();
31517
31518
  case "SELECT" /* SELECT */:
31518
- return this.tryParseUnionChain(this.parseSelect());
31519
+ return this.tryParseUnionChain(this.parseSelect(true));
31519
31520
  case "INSERT" /* INSERT */:
31520
31521
  return this.parseInsert();
31521
31522
  case "UPDATE" /* UPDATE */:
@@ -31705,7 +31706,7 @@ var Parser = class {
31705
31706
  }
31706
31707
  query = w;
31707
31708
  } else if (tok.kind === "SELECT" /* SELECT */) {
31708
- const sel = this.parseSelect();
31709
+ const sel = this.parseSelect(true);
31709
31710
  const chained = this.tryParseUnionChain(sel);
31710
31711
  query = chained;
31711
31712
  } else if (tok.kind === "INSERT" /* INSERT */) {
@@ -31898,7 +31899,7 @@ var Parser = class {
31898
31899
  // ----------------------------------------------------------
31899
31900
  // SELECT
31900
31901
  // ----------------------------------------------------------
31901
- parseSelect() {
31902
+ parseSelect(allowKorder = false) {
31902
31903
  this.expect("SELECT" /* SELECT */);
31903
31904
  const distinct = this.consume("DISTINCT" /* DISTINCT */);
31904
31905
  const columns = this.parseSelectColumns();
@@ -31915,7 +31916,19 @@ var Parser = class {
31915
31916
  having = this.parseWhereExpr();
31916
31917
  }
31917
31918
  }
31918
- const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy()) : [];
31919
+ let orderMode = "CANONICAL";
31920
+ let orderBy = [];
31921
+ if (this.consume("ORDER" /* ORDER */)) {
31922
+ this.expect("BY" /* BY */);
31923
+ orderBy = this.parseOrderBy();
31924
+ } else if (this.consume("KORDER" /* KORDER */)) {
31925
+ if (!allowKorder) {
31926
+ throw new ParseError("KORDER BY \u306F\u5229\u7528\u8005\u3078\u7D50\u679C\u3092\u8FD4\u3059\u30C8\u30C3\u30D7\u30EC\u30D9\u30EB SELECT \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059", this.prev());
31927
+ }
31928
+ orderMode = "KINTONE_NATIVE";
31929
+ this.expect("BY" /* BY */);
31930
+ orderBy = this.parseOrderBy();
31931
+ }
31919
31932
  const limit = this.consume("LIMIT" /* LIMIT */) ? this.parseUnsignedInt() : null;
31920
31933
  const offset = this.consume("OFFSET" /* OFFSET */) ? this.parseUnsignedInt() : null;
31921
31934
  const hasWindow = columns.some((column) => column.type === "WINDOW_COL");
@@ -31932,6 +31945,7 @@ var Parser = class {
31932
31945
  where,
31933
31946
  groupBy,
31934
31947
  having,
31948
+ orderMode,
31935
31949
  orderBy,
31936
31950
  limit,
31937
31951
  offset
@@ -31969,6 +31983,9 @@ var Parser = class {
31969
31983
  // ----------------------------------------------------------
31970
31984
  tryParseUnionChain(left) {
31971
31985
  if (this.peek().kind !== "UNION" /* UNION */) return left;
31986
+ if (left.type === "SELECT" && left.orderMode === "KINTONE_NATIVE") {
31987
+ throw new ParseError("KORDER BY \u306F UNION \u5206\u5C90\u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
31988
+ }
31972
31989
  this.advance();
31973
31990
  const all = this.consume("ALL" /* ALL */);
31974
31991
  const right = this.parseSelect();
@@ -33622,7 +33639,50 @@ function isReadOnlyStatement(stmt) {
33622
33639
  return !writesKintone(stmt) && (isReadOnlyType(stmt.type) || isDmlType(stmt.type));
33623
33640
  }
33624
33641
  function requiresCompleteInput(stmt) {
33625
- return isDmlType(stmt.type);
33642
+ if (isDmlType(stmt.type)) return true;
33643
+ switch (stmt.type) {
33644
+ case "SELECT":
33645
+ return selectRequiresCompleteInput(stmt);
33646
+ case "UNION":
33647
+ return unionRequiresCompleteInput(stmt);
33648
+ case "WITH":
33649
+ return stmt.ctes.some(
33650
+ (cte) => cte.query.type === "SELECT" && selectRequiresCompleteInput(cte.query) || cte.query.type === "UNION" && unionRequiresCompleteInput(cte.query)
33651
+ ) || (stmt.query.type === "SELECT" ? selectRequiresCompleteInput(stmt.query) : unionRequiresCompleteInput(stmt.query));
33652
+ case "CREATE_TEMP_TABLE":
33653
+ return stmt.query.type === "SELECT" ? selectRequiresCompleteInput(stmt.query) : stmt.query.type === "UNION" ? unionRequiresCompleteInput(stmt.query) : requiresCompleteInput(stmt.query);
33654
+ default:
33655
+ return false;
33656
+ }
33657
+ }
33658
+ function unionRequiresCompleteInput(stmt) {
33659
+ const left = stmt.left.type === "SELECT" ? selectRequiresCompleteInput(stmt.left) : unionRequiresCompleteInput(stmt.left);
33660
+ return left || selectRequiresCompleteInput(stmt.right);
33661
+ }
33662
+ function selectRequiresCompleteInput(stmt) {
33663
+ if (stmt.orderBy.length > 0) return true;
33664
+ if (stmt.columns.some(
33665
+ (column) => column.type === "WINDOW_COL" && column.orderBy.length > 0 || column.type === "SCALAR_SUBQUERY_COL" && selectRequiresCompleteInput(column.query) || column.type === "CASE_COL" && column.expr.branches.some(
33666
+ (branch) => whereRequiresCompleteInput(branch.condition)
33667
+ )
33668
+ )) return true;
33669
+ return whereRequiresCompleteInput(stmt.where) || whereRequiresCompleteInput(stmt.having);
33670
+ }
33671
+ function whereRequiresCompleteInput(where) {
33672
+ if (where === null) return false;
33673
+ switch (where.type) {
33674
+ case "BINARY":
33675
+ return (where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY") && selectRequiresCompleteInput(where.right.query);
33676
+ case "LOGICAL":
33677
+ return whereRequiresCompleteInput(where.left) || whereRequiresCompleteInput(where.right);
33678
+ case "NOT":
33679
+ case "GROUP":
33680
+ return whereRequiresCompleteInput(where.expr);
33681
+ case "EXISTS":
33682
+ return selectRequiresCompleteInput(where.query);
33683
+ case "NULL_CHECK":
33684
+ return false;
33685
+ }
33626
33686
  }
33627
33687
  function hasWhereClause(stmt) {
33628
33688
  if (!stmt || typeof stmt !== "object") return false;
@@ -34425,6 +34485,7 @@ function buildInlinedQuery(stmt) {
34425
34485
  where,
34426
34486
  groupBy: [],
34427
34487
  having: null,
34488
+ orderMode: "CANONICAL",
34428
34489
  orderBy: final.orderBy.length > 0 ? final.orderBy : cteBody.orderBy,
34429
34490
  limit: final.limit ?? cteBody.limit,
34430
34491
  offset: final.offset ?? cteBody.offset,
@@ -35019,6 +35080,72 @@ function analyzeBatch(statements) {
35019
35080
  };
35020
35081
  }
35021
35082
 
35083
+ // src/core/fieldSemantics.ts
35084
+ var STRING_FIELD_TYPES = /* @__PURE__ */ new Set([
35085
+ "SINGLE_LINE_TEXT",
35086
+ "MULTI_LINE_TEXT",
35087
+ "RICH_TEXT",
35088
+ "LINK",
35089
+ "DATE",
35090
+ "TIME",
35091
+ "DATETIME",
35092
+ "CREATED_TIME",
35093
+ "UPDATED_TIME",
35094
+ "CREATOR",
35095
+ "MODIFIER"
35096
+ ]);
35097
+ var OPTION_FIELD_TYPES = /* @__PURE__ */ new Set([
35098
+ "DROP_DOWN",
35099
+ "RADIO_BUTTON",
35100
+ "CHECK_BOX",
35101
+ "MULTI_SELECT",
35102
+ "STATUS"
35103
+ ]);
35104
+ function resolveFieldSemantics(source) {
35105
+ let compareMode;
35106
+ if (source.fieldType === "RECORD_NUMBER" || source.fieldType === "__ID__") {
35107
+ compareMode = "recordNumber";
35108
+ } else if (source.fieldType === "NUMBER") {
35109
+ compareMode = "number";
35110
+ } else if (source.fieldType === "CALC") {
35111
+ compareMode = source.sortKind === "number" ? "number" : "string";
35112
+ } else if (OPTION_FIELD_TYPES.has(source.fieldType)) {
35113
+ compareMode = "option";
35114
+ } else if (STRING_FIELD_TYPES.has(source.fieldType)) {
35115
+ compareMode = "string";
35116
+ } else {
35117
+ compareMode = "unsupported";
35118
+ }
35119
+ const optionOrder = source.optionOrder ? new Map(Object.entries(source.optionOrder)) : void 0;
35120
+ return {
35121
+ fieldType: source.fieldType,
35122
+ compareMode,
35123
+ inSubtable: source.inSubtable === true,
35124
+ requiresCollectionOperators: source.inSubtable === true || source.requiresCollectionOperators === true,
35125
+ ...optionOrder && optionOrder.size > 0 ? { optionOrder } : {}
35126
+ };
35127
+ }
35128
+ function syntheticSemantics(compareMode, fieldType = compareMode === "number" ? "KSQL_NUMBER" : "KSQL_STRING") {
35129
+ return { fieldType, compareMode, inSubtable: false, requiresCollectionOperators: false };
35130
+ }
35131
+ function withFieldSemanticSource(semantics, appId, fieldCode) {
35132
+ return { ...semantics, source: { appId, fieldCode } };
35133
+ }
35134
+ function fieldSemanticsEqual(left, right) {
35135
+ if (left === right) return true;
35136
+ if (!left || !right) return false;
35137
+ if (left.fieldType !== right.fieldType || left.compareMode !== right.compareMode || left.inSubtable !== right.inSubtable || left.requiresCollectionOperators !== right.requiresCollectionOperators) return false;
35138
+ if (left.source?.appId !== right.source?.appId || left.source?.fieldCode !== right.source?.fieldCode) return false;
35139
+ const a = left.optionOrder;
35140
+ const b = right.optionOrder;
35141
+ if (a === b) return true;
35142
+ if (!a || !b || a.size !== b.size) return false;
35143
+ for (const [key, value] of a) {
35144
+ if (b.get(key) !== value) return false;
35145
+ }
35146
+ return true;
35147
+ }
35148
+
35022
35149
  // src/core/batchVariables.ts
35023
35150
  var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
35024
35151
  function normalizeBatchVariableName(name) {
@@ -35054,24 +35181,129 @@ function validateDeclaredBatchVariables(statements, input) {
35054
35181
  }
35055
35182
 
35056
35183
  // src/core/scalarCompare.ts
35057
- function compareScalarValues(op, leftStr, rightStr) {
35058
- if (op === "=") return leftStr === rightStr;
35059
- if (op === "!=" || op === "<>") return leftStr !== rightStr;
35060
- const rightNum = Number(rightStr);
35061
- if (leftStr === "" && rightStr !== "" && Number.isFinite(rightNum)) {
35062
- return op === "<" || op === "<=";
35063
- }
35064
- const leftNum = Number(leftStr);
35065
- const numeric = !Number.isNaN(leftNum) && !Number.isNaN(rightNum);
35184
+ function compareCodePointStrings(left, right) {
35185
+ const a = left[Symbol.iterator]();
35186
+ const b = right[Symbol.iterator]();
35187
+ while (true) {
35188
+ const av = a.next();
35189
+ const bv = b.next();
35190
+ if (av.done || bv.done) {
35191
+ if (av.done && bv.done) return 0;
35192
+ return av.done ? -1 : 1;
35193
+ }
35194
+ const ac = av.value.codePointAt(0) ?? 0;
35195
+ const bc = bv.value.codePointAt(0) ?? 0;
35196
+ if (ac < bc) return -1;
35197
+ if (ac > bc) return 1;
35198
+ }
35199
+ }
35200
+ function triCompare(left, right) {
35201
+ return left < right ? -1 : left > right ? 1 : 0;
35202
+ }
35203
+ function numberKey(value) {
35204
+ if (value === "") return { band: 0 };
35205
+ const numeric = Number(value);
35206
+ if (numeric === Number.NEGATIVE_INFINITY) return { band: 1 };
35207
+ if (Number.isFinite(numeric)) return { band: 2, value: numeric };
35208
+ if (numeric === Number.POSITIVE_INFINITY) return { band: 3 };
35209
+ if (value === "NaN") return { band: 4 };
35210
+ return { band: 5, value };
35211
+ }
35212
+ function compareNumbers(left, right) {
35213
+ const a = numberKey(left);
35214
+ const b = numberKey(right);
35215
+ if (a.band !== b.band) return a.band < b.band ? -1 : 1;
35216
+ if (a.band === 2 && b.band === 2) return triCompare(a.value, b.value);
35217
+ if (a.band === 5 && b.band === 5) return compareCodePointStrings(a.value, b.value);
35218
+ return 0;
35219
+ }
35220
+ function recordNumberKey(value, allowPrefix) {
35221
+ if (value === "") return { empty: true, normalizedId: "", display: value };
35222
+ const match = /^\d+$/.test(value) ? value : allowPrefix ? /-(\d+)$/.exec(value)?.[1] : void 0;
35223
+ if (match === void 0) {
35224
+ throw new Error(`ArgumentError: invalid ${allowPrefix ? "RECORD_NUMBER" : "$id"} value: ${value}`);
35225
+ }
35226
+ return {
35227
+ empty: false,
35228
+ normalizedId: match.replace(/^0+(?=\d)/, ""),
35229
+ display: value
35230
+ };
35231
+ }
35232
+ function compareRecordNumbers(left, right, allowPrefix) {
35233
+ const a = recordNumberKey(left, allowPrefix);
35234
+ const b = recordNumberKey(right, allowPrefix);
35235
+ if (a.empty || b.empty) return a.empty === b.empty ? 0 : a.empty ? -1 : 1;
35236
+ if (a.normalizedId.length !== b.normalizedId.length) {
35237
+ return a.normalizedId.length < b.normalizedId.length ? -1 : 1;
35238
+ }
35239
+ const idCmp = compareCodePointStrings(a.normalizedId, b.normalizedId);
35240
+ return idCmp !== 0 ? idCmp : compareCodePointStrings(a.display, b.display);
35241
+ }
35242
+ function parseOptionValues(value, fieldType) {
35243
+ if (value === "") return [];
35244
+ if (fieldType !== "CHECK_BOX" && fieldType !== "MULTI_SELECT") return [value];
35245
+ try {
35246
+ const parsed = JSON.parse(value);
35247
+ return Array.isArray(parsed) ? parsed.map((item) => String(item ?? "")) : [value];
35248
+ } catch {
35249
+ return [value];
35250
+ }
35251
+ }
35252
+ function optionVector(value, semantics) {
35253
+ const order = semantics.optionOrder ?? /* @__PURE__ */ new Map();
35254
+ const unique = [...new Set(parseOptionValues(value, semantics.fieldType))];
35255
+ const vector = unique.map((label) => {
35256
+ const rank = order.get(label);
35257
+ return rank === void 0 ? { knownBand: 1, rank: 0, label } : { knownBand: 0, rank, label };
35258
+ });
35259
+ vector.sort(compareOptionElement);
35260
+ return vector;
35261
+ }
35262
+ function compareOptionElement(left, right) {
35263
+ if (left.knownBand !== right.knownBand) return left.knownBand < right.knownBand ? -1 : 1;
35264
+ if (left.rank !== right.rank) return left.rank < right.rank ? -1 : 1;
35265
+ return compareCodePointStrings(left.label, right.label);
35266
+ }
35267
+ function compareOptions(left, right, semantics) {
35268
+ const a = optionVector(left, semantics);
35269
+ const b = optionVector(right, semantics);
35270
+ const length = Math.min(a.length, b.length);
35271
+ for (let index = 0; index < length; index++) {
35272
+ const cmp = compareOptionElement(a[index], b[index]);
35273
+ if (cmp !== 0) return cmp;
35274
+ }
35275
+ return a.length < b.length ? -1 : a.length > b.length ? 1 : 0;
35276
+ }
35277
+ function compareCanonicalValues(left, right, semantics) {
35278
+ switch (semantics.compareMode) {
35279
+ case "string":
35280
+ return compareCodePointStrings(left, right);
35281
+ case "number":
35282
+ return compareNumbers(left, right);
35283
+ case "recordNumber":
35284
+ return compareRecordNumbers(left, right, semantics.fieldType === "RECORD_NUMBER");
35285
+ case "option":
35286
+ return compareOptions(left, right, semantics);
35287
+ case "unsupported":
35288
+ throw new Error(`ArgumentError: values of type ${semantics.fieldType} cannot be compared.`);
35289
+ }
35290
+ }
35291
+ function compareScalarValues(op, left, right, semantics = syntheticSemantics("string")) {
35292
+ const cmp = compareCanonicalValues(left, right, semantics);
35066
35293
  switch (op) {
35294
+ case "=":
35295
+ return cmp === 0;
35296
+ case "!=":
35297
+ case "<>":
35298
+ return cmp !== 0;
35067
35299
  case ">":
35068
- return numeric ? leftNum > rightNum : leftStr > rightStr;
35300
+ return cmp > 0;
35069
35301
  case "<":
35070
- return numeric ? leftNum < rightNum : leftStr < rightStr;
35302
+ return cmp < 0;
35071
35303
  case ">=":
35072
- return numeric ? leftNum >= rightNum : leftStr >= rightStr;
35304
+ return cmp >= 0;
35073
35305
  case "<=":
35074
- return numeric ? leftNum <= rightNum : leftStr <= rightStr;
35306
+ return cmp <= 0;
35075
35307
  }
35076
35308
  }
35077
35309
  function selectScalarExtreme(values, extreme) {
@@ -35081,12 +35313,10 @@ function selectScalarExtreme(values, extreme) {
35081
35313
  const numeric = candidates.every((value) => !Number.isNaN(Number(value)));
35082
35314
  const compare = (left, right) => {
35083
35315
  if (numeric) {
35084
- const leftNum = Number(left);
35085
- const rightNum = Number(right);
35086
- if (leftNum < rightNum) return -1;
35087
- if (leftNum > rightNum) return 1;
35316
+ const numericCmp = triCompare(Number(left), Number(right));
35317
+ if (numericCmp !== 0) return numericCmp;
35088
35318
  }
35089
- return left < right ? -1 : left > right ? 1 : 0;
35319
+ return compareCodePointStrings(left, right);
35090
35320
  };
35091
35321
  return candidates.reduce((best, candidate) => {
35092
35322
  const cmp = compare(candidate, best);
@@ -35094,6 +35324,55 @@ function selectScalarExtreme(values, extreme) {
35094
35324
  });
35095
35325
  }
35096
35326
 
35327
+ // src/core/explainMetadata.ts
35328
+ function whereNeedsFieldMetadata(where) {
35329
+ if (where === null) return false;
35330
+ switch (where.type) {
35331
+ case "BINARY":
35332
+ return valueNeedsFieldMetadata(where.left);
35333
+ case "NULL_CHECK":
35334
+ return valueNeedsFieldMetadata(where.field);
35335
+ case "LOGICAL":
35336
+ return whereNeedsFieldMetadata(where.left) || whereNeedsFieldMetadata(where.right);
35337
+ case "NOT":
35338
+ case "GROUP":
35339
+ return whereNeedsFieldMetadata(where.expr);
35340
+ case "EXISTS":
35341
+ return false;
35342
+ }
35343
+ }
35344
+ function valueNeedsFieldMetadata(value) {
35345
+ if (Array.isArray(value)) return value.some(valueNeedsFieldMetadata);
35346
+ if (value === null || typeof value !== "object") return false;
35347
+ const item = value;
35348
+ if (item["type"] === "FIELD") return item["field"] !== "$id";
35349
+ if (item["type"] === "SELECT") return false;
35350
+ return Object.values(item).some(valueNeedsFieldMetadata);
35351
+ }
35352
+ function selectNeedsOwnMetadata(statement) {
35353
+ return whereNeedsFieldMetadata(statement.where) || statement.orderBy.length > 0 || statement.columns.some(
35354
+ (column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
35355
+ );
35356
+ }
35357
+ function explainNeedsAppMetadata(statement) {
35358
+ const seen = /* @__PURE__ */ new Set();
35359
+ const visit = (node) => {
35360
+ if (node === null || typeof node !== "object") return false;
35361
+ if (seen.has(node)) return false;
35362
+ seen.add(node);
35363
+ if (Array.isArray(node)) return node.some(visit);
35364
+ const item = node;
35365
+ if (item["type"] === "SELECT" && selectNeedsOwnMetadata(node)) {
35366
+ return true;
35367
+ }
35368
+ if ((item["type"] === "UPDATE" || item["type"] === "DELETE") && whereNeedsFieldMetadata(node.where)) {
35369
+ return true;
35370
+ }
35371
+ return Object.values(item).some(visit);
35372
+ };
35373
+ return visit(statement);
35374
+ }
35375
+
35097
35376
  // src/engine/evalFunc.ts
35098
35377
  function evalArithExpr(expr, row) {
35099
35378
  if (expr.type === "NUMBER") return expr.value;
@@ -35358,34 +35637,35 @@ function resolveFieldRef(row, field) {
35358
35637
  }
35359
35638
 
35360
35639
  // src/engine/evalWhere.ts
35361
- function evalWhere(expr, row, resolveFieldType, appliedKlikes) {
35640
+ function evalWhere(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
35362
35641
  switch (expr.type) {
35363
35642
  case "BINARY":
35364
- return evalBinary(expr, row, resolveFieldType, appliedKlikes);
35643
+ return evalBinary(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
35365
35644
  case "NULL_CHECK":
35366
35645
  return evalNullCheck(expr, row);
35367
35646
  case "LOGICAL":
35368
- return evalLogical(expr, row, resolveFieldType, appliedKlikes);
35647
+ return evalLogical(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
35369
35648
  case "NOT":
35370
- return !evalWhere(expr.expr, row, resolveFieldType, appliedKlikes);
35649
+ return !evalWhere(expr.expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
35371
35650
  case "GROUP":
35372
- return evalWhere(expr.expr, row, resolveFieldType, appliedKlikes);
35651
+ return evalWhere(expr.expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
35373
35652
  case "EXISTS": {
35374
35653
  const exists = expr.resolved;
35375
35654
  return expr.not ? !exists : exists;
35376
35655
  }
35377
35656
  }
35378
35657
  }
35379
- function evalBinary(expr, row, resolveFieldType, appliedKlikes) {
35658
+ function evalBinary(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
35380
35659
  if (expr.op === "KLIKE" || expr.op === "NOT_KLIKE") {
35381
35660
  if (appliedKlikes?.has(expr)) return true;
35382
35661
  throw new Error("KLIKE / NOT KLIKE \u306F\u62BC\u3057\u4E0B\u3052\u6E08\u307F\u96C6\u5408\u306B\u542B\u307E\u308C\u306A\u3044\u305F\u3081 JavaScript \u5074\u3067\u306F\u8A55\u4FA1\u3067\u304D\u307E\u305B\u3093");
35383
35662
  }
35384
- const left = resolveField(expr.left, row, resolveFieldType);
35663
+ const left = resolveField(expr.left, row, resolveFieldType, resolveFieldSemantics2);
35385
35664
  const fieldType = expr.left.type === "FIELD" ? resolveFieldType?.(expr.left) : void 0;
35386
- return evalOp(expr.op, left, expr.right, row, fieldType, resolveFieldType);
35665
+ const semantics = semanticsForLeft(expr.left, fieldType, resolveFieldSemantics2);
35666
+ return evalOp(expr.op, left, expr.right, row, fieldType, resolveFieldType, semantics, resolveFieldSemantics2);
35387
35667
  }
35388
- function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
35668
+ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType, semantics = syntheticSemantics("string"), resolveFieldSemantics2) {
35389
35669
  if (op === "IN" || op === "NOT_IN") {
35390
35670
  let values = null;
35391
35671
  if (right.type === "IN_LIST") {
@@ -35410,8 +35690,53 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
35410
35690
  if (op === "KLIKE" || op === "NOT_KLIKE") {
35411
35691
  throw new Error("KLIKE / NOT KLIKE \u306F JavaScript \u5074\u3067\u306F\u8A55\u4FA1\u3067\u304D\u307E\u305B\u3093\uFF08SIMPLE SELECT \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059\uFF09");
35412
35692
  }
35413
- const rightStr = resolveValue(right, row, resolveFieldType);
35414
- return compareScalarValues(op, leftStr, rightStr);
35693
+ const rightStr = resolveValue(right, row, resolveFieldType, resolveFieldSemantics2);
35694
+ return compareScalarValues(op, leftStr, rightStr, semantics);
35695
+ }
35696
+ var NUMERIC_STRING_FUNCTIONS = /* @__PURE__ */ new Set([
35697
+ "LENGTH",
35698
+ "INSTR",
35699
+ "ROUND",
35700
+ "FLOOR",
35701
+ "CEIL",
35702
+ "TRUNCATE",
35703
+ "YEAR",
35704
+ "MONTH",
35705
+ "DAY",
35706
+ "DATEDIFF",
35707
+ "ABS",
35708
+ "MOD",
35709
+ "POWER",
35710
+ "SQRT"
35711
+ ]);
35712
+ function semanticsForLeft(left, fieldType, resolveSemantics) {
35713
+ if (left.type === "FIELD") {
35714
+ return resolveSemantics?.(left) ?? (fieldType ? resolveFieldSemantics({ fieldType }) : syntheticSemantics("string"));
35715
+ }
35716
+ if (left.type === "ARITH_FIELD") return syntheticSemantics("number");
35717
+ if (left.type === "FUNC_FIELD") {
35718
+ return syntheticSemantics(NUMERIC_STRING_FUNCTIONS.has(left.expr.func) ? "number" : "string");
35719
+ }
35720
+ if (left.type === "CASE_FIELD") {
35721
+ const results = [
35722
+ ...left.expr.branches.map((branch) => branch.result),
35723
+ ...left.expr.elseResult ? [left.expr.elseResult] : []
35724
+ ];
35725
+ const modes = results.map((result) => {
35726
+ if (result.type === "NUMBER" || result.type === "ARITH") return syntheticSemantics("number");
35727
+ if (result.type === "STRING_FUNC") {
35728
+ return syntheticSemantics(NUMERIC_STRING_FUNCTIONS.has(result.func) ? "number" : "string");
35729
+ }
35730
+ if (result.type === "FIELD_REF") {
35731
+ const dot = result.field.indexOf(".");
35732
+ const ref = dot > 0 ? { type: "FIELD", tableAlias: result.field.slice(0, dot), field: result.field.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: result.field };
35733
+ return resolveSemantics?.(ref) ?? syntheticSemantics("string");
35734
+ }
35735
+ return syntheticSemantics("string");
35736
+ });
35737
+ if (modes.length > 0 && modes.every((mode) => mode.compareMode === modes[0].compareMode)) return modes[0];
35738
+ }
35739
+ return syntheticSemantics("string");
35415
35740
  }
35416
35741
  var STRING_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
35417
35742
  var OBJECT_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([
@@ -35462,20 +35787,20 @@ function evalNullCheck(expr, row) {
35462
35787
  const val = resolveField(expr.field, row);
35463
35788
  return expr.not ? val !== "" : val === "";
35464
35789
  }
35465
- function evalLogical(expr, row, resolveFieldType, appliedKlikes) {
35790
+ function evalLogical(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
35466
35791
  if (expr.op === "AND") {
35467
- return evalWhere(expr.left, row, resolveFieldType, appliedKlikes) && evalWhere(expr.right, row, resolveFieldType, appliedKlikes);
35792
+ return evalWhere(expr.left, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) && evalWhere(expr.right, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
35468
35793
  }
35469
- return evalWhere(expr.left, row, resolveFieldType, appliedKlikes) || evalWhere(expr.right, row, resolveFieldType, appliedKlikes);
35794
+ return evalWhere(expr.left, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) || evalWhere(expr.right, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
35470
35795
  }
35471
- function resolveField(field, row, resolveFieldType) {
35796
+ function resolveField(field, row, resolveFieldType, resolveFieldSemantics2) {
35472
35797
  if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
35473
35798
  if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
35474
- if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType);
35799
+ if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType, resolveFieldSemantics2);
35475
35800
  const key = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
35476
35801
  return resolveFieldRef(row, key);
35477
35802
  }
35478
- function resolveValue(value, row, resolveFieldType) {
35803
+ function resolveValue(value, row, resolveFieldType, resolveFieldSemantics2) {
35479
35804
  switch (value.type) {
35480
35805
  case "VARIABLE":
35481
35806
  throw new Error(`ParseError: unresolved batch variable @${value.name}.`);
@@ -35498,14 +35823,14 @@ function resolveValue(value, row, resolveFieldType) {
35498
35823
  if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
35499
35824
  return String(evalArithExpr(value.expr, row));
35500
35825
  case "CASE_VALUE":
35501
- return evalCaseWhen(value.expr, row, resolveFieldType);
35826
+ return evalCaseWhen(value.expr, row, resolveFieldType, resolveFieldSemantics2);
35502
35827
  case "ARRAY":
35503
35828
  return value.elements.map((e) => e.value).join(",");
35504
35829
  }
35505
35830
  }
35506
- function evalCaseWhen(expr, row, resolveFieldType) {
35831
+ function evalCaseWhen(expr, row, resolveFieldType, resolveFieldSemantics2) {
35507
35832
  for (const branch of expr.branches) {
35508
- if (evalWhere(branch.condition, row, resolveFieldType)) {
35833
+ if (evalWhere(branch.condition, row, resolveFieldType, void 0, resolveFieldSemantics2)) {
35509
35834
  return evalCaseResult(branch.result, row);
35510
35835
  }
35511
35836
  }
@@ -36136,6 +36461,141 @@ async function resolveDmlTargetIds(getRecords, app, query, options) {
36136
36461
  };
36137
36462
  }
36138
36463
 
36464
+ // src/core/optimization/canonicalOrderPlanner.ts
36465
+ var REST_OFFSET_MAX = 1e4;
36466
+ var REST_LIMIT_MAX = 500;
36467
+ function fieldSemantics(item, semantics) {
36468
+ return item.key.type === "FIELD_NAME" ? semantics.get(item.key.name) : void 0;
36469
+ }
36470
+ function planCanonicalOrder(input) {
36471
+ const { stmt } = input;
36472
+ const reasons = [];
36473
+ const windowOrderBy = stmt.columns.flatMap(
36474
+ (column) => column.type === "WINDOW_COL" ? column.orderBy : []
36475
+ );
36476
+ const allOrderBy = [...stmt.orderBy, ...windowOrderBy];
36477
+ for (const item of allOrderBy) {
36478
+ if (item.key.type !== "FIELD_NAME") continue;
36479
+ const semantics = fieldSemantics(item, input.orderSemantics);
36480
+ if (!semantics) {
36481
+ reasons.push("ORDER_KEY_UNRESOLVED");
36482
+ continue;
36483
+ }
36484
+ if (semantics.fieldType === "KSQL_AMBIGUOUS") reasons.push("ORDER_KEY_AMBIGUOUS");
36485
+ else if (semantics.compareMode === "unsupported") reasons.push("ORDER_KEY_UNSUPPORTED");
36486
+ }
36487
+ if (reasons.includes("ORDER_KEY_AMBIGUOUS")) {
36488
+ throw new Error(
36489
+ "ArgumentError: ORDER BY key is an ambiguous column reference (reason=ORDER_KEY_AMBIGUOUS). Qualify the key with its table alias."
36490
+ );
36491
+ }
36492
+ if (reasons.includes("ORDER_KEY_UNSUPPORTED") || reasons.includes("ORDER_KEY_UNRESOLVED")) {
36493
+ const reason = reasons.includes("ORDER_KEY_UNSUPPORTED") ? "ORDER_KEY_UNSUPPORTED" : "ORDER_KEY_UNRESOLVED";
36494
+ throw new Error(`ArgumentError: ORDER BY key has no canonical comparison contract (reason=${reason}).`);
36495
+ }
36496
+ const allRestEquivalent = stmt.orderBy.length > 0 && windowOrderBy.length === 0 && stmt.orderBy.every(
36497
+ (item) => item.key.type === "FIELD_NAME" && item.key.name === "$id"
36498
+ );
36499
+ if (!allRestEquivalent) reasons.push("ORDER_KEY_NOT_REST_EQUIVALENT");
36500
+ if (input.whereCapability !== "EXACT_PUSHDOWN") reasons.push("WHERE_NOT_EXACT");
36501
+ if (input.staticMode !== "SIMPLE") reasons.push("QUERY_SHAPE_LOCAL");
36502
+ if (stmt.limit === null || stmt.limit < 0 || stmt.limit > REST_LIMIT_MAX) {
36503
+ reasons.push("LIMIT_NOT_REST_WINDOW");
36504
+ }
36505
+ if ((stmt.offset ?? 0) < 0 || (stmt.offset ?? 0) > REST_OFFSET_MAX) {
36506
+ reasons.push("OFFSET_NOT_REST_WINDOW");
36507
+ }
36508
+ if (stmt.limit !== null && stmt.limit > input.maxRecords) reasons.push("MAX_RECORDS_WINDOW");
36509
+ if (input.hasKlike) reasons.push("KLIKE_NOT_REST_WINDOW");
36510
+ if (reasons.length === 0) {
36511
+ return {
36512
+ kind: "CANONICAL_REST_TOP_N",
36513
+ requiresCompleteInput: false,
36514
+ localOrderBy: false,
36515
+ applyLocalOffsetLimit: false,
36516
+ reasonCodes: []
36517
+ };
36518
+ }
36519
+ return {
36520
+ kind: "CANONICAL_LOCAL",
36521
+ requiresCompleteInput: allOrderBy.length > 0,
36522
+ localOrderBy: stmt.orderBy.length > 0,
36523
+ applyLocalOffsetLimit: stmt.orderBy.length > 0,
36524
+ reasonCodes: [...new Set(reasons)]
36525
+ };
36526
+ }
36527
+
36528
+ // src/core/optimization/korderPlanner.ts
36529
+ var KORDER_NATIVE_FIELD_TYPES = /* @__PURE__ */ new Set([
36530
+ "RECORD_NUMBER",
36531
+ "SINGLE_LINE_TEXT",
36532
+ "NUMBER",
36533
+ "CALC",
36534
+ "DATE",
36535
+ "DATETIME",
36536
+ "TIME",
36537
+ "CREATED_TIME",
36538
+ "UPDATED_TIME",
36539
+ "DROP_DOWN",
36540
+ "RADIO_BUTTON",
36541
+ "STATUS",
36542
+ "LINK",
36543
+ "CREATOR",
36544
+ "MODIFIER"
36545
+ ]);
36546
+ function planKorderNative(input) {
36547
+ const { stmt } = input;
36548
+ const reasons = [];
36549
+ if (stmt.orderMode !== "KINTONE_NATIVE") reasons.push("KORDER_MODE_REQUIRED");
36550
+ if (stmt.from.cteName !== null || stmt.from.subtableCode || input.staticMode !== "SIMPLE") {
36551
+ reasons.push("KORDER_QUERY_SHAPE_UNSUPPORTED");
36552
+ }
36553
+ if (input.whereCapability !== "EXACT_PUSHDOWN") reasons.push("KORDER_WHERE_NOT_EXACT");
36554
+ if (input.hasKlike) reasons.push("KORDER_KLIKE_UNSUPPORTED");
36555
+ if (stmt.orderBy.length === 0) reasons.push("KORDER_KEY_REQUIRED");
36556
+ for (const item of stmt.orderBy) {
36557
+ if (item.key.type !== "FIELD_NAME") {
36558
+ reasons.push(`KORDER_KEY_NOT_DIRECT_FIELD(key=${item.key.type})`);
36559
+ continue;
36560
+ }
36561
+ const name = item.key.name;
36562
+ const semantics = input.orderSemantics.get(name);
36563
+ if (!semantics) {
36564
+ reasons.push(`KORDER_KEY_UNRESOLVED(field=${name})`);
36565
+ continue;
36566
+ }
36567
+ if (name === "$id") continue;
36568
+ if (!semantics.source || semantics.source.fieldCode !== name) {
36569
+ reasons.push(`KORDER_KEY_NOT_DIRECT_FIELD(field=${name})`);
36570
+ continue;
36571
+ }
36572
+ if (!KORDER_NATIVE_FIELD_TYPES.has(semantics.fieldType)) {
36573
+ reasons.push(`KORDER_TYPE_UNSUPPORTED(field=${name}, type=${semantics.fieldType})`);
36574
+ }
36575
+ }
36576
+ if (stmt.limit === null || stmt.limit < 0 || stmt.limit > 500) {
36577
+ reasons.push(`KORDER_LIMIT_INVALID(limit=${String(stmt.limit)})`);
36578
+ }
36579
+ if (stmt.limit !== null && stmt.limit > input.maxRecords) {
36580
+ reasons.push(`KORDER_LIMIT_EXCEEDS_MAX_RECORDS(limit=${stmt.limit}, maxRecords=${input.maxRecords})`);
36581
+ }
36582
+ const offset = stmt.offset ?? 0;
36583
+ if (offset < 0 || offset > 1e4) reasons.push(`KORDER_OFFSET_INVALID(offset=${offset})`);
36584
+ const unique = [...new Set(reasons)];
36585
+ if (unique.length > 0) {
36586
+ throw new Error(
36587
+ `ArgumentError: KORDER BY cannot be executed (mode=KINTONE_NATIVE; ${unique.join(", ")}). Use ORDER BY for canonical local ordering or simplify the query.`
36588
+ );
36589
+ }
36590
+ return {
36591
+ kind: "KORDER_NATIVE",
36592
+ requiresCompleteInput: false,
36593
+ localOrderBy: false,
36594
+ applyLocalOffsetLimit: false,
36595
+ reasonCodes: []
36596
+ };
36597
+ }
36598
+
36139
36599
  // src/engine/process.ts
36140
36600
  function flatten(record2, alias) {
36141
36601
  const row = {};
@@ -36200,9 +36660,9 @@ function applyJoin(leftRows, rightRows, join) {
36200
36660
  }
36201
36661
  return result;
36202
36662
  }
36203
- function applyFilter(rows, where, resolveFieldType, appliedKlikes) {
36663
+ function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
36204
36664
  if (where === null) return rows;
36205
- return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes));
36665
+ return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2));
36206
36666
  }
36207
36667
  function hasAggregateColumns(columns) {
36208
36668
  return columns.some(
@@ -36263,7 +36723,7 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
36263
36723
  let strVal;
36264
36724
  if (arg.type === "FIELD_REF") {
36265
36725
  const raw = row[arg.field];
36266
- if (raw === void 0 || raw === "") continue;
36726
+ if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") continue;
36267
36727
  strVal = raw;
36268
36728
  } else {
36269
36729
  const n = evalArithExpr(arg, row);
@@ -36275,10 +36735,16 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
36275
36735
  const eff = distinct ? [...new Set(strValues)] : strValues;
36276
36736
  if (func === "COUNT") return eff.length;
36277
36737
  if (func === "GROUP_CONCAT") return eff.join(separator ?? ",");
36278
- const sortKind = (func === "MIN" || func === "MAX") && arg.type === "FIELD_REF" ? resolveAggSortKind?.(toAggregateFieldRef(arg.field)) : void 0;
36279
- if (sortKind === "string") {
36280
- if (eff.length === 0) return "";
36281
- return func === "MAX" ? maxStringOf(eff) : minStringOf(eff);
36738
+ const comparison = (func === "MIN" || func === "MAX") && arg.type === "FIELD_REF" ? resolveAggSortKind?.(toAggregateFieldRef(arg.field)) : void 0;
36739
+ if (func === "MIN" || func === "MAX") {
36740
+ if (eff.length === 0) return 0;
36741
+ const semantics = typeof comparison === "string" ? syntheticSemantics(comparison) : comparison ?? (arg.type === "FIELD_REF" ? syntheticSemantics("string") : syntheticSemantics("number"));
36742
+ let result = eff[0];
36743
+ for (const candidate of eff.slice(1)) {
36744
+ const cmp = compareCanonicalValues(candidate, result, semantics);
36745
+ if (func === "MAX" && cmp > 0 || func === "MIN" && cmp < 0) result = candidate;
36746
+ }
36747
+ return result;
36282
36748
  }
36283
36749
  const nums = eff.map(Number);
36284
36750
  switch (func) {
@@ -36286,37 +36752,12 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
36286
36752
  return nums.reduce((a, b) => a + b, 0);
36287
36753
  case "AVG":
36288
36754
  return nums.length === 0 ? 0 : nums.reduce((a, b) => a + b, 0) / nums.length;
36289
- // Math.max(...nums) は要素数が多いと RangeError になるためループで求める
36290
- case "MAX":
36291
- return nums.length === 0 ? 0 : maxOf(nums);
36292
- case "MIN":
36293
- return nums.length === 0 ? 0 : minOf(nums);
36294
36755
  }
36295
36756
  }
36296
36757
  function toAggregateFieldRef(field) {
36297
36758
  const dot = field.indexOf(".");
36298
36759
  return dot > 0 ? { type: "FIELD", tableAlias: field.slice(0, dot), field: field.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field };
36299
36760
  }
36300
- function maxStringOf(values) {
36301
- let value = values[0];
36302
- for (const candidate of values) if (candidate > value) value = candidate;
36303
- return value;
36304
- }
36305
- function minStringOf(values) {
36306
- let value = values[0];
36307
- for (const candidate of values) if (candidate < value) value = candidate;
36308
- return value;
36309
- }
36310
- function maxOf(nums) {
36311
- let m = nums[0];
36312
- for (const n of nums) if (n > m) m = n;
36313
- return m;
36314
- }
36315
- function minOf(nums) {
36316
- let m = nums[0];
36317
- for (const n of nums) if (n < m) m = n;
36318
- return m;
36319
- }
36320
36761
  function evalAggArithExpr(node, rows, resolveAggSortKind) {
36321
36762
  if (node.type === "NUMBER") return node.value;
36322
36763
  if (node.type === "AGG_REF") return Number(evalAggregate(node.func, node.distinct, node.arg, node.separator, rows, resolveAggSortKind));
@@ -36348,9 +36789,9 @@ function aggregateSyntheticName2(func, distinct, arg) {
36348
36789
  const argStr = aggregateArgLabel(arg);
36349
36790
  return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
36350
36791
  }
36351
- function applyHaving(rows, having, resolveFieldType) {
36792
+ function applyHaving(rows, having, resolveFieldType, resolveFieldSemantics2) {
36352
36793
  if (having === null) return rows;
36353
- return rows.filter((row) => evalWhere(having, row, resolveFieldType));
36794
+ return rows.filter((row) => evalWhere(having, row, resolveFieldType, void 0, resolveFieldSemantics2));
36354
36795
  }
36355
36796
  function applyDistinct(rows, columns) {
36356
36797
  if (rows.length === 0) return rows;
@@ -36402,27 +36843,37 @@ function buildDistinctKeyBuilder(rows, columns) {
36402
36843
  return JSON.stringify(values);
36403
36844
  };
36404
36845
  }
36405
- function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
36846
+ function applyOrderBy(rows, orderBy, optionOrders, sortKinds, fieldSemantics2) {
36406
36847
  if (orderBy.length === 0) return rows;
36407
- return sortDecoratedRows(rows, orderBy, optionOrders, sortKinds).rows.map((item) => item.row);
36408
- }
36409
- function sortDecoratedRows(rows, orderBy, optionOrders, sortKinds) {
36410
- const keyMeta = orderBy.map(({ key }) => ({
36411
- orderMap: key.type === "FIELD_NAME" ? optionOrders?.get(key.name) : void 0,
36412
- sortKind: key.type === "FIELD_NAME" ? sortKinds?.get(key.name) : void 0
36413
- }));
36848
+ return sortDecoratedRows(rows, orderBy, optionOrders, sortKinds, fieldSemantics2).rows.map((item) => item.row);
36849
+ }
36850
+ function sortDecoratedRows(rows, orderBy, optionOrders, sortKinds, fieldSemantics2) {
36851
+ const keyMeta = orderBy.map(({ key }) => {
36852
+ if (key.type === "ARITH_KEY") return { semantics: syntheticSemantics("number") };
36853
+ if (key.type === "FUNC_KEY") {
36854
+ return { semantics: syntheticSemantics(NUMERIC_ORDER_FUNCTIONS.has(key.expr.func) ? "number" : "string") };
36855
+ }
36856
+ const semantics = fieldSemantics2?.get(key.name);
36857
+ if (semantics) return { semantics };
36858
+ const orderMap = optionOrders?.get(key.name);
36859
+ if (orderMap) {
36860
+ return {
36861
+ semantics: {
36862
+ fieldType: "MULTI_SELECT",
36863
+ compareMode: "option",
36864
+ inSubtable: false,
36865
+ requiresCollectionOperators: false,
36866
+ optionOrder: orderMap
36867
+ }
36868
+ };
36869
+ }
36870
+ return { semantics: syntheticSemantics(sortKinds?.get(key.name) ?? "string") };
36871
+ });
36414
36872
  const decorated = rows.map((row) => ({
36415
36873
  row,
36416
36874
  keys: orderBy.map(({ key }, i) => {
36417
36875
  const s = evalOrderKey(key, row);
36418
- const n = Number(s);
36419
- const orderMap = keyMeta[i].orderMap;
36420
- return {
36421
- s,
36422
- n,
36423
- isNum: !Number.isNaN(n),
36424
- rank: orderMap ? minChoiceIndex(parseChoiceValues(s), orderMap) : 0
36425
- };
36876
+ return { s };
36426
36877
  })
36427
36878
  }));
36428
36879
  const compare = (a, b) => compareDecoratedRows(a, b, orderBy, keyMeta);
@@ -36437,15 +36888,24 @@ function compareDecoratedRows(a, b, orderBy, keyMeta) {
36437
36888
  return 0;
36438
36889
  }
36439
36890
  function compareSortKeys(a, b, meta3) {
36440
- if (meta3.orderMap) {
36441
- if (a.rank !== b.rank) return a.rank - b.rank;
36442
- return a.s.localeCompare(b.s, "ja");
36443
- }
36444
- if (meta3.sortKind === "string") {
36445
- return a.s.localeCompare(b.s, "ja");
36446
- }
36447
- return a.isNum && b.isNum ? a.n - b.n : a.s.localeCompare(b.s, "ja");
36448
- }
36891
+ return compareCanonicalValues(a.s, b.s, meta3.semantics);
36892
+ }
36893
+ var NUMERIC_ORDER_FUNCTIONS = /* @__PURE__ */ new Set([
36894
+ "LENGTH",
36895
+ "INSTR",
36896
+ "ROUND",
36897
+ "FLOOR",
36898
+ "CEIL",
36899
+ "TRUNCATE",
36900
+ "YEAR",
36901
+ "MONTH",
36902
+ "DAY",
36903
+ "DATEDIFF",
36904
+ "ABS",
36905
+ "MOD",
36906
+ "POWER",
36907
+ "SQRT"
36908
+ ]);
36449
36909
  function evalOrderKey(key, row) {
36450
36910
  switch (key.type) {
36451
36911
  case "FIELD_NAME":
@@ -36456,30 +36916,7 @@ function evalOrderKey(key, row) {
36456
36916
  return evalStringFunc(key.expr, row);
36457
36917
  }
36458
36918
  }
36459
- function parseChoiceValues(raw) {
36460
- const trimmed = raw.trim();
36461
- if (trimmed === "") return [""];
36462
- if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
36463
- try {
36464
- const arr = JSON.parse(trimmed);
36465
- if (Array.isArray(arr)) {
36466
- return arr.map((v) => String(v ?? ""));
36467
- }
36468
- } catch {
36469
- }
36470
- }
36471
- return [trimmed];
36472
- }
36473
- function minChoiceIndex(values, orderMap) {
36474
- let min = Number.MAX_SAFE_INTEGER;
36475
- for (const value of values) {
36476
- const idx = orderMap.get(value);
36477
- const rank = idx ?? Number.MAX_SAFE_INTEGER;
36478
- if (rank < min) min = rank;
36479
- }
36480
- return min;
36481
- }
36482
- function applyWindow(rows, columns, optionOrders, sortKinds) {
36919
+ function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
36483
36920
  const windows = columns.filter((column) => column.type === "WINDOW_COL");
36484
36921
  if (rows.length === 0 || windows.length === 0) return rows;
36485
36922
  for (const window of windows) {
@@ -36491,7 +36928,7 @@ function applyWindow(rows, columns, optionOrders, sortKinds) {
36491
36928
  else partitions.set(key, [row]);
36492
36929
  }
36493
36930
  for (const partition of partitions.values()) {
36494
- const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds);
36931
+ const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds, fieldSemantics2);
36495
36932
  const sorted = sortedResult.rows;
36496
36933
  let rank = 1;
36497
36934
  let denseRank = 1;
@@ -36516,7 +36953,7 @@ function applyLimit(rows, limit, offset) {
36516
36953
  if (limit === null) return rows.slice(start);
36517
36954
  return rows.slice(start, start + limit);
36518
36955
  }
36519
- function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
36956
+ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2) {
36520
36957
  if (columns.length === 1 && columns[0].type === "WILDCARD") {
36521
36958
  const projected2 = rows.map((row) => stripParentShortcutColumns(row));
36522
36959
  const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
@@ -36580,7 +37017,7 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
36580
37017
  }
36581
37018
  case "CASE_COL": {
36582
37019
  const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
36583
- out[key] = evalCaseWhen(col.expr, row, resolveFieldType);
37020
+ out[key] = evalCaseWhen(col.expr, row, resolveFieldType, resolveFieldSemantics2);
36584
37021
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
36585
37022
  break;
36586
37023
  }
@@ -36735,6 +37172,26 @@ function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
36735
37172
  args: expr.args.map((arg) => resolveAggInStringFuncArg(arg, rows, resolveAggSortKind))
36736
37173
  };
36737
37174
  }
37175
+ function deriveOutputOrderSemantics(columns) {
37176
+ const result = /* @__PURE__ */ new Map();
37177
+ for (const column of columns) {
37178
+ if (!("alias" in column) || !column.alias) continue;
37179
+ if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
37180
+ result.set(column.alias, syntheticSemantics("number"));
37181
+ } else if (column.type === "AGGREGATE") {
37182
+ if (column.func === "COUNT" || column.func === "SUM" || column.func === "AVG") {
37183
+ result.set(column.alias, syntheticSemantics("number"));
37184
+ } else if (column.func === "GROUP_CONCAT") {
37185
+ result.set(column.alias, syntheticSemantics("string"));
37186
+ }
37187
+ } else if (column.type === "LITERAL_COL" || column.type === "CASE_COL" || column.type === "SCALAR_SUBQUERY_COL") {
37188
+ result.set(column.alias, syntheticSemantics("string"));
37189
+ } else if (column.type === "STRFUNC_COL") {
37190
+ result.set(column.alias, syntheticSemantics(NUMERIC_ORDER_FUNCTIONS.has(column.expr.func) ? "number" : "string"));
37191
+ }
37192
+ }
37193
+ return result;
37194
+ }
36738
37195
  function runFullScan(input) {
36739
37196
  const {
36740
37197
  stmt,
@@ -36742,12 +37199,17 @@ function runFullScan(input) {
36742
37199
  scalarCache,
36743
37200
  optionOrders,
36744
37201
  sortKinds,
37202
+ orderSemantics,
36745
37203
  fieldTypeResolver,
37204
+ fieldSemanticsResolver,
36746
37205
  havingFieldTypeResolver,
37206
+ havingFieldSemanticsResolver,
36747
37207
  aggregateSortKindResolver,
36748
37208
  appliedKlikes,
36749
37209
  sourceColumns
36750
37210
  } = input;
37211
+ const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
37212
+ for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
36751
37213
  let rows = [];
36752
37214
  const mainAlias = stmt.from.alias;
36753
37215
  const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
@@ -36758,18 +37220,18 @@ function runFullScan(input) {
36758
37220
  const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
36759
37221
  rows = applyJoin(rows, rightRows, join);
36760
37222
  }
36761
- rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes);
37223
+ rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes, fieldSemanticsResolver);
36762
37224
  if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
36763
37225
  rows = applyGroupBy(rows, stmt.groupBy, stmt.columns, aggregateSortKindResolver);
36764
37226
  }
36765
- rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
36766
- rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds);
37227
+ rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, havingFieldSemanticsResolver);
37228
+ rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds, effectiveOrderSemantics);
36767
37229
  if (stmt.distinct) {
36768
37230
  rows = applyDistinct(rows, stmt.columns);
36769
37231
  }
36770
- rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
37232
+ rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds, effectiveOrderSemantics);
36771
37233
  rows = applyLimit(rows, stmt.limit, stmt.offset);
36772
- return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns);
37234
+ return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns, fieldSemanticsResolver);
36773
37235
  }
36774
37236
 
36775
37237
  // src/converter/subtableAdapter.ts
@@ -37037,6 +37499,192 @@ function renderValidationValue(value) {
37037
37499
  return String(value);
37038
37500
  }
37039
37501
 
37502
+ // src/core/optimization/whereCapability.ts
37503
+ var RANGE_AND_EQUALITY = ["=", "!=", ">", "<", ">=", "<="];
37504
+ var EQUALITY_IN = ["=", "!=", "in", "not in"];
37505
+ var NATIVE_OPERATORS = /* @__PURE__ */ new Map([
37506
+ ["RECORD_NUMBER", /* @__PURE__ */ new Set([...RANGE_AND_EQUALITY, "in", "not in"])],
37507
+ ["__ID__", /* @__PURE__ */ new Set([...RANGE_AND_EQUALITY, "in", "not in"])],
37508
+ ["CREATOR", /* @__PURE__ */ new Set(["in", "not in"])],
37509
+ ["MODIFIER", /* @__PURE__ */ new Set(["in", "not in"])],
37510
+ ["CREATED_TIME", new Set(RANGE_AND_EQUALITY)],
37511
+ ["UPDATED_TIME", new Set(RANGE_AND_EQUALITY)],
37512
+ ["DATE", new Set(RANGE_AND_EQUALITY)],
37513
+ ["TIME", new Set(RANGE_AND_EQUALITY)],
37514
+ ["DATETIME", new Set(RANGE_AND_EQUALITY)],
37515
+ ["SINGLE_LINE_TEXT", /* @__PURE__ */ new Set(["=", "!=", "in", "not in", "like", "not like"])],
37516
+ ["LINK", /* @__PURE__ */ new Set(["=", "!=", "in", "not in", "like", "not like"])],
37517
+ ["NUMBER", /* @__PURE__ */ new Set([...RANGE_AND_EQUALITY, "in", "not in"])],
37518
+ ["CALC", /* @__PURE__ */ new Set([...RANGE_AND_EQUALITY, "in", "not in"])],
37519
+ ["MULTI_LINE_TEXT", /* @__PURE__ */ new Set(["like", "not like"])],
37520
+ ["RICH_TEXT", /* @__PURE__ */ new Set(["like", "not like"])],
37521
+ ["CHECK_BOX", /* @__PURE__ */ new Set(["in", "not in"])],
37522
+ ["RADIO_BUTTON", /* @__PURE__ */ new Set(["in", "not in"])],
37523
+ ["DROP_DOWN", /* @__PURE__ */ new Set(["in", "not in"])],
37524
+ ["MULTI_SELECT", /* @__PURE__ */ new Set(["in", "not in"])],
37525
+ ["FILE", /* @__PURE__ */ new Set(["like", "not like"])],
37526
+ ["USER_SELECT", /* @__PURE__ */ new Set(["in", "not in"])],
37527
+ ["ORGANIZATION_SELECT", /* @__PURE__ */ new Set(["in", "not in"])],
37528
+ ["GROUP_SELECT", /* @__PURE__ */ new Set(["in", "not in"])],
37529
+ ["STATUS", new Set(EQUALITY_IN)]
37530
+ ]);
37531
+ var LOCAL_SCALAR_TYPES = /* @__PURE__ */ new Set([
37532
+ "RECORD_NUMBER",
37533
+ "__ID__",
37534
+ "CREATOR",
37535
+ "MODIFIER",
37536
+ "CREATED_TIME",
37537
+ "UPDATED_TIME",
37538
+ "DATE",
37539
+ "TIME",
37540
+ "DATETIME",
37541
+ "SINGLE_LINE_TEXT",
37542
+ "LINK",
37543
+ "NUMBER",
37544
+ "CALC",
37545
+ "MULTI_LINE_TEXT",
37546
+ "RICH_TEXT",
37547
+ "RADIO_BUTTON",
37548
+ "DROP_DOWN",
37549
+ "STATUS",
37550
+ // 一時表・CTE・式列は kintone REST へは送らず、共有ローカル評価器で扱う。
37551
+ "KSQL_STRING",
37552
+ "KSQL_NUMBER",
37553
+ "KSQL_BOOLEAN"
37554
+ ]);
37555
+ var LOCAL_COLLECTION_TYPES = /* @__PURE__ */ new Set([
37556
+ "CHECK_BOX",
37557
+ "MULTI_SELECT",
37558
+ "FILE",
37559
+ "USER_SELECT",
37560
+ "ORGANIZATION_SELECT",
37561
+ "GROUP_SELECT",
37562
+ "STATUS_ASSIGNEE",
37563
+ "CATEGORY"
37564
+ ]);
37565
+ function nativeWhereOperatorsForType(fieldType) {
37566
+ return NATIVE_OPERATORS.get(fieldType) ?? /* @__PURE__ */ new Set();
37567
+ }
37568
+ function classifyWhereCapability(where, resolveField2) {
37569
+ if (where === null) {
37570
+ return { capability: "EXACT_PUSHDOWN", reasons: [{ code: "WHERE_EXACT" }] };
37571
+ }
37572
+ return classifyNode(where, resolveField2);
37573
+ }
37574
+ function classifyNode(where, resolveField2) {
37575
+ switch (where.type) {
37576
+ case "BINARY":
37577
+ return classifyBinary(where.op, where.left, where.right.type, resolveField2);
37578
+ case "NULL_CHECK":
37579
+ if (where.field.type !== "FIELD") return localExpression();
37580
+ return classifyLocalOnlyField(where.field, where.not ? "IS NOT NULL" : "IS NULL", resolveField2);
37581
+ case "EXISTS":
37582
+ return localExpression();
37583
+ case "GROUP":
37584
+ return classifyNode(where.expr, resolveField2);
37585
+ case "NOT": {
37586
+ const inner = classifyNode(where.expr, resolveField2);
37587
+ return inner.capability === "SUPERSET_PREFILTER" ? { capability: "LOCAL_ONLY", reasons: [{ code: "WHERE_EXPRESSION_LOCAL_ONLY" }] } : inner;
37588
+ }
37589
+ case "LOGICAL": {
37590
+ const left = classifyNode(where.left, resolveField2);
37591
+ const right = classifyNode(where.right, resolveField2);
37592
+ return combineLogical(where.op, left, right);
37593
+ }
37594
+ }
37595
+ }
37596
+ function classifyBinary(op, left, rightType, resolveField2) {
37597
+ if (left.type !== "FIELD") return localExpression();
37598
+ const semantics = resolveField2(left);
37599
+ if (!semantics) {
37600
+ return unsupported("WHERE_FIELD_UNRESOLVED", left.field, void 0, normalizeOperator(op));
37601
+ }
37602
+ if (!hasLocalContract(semantics.fieldType, op)) {
37603
+ return unsupported("WHERE_OPERATOR_UNSUPPORTED", left.field, semantics.fieldType, normalizeOperator(op));
37604
+ }
37605
+ const nativeOp = normalizeOperator(op);
37606
+ const native = nativeWhereOperatorsForType(semantics.fieldType);
37607
+ const rightCanPush = rightType === "STRING" || rightType === "NUMBER" || rightType === "IN_LIST" || rightType === "KINTONE_FUNC";
37608
+ const structureAllows = !semantics.requiresCollectionOperators || nativeOp !== "=" && nativeOp !== "!=";
37609
+ const sqlLikeIsResidual = op === "LIKE" || op === "NOT_LIKE";
37610
+ if (rightCanPush && structureAllows && native.has(nativeOp) && !sqlLikeIsResidual) {
37611
+ return {
37612
+ capability: "EXACT_PUSHDOWN",
37613
+ reasons: [{
37614
+ code: "WHERE_EXACT",
37615
+ field: left.field,
37616
+ fieldType: semantics.fieldType,
37617
+ operator: nativeOp
37618
+ }]
37619
+ };
37620
+ }
37621
+ return {
37622
+ capability: "LOCAL_ONLY",
37623
+ reasons: [{
37624
+ code: "WHERE_RESIDUAL",
37625
+ field: left.field,
37626
+ fieldType: semantics.fieldType,
37627
+ operator: nativeOp
37628
+ }]
37629
+ };
37630
+ }
37631
+ function classifyLocalOnlyField(field, operator, resolveField2) {
37632
+ const semantics = resolveField2(field);
37633
+ if (!semantics) return unsupported("WHERE_FIELD_UNRESOLVED", field.field, void 0, operator);
37634
+ if (!LOCAL_SCALAR_TYPES.has(semantics.fieldType) && !LOCAL_COLLECTION_TYPES.has(semantics.fieldType)) {
37635
+ return unsupported("WHERE_OPERATOR_UNSUPPORTED", field.field, semantics.fieldType, operator);
37636
+ }
37637
+ return {
37638
+ capability: "LOCAL_ONLY",
37639
+ reasons: [{ code: "WHERE_RESIDUAL", field: field.field, fieldType: semantics.fieldType, operator }]
37640
+ };
37641
+ }
37642
+ function hasLocalContract(fieldType, op) {
37643
+ if (LOCAL_SCALAR_TYPES.has(fieldType)) return true;
37644
+ if (!LOCAL_COLLECTION_TYPES.has(fieldType)) return false;
37645
+ return op === "=" || op === "!=" || op === "<>" || op === "IN" || op === "NOT_IN" || op === "LIKE" || op === "NOT_LIKE" || op === "KLIKE" || op === "NOT_KLIKE";
37646
+ }
37647
+ function normalizeOperator(op) {
37648
+ switch (op) {
37649
+ case "<>":
37650
+ return "!=";
37651
+ case "IN":
37652
+ return "in";
37653
+ case "NOT_IN":
37654
+ return "not in";
37655
+ case "LIKE":
37656
+ case "KLIKE":
37657
+ return "like";
37658
+ case "NOT_LIKE":
37659
+ case "NOT_KLIKE":
37660
+ return "not like";
37661
+ default:
37662
+ return op;
37663
+ }
37664
+ }
37665
+ function combineLogical(op, left, right) {
37666
+ const reasons = [...left.reasons, ...right.reasons];
37667
+ if (left.capability === "UNSUPPORTED" || right.capability === "UNSUPPORTED") {
37668
+ return { capability: "UNSUPPORTED", reasons };
37669
+ }
37670
+ if (left.capability === "EXACT_PUSHDOWN" && right.capability === "EXACT_PUSHDOWN") {
37671
+ return { capability: "EXACT_PUSHDOWN", reasons };
37672
+ }
37673
+ if (op === "AND" && (left.capability === "EXACT_PUSHDOWN" || right.capability === "EXACT_PUSHDOWN" || left.capability === "SUPERSET_PREFILTER" || right.capability === "SUPERSET_PREFILTER")) {
37674
+ return {
37675
+ capability: "SUPERSET_PREFILTER",
37676
+ reasons: [{ code: "WHERE_SUPERSET_PREFILTER" }, ...reasons]
37677
+ };
37678
+ }
37679
+ return { capability: "LOCAL_ONLY", reasons };
37680
+ }
37681
+ function localExpression() {
37682
+ return { capability: "LOCAL_ONLY", reasons: [{ code: "WHERE_EXPRESSION_LOCAL_ONLY" }] };
37683
+ }
37684
+ function unsupported(code, field, fieldType, operator) {
37685
+ return { capability: "UNSUPPORTED", reasons: [{ code, field, fieldType, operator }] };
37686
+ }
37687
+
37040
37688
  // src/execute.ts
37041
37689
  var SEARCH_ABORTED_WARNING = "\u691C\u7D22\u304C 10 \u4E07\u4EF6\u3067\u6253\u3061\u5207\u3089\u308C\u3001\u7D50\u679C\u304C\u6B20\u843D\u3057\u305F\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002";
37042
37690
  var SearchAbortedError = class extends Error {
@@ -37047,8 +37695,20 @@ var SearchAbortedError = class extends Error {
37047
37695
  };
37048
37696
  var materializedMetaBySelectResult = /* @__PURE__ */ new WeakMap();
37049
37697
  var materializedMetaByValidationResult = /* @__PURE__ */ new WeakMap();
37698
+ var defaultCacheContextByClient = /* @__PURE__ */ new WeakMap();
37699
+ var nextDefaultCacheContextId = 1;
37700
+ function resolveCacheContext(client, explicit) {
37701
+ if (explicit) return explicit;
37702
+ let context = defaultCacheContextByClient.get(client);
37703
+ if (!context) {
37704
+ context = `client:${nextDefaultCacheContextId++}`;
37705
+ defaultCacheContextByClient.set(client, context);
37706
+ }
37707
+ return context;
37708
+ }
37050
37709
  async function execute(sql, client, options = {}) {
37051
37710
  const startedAt = Date.now();
37711
+ const cacheContext = resolveCacheContext(client, options.cacheContext);
37052
37712
  const stmt = parseSql(sql);
37053
37713
  const metrics = createEmptyMetrics();
37054
37714
  const countedClient = wrapClientWithMetrics(client, metrics);
@@ -37062,7 +37722,7 @@ async function execute(sql, client, options = {}) {
37062
37722
  stmt,
37063
37723
  guardedClient,
37064
37724
  options,
37065
- options.cacheContext ?? "default"
37725
+ cacheContext
37066
37726
  );
37067
37727
  metrics.elapsedMs = Date.now() - startedAt;
37068
37728
  return { ...attachSearchAbortWarning(result, collector), metrics };
@@ -37177,7 +37837,7 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
37177
37837
  case "DESCRIBE":
37178
37838
  return executeDescribe(stmt, client, cacheContext);
37179
37839
  case "EXPLAIN":
37180
- return executeExplain(stmt);
37840
+ return executeExplain(stmt, client, cacheContext, options.maxRecords ?? 1e4);
37181
37841
  // 一時テーブルはバッチスコープのため単文実行では拒否する(executeBatch を使う)
37182
37842
  case "CREATE_TEMP_TABLE":
37183
37843
  throw new Error("ArgumentError: CREATE TEMP TABLE requires a batch (temp tables are batch-scoped).");
@@ -37208,7 +37868,7 @@ function materializedColumnMetaEqual(left, right) {
37208
37868
  if (!left || !right || left.size !== right.size) return false;
37209
37869
  for (const [column, meta3] of left) {
37210
37870
  const candidate = right.get(column);
37211
- if (!candidate || candidate.sortKind !== meta3.sortKind || candidate.fieldType !== meta3.fieldType) return false;
37871
+ if (!candidate || candidate.sortKind !== meta3.sortKind || candidate.fieldType !== meta3.fieldType || !fieldSemanticsEqual(candidate.semantics, meta3.semantics)) return false;
37212
37872
  }
37213
37873
  return true;
37214
37874
  }
@@ -37239,7 +37899,7 @@ async function executeBatch(sql, client, options = {}) {
37239
37899
  const countedClient = wrapClientWithMetrics(client, metrics);
37240
37900
  const startedAt = Date.now();
37241
37901
  const deadline = options.timeoutMs != null ? startedAt + options.timeoutMs : null;
37242
- const cacheContext = options.cacheContext ?? "default";
37902
+ const cacheContext = resolveCacheContext(client, options.cacheContext);
37243
37903
  const tempTables = /* @__PURE__ */ new Map();
37244
37904
  const variables = /* @__PURE__ */ new Map();
37245
37905
  const results = [];
@@ -37333,7 +37993,10 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
37333
37993
  cacheContext,
37334
37994
  tempTables
37335
37995
  );
37336
- variables.set(stmt.name, { type: "string", value });
37996
+ const first = resolvedStmt2.expr.query.columns[0];
37997
+ const numeric = first?.type === "ARITH_COL" || first?.type === "ARITH_AGG_COL" || first?.type === "WINDOW_COL" || first?.type === "AGGREGATE" && (first.func === "COUNT" || first.func === "SUM" || first.func === "AVG");
37998
+ const numberValue = numeric ? Number(value) : Number.NaN;
37999
+ variables.set(stmt.name, numeric && Number.isFinite(numberValue) ? { type: "number", value: numberValue } : { type: "string", value });
37337
38000
  } catch (e) {
37338
38001
  if (e instanceof ScalarSubqueryError) {
37339
38002
  throw new Error(`ArgumentError: ${e.message}`);
@@ -37564,13 +38227,14 @@ var ScalarSubqueryError = class extends Error {
37564
38227
  };
37565
38228
  async function executeAssert(stmt, client, options, cacheContext, tempTables) {
37566
38229
  const left = await evalAssertOperand(stmt.left, client, options, cacheContext, tempTables);
38230
+ const semantics = stmt.left.type === "NUMBER" || stmt.left.type === "ARITH" ? syntheticSemantics("number") : syntheticSemantics("string");
37567
38231
  if (stmt.op === "BETWEEN") {
37568
38232
  if (stmt.low === null || stmt.high === null) {
37569
38233
  throw new Error("ArgumentError: malformed ASSERT statement.");
37570
38234
  }
37571
38235
  const low = await evalAssertOperand(stmt.low, client, options, cacheContext, tempTables);
37572
38236
  const high = await evalAssertOperand(stmt.high, client, options, cacheContext, tempTables);
37573
- if (!compareScalarValues(">=", left, low) || !compareScalarValues("<=", left, high)) {
38237
+ if (!compareScalarValues(">=", left, low, semantics) || !compareScalarValues("<=", left, high, semantics)) {
37574
38238
  throw new AssertError(`assertion failed: ${stmt.text} (actual: ${left}).`);
37575
38239
  }
37576
38240
  return { type: "ASSERT", condition: stmt.text };
@@ -37579,7 +38243,7 @@ async function executeAssert(stmt, client, options, cacheContext, tempTables) {
37579
38243
  throw new Error("ArgumentError: malformed ASSERT statement.");
37580
38244
  }
37581
38245
  const right = await evalAssertOperand(stmt.right, client, options, cacheContext, tempTables);
37582
- if (!compareScalarValues(stmt.op, left, right)) {
38246
+ if (!compareScalarValues(stmt.op, left, right, semantics)) {
37583
38247
  throw new AssertError(`assertion failed: ${stmt.text} (actual: ${left}).`);
37584
38248
  }
37585
38249
  return { type: "ASSERT", condition: stmt.text };
@@ -37652,6 +38316,149 @@ function evalAssertArith(node) {
37652
38316
  }
37653
38317
  throw new Error(`ArgumentError: unsupported operand in ASSERT expression: ${node.type}`);
37654
38318
  }
38319
+ async function buildWhereFieldSemanticsResolver(stmt, client, cacheContext, materializedTables, forcePhysicalMetadata = false) {
38320
+ const tables = [stmt.from, ...stmt.joins.map((join) => join.table)];
38321
+ const physicalAppIds = forcePhysicalMetadata || whereNeedsFieldMetadata(stmt.where) ? [...new Set(tables.filter((table) => table.cteName === null).map((table) => table.appId))] : [];
38322
+ const infosByApp = new Map(
38323
+ await Promise.all(physicalAppIds.map(async (appId) => {
38324
+ const infos = await getFieldsCached(appId, client, cacheContext);
38325
+ return [appId, new Map(infos.map((info) => [info.code, info]))];
38326
+ }))
38327
+ );
38328
+ const orderedFields = /* @__PURE__ */ new Set();
38329
+ const collectOrderedFields = (node) => {
38330
+ if (Array.isArray(node)) {
38331
+ node.forEach(collectOrderedFields);
38332
+ return;
38333
+ }
38334
+ if (node === null || typeof node !== "object") return;
38335
+ const value = node;
38336
+ if (value["type"] === "SELECT") return;
38337
+ if (value["type"] === "BINARY" && [">", "<", ">=", "<="].includes(String(value["op"]))) {
38338
+ const left = value["left"];
38339
+ if (left?.["type"] === "FIELD" && typeof left["field"] === "string") {
38340
+ orderedFields.add(left["field"]);
38341
+ }
38342
+ }
38343
+ Object.values(value).forEach(collectOrderedFields);
38344
+ };
38345
+ collectOrderedFields(stmt.where);
38346
+ collectOrderedFields(stmt.having);
38347
+ for (const column of stmt.columns) {
38348
+ if (column.type === "CASE_COL") collectOrderedFields(column.expr);
38349
+ }
38350
+ const statusOrdersByApp = /* @__PURE__ */ new Map();
38351
+ await Promise.all([...infosByApp].map(async ([appId, infos]) => {
38352
+ const needsStatus = [...orderedFields].some((field) => infos.get(field)?.fieldType === "STATUS");
38353
+ if (!needsStatus) return;
38354
+ const order = await loadProcessStatusOrder(appId, client, cacheContext);
38355
+ if (order) statusOrdersByApp.set(appId, order);
38356
+ }));
38357
+ const fromPhysical = (table, field) => {
38358
+ if (field === "$id") return withFieldSemanticSource(
38359
+ resolveFieldSemantics({ fieldType: "__ID__" }),
38360
+ table.appId,
38361
+ "$id"
38362
+ );
38363
+ const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field));
38364
+ if (!info) return void 0;
38365
+ const base = info.semantics ?? resolveFieldSemantics(info);
38366
+ const semantics = info.fieldType === "STATUS" && statusOrdersByApp.has(table.appId) ? { ...base, optionOrder: statusOrdersByApp.get(table.appId) } : base;
38367
+ return withFieldSemanticSource(
38368
+ semantics,
38369
+ table.appId,
38370
+ info.code
38371
+ );
38372
+ };
38373
+ return (field) => {
38374
+ if (field.tableAlias !== null) {
38375
+ if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
38376
+ return fromPhysical(stmt.from, field.field);
38377
+ }
38378
+ const table = tables.find((candidate) => candidate.alias === field.tableAlias);
38379
+ if (!table) return void 0;
38380
+ if (table.cteName !== null) {
38381
+ return materializedTables?.get(table.cteName)?.columnMeta?.get(field.field)?.semantics ?? syntheticSemantics("string");
38382
+ }
38383
+ return fromPhysical(table, field.field);
38384
+ }
38385
+ if (stmt.joins.length === 0) {
38386
+ if (stmt.from.cteName !== null) {
38387
+ return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(field.field)?.semantics ?? syntheticSemantics("string");
38388
+ }
38389
+ return fromPhysical(stmt.from, field.field);
38390
+ }
38391
+ const matches = tables.flatMap((table) => {
38392
+ const semantics = table.cteName !== null ? materializedTables?.get(table.cteName)?.columnMeta?.get(field.field)?.semantics : fromPhysical(table, field.field);
38393
+ return semantics ? [semantics] : [];
38394
+ });
38395
+ if (matches.length === 1) return matches[0];
38396
+ return matches.length > 1 ? syntheticSemantics("string") : void 0;
38397
+ };
38398
+ }
38399
+ function selectCaseConditionsNeedFieldMetadata(stmt) {
38400
+ return stmt.columns.some((column) => column.type === "CASE_COL" && column.expr.branches.some((branch) => whereNeedsFieldMetadata(branch.condition)));
38401
+ }
38402
+ function buildHavingFieldSemanticsResolver(stmt, rowResolver) {
38403
+ const aliases = /* @__PURE__ */ new Map();
38404
+ for (const column of stmt.columns) {
38405
+ if (!("alias" in column) || !column.alias) continue;
38406
+ let semantics;
38407
+ if (column.type === "FIELD") semantics = rowResolver(aggregateFieldRef(column.field));
38408
+ else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
38409
+ semantics = syntheticSemantics("number");
38410
+ } else if (column.type === "AGGREGATE") {
38411
+ if (column.func === "MIN" || column.func === "MAX") {
38412
+ semantics = column.arg.type === "FIELD_REF" ? rowResolver(aggregateFieldRef(column.arg.field)) : syntheticSemantics("number");
38413
+ } else {
38414
+ semantics = column.func === "GROUP_CONCAT" ? syntheticSemantics("string") : syntheticSemantics("number");
38415
+ }
38416
+ } else if (column.type === "STRFUNC_COL") {
38417
+ semantics = stringFunctionColumnMeta(column.expr).semantics;
38418
+ } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "CASE_COL") {
38419
+ semantics = syntheticSemantics("string");
38420
+ }
38421
+ if (semantics) aliases.set(column.alias, semantics);
38422
+ }
38423
+ return (field) => field.tableAlias === null && aliases.has(field.field) ? aliases.get(field.field) : rowResolver(field);
38424
+ }
38425
+ async function resolveSelectWhereCapability(stmt, client, cacheContext, materializedTables) {
38426
+ if (stmt.where === null) return classifyWhereCapability(null, () => void 0);
38427
+ const resolver = await buildWhereFieldSemanticsResolver(stmt, client, cacheContext, materializedTables);
38428
+ return classifyWhereCapability(stmt.where, resolver);
38429
+ }
38430
+ function formatWhereCapabilityFailure(result) {
38431
+ const reason = result.reasons.find(
38432
+ (candidate) => candidate.code === "WHERE_FIELD_UNRESOLVED" || candidate.code === "WHERE_OPERATOR_UNSUPPORTED"
38433
+ ) ?? result.reasons[0];
38434
+ const details = [
38435
+ reason?.field ? `field=${reason.field}` : null,
38436
+ reason?.fieldType ? `type=${reason.fieldType}` : null,
38437
+ reason?.operator ? `operator=${reason.operator}` : null,
38438
+ reason?.code ? `reason=${reason.code}` : null
38439
+ ].filter((value) => value !== null).join(", ");
38440
+ return details || "reason=WHERE_UNSUPPORTED";
38441
+ }
38442
+ function hasCanonicalOrder(stmt) {
38443
+ return stmt.orderBy.length > 0 || stmt.columns.some(
38444
+ (column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
38445
+ );
38446
+ }
38447
+ async function assertDmlWhereCapability(stmt, client, cacheContext) {
38448
+ if (stmt.subtableCode || stmt.type === "UPDATE" && stmt.from != null) return;
38449
+ const fields = whereNeedsFieldMetadata(stmt.where) ? await getFieldsCached(stmt.appId, client, cacheContext) : [];
38450
+ const byCode = new Map(fields.map((field) => [field.code, field]));
38451
+ const result = classifyWhereCapability(stmt.where, (field) => {
38452
+ if (field.field === "$id") return resolveFieldSemantics({ fieldType: "__ID__" });
38453
+ const info = byCode.get(field.field);
38454
+ return info?.semantics ?? (info ? resolveFieldSemantics(info) : void 0);
38455
+ });
38456
+ if (result.capability !== "EXACT_PUSHDOWN") {
38457
+ throw new DmlConvertError(
38458
+ `WHERE predicate cannot be represented by kintone REST (${formatWhereCapabilityFailure(result)})`
38459
+ );
38460
+ }
38461
+ }
37655
38462
  async function executeSelect(stmt, client, options, cacheContext, cteCache, captureColumnMeta = false) {
37656
38463
  let result;
37657
38464
  if (isNoFromSelect(stmt)) {
@@ -37662,12 +38469,51 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
37662
38469
  return result;
37663
38470
  }
37664
38471
  await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
37665
- const mode = resolveSelectMode(stmt);
37666
- await validateSelectFieldCodes(stmt, mode, client, cacheContext);
37667
- if (mode === "SIMPLE") {
37668
- result = await executeSimpleSelect(stmt, client, options, cacheContext);
37669
- } else {
37670
- result = await executeFullScanSelect(stmt, client, options, cacheContext, cteCache);
38472
+ const whereCapability = await resolveSelectWhereCapability(stmt, client, cacheContext, cteCache);
38473
+ if (whereCapability.capability === "UNSUPPORTED") {
38474
+ throw new Error(`ArgumentError: WHERE predicate is unsupported (${formatWhereCapabilityFailure(whereCapability)}).`);
38475
+ }
38476
+ const staticMode = resolveSelectMode(stmt);
38477
+ const mode = whereCapability.capability === "EXACT_PUSHDOWN" ? staticMode : "FULL_SCAN";
38478
+ const orderMeta = await buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
38479
+ const orderPlan = hasCanonicalOrder(stmt) ? (stmt.orderMode === "KINTONE_NATIVE" ? planKorderNative : planCanonicalOrder)({
38480
+ stmt,
38481
+ staticMode: mode,
38482
+ whereCapability: whereCapability.capability,
38483
+ orderSemantics: orderMeta.semantics,
38484
+ maxRecords: options.maxRecords ?? 1e4,
38485
+ hasKlike: whereHasKlike(stmt.where)
38486
+ }) : null;
38487
+ await validateSelectFieldCodes(
38488
+ stmt,
38489
+ orderPlan?.kind === "CANONICAL_LOCAL" ? "FULL_SCAN" : mode,
38490
+ client,
38491
+ cacheContext
38492
+ );
38493
+ const completeInputRequired = orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" ? requiresCompleteInput({ ...stmt, orderBy: [] }) : requiresCompleteInput(stmt);
38494
+ const truncateWasDisabled = completeInputRequired && options.onLimitReached === "truncate";
38495
+ const effectiveOptions = truncateWasDisabled ? { ...options, onLimitReached: "error" } : options;
38496
+ try {
38497
+ if (mode === "SIMPLE") {
38498
+ result = await executeSimpleSelect(stmt, client, effectiveOptions, cacheContext, orderPlan, orderMeta);
38499
+ } else {
38500
+ result = await executeFullScanSelect(
38501
+ stmt,
38502
+ client,
38503
+ effectiveOptions,
38504
+ cacheContext,
38505
+ cteCache,
38506
+ whereCapability.capability === "EXACT_PUSHDOWN",
38507
+ orderMeta
38508
+ );
38509
+ }
38510
+ } catch (error51) {
38511
+ if (completeInputRequired && error51 instanceof FetchAllLimitError) {
38512
+ throw new FetchAllLimitError(
38513
+ "ORDER BY\u306E\u6B63\u3057\u3044\u7D50\u679C\u306B\u306F\u5B8C\u5168\u306A\u5019\u88DC\u96C6\u5408\u304C\u5FC5\u8981\u3067\u3059\u3002" + (truncateWasDisabled ? "onLimit=truncate\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002" : "") + error51.message
38514
+ );
38515
+ }
38516
+ throw error51;
37671
38517
  }
37672
38518
  if (captureColumnMeta) {
37673
38519
  materializedMetaBySelectResult.set(result, await inferSelectColumnMeta(stmt, result.columns, client, cacheContext, cteCache));
@@ -37728,19 +38574,30 @@ function executeNoFromSelect(stmt) {
37728
38574
  const rows = applyLimit(projected, stmt.limit, stmt.offset);
37729
38575
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [] };
37730
38576
  }
37731
- async function executeSimpleSelect(stmt, client, options, cacheContext) {
37732
- const params = selectToKintoneParams(stmt);
38577
+ async function executeSimpleSelect(stmt, client, options, cacheContext, orderPlan, orderMeta) {
38578
+ const restStmt = orderPlan?.kind === "CANONICAL_REST_TOP_N" ? withCanonicalRestTie(stmt) : stmt;
38579
+ const params = selectToKintoneParams(restStmt);
38580
+ const fetchFields = orderPlan?.kind === "CANONICAL_LOCAL" ? selectToFetchAllFields(stmt, stmt.from) : params.fields;
37733
38581
  const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
37734
38582
  const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
38583
+ const projectionSemanticsResolver = stmt.columns.some((column) => column.type === "CASE_COL") ? await buildWhereFieldSemanticsResolver(
38584
+ stmt,
38585
+ client,
38586
+ cacheContext,
38587
+ void 0,
38588
+ selectCaseConditionsNeedFieldMetadata(stmt)
38589
+ ) : void 0;
37735
38590
  const maxRecords2 = options.maxRecords ?? 1e4;
37736
38591
  const warnings = /* @__PURE__ */ new Set();
37737
38592
  const onLimit2 = options.onLimitReached ?? "error";
37738
38593
  const parallel = options.fetchParallel ?? 1;
37739
- const useSingleGet = stmt.limit !== null && stmt.limit <= 500;
38594
+ const useRestWindow = stmt.orderBy.length > 0 ? orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" : stmt.limit !== null && stmt.limit <= 500;
37740
38595
  const needed = stmt.limit === null ? null : (stmt.offset ?? 0) + stmt.limit;
37741
38596
  const stopAfter = stmt.orderBy.length === 0 && needed !== null && needed <= maxRecords2 && !whereHasKlike(stmt.where) ? needed : void 0;
37742
38597
  let records;
37743
- if (useSingleGet) {
38598
+ if (orderPlan?.kind === "KORDER_NATIVE" && stmt.limit === 0) {
38599
+ records = [];
38600
+ } else if (useRestWindow) {
37744
38601
  const res = await client.getRecords({
37745
38602
  app: params.app,
37746
38603
  query: params.query,
@@ -37753,7 +38610,7 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
37753
38610
  client.getRecords,
37754
38611
  params.app,
37755
38612
  baseQuery,
37756
- params.fields,
38613
+ fetchFields,
37757
38614
  {
37758
38615
  parallel,
37759
38616
  maxRecords: maxRecords2,
@@ -37766,16 +38623,23 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
37766
38623
  );
37767
38624
  }
37768
38625
  let rows = records.map((r) => flatten(r, null));
37769
- if (!useSingleGet) {
37770
- const { optionOrders, sortKinds } = await buildOrderByMetaForSelect(stmt, client, cacheContext);
37771
- rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
38626
+ if (!useRestWindow) {
38627
+ rows = applyOrderBy(
38628
+ rows,
38629
+ stmt.orderBy,
38630
+ orderMeta.optionOrders,
38631
+ orderMeta.sortKinds,
38632
+ orderMeta.semantics
38633
+ );
37772
38634
  rows = applyLimit(rows, stmt.limit, stmt.offset);
37773
38635
  }
37774
38636
  const { rows: projected, columns } = project(
37775
38637
  rows,
37776
38638
  stmt.columns,
37777
38639
  void 0,
37778
- fieldTypeResolvers.row
38640
+ fieldTypeResolvers.row,
38641
+ void 0,
38642
+ projectionSemanticsResolver
37779
38643
  );
37780
38644
  return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
37781
38645
  }
@@ -37848,8 +38712,8 @@ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
37848
38712
  const statusFields = collectCandidateFieldCodes(candidates).filter((fieldCode) => fieldTypes.get(fieldCode) === "STATUS");
37849
38713
  if (statusFields.length > 0) {
37850
38714
  const process4 = await getProcessStatusesCached(appId, client, cacheContext);
37851
- if (process4.enable && process4.states.length > 0) {
37852
- const states = new Set(process4.states);
38715
+ if (process4.enable && process4.states && process4.states.length > 0) {
38716
+ const states = new Set(process4.states.map((state) => state.name));
37853
38717
  for (const fieldCode of statusFields) fieldOptions.set(fieldCode, states);
37854
38718
  }
37855
38719
  }
@@ -38027,7 +38891,18 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
38027
38891
  return [appId, new Map(infos.map((info) => [info.code, info]))];
38028
38892
  }))
38029
38893
  );
38894
+ const statusOrdersByApp = /* @__PURE__ */ new Map();
38895
+ const aggregateFieldNames = new Set(refs.map((ref) => ref.field));
38896
+ await Promise.all([...fieldInfosByApp].map(async ([appId, infos]) => {
38897
+ if (![...aggregateFieldNames].some((field) => infos.get(field)?.fieldType === "STATUS")) return;
38898
+ const order = await loadProcessStatusOrder(appId, client, cacheContext);
38899
+ if (order) statusOrdersByApp.set(appId, order);
38900
+ }));
38030
38901
  const tables = [stmt.from, ...stmt.joins.map((join) => join.table)];
38902
+ const semanticsForInfo = (info, appId) => {
38903
+ const base = info.semantics ?? resolveFieldSemantics(info);
38904
+ return info.fieldType === "STATUS" && statusOrdersByApp.has(appId) ? { ...base, optionOrder: statusOrdersByApp.get(appId) } : base;
38905
+ };
38031
38906
  return (ref) => {
38032
38907
  let info;
38033
38908
  if (ref.tableAlias !== null) {
@@ -38037,40 +38912,130 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
38037
38912
  const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
38038
38913
  if (!table) return void 0;
38039
38914
  if (table.cteName !== null) {
38040
- return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.sortKind;
38915
+ return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
38041
38916
  }
38042
38917
  info = fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
38043
38918
  }
38044
38919
  } else if (stmt.joins.length === 0) {
38045
38920
  if (stmt.from.cteName !== null) {
38046
- return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field)?.sortKind;
38921
+ return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
38047
38922
  }
38048
38923
  info = fieldInfosByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
38049
38924
  } else {
38050
38925
  const matches = tables.flatMap((table) => {
38051
38926
  if (table.cteName !== null) {
38052
38927
  const materialized = materializedTables?.get(table.cteName);
38053
- return materialized?.columns.includes(ref.field) ? [materialized.columnMeta?.get(ref.field)?.sortKind] : [];
38928
+ return materialized?.columns.includes(ref.field) ? [materialized.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string")] : [];
38054
38929
  }
38055
38930
  const candidate = fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
38056
- return candidate ? [aggregateSortKind(candidate)] : [];
38931
+ return candidate ? [semanticsForInfo(candidate, table.appId)] : [];
38057
38932
  });
38058
38933
  if (matches.length !== 1) return void 0;
38059
38934
  return matches[0];
38060
38935
  }
38061
- return info ? aggregateSortKind(info) : void 0;
38936
+ if (!info) return void 0;
38937
+ const sourceTable = ref.tableAlias !== null ? tables.find((table) => table.alias === ref.tableAlias) : stmt.joins.length === 0 ? stmt.from : void 0;
38938
+ return semanticsForInfo(info, sourceTable?.appId ?? stmt.from.appId);
38062
38939
  };
38063
38940
  }
38064
38941
  function fieldCodeForTypeLookup(table, field) {
38065
38942
  if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
38066
38943
  return field;
38067
38944
  }
38068
- function materializedMetaFromFieldInfo(info) {
38069
- return { sortKind: aggregateSortKind(info), fieldType: info.fieldType };
38945
+ function materializedMetaFromFieldInfo(info, sourceAppId) {
38946
+ const semantics = info.semantics ?? resolveFieldSemantics(info);
38947
+ return {
38948
+ sortKind: aggregateSortKind(info),
38949
+ fieldType: info.fieldType,
38950
+ semantics: sourceAppId === void 0 ? semantics : withFieldSemanticSource(semantics, sourceAppId, info.code)
38951
+ };
38952
+ }
38953
+ function withCanonicalRestTie(stmt) {
38954
+ const hasId = stmt.orderBy.some(
38955
+ (item) => item.key.type === "FIELD_NAME" && item.key.name === "$id"
38956
+ );
38957
+ return hasId ? stmt : {
38958
+ ...stmt,
38959
+ orderBy: [...stmt.orderBy, { key: { type: "FIELD_NAME", name: "$id" }, direction: "ASC" }]
38960
+ };
38961
+ }
38962
+ function syntheticColumnMeta(compareMode) {
38963
+ return { sortKind: compareMode, semantics: syntheticSemantics(compareMode) };
38964
+ }
38965
+ function unknownStringColumnMeta() {
38966
+ return { semantics: syntheticSemantics("string", "KSQL_UNKNOWN") };
38967
+ }
38968
+ function unsupportedColumnMeta(fieldType = "KSQL_ARRAY") {
38969
+ return {
38970
+ semantics: { fieldType, compareMode: "unsupported", inSubtable: false, requiresCollectionOperators: false }
38971
+ };
38972
+ }
38973
+ function systemColumnMeta(field) {
38974
+ if (field === "$id" || field === "_rid" || field === "_pid") {
38975
+ return {
38976
+ sortKind: "number",
38977
+ fieldType: "__ID__",
38978
+ semantics: resolveFieldSemantics({ fieldType: "__ID__" })
38979
+ };
38980
+ }
38981
+ if (field === "$revision") return syntheticColumnMeta("number");
38982
+ return void 0;
38983
+ }
38984
+ var NUMBER_RETURNING_STRING_FUNCTIONS = /* @__PURE__ */ new Set([
38985
+ "LENGTH",
38986
+ "INSTR",
38987
+ "ROUND",
38988
+ "FLOOR",
38989
+ "CEIL",
38990
+ "TRUNCATE",
38991
+ "YEAR",
38992
+ "MONTH",
38993
+ "DAY",
38994
+ "DATEDIFF",
38995
+ "ABS",
38996
+ "MOD",
38997
+ "POWER",
38998
+ "SQRT"
38999
+ ]);
39000
+ function stringFunctionColumnMeta(expr) {
39001
+ if (expr.func === "CAST") {
39002
+ const target = expr.args[1];
39003
+ return target?.type === "STRING" && target.value === "NUMBER" ? syntheticColumnMeta("number") : syntheticColumnMeta("string");
39004
+ }
39005
+ return NUMBER_RETURNING_STRING_FUNCTIONS.has(expr.func) ? syntheticColumnMeta("number") : syntheticColumnMeta("string");
39006
+ }
39007
+ function caseResultColumnMeta(result, resolveField2) {
39008
+ if (result.type === "STRING") return syntheticColumnMeta("string");
39009
+ if (result.type === "ARRAY") return unsupportedColumnMeta();
39010
+ if (result.type === "NUMBER" || result.type === "ARITH") return syntheticColumnMeta("number");
39011
+ if (result.type === "STRING_FUNC") return stringFunctionColumnMeta(result);
39012
+ const source = resolveField2(aggregateFieldRef(result.field));
39013
+ return source ?? unknownStringColumnMeta();
39014
+ }
39015
+ function mergeExpressionColumnMeta(candidates) {
39016
+ if (candidates.length === 0) return unknownStringColumnMeta();
39017
+ const first = candidates[0];
39018
+ const withoutSource = (semantics) => {
39019
+ if (!semantics) return void 0;
39020
+ const { source: _source, ...rest } = semantics;
39021
+ return rest;
39022
+ };
39023
+ if (candidates.every(
39024
+ (candidate) => candidate.sortKind === first.sortKind && candidate.fieldType === first.fieldType && fieldSemanticsEqual(withoutSource(candidate.semantics), withoutSource(first.semantics))
39025
+ )) {
39026
+ const sameSource = candidates.every(
39027
+ (candidate) => fieldSemanticsEqual(candidate.semantics, first.semantics)
39028
+ );
39029
+ return sameSource ? first : { ...first, semantics: withoutSource(first.semantics) };
39030
+ }
39031
+ if (candidates.some((candidate) => candidate.semantics?.compareMode === "unsupported")) {
39032
+ return unsupportedColumnMeta("KSQL_MIXED_UNSUPPORTED");
39033
+ }
39034
+ return unknownStringColumnMeta();
38070
39035
  }
38071
39036
  function selectNeedsSourceColumnMeta(stmt) {
38072
39037
  return stmt.columns.some(
38073
- (column) => column.type === "FIELD" || column.type === "WILDCARD" || column.type === "PARENT_WILDCARD" || column.type === "AGGREGATE" && (column.func === "MIN" || column.func === "MAX") && column.arg.type === "FIELD_REF"
39038
+ (column) => column.type === "FIELD" || column.type === "WILDCARD" || column.type === "PARENT_WILDCARD" || column.type === "CASE_COL" || column.type === "AGGREGATE" && (column.func === "MIN" || column.func === "MAX") && column.arg.type === "FIELD_REF"
38074
39039
  );
38075
39040
  }
38076
39041
  async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables) {
@@ -38087,18 +39052,18 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
38087
39052
  if (ref.tableAlias !== null) {
38088
39053
  if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
38089
39054
  const info2 = physicalInfos.get(stmt.from.appId)?.get(ref.field);
38090
- return info2 ? materializedMetaFromFieldInfo(info2) : void 0;
39055
+ return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
38091
39056
  }
38092
39057
  const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
38093
39058
  if (!table) return void 0;
38094
39059
  if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
38095
39060
  const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
38096
- return info ? materializedMetaFromFieldInfo(info) : void 0;
39061
+ return info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
38097
39062
  }
38098
39063
  if (stmt.joins.length === 0) {
38099
39064
  if (stmt.from.cteName !== null) return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field);
38100
39065
  const info = physicalInfos.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
38101
- return info ? materializedMetaFromFieldInfo(info) : void 0;
39066
+ return info ? materializedMetaFromFieldInfo(info, stmt.from.appId) : systemColumnMeta(ref.field);
38102
39067
  }
38103
39068
  const matches = tables.flatMap((table) => {
38104
39069
  if (table.cteName !== null) {
@@ -38107,7 +39072,8 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
38107
39072
  return [materialized.columnMeta?.get(ref.field)];
38108
39073
  }
38109
39074
  const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
38110
- return info ? [materializedMetaFromFieldInfo(info)] : [];
39075
+ const meta3 = info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
39076
+ return meta3 ? [meta3] : [];
38111
39077
  });
38112
39078
  return matches.length === 1 ? matches[0] : void 0;
38113
39079
  };
@@ -38137,19 +39103,27 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
38137
39103
  meta3 = resolveField2(aggregateFieldRef(column.field));
38138
39104
  } else if (column.type === "AGGREGATE") {
38139
39105
  if (column.func === "GROUP_CONCAT") {
38140
- meta3 = { sortKind: "string" };
39106
+ meta3 = syntheticColumnMeta("string");
38141
39107
  } else if (column.func === "COUNT" || column.func === "SUM" || column.func === "AVG") {
38142
- meta3 = { sortKind: "number" };
39108
+ meta3 = syntheticColumnMeta("number");
38143
39109
  } else if ((column.func === "MIN" || column.func === "MAX") && column.arg.type === "FIELD_REF") {
38144
39110
  const source = resolveField2(aggregateFieldRef(column.arg.field));
38145
- if (source?.sortKind) meta3 = { sortKind: source.sortKind };
39111
+ if (source) meta3 = source;
38146
39112
  }
38147
39113
  } else if (column.type === "ARITH_AGG_COL" || column.type === "ARITH_COL") {
38148
- meta3 = { sortKind: "number" };
39114
+ meta3 = syntheticColumnMeta("number");
38149
39115
  } else if (column.type === "LITERAL_COL") {
38150
- meta3 = { sortKind: "string" };
39116
+ meta3 = syntheticColumnMeta("string");
39117
+ } else if (column.type === "STRFUNC_COL") {
39118
+ meta3 = stringFunctionColumnMeta(column.expr);
38151
39119
  } else if (column.type === "WINDOW_COL") {
38152
- meta3 = { sortKind: "number" };
39120
+ meta3 = syntheticColumnMeta("number");
39121
+ } else if (column.type === "CASE_COL") {
39122
+ const results = column.expr.branches.map((branch) => caseResultColumnMeta(branch.result, resolveField2));
39123
+ if (column.expr.elseResult) results.push(caseResultColumnMeta(column.expr.elseResult, resolveField2));
39124
+ meta3 = mergeExpressionColumnMeta(results);
39125
+ } else if (column.type === "SCALAR_SUBQUERY_COL") {
39126
+ meta3 = unknownStringColumnMeta();
38153
39127
  }
38154
39128
  if (meta3) inferred.set(output, meta3);
38155
39129
  });
@@ -38163,7 +39137,8 @@ function mergeUnionColumnMeta(left, right) {
38163
39137
  const a = leftMeta?.get(column);
38164
39138
  const rightColumn = right.columns[index];
38165
39139
  const b = rightColumn === void 0 ? void 0 : rightMeta?.get(rightColumn);
38166
- if (a && b && a.sortKind === b.sortKind && a.fieldType === b.fieldType) merged.set(column, a);
39140
+ if (a && b) merged.set(column, mergeExpressionColumnMeta([a, b]));
39141
+ else if (a || b) merged.set(column, unknownStringColumnMeta());
38167
39142
  });
38168
39143
  return merged;
38169
39144
  }
@@ -38200,7 +39175,7 @@ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
38200
39175
  };
38201
39176
  return { row, having };
38202
39177
  }
38203
- async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
39178
+ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache, allowOriginalWherePushdown = true, preloadedOrderMeta) {
38204
39179
  const maxRecords2 = options.maxRecords ?? 1e4;
38205
39180
  const warnings = /* @__PURE__ */ new Set();
38206
39181
  const parallel = options.fetchParallel ?? 1;
@@ -38214,6 +39189,14 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
38214
39189
  loadAggregateSortKindResolver(stmt, client, cacheContext, cteCache)
38215
39190
  ]);
38216
39191
  const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
39192
+ const fieldSemanticsResolver = await buildWhereFieldSemanticsResolver(
39193
+ stmt,
39194
+ client,
39195
+ cacheContext,
39196
+ cteCache,
39197
+ whereNeedsFieldMetadata(stmt.having) || selectCaseConditionsNeedFieldMetadata(stmt)
39198
+ );
39199
+ const havingFieldSemanticsResolver = buildHavingFieldSemanticsResolver(stmt, fieldSemanticsResolver);
38217
39200
  const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
38218
39201
  validateKlikePushdownPlan(pushdownPlan);
38219
39202
  const mainPushDown = pushdownPlan.mainCondition;
@@ -38227,7 +39210,8 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
38227
39210
  true,
38228
39211
  options.onLimitReached ?? "error",
38229
39212
  warnings,
38230
- mainPushDown
39213
+ mainPushDown,
39214
+ allowOriginalWherePushdown
38231
39215
  );
38232
39216
  const parallelJoins = [];
38233
39217
  const onOptJoins = [];
@@ -38253,7 +39237,7 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
38253
39237
  }
38254
39238
  }
38255
39239
  const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
38256
- const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
39240
+ const orderByMetaPromise = preloadedOrderMeta ? Promise.resolve(preloadedOrderMeta) : buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
38257
39241
  scalarCachePromise.catch(() => {
38258
39242
  });
38259
39243
  orderByMetaPromise.catch(() => {
@@ -38290,15 +39274,18 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
38290
39274
  tables.set(join.table.alias, joinRecords);
38291
39275
  }));
38292
39276
  const scalarCache = await scalarCachePromise;
38293
- const { optionOrders, sortKinds } = await orderByMetaPromise;
39277
+ const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
38294
39278
  const { rows, columns } = runFullScan({
38295
39279
  tables,
38296
39280
  stmt,
38297
39281
  scalarCache,
38298
39282
  optionOrders,
38299
39283
  sortKinds,
39284
+ orderSemantics: semantics,
38300
39285
  fieldTypeResolver: fieldTypeResolvers.row,
39286
+ fieldSemanticsResolver,
38301
39287
  havingFieldTypeResolver: fieldTypeResolvers.having,
39288
+ havingFieldSemanticsResolver,
38302
39289
  aggregateSortKindResolver,
38303
39290
  appliedKlikes: pushdownPlan.appliedKlikes
38304
39291
  });
@@ -38395,16 +39382,39 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
38395
39382
  resolveSubqueries(stmt.having, client, options, cacheContext, cteCache),
38396
39383
  resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache)
38397
39384
  ]);
39385
+ const whereCapability = await resolveSelectWhereCapability(stmt, client, cacheContext, cteCache);
39386
+ if (whereCapability.capability === "UNSUPPORTED") {
39387
+ throw new Error(`ArgumentError: WHERE predicate is unsupported (${formatWhereCapabilityFailure(whereCapability)}).`);
39388
+ }
39389
+ const orderMeta = await buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
39390
+ if (hasCanonicalOrder(stmt)) {
39391
+ (stmt.orderMode === "KINTONE_NATIVE" ? planKorderNative : planCanonicalOrder)({
39392
+ stmt,
39393
+ staticMode: "FULL_SCAN",
39394
+ whereCapability: whereCapability.capability,
39395
+ orderSemantics: orderMeta.semantics,
39396
+ maxRecords: maxRecords2,
39397
+ hasKlike: whereHasKlike(stmt.where)
39398
+ });
39399
+ }
38398
39400
  const [pushdownMeta, typedInFieldTypes, aggregateSortKindResolver] = await Promise.all([
38399
39401
  loadTypedPushdownMeta(stmt, client, cacheContext),
38400
39402
  loadTypedInFieldTypes(stmt, client, cacheContext),
38401
39403
  loadAggregateSortKindResolver(stmt, client, cacheContext, cteCache)
38402
39404
  ]);
38403
39405
  const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
39406
+ const fieldSemanticsResolver = await buildWhereFieldSemanticsResolver(
39407
+ stmt,
39408
+ client,
39409
+ cacheContext,
39410
+ cteCache,
39411
+ whereNeedsFieldMetadata(stmt.having) || selectCaseConditionsNeedFieldMetadata(stmt)
39412
+ );
39413
+ const havingFieldSemanticsResolver = buildHavingFieldSemanticsResolver(stmt, fieldSemanticsResolver);
38404
39414
  const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
38405
39415
  validateKlikePushdownPlan(pushdownPlan);
38406
39416
  const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
38407
- const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
39417
+ const orderByMetaPromise = Promise.resolve(orderMeta);
38408
39418
  scalarCachePromise.catch(() => {
38409
39419
  });
38410
39420
  orderByMetaPromise.catch(() => {
@@ -38423,7 +39433,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
38423
39433
  true,
38424
39434
  options.onLimitReached ?? "error",
38425
39435
  warnings,
38426
- pushdownPlan.mainCondition
39436
+ pushdownPlan.mainCondition,
39437
+ whereCapability.capability === "EXACT_PUSHDOWN"
38427
39438
  );
38428
39439
  tables.set(stmt.from.alias, mainRecords);
38429
39440
  }
@@ -38460,7 +39471,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
38460
39471
  });
38461
39472
  await Promise.all(joinFetches);
38462
39473
  const scalarCache = await scalarCachePromise;
38463
- const { optionOrders, sortKinds } = await orderByMetaPromise;
39474
+ const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
38464
39475
  const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? cteCache.get(stmt.from.cteName)?.columns : void 0;
38465
39476
  const { rows, columns } = runFullScan({
38466
39477
  tables,
@@ -38468,8 +39479,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
38468
39479
  scalarCache,
38469
39480
  optionOrders,
38470
39481
  sortKinds,
39482
+ orderSemantics: semantics,
38471
39483
  fieldTypeResolver: fieldTypeResolvers.row,
39484
+ fieldSemanticsResolver,
38472
39485
  havingFieldTypeResolver: fieldTypeResolvers.having,
39486
+ havingFieldSemanticsResolver,
38473
39487
  aggregateSortKindResolver,
38474
39488
  appliedKlikes: pushdownPlan.appliedKlikes,
38475
39489
  sourceColumns
@@ -38481,13 +39495,13 @@ function processRowToKintoneRecord(row) {
38481
39495
  Object.entries(row).map(([k, v]) => [k, { value: v ?? "" }])
38482
39496
  );
38483
39497
  }
38484
- async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords2, parallel, isMainTable, onLimit2, warnings, pushDownCond = null) {
39498
+ async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords2, parallel, isMainTable, onLimit2, warnings, pushDownCond = null, allowOriginalWherePushdown = true) {
38485
39499
  const fields = selectToFetchAllFields(stmt, table);
38486
39500
  const onTruncate = (max) => {
38487
39501
  warnings.add(`\u53D6\u5F97\u4E0A\u9650\uFF08${max} \u4EF6\uFF09\u306B\u9054\u3057\u305F\u305F\u3081\u3001${max} \u4EF6\u3067\u6253\u3061\u5207\u3063\u3066\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002`);
38488
39502
  };
38489
39503
  if (!table.subtableCode) {
38490
- const baseQuery = isMainTable ? selectToFetchAllParams(stmt, table.appId).query : "";
39504
+ const baseQuery = isMainTable && allowOriginalWherePushdown ? selectToFetchAllParams(stmt, table.appId).query : "";
38491
39505
  const pushQuery = pushDownCond !== null ? whereToKintone(pushDownCond) : "";
38492
39506
  const query = baseQuery && pushQuery ? `(${baseQuery}) and (${pushQuery})` : baseQuery || pushQuery;
38493
39507
  const resolved = await fetchRecordsForSharedPlan(client.getRecords, table.appId, query, fields, {
@@ -38691,6 +39705,10 @@ async function getProcessStatusesCached(appId, client, cacheContext) {
38691
39705
  setScopedCacheValue(processStatusCache, cacheContext, appId, loading);
38692
39706
  return loading;
38693
39707
  }
39708
+ async function loadProcessStatusOrder(appId, client, cacheContext) {
39709
+ const process4 = await getProcessStatusesCached(appId, client, cacheContext);
39710
+ return process4.enable && process4.states !== null ? new Map(process4.states.map((state) => [state.name, state.index])) : void 0;
39711
+ }
38694
39712
  async function getFieldTypeMap(appId, client, cacheContext) {
38695
39713
  const cached2 = getScopedCacheValue(fieldTypeCache, cacheContext, appId);
38696
39714
  if (cached2) return cached2;
@@ -38734,18 +39752,118 @@ async function getSortKindMapByApp(appId, client, cacheContext) {
38734
39752
  setScopedCacheValue(sortKindCache, cacheContext, appId, map2);
38735
39753
  return map2;
38736
39754
  }
38737
- async function buildOrderByMetaForSelect(stmt, client, cacheContext) {
39755
+ function orderByFieldNames(stmt) {
39756
+ const items = [
39757
+ ...stmt.orderBy,
39758
+ ...stmt.columns.flatMap((column) => column.type === "WINDOW_COL" ? column.orderBy : [])
39759
+ ];
39760
+ return [...new Set(items.flatMap(
39761
+ (item) => item.key.type === "FIELD_NAME" ? [item.key.name] : []
39762
+ ))];
39763
+ }
39764
+ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, materializedTables) {
39765
+ const names = orderByFieldNames(stmt);
39766
+ if (names.length === 0) return /* @__PURE__ */ new Map();
39767
+ const tables = [stmt.from, ...stmt.joins.map((join) => join.table)];
39768
+ const ambiguousFields = /* @__PURE__ */ new Set();
39769
+ const infosByApp = new Map(
39770
+ await Promise.all([...new Set(
39771
+ tables.filter((table) => table.cteName === null).map((table) => table.appId)
39772
+ )].map(async (appId) => {
39773
+ const infos = await getFieldsCached(appId, client, cacheContext);
39774
+ return [appId, new Map(infos.map((info) => [info.code, info]))];
39775
+ }))
39776
+ );
39777
+ const resolveField2 = (ref) => {
39778
+ if (ref.tableAlias !== null) {
39779
+ if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
39780
+ const info2 = infosByApp.get(stmt.from.appId)?.get(ref.field);
39781
+ return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
39782
+ }
39783
+ const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
39784
+ if (!table) return void 0;
39785
+ if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
39786
+ const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
39787
+ return info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
39788
+ }
39789
+ if (stmt.joins.length === 0) {
39790
+ if (stmt.from.cteName !== null) return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field);
39791
+ const info = infosByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
39792
+ return info ? materializedMetaFromFieldInfo(info, stmt.from.appId) : systemColumnMeta(ref.field);
39793
+ }
39794
+ const matches = tables.flatMap((table) => {
39795
+ if (table.cteName !== null) {
39796
+ const materialized = materializedTables?.get(table.cteName);
39797
+ const meta4 = materialized?.columns.includes(ref.field) ? materialized.columnMeta?.get(ref.field) : void 0;
39798
+ return meta4 ? [meta4] : [];
39799
+ }
39800
+ const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
39801
+ const meta3 = info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
39802
+ return meta3 ? [meta3] : [];
39803
+ });
39804
+ if (matches.length > 1) ambiguousFields.add(ref.field);
39805
+ return matches.length === 1 ? matches[0] : void 0;
39806
+ };
39807
+ const aliasSemantics = /* @__PURE__ */ new Map();
39808
+ for (const column of stmt.columns) {
39809
+ if (!("alias" in column) || !column.alias) continue;
39810
+ let meta3;
39811
+ if (column.type === "FIELD") meta3 = resolveField2(aggregateFieldRef(column.field));
39812
+ else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
39813
+ meta3 = syntheticColumnMeta("number");
39814
+ } else if (column.type === "LITERAL_COL") meta3 = syntheticColumnMeta("string");
39815
+ else if (column.type === "STRFUNC_COL") meta3 = stringFunctionColumnMeta(column.expr);
39816
+ else if (column.type === "SCALAR_SUBQUERY_COL") meta3 = unknownStringColumnMeta();
39817
+ else if (column.type === "CASE_COL") {
39818
+ const candidates = column.expr.branches.map((branch) => caseResultColumnMeta(branch.result, resolveField2));
39819
+ if (column.expr.elseResult) candidates.push(caseResultColumnMeta(column.expr.elseResult, resolveField2));
39820
+ meta3 = mergeExpressionColumnMeta(candidates);
39821
+ } else if (column.type === "AGGREGATE") {
39822
+ if (column.func === "MIN" || column.func === "MAX") {
39823
+ meta3 = column.arg.type === "FIELD_REF" ? resolveField2(aggregateFieldRef(column.arg.field)) : syntheticColumnMeta("number");
39824
+ } else {
39825
+ meta3 = column.func === "GROUP_CONCAT" ? syntheticColumnMeta("string") : syntheticColumnMeta("number");
39826
+ }
39827
+ }
39828
+ if (meta3?.semantics) aliasSemantics.set(column.alias, meta3.semantics);
39829
+ }
39830
+ const result = /* @__PURE__ */ new Map();
39831
+ for (const name of names) {
39832
+ const base = aliasSemantics.get(name) ?? resolveField2(aggregateFieldRef(name))?.semantics;
39833
+ if (!base) {
39834
+ const ref = aggregateFieldRef(name);
39835
+ if (ref.tableAlias === null && ambiguousFields.has(ref.field)) {
39836
+ result.set(name, resolveFieldSemantics({ fieldType: "KSQL_AMBIGUOUS" }));
39837
+ }
39838
+ continue;
39839
+ }
39840
+ let semantics = base;
39841
+ if (base.fieldType === "STATUS" && base.source && stmt.orderMode !== "KINTONE_NATIVE") {
39842
+ const process4 = await getProcessStatusesCached(base.source.appId, client, cacheContext);
39843
+ if (process4.enable && process4.states !== null) {
39844
+ semantics = {
39845
+ ...base,
39846
+ optionOrder: new Map(process4.states.map((state) => [state.name, state.index]))
39847
+ };
39848
+ }
39849
+ }
39850
+ result.set(name, semantics);
39851
+ }
39852
+ return result;
39853
+ }
39854
+ async function buildOrderByMetaForSelect(stmt, client, cacheContext, materializedTables) {
38738
39855
  const hasWindowOrderBy = stmt.columns.some(
38739
39856
  (column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
38740
39857
  );
38741
39858
  if (stmt.orderBy.length === 0 && !hasWindowOrderBy) {
38742
- return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map() };
39859
+ return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map(), semantics: /* @__PURE__ */ new Map() };
38743
39860
  }
38744
- const [optionOrders, sortKinds] = await Promise.all([
39861
+ const [optionOrders, sortKinds, semantics] = await Promise.all([
38745
39862
  buildOptionOrdersForSelect(stmt, client, cacheContext),
38746
- buildSortKindsForSelect(stmt, client, cacheContext)
39863
+ buildSortKindsForSelect(stmt, client, cacheContext),
39864
+ buildOrderSemanticsForSelect(stmt, client, cacheContext, materializedTables)
38747
39865
  ]);
38748
- return { optionOrders, sortKinds };
39866
+ return { optionOrders, sortKinds, semantics };
38749
39867
  }
38750
39868
  async function buildOptionOrdersForSelect(stmt, client, cacheContext) {
38751
39869
  const optionOrders = /* @__PURE__ */ new Map();
@@ -38843,6 +39961,9 @@ var RejectLimitExceededError = class extends Error {
38843
39961
  }
38844
39962
  };
38845
39963
  async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
39964
+ if (stmt.type === "UPDATE") {
39965
+ await assertDmlWhereCapability(stmt, client, cacheContext);
39966
+ }
38846
39967
  const operation = stmt.type === "UPDATE" ? "UPDATE" : stmt.type.startsWith("UPSERT") ? "UPSERT" : "INSERT";
38847
39968
  const payloadFields = stmt.type === "UPDATE" ? ["$id", ...stmt.assignments.map((a) => a.field)] : [...stmt.fields];
38848
39969
  if (new Set(payloadFields).size !== payloadFields.length) {
@@ -38882,18 +40003,22 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
38882
40003
  const columnMeta = /* @__PURE__ */ new Map();
38883
40004
  for (const column of payloadFields) {
38884
40005
  if (column === "$id") {
38885
- columnMeta.set(column, { sortKind: "number", fieldType: "RECORD_NUMBER" });
40006
+ columnMeta.set(column, {
40007
+ sortKind: "number",
40008
+ fieldType: "RECORD_NUMBER",
40009
+ semantics: resolveFieldSemantics({ fieldType: "RECORD_NUMBER" })
40010
+ });
38886
40011
  continue;
38887
40012
  }
38888
40013
  const info = infoByCode.get(column);
38889
- if (info) columnMeta.set(column, materializedMetaFromFieldInfo(info));
38890
- }
38891
- columnMeta.set("$err_statement", { sortKind: "number" });
38892
- columnMeta.set("$err_operation", { sortKind: "string" });
38893
- columnMeta.set("$err_row", { sortKind: "number" });
38894
- columnMeta.set("$err_field", { sortKind: "string" });
38895
- columnMeta.set("$err_code", { sortKind: "string" });
38896
- columnMeta.set("$err_message", { sortKind: "string" });
40014
+ if (info) columnMeta.set(column, materializedMetaFromFieldInfo(info, stmt.appId));
40015
+ }
40016
+ columnMeta.set("$err_statement", syntheticColumnMeta("number"));
40017
+ columnMeta.set("$err_operation", syntheticColumnMeta("string"));
40018
+ columnMeta.set("$err_row", syntheticColumnMeta("number"));
40019
+ columnMeta.set("$err_field", syntheticColumnMeta("string"));
40020
+ columnMeta.set("$err_code", syntheticColumnMeta("string"));
40021
+ columnMeta.set("$err_message", syntheticColumnMeta("string"));
38897
40022
  materializedMetaByValidationResult.set(result, columnMeta);
38898
40023
  return { result, candidates, invalidRowNumbers, columnMeta };
38899
40024
  }
@@ -39279,6 +40404,7 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
39279
40404
  };
39280
40405
  }
39281
40406
  async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40407
+ await assertDmlWhereCapability(stmt, client, cacheContext);
39282
40408
  if (stmt.subtableCode) {
39283
40409
  return executeUpdateSubtable(stmt, client, options, cacheContext);
39284
40410
  }
@@ -39356,6 +40482,7 @@ function collectUpdateFromTargetFields(stmt) {
39356
40482
  return [...fields];
39357
40483
  }
39358
40484
  async function executeDelete(stmt, client, options, cacheContext) {
40485
+ await assertDmlWhereCapability(stmt, client, cacheContext);
39359
40486
  if (stmt.subtableCode) {
39360
40487
  return executeDeleteSubtable(stmt, client, options, cacheContext);
39361
40488
  }
@@ -39728,6 +40855,18 @@ async function executeReorder(stmt, client, options, cacheContext) {
39728
40855
  client,
39729
40856
  cacheContext
39730
40857
  );
40858
+ const reorderFields = await getFieldsCached(stmt.appId, client, cacheContext);
40859
+ const reorderSemanticsByCode = new Map(reorderFields.map((field) => [
40860
+ field.code,
40861
+ field.semantics ?? resolveFieldSemantics(field)
40862
+ ]));
40863
+ const resolveReorderSemantics = (field) => {
40864
+ if (field.field === "_idx" || field.field === "_pid" || field.field === "_rid") {
40865
+ return syntheticSemantics("number");
40866
+ }
40867
+ const code = field.field.startsWith("_p.") ? field.field.slice(3) : field.field;
40868
+ return reorderSemanticsByCode.get(code) ?? syntheticSemantics("string");
40869
+ };
39731
40870
  const parents = await fetchAll(
39732
40871
  client.getRecords,
39733
40872
  stmt.appId,
@@ -39736,7 +40875,13 @@ async function executeReorder(stmt, client, options, cacheContext) {
39736
40875
  { maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
39737
40876
  );
39738
40877
  const expanded = expandRowsForSubtableDml(parents, stmt.subtableCode);
39739
- const targetParentIds = stmt.all ? new Set(parents.map((p) => String(p["$id"]?.value ?? "")).filter((id) => id !== "")) : new Set(expanded.filter((r) => stmt.where && evalWhere(stmt.where, r.flat, resolveFieldType)).map((r) => r.parentId));
40878
+ const targetParentIds = stmt.all ? new Set(parents.map((p) => String(p["$id"]?.value ?? "")).filter((id) => id !== "")) : new Set(expanded.filter((r) => stmt.where && evalWhere(
40879
+ stmt.where,
40880
+ r.flat,
40881
+ resolveFieldType,
40882
+ void 0,
40883
+ resolveReorderSemantics
40884
+ )).map((r) => r.parentId));
39740
40885
  if (options.confirm) {
39741
40886
  const ok = await options.confirm(targetParentIds.size, "UPDATE");
39742
40887
  if (!ok) throw new OperationCancelledError("UPDATE", targetParentIds.size);
@@ -39747,7 +40892,7 @@ async function executeReorder(stmt, client, options, cacheContext) {
39747
40892
  if (!parent) continue;
39748
40893
  const rows = getMutableTableRows(parent, stmt.subtableCode);
39749
40894
  const sortable = rows.map((row, i) => ({ row, i, flat: buildFlatRowForSort(parent, stmt.subtableCode, row, i) }));
39750
- sortable.sort((a, b) => compareByOrder(a.flat, b.flat, stmt.by));
40895
+ sortable.sort((a, b) => compareByOrder(a.flat, b.flat, stmt.by, resolveReorderSemantics));
39751
40896
  const orderedRowIds = sortable.map((x) => x.row.id ?? "");
39752
40897
  await client.putRecords(buildSubtableReorderPutParams(stmt.appId, pid, getRevision(parent), stmt.subtableCode, orderedRowIds));
39753
40898
  }
@@ -39768,14 +40913,12 @@ function buildFlatRowForSort(parent, subtableCode, row, idx) {
39768
40913
  }
39769
40914
  return flat;
39770
40915
  }
39771
- function compareByOrder(a, b, orderBy) {
40916
+ function compareByOrder(a, b, orderBy, resolveSemantics) {
39772
40917
  for (const item of orderBy) {
39773
40918
  const av = evalOrderKeyForRow(item.key, a);
39774
40919
  const bv = evalOrderKeyForRow(item.key, b);
39775
- const an = Number(av);
39776
- const bn = Number(bv);
39777
- const numeric = !Number.isNaN(an) && !Number.isNaN(bn);
39778
- const cmp = numeric ? an - bn : av.localeCompare(bv, "ja");
40920
+ const semantics = item.key.type === "FIELD_NAME" ? resolveSemantics(aggregateFieldRef(item.key.name)) : item.key.type === "ARITH_KEY" ? syntheticSemantics("number") : stringFunctionColumnMeta(item.key.expr).semantics ?? syntheticSemantics("string");
40921
+ const cmp = compareCanonicalValues(av, bv, semantics ?? syntheticSemantics("string"));
39779
40922
  if (cmp !== 0) return item.direction === "ASC" ? cmp : -cmp;
39780
40923
  }
39781
40924
  return 0;
@@ -39972,35 +41115,140 @@ async function resolveScalarColumns(columns, client, options, cacheContext, cteC
39972
41115
  pending.forEach(([i], idx) => cache.set(i, values[idx]));
39973
41116
  return cache;
39974
41117
  }
39975
- function buildBatchExplainPlans(sql, injectedVariables) {
41118
+ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords2 = 1e4) {
41119
+ const fieldApps = /* @__PURE__ */ new Set();
41120
+ const processStatusApps = /* @__PURE__ */ new Set();
41121
+ const tracedClient = {
41122
+ ...client,
41123
+ getFields: async (appId) => {
41124
+ fieldApps.add(appId);
41125
+ return client.getFields(appId);
41126
+ },
41127
+ getProcessStatuses: async (appId) => {
41128
+ processStatusApps.add(appId);
41129
+ return client.getProcessStatuses(appId);
41130
+ }
41131
+ };
41132
+ const capabilities = /* @__PURE__ */ new Map();
41133
+ const orderPlans = /* @__PURE__ */ new Map();
41134
+ const seen = /* @__PURE__ */ new Set();
41135
+ const visit = async (node) => {
41136
+ if (node === null || typeof node !== "object") return;
41137
+ if (seen.has(node)) return;
41138
+ seen.add(node);
41139
+ if (Array.isArray(node)) {
41140
+ await Promise.all(node.map(visit));
41141
+ return;
41142
+ }
41143
+ const typed = node;
41144
+ if (typed["type"] === "SELECT") {
41145
+ const select = node;
41146
+ const physicalApps = [select.from, ...select.joins.map((join) => join.table)].filter((table) => table.cteName === null).map((table) => table.appId);
41147
+ const needsWhereSchema = whereNeedsFieldMetadata(select.where);
41148
+ if (needsWhereSchema || select.orderBy.length > 0 || select.columns.some((column) => column.type === "WINDOW_COL" && column.orderBy.length > 0)) {
41149
+ physicalApps.forEach((appId) => fieldApps.add(appId));
41150
+ }
41151
+ const capability = await resolveSelectWhereCapability(select, tracedClient, cacheContext);
41152
+ if (capability.capability === "UNSUPPORTED") {
41153
+ throw new Error(`ArgumentError: WHERE predicate is unsupported (${formatWhereCapabilityFailure(capability)}).`);
41154
+ }
41155
+ capabilities.set(select, capability);
41156
+ if (select.orderBy.length > 0 || select.columns.some((column) => column.type === "WINDOW_COL" && column.orderBy.length > 0)) {
41157
+ const meta3 = await buildOrderByMetaForSelect(select, tracedClient, cacheContext);
41158
+ if (select.orderMode !== "KINTONE_NATIVE") {
41159
+ for (const semantics of meta3.semantics.values()) {
41160
+ if (semantics.fieldType === "STATUS" && semantics.source) {
41161
+ processStatusApps.add(semantics.source.appId);
41162
+ }
41163
+ }
41164
+ }
41165
+ const hasUnmaterializedSource = [select.from, ...select.joins.map((join) => join.table)].some((table) => table.cteName !== null);
41166
+ if (hasCanonicalOrder(select) && !hasUnmaterializedSource) {
41167
+ const mode = capability.capability === "EXACT_PUSHDOWN" ? resolveSelectMode(select) : "FULL_SCAN";
41168
+ orderPlans.set(select, (select.orderMode === "KINTONE_NATIVE" ? planKorderNative : planCanonicalOrder)({
41169
+ stmt: select,
41170
+ staticMode: mode,
41171
+ whereCapability: capability.capability,
41172
+ orderSemantics: meta3.semantics,
41173
+ maxRecords: maxRecords2,
41174
+ hasKlike: whereHasKlike(select.where)
41175
+ }));
41176
+ }
41177
+ }
41178
+ } else if (typed["type"] === "UPDATE" || typed["type"] === "DELETE") {
41179
+ fieldApps.add(node.appId);
41180
+ await assertDmlWhereCapability(
41181
+ node,
41182
+ tracedClient,
41183
+ cacheContext
41184
+ );
41185
+ }
41186
+ await Promise.all(Object.values(typed).map(visit));
41187
+ };
41188
+ await visit(query);
41189
+ if (typeof query === "object" && query !== null && query.type === "WITH" && canInlineSingleCte(query)) {
41190
+ const inlined = buildInlinedQuery(query);
41191
+ const capability = await resolveSelectWhereCapability(inlined, tracedClient, cacheContext);
41192
+ if (capability.capability === "UNSUPPORTED") {
41193
+ throw new Error(`ArgumentError: WHERE predicate is unsupported (${formatWhereCapabilityFailure(capability)}).`);
41194
+ }
41195
+ capabilities.set(inlined, capability);
41196
+ if (hasCanonicalOrder(inlined)) {
41197
+ const meta3 = await buildOrderByMetaForSelect(inlined, tracedClient, cacheContext);
41198
+ orderPlans.set(inlined, (inlined.orderMode === "KINTONE_NATIVE" ? planKorderNative : planCanonicalOrder)({
41199
+ stmt: inlined,
41200
+ staticMode: capability.capability === "EXACT_PUSHDOWN" ? resolveSelectMode(inlined) : "FULL_SCAN",
41201
+ whereCapability: capability.capability,
41202
+ orderSemantics: meta3.semantics,
41203
+ maxRecords: maxRecords2,
41204
+ hasKlike: whereHasKlike(inlined.where)
41205
+ }));
41206
+ }
41207
+ }
41208
+ return { capabilities, orderPlans, fieldApps, processStatusApps };
41209
+ }
41210
+ function explainMetadataLines(analysis) {
41211
+ return [
41212
+ ...[...analysis.fieldApps].sort((a, b) => a - b).map((appId) => ` metadata API: form definition APP${appId}`),
41213
+ ...[...analysis.processStatusApps].sort((a, b) => a - b).map((appId) => ` metadata API: process status APP${appId}`)
41214
+ ];
41215
+ }
41216
+ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords2 = 1e4) {
39976
41217
  const statements = parseSqlBatch(sql);
39977
41218
  const analysis = analyzeBatch(statements);
39978
41219
  validateDeclaredBatchVariables(statements, injectedVariables);
39979
41220
  const variables = /* @__PURE__ */ new Map();
39980
- return {
39981
- statementCount: statements.length,
39982
- statements: statements.map((stmt, i) => {
39983
- const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveVariableRefs(stmt.expr, variables) } : stmt : resolveVariableRefs(stmt, variables);
39984
- validateKlikeStatement(planStmt);
39985
- const result = {
39986
- index: i,
39987
- type: analysis.statements[i].statementType,
39988
- plan: buildBatchStatementPlan(planStmt, analysis.statements[i])
39989
- };
39990
- if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
39991
- variables.set(stmt.name, { type: "string", value: `@${stmt.name}` });
39992
- }
39993
- return result;
39994
- })
39995
- };
41221
+ const plans = [];
41222
+ for (let i = 0; i < statements.length; i++) {
41223
+ const stmt = statements[i];
41224
+ const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveVariableRefs(stmt.expr, variables) } : stmt : resolveVariableRefs(stmt, variables);
41225
+ validateKlikeStatement(planStmt);
41226
+ const whereAnalysis = await buildExplainWhereAnalysis(planStmt, client, cacheContext, maxRecords2);
41227
+ const statementPlan = buildBatchStatementPlan(
41228
+ planStmt,
41229
+ analysis.statements[i],
41230
+ whereAnalysis.capabilities,
41231
+ whereAnalysis.orderPlans
41232
+ );
41233
+ const metadataPlan = explainMetadataLines(whereAnalysis);
41234
+ plans.push({
41235
+ index: i,
41236
+ type: analysis.statements[i].statementType,
41237
+ plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
41238
+ });
41239
+ if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
41240
+ variables.set(stmt.name, { type: "string", value: `@${stmt.name}` });
41241
+ }
41242
+ }
41243
+ return { statementCount: statements.length, statements: plans };
39996
41244
  }
39997
- function buildBatchStatementPlan(stmt, info) {
41245
+ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans) {
39998
41246
  if (stmt.type === "CREATE_TEMP_TABLE") {
39999
41247
  return [
40000
41248
  `CREATE TEMP TABLE ${stmt.name}`,
40001
41249
  ` scope: batch\uFF08\u30D0\u30C3\u30C1\u7D42\u4E86\u6642\u306B\u81EA\u52D5\u7834\u68C4\uFF09`,
40002
41250
  ` rows: \u5B9F\u4F53\u5316\u524D\u306E\u305F\u3081\u4E0D\u660E\uFF08\u65E2\u5B9A\u4E0A\u9650 ${TEMP_TABLE_MAX_ROWS} \u884C\u3001tempTableMaxRows \u3067\u5909\u66F4\u53EF\u3001\u8D85\u904E\u306F\u30A8\u30E9\u30FC\uFF09`,
40003
- ...buildPlanForBatchQuery(stmt.query, info).map((l) => ` ${l}`)
41251
+ ...buildPlanForBatchQuery(stmt.query, info, capabilities, orderPlans).map((l) => ` ${l}`)
40004
41252
  ];
40005
41253
  }
40006
41254
  if (stmt.type === "DROP_TEMP_TABLE") {
@@ -40016,7 +41264,7 @@ function buildBatchStatementPlan(stmt, info) {
40016
41264
  `SET @${stmt.name} = (SELECT ...)`,
40017
41265
  " value: \u30B5\u30D6\u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u6642\u306B1\u56DE\u8A55\u4FA1\uFF081\u884C1\u5217\u30FB\u30D0\u30C3\u30C1\u5185\u5B9A\u6570\u30FB\u7D50\u679C\u30E1\u30BF\u30C7\u30FC\u30BF\u306B\u306F\u975E\u516C\u958B\uFF09",
40018
41266
  " subquery:",
40019
- ...buildPlanForBatchQuery(stmt.expr.query, subInfo).map((l) => ` ${l}`)
41267
+ ...buildPlanForBatchQuery(stmt.expr.query, subInfo, capabilities, orderPlans).map((l) => ` ${l}`)
40020
41268
  ];
40021
41269
  }
40022
41270
  return [
@@ -40032,7 +41280,7 @@ function buildBatchStatementPlan(stmt, info) {
40032
41280
  }
40033
41281
  if (stmt.type === "SHOW_APPS") return ["SHOW APPS\uFF08\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\uFF09"];
40034
41282
  if (stmt.type === "DESCRIBE") return [`DESCRIBE APP${stmt.appId}\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\uFF09`];
40035
- if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info);
41283
+ if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info, capabilities, orderPlans);
40036
41284
  if (stmt.type === "ASSERT") {
40037
41285
  const lines = [
40038
41286
  `ASSERT ${stmt.text}`,
@@ -40044,11 +41292,11 @@ function buildBatchStatementPlan(stmt, info) {
40044
41292
  subqueries.forEach((sq, i) => {
40045
41293
  lines.push(subqueries.length > 1 ? ` subquery[${i + 1}]:` : " subquery:");
40046
41294
  const subInfo = hasTempTableRef(sq.query) ? info : { ...info, tempTablesReferenced: [] };
40047
- lines.push(...buildPlanForBatchQuery(sq.query, subInfo).map((l) => ` ${l}`));
41295
+ lines.push(...buildPlanForBatchQuery(sq.query, subInfo, capabilities, orderPlans).map((l) => ` ${l}`));
40048
41296
  });
40049
41297
  return lines;
40050
41298
  }
40051
- return buildPlanForBatchQuery(stmt, info);
41299
+ return buildPlanForBatchQuery(stmt, info, capabilities, orderPlans);
40052
41300
  }
40053
41301
  function hasTempTableRef(node) {
40054
41302
  if (Array.isArray(node)) return node.some(hasTempTableRef);
@@ -40060,9 +41308,9 @@ function hasTempTableRef(node) {
40060
41308
  }
40061
41309
  return false;
40062
41310
  }
40063
- function buildPlanForBatchQuery(query, info) {
41311
+ function buildPlanForBatchQuery(query, info, capabilities, orderPlans) {
40064
41312
  if (info.tempTablesReferenced.length === 0) {
40065
- return buildExplainPlan(query);
41313
+ return buildExplainPlan(query, void 0, capabilities, orderPlans);
40066
41314
  }
40067
41315
  const lines = [];
40068
41316
  if (query.type === "INSERT_SELECT") {
@@ -40087,8 +41335,12 @@ function buildPlanForBatchQuery(query, info) {
40087
41335
  lines.push(" note: \u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u3078\u306E WHERE \u30D7\u30C3\u30B7\u30E5\u30C0\u30A6\u30F3\u306F\u884C\u308F\u308C\u306A\u3044");
40088
41336
  return lines;
40089
41337
  }
40090
- function executeExplain(stmt) {
40091
- const lines = buildExplainPlan(stmt.query);
41338
+ async function executeExplain(stmt, client, cacheContext, maxRecords2) {
41339
+ const analysis = await buildExplainWhereAnalysis(stmt.query, client, cacheContext, maxRecords2);
41340
+ const lines = [
41341
+ ...explainMetadataLines(analysis),
41342
+ ...buildExplainPlan(stmt.query, void 0, analysis.capabilities, analysis.orderPlans)
41343
+ ];
40092
41344
  return {
40093
41345
  type: "SELECT",
40094
41346
  columns: ["plan"],
@@ -40096,29 +41348,45 @@ function executeExplain(stmt) {
40096
41348
  rowCount: lines.length
40097
41349
  };
40098
41350
  }
40099
- function buildExplainPlan(query, label) {
40100
- if (query.type === "UNION") return buildUnionPlan(query);
40101
- if (query.type === "WITH") return buildWithPlan(query);
41351
+ function buildExplainPlan(query, label, capabilities, orderPlans) {
41352
+ if (query.type === "UNION") return buildUnionPlan(query, capabilities, orderPlans);
41353
+ if (query.type === "WITH") return buildWithPlan(query, capabilities, orderPlans);
40102
41354
  if (query.type === "INSERT") return buildInsertPlan(query, label);
40103
- if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label);
41355
+ if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label, capabilities, orderPlans);
40104
41356
  if (query.type === "UPSERT") return buildUpsertPlan(query, label);
40105
- if (query.type === "UPSERT_SELECT") return buildUpsertSelectPlan(query, label);
40106
- if (query.type === "UPDATE") return buildUpdatePlan(query, label);
41357
+ if (query.type === "UPSERT_SELECT") return buildUpsertSelectPlan(query, label, capabilities, orderPlans);
41358
+ if (query.type === "UPDATE") return buildUpdatePlan(query, label, capabilities, orderPlans);
40107
41359
  if (query.type === "DELETE") return buildDeletePlan(query, label);
40108
41360
  if (query.type === "REORDER") return buildReorderPlan(query, label);
40109
- return buildSelectPlan(query, label);
41361
+ return buildSelectPlan(query, label, capabilities, orderPlans);
40110
41362
  }
40111
- function buildSelectPlan(stmt, label) {
40112
- const mode = resolveSelectMode(stmt);
41363
+ function buildSelectPlan(stmt, label, capabilities, orderPlans) {
41364
+ const whereCapability = capabilities?.get(stmt) ?? (capabilities ? [...capabilities].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
41365
+ const orderPlan = orderPlans?.get(stmt) ?? (orderPlans ? [...orderPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
41366
+ const mode = orderPlan?.kind === "CANONICAL_LOCAL" ? "FULL_SCAN" : whereCapability && whereCapability.capability !== "EXACT_PUSHDOWN" ? "FULL_SCAN" : resolveSelectMode(stmt);
40113
41367
  const reasons = collectFullScanReasons(stmt);
41368
+ if (whereCapability && whereCapability.capability !== "EXACT_PUSHDOWN") {
41369
+ reasons.push(...whereCapability.reasons.map((reason) => reason.code));
41370
+ }
40114
41371
  const lines = [];
40115
41372
  if (label) lines.push(label);
40116
41373
  lines.push(` mode: ${mode}`);
41374
+ if (orderPlan) {
41375
+ lines.push(` order plan: ${orderPlan.kind}`);
41376
+ if (orderPlan.reasonCodes.length > 0) lines.push(` order reason: ${orderPlan.reasonCodes.join(", ")}`);
41377
+ if (orderPlan.kind === "KORDER_NATIVE") {
41378
+ lines.push(" order semantics: kintone native (not kSQL canonical)");
41379
+ lines.push(" REST execution: single GET");
41380
+ }
41381
+ }
41382
+ if (orderPlan?.requiresCompleteInput ?? requiresCompleteInput(stmt)) {
41383
+ lines.push(" complete input: required (ORDER BY / window ORDER BY; onLimit=truncate disabled)");
41384
+ }
40117
41385
  if (mode === "FULL_SCAN" && reasons.length > 0) {
40118
41386
  lines.push(` reason: ${reasons.join(", ")}`);
40119
41387
  }
40120
41388
  if (mode === "SIMPLE") {
40121
- const params = selectToKintoneParams(stmt);
41389
+ const params = selectToKintoneParams(orderPlan?.kind === "CANONICAL_REST_TOP_N" ? withCanonicalRestTie(stmt) : stmt);
40122
41390
  lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);
40123
41391
  lines.push(` kintone query: ${params.query || "(\u306A\u3057)"}`);
40124
41392
  lines.push(` fields: ${params.fields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : params.fields.join(", ")}`);
@@ -40128,7 +41396,8 @@ function buildSelectPlan(stmt, label) {
40128
41396
  const mainAliasStr = stmt.from.alias ? ` AS ${stmt.from.alias}` : "";
40129
41397
  const mainPushDown = pushdownPlan.mainCondition;
40130
41398
  const mainCandidate = extractMainTypedPushdownCandidate(stmt);
40131
- const mainQ = mainPushDown !== null ? whereToKintone(mainPushDown) : "(\u5168\u4EF6\u53D6\u5F97)";
41399
+ const exactOriginalWhere = stmt.joins.length === 0 && whereCapability?.capability === "EXACT_PUSHDOWN" && stmt.where !== null && !whereRequiresJsEval(stmt.where) ? whereToKintone(stmt.where) : "";
41400
+ const mainQ = mainPushDown !== null ? whereToKintone(mainPushDown) : exactOriginalWhere || "(\u5168\u4EF6\u53D6\u5F97)";
40132
41401
  lines.push(` app: APP${stmt.from.appId}${mainAliasStr} (${stmt.from.appId})`);
40133
41402
  lines.push(` kintone query: ${mainQ}`);
40134
41403
  if (mainCandidate !== null) {
@@ -40150,10 +41419,10 @@ function buildSelectPlan(stmt, label) {
40150
41419
  lines.push(` fields: ${joinFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : joinFields.join(", ")}`);
40151
41420
  }
40152
41421
  }
40153
- lines.push(...collectSubqueryPlans(stmt));
41422
+ lines.push(...collectSubqueryPlans(stmt, capabilities, orderPlans));
40154
41423
  return lines;
40155
41424
  }
40156
- function buildUnionPlan(stmt) {
41425
+ function buildUnionPlan(stmt, capabilities, orderPlans) {
40157
41426
  const selects = [];
40158
41427
  const collect = (u) => {
40159
41428
  if (u.type === "SELECT") {
@@ -40167,24 +41436,25 @@ function buildUnionPlan(stmt) {
40167
41436
  const lines = [];
40168
41437
  selects.forEach((sel, i) => {
40169
41438
  if (i > 0) lines.push("");
40170
- lines.push(...buildSelectPlan(sel, `[union:${i + 1}]`));
41439
+ lines.push(...buildSelectPlan(sel, `[union:${i + 1}]`, capabilities, orderPlans));
40171
41440
  });
40172
41441
  return lines;
40173
41442
  }
40174
- function buildWithPlan(stmt) {
41443
+ function buildWithPlan(stmt, capabilities, orderPlans) {
40175
41444
  const lines = [];
40176
41445
  for (const cte of stmt.ctes) {
40177
41446
  if (cte.query.type === "SELECT") {
40178
- lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]`));
41447
+ lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]`, capabilities, orderPlans));
40179
41448
  lines.push("");
40180
41449
  }
40181
41450
  }
40182
41451
  if (stmt.query.type === "SELECT" || stmt.query.type === "UNION") {
40183
- lines.push(...buildExplainPlan(stmt.query, "[main]"));
41452
+ lines.push(...buildExplainPlan(stmt.query, "[main]", capabilities, orderPlans));
40184
41453
  }
40185
41454
  if (canInlineSingleCte(stmt)) {
40186
41455
  lines.push("");
40187
- lines.push(...buildSelectPlan(buildInlinedQuery(stmt), "[effective: inlined CTE]"));
41456
+ const inlined = buildInlinedQuery(stmt);
41457
+ lines.push(...buildSelectPlan(inlined, "[effective: inlined CTE]", capabilities, orderPlans));
40188
41458
  }
40189
41459
  return lines;
40190
41460
  }
@@ -40212,7 +41482,7 @@ function collectFullScanReasons(stmt) {
40212
41482
  r.push("ORDER BY \u306B\u5F0F");
40213
41483
  return r;
40214
41484
  }
40215
- function collectSubqueryPlans(stmt) {
41485
+ function collectSubqueryPlans(stmt, capabilities, orderPlans) {
40216
41486
  const lines = [];
40217
41487
  let idx = 1;
40218
41488
  const visitWhere = (w) => {
@@ -40221,16 +41491,16 @@ function collectSubqueryPlans(stmt) {
40221
41491
  case "BINARY":
40222
41492
  if (w.right.type === "SCALAR_SUBQUERY") {
40223
41493
  lines.push("");
40224
- lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`));
41494
+ lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans));
40225
41495
  }
40226
41496
  if (w.right.type === "SUBQUERY_IN_LIST") {
40227
41497
  lines.push("");
40228
- lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`));
41498
+ lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans));
40229
41499
  }
40230
41500
  break;
40231
41501
  case "EXISTS":
40232
41502
  lines.push("");
40233
- lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`));
41503
+ lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans));
40234
41504
  break;
40235
41505
  case "LOGICAL":
40236
41506
  visitWhere(w.left);
@@ -40248,7 +41518,7 @@ function collectSubqueryPlans(stmt) {
40248
41518
  for (const col of stmt.columns) {
40249
41519
  if (col.type === "SCALAR_SUBQUERY_COL") {
40250
41520
  lines.push("");
40251
- lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`));
41521
+ lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans));
40252
41522
  }
40253
41523
  }
40254
41524
  if (stmt.having) visitWhere(stmt.having);
@@ -40266,7 +41536,7 @@ function buildInsertPlan(stmt, label) {
40266
41536
  lines.push(` fields: ${stmt.fields.join(", ")}`);
40267
41537
  return lines;
40268
41538
  }
40269
- function buildInsertSelectPlan(stmt, label) {
41539
+ function buildInsertSelectPlan(stmt, label, capabilities, orderPlans) {
40270
41540
  const lines = [];
40271
41541
  if (label) lines.push(label);
40272
41542
  lines.push(` [INSERT SELECT]`);
@@ -40274,10 +41544,10 @@ function buildInsertSelectPlan(stmt, label) {
40274
41544
  lines.push(` fields: ${stmt.fields.join(", ")}`);
40275
41545
  lines.push(` api: POST /k/v1/records.json\uFF08\u4EF6\u6570\u306F SELECT \u7D50\u679C\u306B\u4F9D\u5B58\u3001100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`);
40276
41546
  lines.push("");
40277
- lines.push(...buildSelectPlan(stmt.select, "[source SELECT]"));
41547
+ lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans));
40278
41548
  return lines;
40279
41549
  }
40280
- function buildUpdatePlan(stmt, label) {
41550
+ function buildUpdatePlan(stmt, label, capabilities, orderPlans) {
40281
41551
  const isArith = hasArithAssignment(stmt);
40282
41552
  const isSubq = stmt.assignments.some((a) => a.value.type === "SCALAR_SUBQUERY");
40283
41553
  const lines = [];
@@ -40311,7 +41581,7 @@ function buildUpdatePlan(stmt, label) {
40311
41581
  for (const a of stmt.assignments) {
40312
41582
  if (a.value.type === "SCALAR_SUBQUERY") {
40313
41583
  lines.push("");
40314
- lines.push(...buildSelectPlan(a.value.query, `[subquery: ${a.field}]`));
41584
+ lines.push(...buildSelectPlan(a.value.query, `[subquery: ${a.field}]`, capabilities, orderPlans));
40315
41585
  }
40316
41586
  }
40317
41587
  return lines;
@@ -40338,7 +41608,7 @@ function buildUpsertPlan(stmt, label) {
40338
41608
  ` api: GET /k/v1/records.json\uFF08\u91CD\u8907\u5224\u5B9A\uFF09\u2192 POST \u307E\u305F\u306F PUT /k/v1/records.json \xD7 ${batchCount}`
40339
41609
  ];
40340
41610
  }
40341
- function buildUpsertSelectPlan(stmt, label) {
41611
+ function buildUpsertSelectPlan(stmt, label, capabilities, orderPlans) {
40342
41612
  const lines = [
40343
41613
  ...label ? [label] : [],
40344
41614
  ` [UPSERT SELECT]`,
@@ -40348,7 +41618,7 @@ function buildUpsertSelectPlan(stmt, label) {
40348
41618
  ` api: GET /k/v1/records.json\uFF08\u91CD\u8907\u5224\u5B9A\uFF09\u2192 POST \u307E\u305F\u306F PUT /k/v1/records.json\uFF08100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`,
40349
41619
  ``
40350
41620
  ];
40351
- lines.push(...buildSelectPlan(stmt.select, "[source SELECT]"));
41621
+ lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans));
40352
41622
  return lines;
40353
41623
  }
40354
41624
  function buildReorderPlan(stmt, label) {
@@ -40883,12 +42153,14 @@ function flattenFormFieldProperties(properties) {
40883
42153
  function flattenFields(properties, lookupCopyFields, inSubtable = false) {
40884
42154
  const out = [];
40885
42155
  for (const field of Object.values(properties)) {
40886
- out.push({
42156
+ const optionOrder = toOptionOrderMap(field.options);
42157
+ const sortKind = detectSortKind(field.type, field.format);
42158
+ const info = {
40887
42159
  code: field.code,
40888
42160
  label: field.label,
40889
42161
  fieldType: field.type,
40890
- optionOrder: toOptionOrderMap(field.options),
40891
- sortKind: detectSortKind(field.type, field.format),
42162
+ optionOrder,
42163
+ sortKind,
40892
42164
  required: field.required,
40893
42165
  minValue: normalizeConstraintValue(field.minValue),
40894
42166
  maxValue: normalizeConstraintValue(field.maxValue),
@@ -40897,7 +42169,9 @@ function flattenFields(properties, lookupCopyFields, inSubtable = false) {
40897
42169
  defaultValue: field.defaultValue,
40898
42170
  inSubtable,
40899
42171
  writable: !lookupCopyFields.has(field.code) && !NON_WRITABLE_FIELD_TYPES2.has(field.type)
40900
- });
42172
+ };
42173
+ info.semantics = resolveFieldSemantics(info);
42174
+ out.push(info);
40901
42175
  if (field.fields) out.push(...flattenFields(field.fields, lookupCopyFields, true));
40902
42176
  }
40903
42177
  return out;
@@ -40952,6 +42226,18 @@ function detectSortKind(fieldType, calcFormat) {
40952
42226
  return void 0;
40953
42227
  }
40954
42228
 
42229
+ // src/core/processStatus.ts
42230
+ function normalizeProcessStatusStates(states) {
42231
+ if (states === null) return null;
42232
+ return Object.values(states).map((state) => {
42233
+ const index = Number(state.index);
42234
+ if (!Number.isSafeInteger(index) || index < 0) {
42235
+ throw new Error(`ArgumentError: invalid process status index: ${String(state.index)}`);
42236
+ }
42237
+ return { name: state.name, index };
42238
+ });
42239
+ }
42240
+
40955
42241
  // src/cli/nodeKintoneClient.ts
40956
42242
  var SEARCH_ABORTED_HEADER_VALUE = "Filter aborted because of too many search results";
40957
42243
  function createNodeKintoneClient(baseUrl, tokenResolver) {
@@ -41149,7 +42435,7 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
41149
42435
  const res = await requestJson(`${apiBasePath}/app/status.json?${qs.toString()}`, { method: "GET" }, appId);
41150
42436
  return {
41151
42437
  enable: res.enable,
41152
- states: Object.values(res.states ?? {}).map((state) => state.name)
42438
+ states: normalizeProcessStatusStates(res.states)
41153
42439
  };
41154
42440
  }
41155
42441
  };
@@ -42156,8 +43442,23 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
42156
43442
  } catch (err) {
42157
43443
  throw restoreSqlContextError(err, normalized.sourceSql, normalized.sqlContext);
42158
43444
  }
43445
+ const needsAppMetadata = normalized.appBindingByMappedApp.size > 0 && statements.some(explainNeedsAppMetadata);
43446
+ const runtime = needsAppMetadata ? await createRuntime(serverOptions, {
43447
+ sql: input.sql,
43448
+ sqlContext: normalized.sqlContext,
43449
+ profile: input.profile
43450
+ }) : null;
43451
+ const explainClient = runtime?.client ?? noOpClient();
43452
+ const explainCacheContext = runtime?.cacheContext ?? normalized.cacheContext;
43453
+ const explainSourceSql = runtime?.sql ?? normalized.normalizedSql;
42159
43454
  if (statements.length > 1) {
42160
- const plans = buildBatchExplainPlans(normalized.normalizedSql);
43455
+ const plans = await buildBatchExplainPlans(
43456
+ explainSourceSql,
43457
+ explainClient,
43458
+ void 0,
43459
+ explainCacheContext,
43460
+ runtime?.maxRecords
43461
+ );
42161
43462
  return {
42162
43463
  ok: true,
42163
43464
  batch: true,
@@ -42166,8 +43467,9 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
42166
43467
  appBindings
42167
43468
  };
42168
43469
  }
42169
- const result = await executeSql(explainSql(normalized.normalizedSql), noOpClient(), {
42170
- cacheContext: normalized.cacheContext
43470
+ const result = await executeSql(explainSql(explainSourceSql), explainClient, {
43471
+ cacheContext: explainCacheContext,
43472
+ maxRecords: runtime?.maxRecords
42171
43473
  });
42172
43474
  if (result.type !== "SELECT") {
42173
43475
  throw new Error(`ArgumentError: EXPLAIN returned unexpected result type ${result.type}.`);
@@ -42192,7 +43494,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
42192
43494
  profile: input.profile,
42193
43495
  maxRecords: input.maxRecords,
42194
43496
  fetchParallel: input.fetchParallel,
42195
- onLimit: validation.requiresCompleteInput ? "error" : input.onLimit,
43497
+ onLimit: validation.containsValidationOnly ? "error" : input.onLimit,
42196
43498
  timeout: input.timeout,
42197
43499
  tempTableMaxRows: input.tempTableMaxRows
42198
43500
  });
@@ -42237,7 +43539,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
42237
43539
  profile: input.profile,
42238
43540
  maxRecords: input.maxRecords,
42239
43541
  fetchParallel: input.fetchParallel,
42240
- onLimit: validation.requiresCompleteInput ? "error" : input.onLimit,
43542
+ onLimit: validation.containsValidationOnly ? "error" : input.onLimit,
42241
43543
  timeout: input.timeout
42242
43544
  });
42243
43545
  const result = await executeSql(runtime.sql, runtime.client, {
@@ -42533,7 +43835,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
42533
43835
  var profile = external_exports.string().min(1).describe("kintone connection profile name from ksql.config.json (default: the server's default profile).").optional();
42534
43836
  var maxRecords = external_exports.number().int().positive().describe("Maximum records fetched per SELECT (default 500).").optional();
42535
43837
  var fetchParallel = external_exports.number().int().min(1).max(10).describe("Number of parallel kintone record-fetch requests (1-10).").optional();
42536
- var onLimit = external_exports.enum(["error", "truncate"]).describe("Behavior when maxRecords is exceeded: 'error' rejects, 'truncate' returns the first maxRecords rows (default 'error'). VALIDATE ONLY always requires complete input and therefore overrides 'truncate' to 'error'.").optional();
43838
+ var onLimit = external_exports.enum(["error", "truncate"]).describe("Behavior when maxRecords is exceeded: 'error' rejects, 'truncate' returns the first maxRecords rows (default 'error'). Local ORDER BY plans require complete input and fail instead of returning a truncated top-N; REST top-N and KORDER_NATIVE do not fetch a partial candidate set. VALIDATE ONLY always overrides 'truncate' to 'error'.").optional();
42537
43839
  var tempTableMaxRows = external_exports.number().int().positive().describe("Per-temp-table cap on materialized rows for CREATE TEMP TABLE ... AS SELECT (default 10000). Overflow always errors \u2014 'truncate' never applies to temp tables, so downstream statements never see silently truncated data. Raising this increases memory use (up to 16 temp tables per batch); prefer narrowing the SELECT with WHERE.").optional();
42538
43840
  var timeout = external_exports.number().int().positive().describe("Request timeout in milliseconds. For multi-statement batches this also acts as the total batch deadline.").optional();
42539
43841
  var savedQueryName = external_exports.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/).describe("Saved query name (alphanumeric, '_' and '-', up to 64 chars).");
@@ -42657,7 +43959,7 @@ Options:
42657
43959
  -h, --help Show help
42658
43960
  `);
42659
43961
  }
42660
- var SERVER_VERSION = true ? "2.17.0" : "0.0.0-dev";
43962
+ var SERVER_VERSION = true ? "3.0.0" : "0.0.0-dev";
42661
43963
  function createServer(args) {
42662
43964
  const server = new McpServer({
42663
43965
  name: "ksql-mcp",
@@ -42674,12 +43976,12 @@ function createServer(args) {
42674
43976
  }, tools.validateTool);
42675
43977
  server.registerTool("ksql_explain", {
42676
43978
  title: "Explain kSQL",
42677
- description: "Return the kSQL execution plan without calling kintone APIs.",
43979
+ description: "Return the schema-aware kSQL execution plan. Reads form metadata and, when needed, process status metadata; never reads or writes records.",
42678
43980
  inputSchema: explainInputShape
42679
43981
  }, tools.explainTool);
42680
43982
  server.registerTool("ksql_query", {
42681
43983
  title: "Run read-only kSQL",
42682
- description: "Execute read-only kSQL: SELECT, WITH, UNION, EXPLAIN, SHOW APPS, DESCRIBE, ASSERT, and INSERT/UPSERT/UPDATE ... VALIDATE ONLY. ASSERT failure always stops the batch. VALIDATE ONLY performs local Tier-0 validation with zero write API calls; it always requires complete input, so onLimit=truncate is ignored and treated as error. Supports multi-statement batches with temp tables, including VALIDATE ONLY INTO #err for later SELECT. Mutating DML is rejected.",
43984
+ description: "Execute read-only kSQL: SELECT, WITH, UNION, EXPLAIN, SHOW APPS, DESCRIBE, ASSERT, and INSERT/UPSERT/UPDATE ... VALIDATE ONLY. ASSERT failure always stops the batch. Local ORDER BY plans require complete input and fail instead of returning a truncated top-N; REST top-N and KORDER_NATIVE do not fetch a partial candidate set. VALIDATE ONLY always treats onLimit=truncate as error. VALIDATE ONLY performs local Tier-0 validation with zero write API calls. Supports multi-statement batches with temp tables, including VALIDATE ONLY INTO #err for later SELECT. Mutating DML is rejected.",
42683
43985
  inputSchema: queryInputShape
42684
43986
  }, tools.queryTool);
42685
43987
  server.registerTool("ksql_mutate", {