@rex0220/kintone-sql-tools 2.17.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist-cli/ksql.js +2152 -310
- package/dist-mcp/ksql-mcp.js +2169 -319
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
35058
|
-
|
|
35059
|
-
|
|
35060
|
-
|
|
35061
|
-
|
|
35062
|
-
|
|
35063
|
-
|
|
35064
|
-
|
|
35065
|
-
|
|
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
|
|
35300
|
+
return cmp > 0;
|
|
35069
35301
|
case "<":
|
|
35070
|
-
return
|
|
35302
|
+
return cmp < 0;
|
|
35071
35303
|
case ">=":
|
|
35072
|
-
return
|
|
35304
|
+
return cmp >= 0;
|
|
35073
35305
|
case "<=":
|
|
35074
|
-
return
|
|
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
|
|
35085
|
-
|
|
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
|
|
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
|
-
|
|
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,232 @@ 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 planKorder(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 || !Number.isSafeInteger(stmt.limit) || stmt.limit < 0) {
|
|
36577
|
+
reasons.push(`KORDER_LIMIT_INVALID(limit=${String(stmt.limit)})`);
|
|
36578
|
+
}
|
|
36579
|
+
const offset = stmt.offset ?? 0;
|
|
36580
|
+
if (!Number.isSafeInteger(offset) || offset < 0) {
|
|
36581
|
+
reasons.push(`KORDER_OFFSET_INVALID(offset=${offset})`);
|
|
36582
|
+
}
|
|
36583
|
+
const scanRows = stmt.limit === null ? Number.NaN : offset + stmt.limit;
|
|
36584
|
+
if (stmt.limit !== null && !Number.isSafeInteger(scanRows)) {
|
|
36585
|
+
reasons.push(`KORDER_SCAN_ROWS_INVALID(offset=${offset}, limit=${stmt.limit})`);
|
|
36586
|
+
}
|
|
36587
|
+
const unique = [...new Set(reasons)];
|
|
36588
|
+
if (unique.length > 0) {
|
|
36589
|
+
throw new Error(
|
|
36590
|
+
`ArgumentError: KORDER BY cannot be executed (mode=KINTONE_NATIVE; ${unique.join(", ")}). Use ORDER BY for canonical local ordering or simplify the query.`
|
|
36591
|
+
);
|
|
36592
|
+
}
|
|
36593
|
+
const native = stmt.limit <= 500 && offset <= 1e4 && stmt.limit <= input.maxRecords;
|
|
36594
|
+
if (!native && scanRows > input.maxRecords) {
|
|
36595
|
+
throw new Error(
|
|
36596
|
+
`ArgumentError: KORDER BY cannot be executed (mode=KINTONE_NATIVE; KORDER_SCAN_ROWS_EXCEEDS_MAX_RECORDS(scanRows=${scanRows}, maxRecords=${input.maxRecords})). Use ORDER BY for canonical local ordering, raise maxRecords, or reduce LIMIT/OFFSET.`
|
|
36597
|
+
);
|
|
36598
|
+
}
|
|
36599
|
+
return {
|
|
36600
|
+
kind: native ? "KORDER_NATIVE" : "KORDER_CURSOR",
|
|
36601
|
+
requiresCompleteInput: false,
|
|
36602
|
+
localOrderBy: false,
|
|
36603
|
+
applyLocalOffsetLimit: false,
|
|
36604
|
+
reasonCodes: [],
|
|
36605
|
+
scanRows
|
|
36606
|
+
};
|
|
36607
|
+
}
|
|
36608
|
+
|
|
36609
|
+
// src/core/errors/cursorErrors.ts
|
|
36610
|
+
var CursorCapacityError = class extends Error {
|
|
36611
|
+
constructor(host, limit, waitMs) {
|
|
36612
|
+
super(`CursorCapacityError: host=${host} \u306E active cursor \u4E0A\u9650 ${limit} \u306B ${waitMs}ms \u4EE5\u5185\u3067\u7A7A\u304D\u304C\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002`);
|
|
36613
|
+
this.name = "CursorCapacityError";
|
|
36614
|
+
}
|
|
36615
|
+
};
|
|
36616
|
+
var CursorCreateOutcomeUnknownError = class extends Error {
|
|
36617
|
+
constructor(cause) {
|
|
36618
|
+
super("CursorCreateOutcomeUnknownError: Create Cursor \u306E\u6210\u5426\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002\u81EA\u52D5\u518D\u8A66\u884C\u305B\u305A\u3001\u6700\u592710\u5206+\u5B89\u5168\u4F59\u88D5\u306E\u9593\u306F\u67A0\u3092\u9694\u96E2\u3057\u307E\u3059\u3002");
|
|
36619
|
+
this.name = "CursorCreateOutcomeUnknownError";
|
|
36620
|
+
this.cause = cause;
|
|
36621
|
+
}
|
|
36622
|
+
};
|
|
36623
|
+
var CursorCleanupWarning = class extends Error {
|
|
36624
|
+
constructor(cause) {
|
|
36625
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
36626
|
+
super(`CursorCleanupWarning: Cursor \u306E\u89E3\u653E\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002\u7D50\u679C\u306F\u6709\u52B9\u3067\u3059\u304C\u3001\u6700\u592710\u5206+\u5B89\u5168\u4F59\u88D5\u306E\u9593\u306F\u67A0\u3092\u9694\u96E2\u3057\u307E\u3059\u3002\u8A73\u7D30: ${detail}`);
|
|
36627
|
+
this.name = "CursorCleanupWarning";
|
|
36628
|
+
this.cause = cause;
|
|
36629
|
+
}
|
|
36630
|
+
};
|
|
36631
|
+
|
|
36632
|
+
// src/core/optimization/korderCursorExecutor.ts
|
|
36633
|
+
async function executeKorderCursor(input) {
|
|
36634
|
+
const handle = await input.client.openCursor({
|
|
36635
|
+
app: input.app,
|
|
36636
|
+
fields: input.fields.length > 0 ? input.fields : void 0,
|
|
36637
|
+
query: input.query,
|
|
36638
|
+
size: 500
|
|
36639
|
+
});
|
|
36640
|
+
const records = [];
|
|
36641
|
+
let seen = 0;
|
|
36642
|
+
let primaryError;
|
|
36643
|
+
let cleanupWarning;
|
|
36644
|
+
try {
|
|
36645
|
+
if (handle.totalCount > input.offset) {
|
|
36646
|
+
while (records.length < input.limit) {
|
|
36647
|
+
const page = await handle.nextPage();
|
|
36648
|
+
for (const record2 of page.records) {
|
|
36649
|
+
if (seen < input.offset) seen += 1;
|
|
36650
|
+
else if (records.length < input.limit) records.push(record2);
|
|
36651
|
+
else break;
|
|
36652
|
+
}
|
|
36653
|
+
if (!page.next) break;
|
|
36654
|
+
}
|
|
36655
|
+
}
|
|
36656
|
+
} catch (error51) {
|
|
36657
|
+
primaryError = error51;
|
|
36658
|
+
throw error51;
|
|
36659
|
+
} finally {
|
|
36660
|
+
try {
|
|
36661
|
+
await handle.close();
|
|
36662
|
+
} catch (cleanupError) {
|
|
36663
|
+
if (primaryError && primaryError instanceof Error) {
|
|
36664
|
+
Object.defineProperty(primaryError, "cursorCleanupError", {
|
|
36665
|
+
value: cleanupError,
|
|
36666
|
+
configurable: true
|
|
36667
|
+
});
|
|
36668
|
+
} else {
|
|
36669
|
+
cleanupWarning = new CursorCleanupWarning(cleanupError).message;
|
|
36670
|
+
}
|
|
36671
|
+
}
|
|
36672
|
+
}
|
|
36673
|
+
return { records, cleanupWarning };
|
|
36674
|
+
}
|
|
36675
|
+
|
|
36676
|
+
// src/converter/korderCursorQuery.ts
|
|
36677
|
+
function buildKorderCursorQuery(stmt) {
|
|
36678
|
+
const parts = [];
|
|
36679
|
+
if (stmt.where) parts.push(whereToKintone(stmt.where));
|
|
36680
|
+
const order = stmt.orderBy.map((item) => {
|
|
36681
|
+
if (item.key.type !== "FIELD_NAME") {
|
|
36682
|
+
throw new Error("ArgumentError: KORDER cursor key must be a direct field.");
|
|
36683
|
+
}
|
|
36684
|
+
return `${item.key.name} ${item.direction === "ASC" ? "asc" : "desc"}`;
|
|
36685
|
+
});
|
|
36686
|
+
parts.push(`order by ${order.join(", ")}`);
|
|
36687
|
+
return parts.join(" ");
|
|
36688
|
+
}
|
|
36689
|
+
|
|
36139
36690
|
// src/engine/process.ts
|
|
36140
36691
|
function flatten(record2, alias) {
|
|
36141
36692
|
const row = {};
|
|
@@ -36200,9 +36751,9 @@ function applyJoin(leftRows, rightRows, join) {
|
|
|
36200
36751
|
}
|
|
36201
36752
|
return result;
|
|
36202
36753
|
}
|
|
36203
|
-
function applyFilter(rows, where, resolveFieldType, appliedKlikes) {
|
|
36754
|
+
function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
|
|
36204
36755
|
if (where === null) return rows;
|
|
36205
|
-
return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes));
|
|
36756
|
+
return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2));
|
|
36206
36757
|
}
|
|
36207
36758
|
function hasAggregateColumns(columns) {
|
|
36208
36759
|
return columns.some(
|
|
@@ -36263,7 +36814,7 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
36263
36814
|
let strVal;
|
|
36264
36815
|
if (arg.type === "FIELD_REF") {
|
|
36265
36816
|
const raw = row[arg.field];
|
|
36266
|
-
if (raw === void 0 || raw === "") continue;
|
|
36817
|
+
if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") continue;
|
|
36267
36818
|
strVal = raw;
|
|
36268
36819
|
} else {
|
|
36269
36820
|
const n = evalArithExpr(arg, row);
|
|
@@ -36275,10 +36826,16 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
36275
36826
|
const eff = distinct ? [...new Set(strValues)] : strValues;
|
|
36276
36827
|
if (func === "COUNT") return eff.length;
|
|
36277
36828
|
if (func === "GROUP_CONCAT") return eff.join(separator ?? ",");
|
|
36278
|
-
const
|
|
36279
|
-
if (
|
|
36280
|
-
if (eff.length === 0) return
|
|
36281
|
-
|
|
36829
|
+
const comparison = (func === "MIN" || func === "MAX") && arg.type === "FIELD_REF" ? resolveAggSortKind?.(toAggregateFieldRef(arg.field)) : void 0;
|
|
36830
|
+
if (func === "MIN" || func === "MAX") {
|
|
36831
|
+
if (eff.length === 0) return 0;
|
|
36832
|
+
const semantics = typeof comparison === "string" ? syntheticSemantics(comparison) : comparison ?? (arg.type === "FIELD_REF" ? syntheticSemantics("string") : syntheticSemantics("number"));
|
|
36833
|
+
let result = eff[0];
|
|
36834
|
+
for (const candidate of eff.slice(1)) {
|
|
36835
|
+
const cmp = compareCanonicalValues(candidate, result, semantics);
|
|
36836
|
+
if (func === "MAX" && cmp > 0 || func === "MIN" && cmp < 0) result = candidate;
|
|
36837
|
+
}
|
|
36838
|
+
return result;
|
|
36282
36839
|
}
|
|
36283
36840
|
const nums = eff.map(Number);
|
|
36284
36841
|
switch (func) {
|
|
@@ -36286,37 +36843,12 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
36286
36843
|
return nums.reduce((a, b) => a + b, 0);
|
|
36287
36844
|
case "AVG":
|
|
36288
36845
|
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
36846
|
}
|
|
36295
36847
|
}
|
|
36296
36848
|
function toAggregateFieldRef(field) {
|
|
36297
36849
|
const dot = field.indexOf(".");
|
|
36298
36850
|
return dot > 0 ? { type: "FIELD", tableAlias: field.slice(0, dot), field: field.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field };
|
|
36299
36851
|
}
|
|
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
36852
|
function evalAggArithExpr(node, rows, resolveAggSortKind) {
|
|
36321
36853
|
if (node.type === "NUMBER") return node.value;
|
|
36322
36854
|
if (node.type === "AGG_REF") return Number(evalAggregate(node.func, node.distinct, node.arg, node.separator, rows, resolveAggSortKind));
|
|
@@ -36348,9 +36880,9 @@ function aggregateSyntheticName2(func, distinct, arg) {
|
|
|
36348
36880
|
const argStr = aggregateArgLabel(arg);
|
|
36349
36881
|
return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
|
|
36350
36882
|
}
|
|
36351
|
-
function applyHaving(rows, having, resolveFieldType) {
|
|
36883
|
+
function applyHaving(rows, having, resolveFieldType, resolveFieldSemantics2) {
|
|
36352
36884
|
if (having === null) return rows;
|
|
36353
|
-
return rows.filter((row) => evalWhere(having, row, resolveFieldType));
|
|
36885
|
+
return rows.filter((row) => evalWhere(having, row, resolveFieldType, void 0, resolveFieldSemantics2));
|
|
36354
36886
|
}
|
|
36355
36887
|
function applyDistinct(rows, columns) {
|
|
36356
36888
|
if (rows.length === 0) return rows;
|
|
@@ -36402,27 +36934,37 @@ function buildDistinctKeyBuilder(rows, columns) {
|
|
|
36402
36934
|
return JSON.stringify(values);
|
|
36403
36935
|
};
|
|
36404
36936
|
}
|
|
36405
|
-
function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
|
|
36937
|
+
function applyOrderBy(rows, orderBy, optionOrders, sortKinds, fieldSemantics2) {
|
|
36406
36938
|
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
|
-
|
|
36412
|
-
|
|
36413
|
-
|
|
36939
|
+
return sortDecoratedRows(rows, orderBy, optionOrders, sortKinds, fieldSemantics2).rows.map((item) => item.row);
|
|
36940
|
+
}
|
|
36941
|
+
function sortDecoratedRows(rows, orderBy, optionOrders, sortKinds, fieldSemantics2) {
|
|
36942
|
+
const keyMeta = orderBy.map(({ key }) => {
|
|
36943
|
+
if (key.type === "ARITH_KEY") return { semantics: syntheticSemantics("number") };
|
|
36944
|
+
if (key.type === "FUNC_KEY") {
|
|
36945
|
+
return { semantics: syntheticSemantics(NUMERIC_ORDER_FUNCTIONS.has(key.expr.func) ? "number" : "string") };
|
|
36946
|
+
}
|
|
36947
|
+
const semantics = fieldSemantics2?.get(key.name);
|
|
36948
|
+
if (semantics) return { semantics };
|
|
36949
|
+
const orderMap = optionOrders?.get(key.name);
|
|
36950
|
+
if (orderMap) {
|
|
36951
|
+
return {
|
|
36952
|
+
semantics: {
|
|
36953
|
+
fieldType: "MULTI_SELECT",
|
|
36954
|
+
compareMode: "option",
|
|
36955
|
+
inSubtable: false,
|
|
36956
|
+
requiresCollectionOperators: false,
|
|
36957
|
+
optionOrder: orderMap
|
|
36958
|
+
}
|
|
36959
|
+
};
|
|
36960
|
+
}
|
|
36961
|
+
return { semantics: syntheticSemantics(sortKinds?.get(key.name) ?? "string") };
|
|
36962
|
+
});
|
|
36414
36963
|
const decorated = rows.map((row) => ({
|
|
36415
36964
|
row,
|
|
36416
36965
|
keys: orderBy.map(({ key }, i) => {
|
|
36417
36966
|
const s = evalOrderKey(key, row);
|
|
36418
|
-
|
|
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
|
-
};
|
|
36967
|
+
return { s };
|
|
36426
36968
|
})
|
|
36427
36969
|
}));
|
|
36428
36970
|
const compare = (a, b) => compareDecoratedRows(a, b, orderBy, keyMeta);
|
|
@@ -36437,15 +36979,24 @@ function compareDecoratedRows(a, b, orderBy, keyMeta) {
|
|
|
36437
36979
|
return 0;
|
|
36438
36980
|
}
|
|
36439
36981
|
function compareSortKeys(a, b, meta3) {
|
|
36440
|
-
|
|
36441
|
-
|
|
36442
|
-
|
|
36443
|
-
|
|
36444
|
-
|
|
36445
|
-
|
|
36446
|
-
|
|
36447
|
-
|
|
36448
|
-
|
|
36982
|
+
return compareCanonicalValues(a.s, b.s, meta3.semantics);
|
|
36983
|
+
}
|
|
36984
|
+
var NUMERIC_ORDER_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
36985
|
+
"LENGTH",
|
|
36986
|
+
"INSTR",
|
|
36987
|
+
"ROUND",
|
|
36988
|
+
"FLOOR",
|
|
36989
|
+
"CEIL",
|
|
36990
|
+
"TRUNCATE",
|
|
36991
|
+
"YEAR",
|
|
36992
|
+
"MONTH",
|
|
36993
|
+
"DAY",
|
|
36994
|
+
"DATEDIFF",
|
|
36995
|
+
"ABS",
|
|
36996
|
+
"MOD",
|
|
36997
|
+
"POWER",
|
|
36998
|
+
"SQRT"
|
|
36999
|
+
]);
|
|
36449
37000
|
function evalOrderKey(key, row) {
|
|
36450
37001
|
switch (key.type) {
|
|
36451
37002
|
case "FIELD_NAME":
|
|
@@ -36456,30 +37007,7 @@ function evalOrderKey(key, row) {
|
|
|
36456
37007
|
return evalStringFunc(key.expr, row);
|
|
36457
37008
|
}
|
|
36458
37009
|
}
|
|
36459
|
-
function
|
|
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) {
|
|
37010
|
+
function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
|
|
36483
37011
|
const windows = columns.filter((column) => column.type === "WINDOW_COL");
|
|
36484
37012
|
if (rows.length === 0 || windows.length === 0) return rows;
|
|
36485
37013
|
for (const window of windows) {
|
|
@@ -36491,7 +37019,7 @@ function applyWindow(rows, columns, optionOrders, sortKinds) {
|
|
|
36491
37019
|
else partitions.set(key, [row]);
|
|
36492
37020
|
}
|
|
36493
37021
|
for (const partition of partitions.values()) {
|
|
36494
|
-
const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds);
|
|
37022
|
+
const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds, fieldSemantics2);
|
|
36495
37023
|
const sorted = sortedResult.rows;
|
|
36496
37024
|
let rank = 1;
|
|
36497
37025
|
let denseRank = 1;
|
|
@@ -36516,7 +37044,7 @@ function applyLimit(rows, limit, offset) {
|
|
|
36516
37044
|
if (limit === null) return rows.slice(start);
|
|
36517
37045
|
return rows.slice(start, start + limit);
|
|
36518
37046
|
}
|
|
36519
|
-
function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
|
|
37047
|
+
function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2) {
|
|
36520
37048
|
if (columns.length === 1 && columns[0].type === "WILDCARD") {
|
|
36521
37049
|
const projected2 = rows.map((row) => stripParentShortcutColumns(row));
|
|
36522
37050
|
const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
|
|
@@ -36580,7 +37108,7 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
|
|
|
36580
37108
|
}
|
|
36581
37109
|
case "CASE_COL": {
|
|
36582
37110
|
const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
|
|
36583
|
-
out[key] = evalCaseWhen(col.expr, row, resolveFieldType);
|
|
37111
|
+
out[key] = evalCaseWhen(col.expr, row, resolveFieldType, resolveFieldSemantics2);
|
|
36584
37112
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
36585
37113
|
break;
|
|
36586
37114
|
}
|
|
@@ -36735,6 +37263,26 @@ function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
|
|
|
36735
37263
|
args: expr.args.map((arg) => resolveAggInStringFuncArg(arg, rows, resolveAggSortKind))
|
|
36736
37264
|
};
|
|
36737
37265
|
}
|
|
37266
|
+
function deriveOutputOrderSemantics(columns) {
|
|
37267
|
+
const result = /* @__PURE__ */ new Map();
|
|
37268
|
+
for (const column of columns) {
|
|
37269
|
+
if (!("alias" in column) || !column.alias) continue;
|
|
37270
|
+
if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
|
|
37271
|
+
result.set(column.alias, syntheticSemantics("number"));
|
|
37272
|
+
} else if (column.type === "AGGREGATE") {
|
|
37273
|
+
if (column.func === "COUNT" || column.func === "SUM" || column.func === "AVG") {
|
|
37274
|
+
result.set(column.alias, syntheticSemantics("number"));
|
|
37275
|
+
} else if (column.func === "GROUP_CONCAT") {
|
|
37276
|
+
result.set(column.alias, syntheticSemantics("string"));
|
|
37277
|
+
}
|
|
37278
|
+
} else if (column.type === "LITERAL_COL" || column.type === "CASE_COL" || column.type === "SCALAR_SUBQUERY_COL") {
|
|
37279
|
+
result.set(column.alias, syntheticSemantics("string"));
|
|
37280
|
+
} else if (column.type === "STRFUNC_COL") {
|
|
37281
|
+
result.set(column.alias, syntheticSemantics(NUMERIC_ORDER_FUNCTIONS.has(column.expr.func) ? "number" : "string"));
|
|
37282
|
+
}
|
|
37283
|
+
}
|
|
37284
|
+
return result;
|
|
37285
|
+
}
|
|
36738
37286
|
function runFullScan(input) {
|
|
36739
37287
|
const {
|
|
36740
37288
|
stmt,
|
|
@@ -36742,12 +37290,17 @@ function runFullScan(input) {
|
|
|
36742
37290
|
scalarCache,
|
|
36743
37291
|
optionOrders,
|
|
36744
37292
|
sortKinds,
|
|
37293
|
+
orderSemantics,
|
|
36745
37294
|
fieldTypeResolver,
|
|
37295
|
+
fieldSemanticsResolver,
|
|
36746
37296
|
havingFieldTypeResolver,
|
|
37297
|
+
havingFieldSemanticsResolver,
|
|
36747
37298
|
aggregateSortKindResolver,
|
|
36748
37299
|
appliedKlikes,
|
|
36749
37300
|
sourceColumns
|
|
36750
37301
|
} = input;
|
|
37302
|
+
const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
|
|
37303
|
+
for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
|
|
36751
37304
|
let rows = [];
|
|
36752
37305
|
const mainAlias = stmt.from.alias;
|
|
36753
37306
|
const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
|
|
@@ -36758,18 +37311,18 @@ function runFullScan(input) {
|
|
|
36758
37311
|
const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
|
|
36759
37312
|
rows = applyJoin(rows, rightRows, join);
|
|
36760
37313
|
}
|
|
36761
|
-
rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes);
|
|
37314
|
+
rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes, fieldSemanticsResolver);
|
|
36762
37315
|
if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
|
|
36763
37316
|
rows = applyGroupBy(rows, stmt.groupBy, stmt.columns, aggregateSortKindResolver);
|
|
36764
37317
|
}
|
|
36765
|
-
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
|
|
36766
|
-
rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds);
|
|
37318
|
+
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, havingFieldSemanticsResolver);
|
|
37319
|
+
rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds, effectiveOrderSemantics);
|
|
36767
37320
|
if (stmt.distinct) {
|
|
36768
37321
|
rows = applyDistinct(rows, stmt.columns);
|
|
36769
37322
|
}
|
|
36770
|
-
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
|
|
37323
|
+
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds, effectiveOrderSemantics);
|
|
36771
37324
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
36772
|
-
return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns);
|
|
37325
|
+
return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns, fieldSemanticsResolver);
|
|
36773
37326
|
}
|
|
36774
37327
|
|
|
36775
37328
|
// src/converter/subtableAdapter.ts
|
|
@@ -37037,36 +37590,234 @@ function renderValidationValue(value) {
|
|
|
37037
37590
|
return String(value);
|
|
37038
37591
|
}
|
|
37039
37592
|
|
|
37040
|
-
// src/
|
|
37041
|
-
var
|
|
37042
|
-
var
|
|
37043
|
-
|
|
37044
|
-
|
|
37045
|
-
|
|
37046
|
-
|
|
37047
|
-
|
|
37048
|
-
|
|
37049
|
-
|
|
37050
|
-
|
|
37051
|
-
|
|
37052
|
-
|
|
37053
|
-
|
|
37054
|
-
|
|
37055
|
-
|
|
37056
|
-
|
|
37057
|
-
|
|
37058
|
-
|
|
37059
|
-
|
|
37060
|
-
)
|
|
37061
|
-
|
|
37062
|
-
|
|
37063
|
-
|
|
37064
|
-
|
|
37065
|
-
|
|
37066
|
-
)
|
|
37067
|
-
|
|
37068
|
-
|
|
37069
|
-
|
|
37593
|
+
// src/core/optimization/whereCapability.ts
|
|
37594
|
+
var RANGE_AND_EQUALITY = ["=", "!=", ">", "<", ">=", "<="];
|
|
37595
|
+
var EQUALITY_IN = ["=", "!=", "in", "not in"];
|
|
37596
|
+
var NATIVE_OPERATORS = /* @__PURE__ */ new Map([
|
|
37597
|
+
["RECORD_NUMBER", /* @__PURE__ */ new Set([...RANGE_AND_EQUALITY, "in", "not in"])],
|
|
37598
|
+
["__ID__", /* @__PURE__ */ new Set([...RANGE_AND_EQUALITY, "in", "not in"])],
|
|
37599
|
+
["CREATOR", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37600
|
+
["MODIFIER", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37601
|
+
["CREATED_TIME", new Set(RANGE_AND_EQUALITY)],
|
|
37602
|
+
["UPDATED_TIME", new Set(RANGE_AND_EQUALITY)],
|
|
37603
|
+
["DATE", new Set(RANGE_AND_EQUALITY)],
|
|
37604
|
+
["TIME", new Set(RANGE_AND_EQUALITY)],
|
|
37605
|
+
["DATETIME", new Set(RANGE_AND_EQUALITY)],
|
|
37606
|
+
["SINGLE_LINE_TEXT", /* @__PURE__ */ new Set(["=", "!=", "in", "not in", "like", "not like"])],
|
|
37607
|
+
["LINK", /* @__PURE__ */ new Set(["=", "!=", "in", "not in", "like", "not like"])],
|
|
37608
|
+
["NUMBER", /* @__PURE__ */ new Set([...RANGE_AND_EQUALITY, "in", "not in"])],
|
|
37609
|
+
["CALC", /* @__PURE__ */ new Set([...RANGE_AND_EQUALITY, "in", "not in"])],
|
|
37610
|
+
["MULTI_LINE_TEXT", /* @__PURE__ */ new Set(["like", "not like"])],
|
|
37611
|
+
["RICH_TEXT", /* @__PURE__ */ new Set(["like", "not like"])],
|
|
37612
|
+
["CHECK_BOX", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37613
|
+
["RADIO_BUTTON", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37614
|
+
["DROP_DOWN", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37615
|
+
["MULTI_SELECT", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37616
|
+
["FILE", /* @__PURE__ */ new Set(["like", "not like"])],
|
|
37617
|
+
["USER_SELECT", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37618
|
+
["ORGANIZATION_SELECT", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37619
|
+
["GROUP_SELECT", /* @__PURE__ */ new Set(["in", "not in"])],
|
|
37620
|
+
["STATUS", new Set(EQUALITY_IN)]
|
|
37621
|
+
]);
|
|
37622
|
+
var LOCAL_SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
37623
|
+
"RECORD_NUMBER",
|
|
37624
|
+
"__ID__",
|
|
37625
|
+
"CREATOR",
|
|
37626
|
+
"MODIFIER",
|
|
37627
|
+
"CREATED_TIME",
|
|
37628
|
+
"UPDATED_TIME",
|
|
37629
|
+
"DATE",
|
|
37630
|
+
"TIME",
|
|
37631
|
+
"DATETIME",
|
|
37632
|
+
"SINGLE_LINE_TEXT",
|
|
37633
|
+
"LINK",
|
|
37634
|
+
"NUMBER",
|
|
37635
|
+
"CALC",
|
|
37636
|
+
"MULTI_LINE_TEXT",
|
|
37637
|
+
"RICH_TEXT",
|
|
37638
|
+
"RADIO_BUTTON",
|
|
37639
|
+
"DROP_DOWN",
|
|
37640
|
+
"STATUS",
|
|
37641
|
+
// 一時表・CTE・式列は kintone REST へは送らず、共有ローカル評価器で扱う。
|
|
37642
|
+
"KSQL_STRING",
|
|
37643
|
+
"KSQL_NUMBER",
|
|
37644
|
+
"KSQL_BOOLEAN"
|
|
37645
|
+
]);
|
|
37646
|
+
var LOCAL_COLLECTION_TYPES = /* @__PURE__ */ new Set([
|
|
37647
|
+
"CHECK_BOX",
|
|
37648
|
+
"MULTI_SELECT",
|
|
37649
|
+
"FILE",
|
|
37650
|
+
"USER_SELECT",
|
|
37651
|
+
"ORGANIZATION_SELECT",
|
|
37652
|
+
"GROUP_SELECT",
|
|
37653
|
+
"STATUS_ASSIGNEE",
|
|
37654
|
+
"CATEGORY"
|
|
37655
|
+
]);
|
|
37656
|
+
function nativeWhereOperatorsForType(fieldType) {
|
|
37657
|
+
return NATIVE_OPERATORS.get(fieldType) ?? /* @__PURE__ */ new Set();
|
|
37658
|
+
}
|
|
37659
|
+
function classifyWhereCapability(where, resolveField2) {
|
|
37660
|
+
if (where === null) {
|
|
37661
|
+
return { capability: "EXACT_PUSHDOWN", reasons: [{ code: "WHERE_EXACT" }] };
|
|
37662
|
+
}
|
|
37663
|
+
return classifyNode(where, resolveField2);
|
|
37664
|
+
}
|
|
37665
|
+
function classifyNode(where, resolveField2) {
|
|
37666
|
+
switch (where.type) {
|
|
37667
|
+
case "BINARY":
|
|
37668
|
+
return classifyBinary(where.op, where.left, where.right.type, resolveField2);
|
|
37669
|
+
case "NULL_CHECK":
|
|
37670
|
+
if (where.field.type !== "FIELD") return localExpression();
|
|
37671
|
+
return classifyLocalOnlyField(where.field, where.not ? "IS NOT NULL" : "IS NULL", resolveField2);
|
|
37672
|
+
case "EXISTS":
|
|
37673
|
+
return localExpression();
|
|
37674
|
+
case "GROUP":
|
|
37675
|
+
return classifyNode(where.expr, resolveField2);
|
|
37676
|
+
case "NOT": {
|
|
37677
|
+
const inner = classifyNode(where.expr, resolveField2);
|
|
37678
|
+
return inner.capability === "SUPERSET_PREFILTER" ? { capability: "LOCAL_ONLY", reasons: [{ code: "WHERE_EXPRESSION_LOCAL_ONLY" }] } : inner;
|
|
37679
|
+
}
|
|
37680
|
+
case "LOGICAL": {
|
|
37681
|
+
const left = classifyNode(where.left, resolveField2);
|
|
37682
|
+
const right = classifyNode(where.right, resolveField2);
|
|
37683
|
+
return combineLogical(where.op, left, right);
|
|
37684
|
+
}
|
|
37685
|
+
}
|
|
37686
|
+
}
|
|
37687
|
+
function classifyBinary(op, left, rightType, resolveField2) {
|
|
37688
|
+
if (left.type !== "FIELD") return localExpression();
|
|
37689
|
+
const semantics = resolveField2(left);
|
|
37690
|
+
if (!semantics) {
|
|
37691
|
+
return unsupported("WHERE_FIELD_UNRESOLVED", left.field, void 0, normalizeOperator(op));
|
|
37692
|
+
}
|
|
37693
|
+
if (!hasLocalContract(semantics.fieldType, op)) {
|
|
37694
|
+
return unsupported("WHERE_OPERATOR_UNSUPPORTED", left.field, semantics.fieldType, normalizeOperator(op));
|
|
37695
|
+
}
|
|
37696
|
+
const nativeOp = normalizeOperator(op);
|
|
37697
|
+
const native = nativeWhereOperatorsForType(semantics.fieldType);
|
|
37698
|
+
const rightCanPush = rightType === "STRING" || rightType === "NUMBER" || rightType === "IN_LIST" || rightType === "KINTONE_FUNC";
|
|
37699
|
+
const structureAllows = !semantics.requiresCollectionOperators || nativeOp !== "=" && nativeOp !== "!=";
|
|
37700
|
+
const sqlLikeIsResidual = op === "LIKE" || op === "NOT_LIKE";
|
|
37701
|
+
if (rightCanPush && structureAllows && native.has(nativeOp) && !sqlLikeIsResidual) {
|
|
37702
|
+
return {
|
|
37703
|
+
capability: "EXACT_PUSHDOWN",
|
|
37704
|
+
reasons: [{
|
|
37705
|
+
code: "WHERE_EXACT",
|
|
37706
|
+
field: left.field,
|
|
37707
|
+
fieldType: semantics.fieldType,
|
|
37708
|
+
operator: nativeOp
|
|
37709
|
+
}]
|
|
37710
|
+
};
|
|
37711
|
+
}
|
|
37712
|
+
return {
|
|
37713
|
+
capability: "LOCAL_ONLY",
|
|
37714
|
+
reasons: [{
|
|
37715
|
+
code: "WHERE_RESIDUAL",
|
|
37716
|
+
field: left.field,
|
|
37717
|
+
fieldType: semantics.fieldType,
|
|
37718
|
+
operator: nativeOp
|
|
37719
|
+
}]
|
|
37720
|
+
};
|
|
37721
|
+
}
|
|
37722
|
+
function classifyLocalOnlyField(field, operator, resolveField2) {
|
|
37723
|
+
const semantics = resolveField2(field);
|
|
37724
|
+
if (!semantics) return unsupported("WHERE_FIELD_UNRESOLVED", field.field, void 0, operator);
|
|
37725
|
+
if (!LOCAL_SCALAR_TYPES.has(semantics.fieldType) && !LOCAL_COLLECTION_TYPES.has(semantics.fieldType)) {
|
|
37726
|
+
return unsupported("WHERE_OPERATOR_UNSUPPORTED", field.field, semantics.fieldType, operator);
|
|
37727
|
+
}
|
|
37728
|
+
return {
|
|
37729
|
+
capability: "LOCAL_ONLY",
|
|
37730
|
+
reasons: [{ code: "WHERE_RESIDUAL", field: field.field, fieldType: semantics.fieldType, operator }]
|
|
37731
|
+
};
|
|
37732
|
+
}
|
|
37733
|
+
function hasLocalContract(fieldType, op) {
|
|
37734
|
+
if (LOCAL_SCALAR_TYPES.has(fieldType)) return true;
|
|
37735
|
+
if (!LOCAL_COLLECTION_TYPES.has(fieldType)) return false;
|
|
37736
|
+
return op === "=" || op === "!=" || op === "<>" || op === "IN" || op === "NOT_IN" || op === "LIKE" || op === "NOT_LIKE" || op === "KLIKE" || op === "NOT_KLIKE";
|
|
37737
|
+
}
|
|
37738
|
+
function normalizeOperator(op) {
|
|
37739
|
+
switch (op) {
|
|
37740
|
+
case "<>":
|
|
37741
|
+
return "!=";
|
|
37742
|
+
case "IN":
|
|
37743
|
+
return "in";
|
|
37744
|
+
case "NOT_IN":
|
|
37745
|
+
return "not in";
|
|
37746
|
+
case "LIKE":
|
|
37747
|
+
case "KLIKE":
|
|
37748
|
+
return "like";
|
|
37749
|
+
case "NOT_LIKE":
|
|
37750
|
+
case "NOT_KLIKE":
|
|
37751
|
+
return "not like";
|
|
37752
|
+
default:
|
|
37753
|
+
return op;
|
|
37754
|
+
}
|
|
37755
|
+
}
|
|
37756
|
+
function combineLogical(op, left, right) {
|
|
37757
|
+
const reasons = [...left.reasons, ...right.reasons];
|
|
37758
|
+
if (left.capability === "UNSUPPORTED" || right.capability === "UNSUPPORTED") {
|
|
37759
|
+
return { capability: "UNSUPPORTED", reasons };
|
|
37760
|
+
}
|
|
37761
|
+
if (left.capability === "EXACT_PUSHDOWN" && right.capability === "EXACT_PUSHDOWN") {
|
|
37762
|
+
return { capability: "EXACT_PUSHDOWN", reasons };
|
|
37763
|
+
}
|
|
37764
|
+
if (op === "AND" && (left.capability === "EXACT_PUSHDOWN" || right.capability === "EXACT_PUSHDOWN" || left.capability === "SUPERSET_PREFILTER" || right.capability === "SUPERSET_PREFILTER")) {
|
|
37765
|
+
return {
|
|
37766
|
+
capability: "SUPERSET_PREFILTER",
|
|
37767
|
+
reasons: [{ code: "WHERE_SUPERSET_PREFILTER" }, ...reasons]
|
|
37768
|
+
};
|
|
37769
|
+
}
|
|
37770
|
+
return { capability: "LOCAL_ONLY", reasons };
|
|
37771
|
+
}
|
|
37772
|
+
function localExpression() {
|
|
37773
|
+
return { capability: "LOCAL_ONLY", reasons: [{ code: "WHERE_EXPRESSION_LOCAL_ONLY" }] };
|
|
37774
|
+
}
|
|
37775
|
+
function unsupported(code, field, fieldType, operator) {
|
|
37776
|
+
return { capability: "UNSUPPORTED", reasons: [{ code, field, fieldType, operator }] };
|
|
37777
|
+
}
|
|
37778
|
+
|
|
37779
|
+
// src/execute.ts
|
|
37780
|
+
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";
|
|
37781
|
+
var SearchAbortedError = class extends Error {
|
|
37782
|
+
constructor() {
|
|
37783
|
+
super("SearchAbortedError: kintone \u306E\u691C\u7D22\u304C 10 \u4E07\u4EF6\u3067\u6253\u3061\u5207\u3089\u308C\u305F\u305F\u3081\u3001\u5B8C\u5168\u306A\u5BFE\u8C61\u96C6\u5408\u3092\u78BA\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002");
|
|
37784
|
+
this.name = "SearchAbortedError";
|
|
37785
|
+
}
|
|
37786
|
+
};
|
|
37787
|
+
var materializedMetaBySelectResult = /* @__PURE__ */ new WeakMap();
|
|
37788
|
+
var materializedMetaByValidationResult = /* @__PURE__ */ new WeakMap();
|
|
37789
|
+
var defaultCacheContextByClient = /* @__PURE__ */ new WeakMap();
|
|
37790
|
+
var nextDefaultCacheContextId = 1;
|
|
37791
|
+
function resolveCacheContext(client, explicit) {
|
|
37792
|
+
if (explicit) return explicit;
|
|
37793
|
+
let context = defaultCacheContextByClient.get(client);
|
|
37794
|
+
if (!context) {
|
|
37795
|
+
context = `client:${nextDefaultCacheContextId++}`;
|
|
37796
|
+
defaultCacheContextByClient.set(client, context);
|
|
37797
|
+
}
|
|
37798
|
+
return context;
|
|
37799
|
+
}
|
|
37800
|
+
async function execute(sql, client, options = {}) {
|
|
37801
|
+
const startedAt = Date.now();
|
|
37802
|
+
const cacheContext = resolveCacheContext(client, options.cacheContext);
|
|
37803
|
+
const stmt = parseSql(sql);
|
|
37804
|
+
const metrics = createEmptyMetrics();
|
|
37805
|
+
const countedClient = wrapClientWithMetrics(client, metrics);
|
|
37806
|
+
const collector = { aborted: false };
|
|
37807
|
+
const guardedClient = wrapClientWithSearchAbort(
|
|
37808
|
+
countedClient,
|
|
37809
|
+
collector,
|
|
37810
|
+
!isSelectLikeStatement(stmt)
|
|
37811
|
+
);
|
|
37812
|
+
const result = await executeParsedStatement(
|
|
37813
|
+
stmt,
|
|
37814
|
+
guardedClient,
|
|
37815
|
+
options,
|
|
37816
|
+
cacheContext
|
|
37817
|
+
);
|
|
37818
|
+
metrics.elapsedMs = Date.now() - startedAt;
|
|
37819
|
+
return { ...attachSearchAbortWarning(result, collector), metrics };
|
|
37820
|
+
}
|
|
37070
37821
|
function createEmptyMetrics() {
|
|
37071
37822
|
return {
|
|
37072
37823
|
getCalls: 0,
|
|
@@ -37076,6 +37827,15 @@ function createEmptyMetrics() {
|
|
|
37076
37827
|
fieldCalls: 0,
|
|
37077
37828
|
appsCalls: 0,
|
|
37078
37829
|
processStatusCalls: 0,
|
|
37830
|
+
cursorCreateCalls: 0,
|
|
37831
|
+
cursorGetCalls: 0,
|
|
37832
|
+
cursorDeleteCalls: 0,
|
|
37833
|
+
cursorRecordsScanned: 0,
|
|
37834
|
+
cursorActiveCurrent: 0,
|
|
37835
|
+
cursorActivePeak: 0,
|
|
37836
|
+
cursorCleanupFailures: 0,
|
|
37837
|
+
cursorCreateOutcomeUnknown: 0,
|
|
37838
|
+
cursorQuarantinedCurrent: 0,
|
|
37079
37839
|
fetchedRows: 0,
|
|
37080
37840
|
elapsedMs: 0
|
|
37081
37841
|
};
|
|
@@ -37088,6 +37848,48 @@ function wrapClientWithMetrics(client, metrics) {
|
|
|
37088
37848
|
metrics.fetchedRows += res.records.length;
|
|
37089
37849
|
return res;
|
|
37090
37850
|
},
|
|
37851
|
+
openCursor: async (params) => {
|
|
37852
|
+
metrics.cursorCreateCalls += 1;
|
|
37853
|
+
let handle;
|
|
37854
|
+
try {
|
|
37855
|
+
handle = await client.openCursor(params);
|
|
37856
|
+
} catch (error51) {
|
|
37857
|
+
if (error51 instanceof Error && error51.name === "CursorCreateOutcomeUnknownError") {
|
|
37858
|
+
metrics.cursorCreateOutcomeUnknown += 1;
|
|
37859
|
+
metrics.cursorQuarantinedCurrent += 1;
|
|
37860
|
+
}
|
|
37861
|
+
throw error51;
|
|
37862
|
+
}
|
|
37863
|
+
metrics.cursorActiveCurrent += 1;
|
|
37864
|
+
metrics.cursorActivePeak = Math.max(metrics.cursorActivePeak, metrics.cursorActiveCurrent);
|
|
37865
|
+
let released = false;
|
|
37866
|
+
const markReleased = () => {
|
|
37867
|
+
if (released) return;
|
|
37868
|
+
released = true;
|
|
37869
|
+
metrics.cursorActiveCurrent -= 1;
|
|
37870
|
+
};
|
|
37871
|
+
return {
|
|
37872
|
+
totalCount: handle.totalCount,
|
|
37873
|
+
nextPage: async () => {
|
|
37874
|
+
metrics.cursorGetCalls += 1;
|
|
37875
|
+
const page = await handle.nextPage();
|
|
37876
|
+
metrics.cursorRecordsScanned += page.records.length;
|
|
37877
|
+
if (!page.next) markReleased();
|
|
37878
|
+
return page;
|
|
37879
|
+
},
|
|
37880
|
+
close: async () => {
|
|
37881
|
+
if (!released) metrics.cursorDeleteCalls += 1;
|
|
37882
|
+
try {
|
|
37883
|
+
await handle.close();
|
|
37884
|
+
markReleased();
|
|
37885
|
+
} catch (error51) {
|
|
37886
|
+
metrics.cursorCleanupFailures += 1;
|
|
37887
|
+
metrics.cursorQuarantinedCurrent += 1;
|
|
37888
|
+
throw error51;
|
|
37889
|
+
}
|
|
37890
|
+
}
|
|
37891
|
+
};
|
|
37892
|
+
},
|
|
37091
37893
|
postRecords: (params) => {
|
|
37092
37894
|
metrics.postCalls += 1;
|
|
37093
37895
|
return client.postRecords(params);
|
|
@@ -37127,6 +37929,37 @@ function wrapClientWithSearchAbort(client, collector, failClosed) {
|
|
|
37127
37929
|
}
|
|
37128
37930
|
};
|
|
37129
37931
|
}
|
|
37932
|
+
function wrapClientWithCursorScope(client) {
|
|
37933
|
+
const active = /* @__PURE__ */ new Set();
|
|
37934
|
+
return {
|
|
37935
|
+
client: {
|
|
37936
|
+
...client,
|
|
37937
|
+
openCursor: async (params) => {
|
|
37938
|
+
const handle = await client.openCursor(params);
|
|
37939
|
+
active.add(handle);
|
|
37940
|
+
const remove = () => active.delete(handle);
|
|
37941
|
+
return {
|
|
37942
|
+
totalCount: handle.totalCount,
|
|
37943
|
+
async nextPage() {
|
|
37944
|
+
const page = await handle.nextPage();
|
|
37945
|
+
if (!page.next) remove();
|
|
37946
|
+
return page;
|
|
37947
|
+
},
|
|
37948
|
+
async close() {
|
|
37949
|
+
try {
|
|
37950
|
+
await handle.close();
|
|
37951
|
+
} finally {
|
|
37952
|
+
remove();
|
|
37953
|
+
}
|
|
37954
|
+
}
|
|
37955
|
+
};
|
|
37956
|
+
}
|
|
37957
|
+
},
|
|
37958
|
+
closeActive: async () => {
|
|
37959
|
+
await Promise.all([...active].map((handle) => handle.close().catch(() => void 0)));
|
|
37960
|
+
}
|
|
37961
|
+
};
|
|
37962
|
+
}
|
|
37130
37963
|
function isSelectLikeStatement(stmt) {
|
|
37131
37964
|
return stmt.type === "SELECT" || stmt.type === "UNION" || stmt.type === "WITH";
|
|
37132
37965
|
}
|
|
@@ -37177,7 +38010,13 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
37177
38010
|
case "DESCRIBE":
|
|
37178
38011
|
return executeDescribe(stmt, client, cacheContext);
|
|
37179
38012
|
case "EXPLAIN":
|
|
37180
|
-
return executeExplain(
|
|
38013
|
+
return executeExplain(
|
|
38014
|
+
stmt,
|
|
38015
|
+
client,
|
|
38016
|
+
cacheContext,
|
|
38017
|
+
options.maxRecords ?? 1e4,
|
|
38018
|
+
options.cursorMaxActive ?? 2
|
|
38019
|
+
);
|
|
37181
38020
|
// 一時テーブルはバッチスコープのため単文実行では拒否する(executeBatch を使う)
|
|
37182
38021
|
case "CREATE_TEMP_TABLE":
|
|
37183
38022
|
throw new Error("ArgumentError: CREATE TEMP TABLE requires a batch (temp tables are batch-scoped).");
|
|
@@ -37208,7 +38047,7 @@ function materializedColumnMetaEqual(left, right) {
|
|
|
37208
38047
|
if (!left || !right || left.size !== right.size) return false;
|
|
37209
38048
|
for (const [column, meta3] of left) {
|
|
37210
38049
|
const candidate = right.get(column);
|
|
37211
|
-
if (!candidate || candidate.sortKind !== meta3.sortKind || candidate.fieldType !== meta3.fieldType) return false;
|
|
38050
|
+
if (!candidate || candidate.sortKind !== meta3.sortKind || candidate.fieldType !== meta3.fieldType || !fieldSemanticsEqual(candidate.semantics, meta3.semantics)) return false;
|
|
37212
38051
|
}
|
|
37213
38052
|
return true;
|
|
37214
38053
|
}
|
|
@@ -37239,7 +38078,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
37239
38078
|
const countedClient = wrapClientWithMetrics(client, metrics);
|
|
37240
38079
|
const startedAt = Date.now();
|
|
37241
38080
|
const deadline = options.timeoutMs != null ? startedAt + options.timeoutMs : null;
|
|
37242
|
-
const cacheContext = options.cacheContext
|
|
38081
|
+
const cacheContext = resolveCacheContext(client, options.cacheContext);
|
|
37243
38082
|
const tempTables = /* @__PURE__ */ new Map();
|
|
37244
38083
|
const variables = /* @__PURE__ */ new Map();
|
|
37245
38084
|
const results = [];
|
|
@@ -37284,9 +38123,11 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
37284
38123
|
searchAbortCollector,
|
|
37285
38124
|
info.statementType !== "SELECT" && info.statementType !== "UNION" && info.statementType !== "WITH"
|
|
37286
38125
|
);
|
|
38126
|
+
const cursorScope = wrapClientWithCursorScope(statementClient);
|
|
37287
38127
|
const outcome = await runWithDeadline(
|
|
37288
|
-
executeBatchStatement(statements[i], info,
|
|
37289
|
-
remaining
|
|
38128
|
+
executeBatchStatement(statements[i], info, cursorScope.client, stmtOptions, cacheContext, tempTables, variables),
|
|
38129
|
+
remaining,
|
|
38130
|
+
cursorScope.closeActive
|
|
37290
38131
|
);
|
|
37291
38132
|
if (outcome.result) {
|
|
37292
38133
|
outcome.result = attachSearchAbortWarning(outcome.result, searchAbortCollector);
|
|
@@ -37333,7 +38174,10 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
37333
38174
|
cacheContext,
|
|
37334
38175
|
tempTables
|
|
37335
38176
|
);
|
|
37336
|
-
|
|
38177
|
+
const first = resolvedStmt2.expr.query.columns[0];
|
|
38178
|
+
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");
|
|
38179
|
+
const numberValue = numeric ? Number(value) : Number.NaN;
|
|
38180
|
+
variables.set(stmt.name, numeric && Number.isFinite(numberValue) ? { type: "number", value: numberValue } : { type: "string", value });
|
|
37337
38181
|
} catch (e) {
|
|
37338
38182
|
if (e instanceof ScalarSubqueryError) {
|
|
37339
38183
|
throw new Error(`ArgumentError: ${e.message}`);
|
|
@@ -37441,19 +38285,47 @@ async function runSelectLike(query, client, options, cacheContext, tempTables) {
|
|
|
37441
38285
|
}
|
|
37442
38286
|
return executeQueryWithCte(query, client, options, tempTables, cacheContext, true);
|
|
37443
38287
|
}
|
|
37444
|
-
async function runWithDeadline(work, remainingMs) {
|
|
38288
|
+
async function runWithDeadline(work, remainingMs, onTimeout) {
|
|
37445
38289
|
if (remainingMs === null) return work;
|
|
37446
38290
|
if (remainingMs <= 0) {
|
|
38291
|
+
if (onTimeout) await onTimeout();
|
|
37447
38292
|
void work.catch(() => {
|
|
37448
38293
|
});
|
|
37449
38294
|
throw new BatchTimeoutError();
|
|
37450
38295
|
}
|
|
37451
38296
|
let timer;
|
|
38297
|
+
let timedOut = false;
|
|
38298
|
+
const guardedWork = work.then(
|
|
38299
|
+
(value) => timedOut ? new Promise(() => void 0) : value,
|
|
38300
|
+
(error51) => {
|
|
38301
|
+
if (timedOut) return new Promise(() => void 0);
|
|
38302
|
+
throw error51;
|
|
38303
|
+
}
|
|
38304
|
+
);
|
|
37452
38305
|
try {
|
|
37453
38306
|
return await Promise.race([
|
|
37454
|
-
|
|
38307
|
+
guardedWork,
|
|
37455
38308
|
new Promise((_, reject) => {
|
|
37456
|
-
timer = setTimeout(() =>
|
|
38309
|
+
timer = setTimeout(() => {
|
|
38310
|
+
timedOut = true;
|
|
38311
|
+
void (async () => {
|
|
38312
|
+
if (onTimeout) {
|
|
38313
|
+
let cleanupTimer;
|
|
38314
|
+
try {
|
|
38315
|
+
await Promise.race([
|
|
38316
|
+
onTimeout(),
|
|
38317
|
+
new Promise((resolve2) => {
|
|
38318
|
+
cleanupTimer = setTimeout(resolve2, 5e3);
|
|
38319
|
+
cleanupTimer.unref?.();
|
|
38320
|
+
})
|
|
38321
|
+
]);
|
|
38322
|
+
} finally {
|
|
38323
|
+
if (cleanupTimer) clearTimeout(cleanupTimer);
|
|
38324
|
+
}
|
|
38325
|
+
}
|
|
38326
|
+
reject(new BatchTimeoutError());
|
|
38327
|
+
})();
|
|
38328
|
+
}, remainingMs);
|
|
37457
38329
|
})
|
|
37458
38330
|
]);
|
|
37459
38331
|
} catch (e) {
|
|
@@ -37564,13 +38436,14 @@ var ScalarSubqueryError = class extends Error {
|
|
|
37564
38436
|
};
|
|
37565
38437
|
async function executeAssert(stmt, client, options, cacheContext, tempTables) {
|
|
37566
38438
|
const left = await evalAssertOperand(stmt.left, client, options, cacheContext, tempTables);
|
|
38439
|
+
const semantics = stmt.left.type === "NUMBER" || stmt.left.type === "ARITH" ? syntheticSemantics("number") : syntheticSemantics("string");
|
|
37567
38440
|
if (stmt.op === "BETWEEN") {
|
|
37568
38441
|
if (stmt.low === null || stmt.high === null) {
|
|
37569
38442
|
throw new Error("ArgumentError: malformed ASSERT statement.");
|
|
37570
38443
|
}
|
|
37571
38444
|
const low = await evalAssertOperand(stmt.low, client, options, cacheContext, tempTables);
|
|
37572
38445
|
const high = await evalAssertOperand(stmt.high, client, options, cacheContext, tempTables);
|
|
37573
|
-
if (!compareScalarValues(">=", left, low) || !compareScalarValues("<=", left, high)) {
|
|
38446
|
+
if (!compareScalarValues(">=", left, low, semantics) || !compareScalarValues("<=", left, high, semantics)) {
|
|
37574
38447
|
throw new AssertError(`assertion failed: ${stmt.text} (actual: ${left}).`);
|
|
37575
38448
|
}
|
|
37576
38449
|
return { type: "ASSERT", condition: stmt.text };
|
|
@@ -37579,7 +38452,7 @@ async function executeAssert(stmt, client, options, cacheContext, tempTables) {
|
|
|
37579
38452
|
throw new Error("ArgumentError: malformed ASSERT statement.");
|
|
37580
38453
|
}
|
|
37581
38454
|
const right = await evalAssertOperand(stmt.right, client, options, cacheContext, tempTables);
|
|
37582
|
-
if (!compareScalarValues(stmt.op, left, right)) {
|
|
38455
|
+
if (!compareScalarValues(stmt.op, left, right, semantics)) {
|
|
37583
38456
|
throw new AssertError(`assertion failed: ${stmt.text} (actual: ${left}).`);
|
|
37584
38457
|
}
|
|
37585
38458
|
return { type: "ASSERT", condition: stmt.text };
|
|
@@ -37652,6 +38525,149 @@ function evalAssertArith(node) {
|
|
|
37652
38525
|
}
|
|
37653
38526
|
throw new Error(`ArgumentError: unsupported operand in ASSERT expression: ${node.type}`);
|
|
37654
38527
|
}
|
|
38528
|
+
async function buildWhereFieldSemanticsResolver(stmt, client, cacheContext, materializedTables, forcePhysicalMetadata = false) {
|
|
38529
|
+
const tables = [stmt.from, ...stmt.joins.map((join) => join.table)];
|
|
38530
|
+
const physicalAppIds = forcePhysicalMetadata || whereNeedsFieldMetadata(stmt.where) ? [...new Set(tables.filter((table) => table.cteName === null).map((table) => table.appId))] : [];
|
|
38531
|
+
const infosByApp = new Map(
|
|
38532
|
+
await Promise.all(physicalAppIds.map(async (appId) => {
|
|
38533
|
+
const infos = await getFieldsCached(appId, client, cacheContext);
|
|
38534
|
+
return [appId, new Map(infos.map((info) => [info.code, info]))];
|
|
38535
|
+
}))
|
|
38536
|
+
);
|
|
38537
|
+
const orderedFields = /* @__PURE__ */ new Set();
|
|
38538
|
+
const collectOrderedFields = (node) => {
|
|
38539
|
+
if (Array.isArray(node)) {
|
|
38540
|
+
node.forEach(collectOrderedFields);
|
|
38541
|
+
return;
|
|
38542
|
+
}
|
|
38543
|
+
if (node === null || typeof node !== "object") return;
|
|
38544
|
+
const value = node;
|
|
38545
|
+
if (value["type"] === "SELECT") return;
|
|
38546
|
+
if (value["type"] === "BINARY" && [">", "<", ">=", "<="].includes(String(value["op"]))) {
|
|
38547
|
+
const left = value["left"];
|
|
38548
|
+
if (left?.["type"] === "FIELD" && typeof left["field"] === "string") {
|
|
38549
|
+
orderedFields.add(left["field"]);
|
|
38550
|
+
}
|
|
38551
|
+
}
|
|
38552
|
+
Object.values(value).forEach(collectOrderedFields);
|
|
38553
|
+
};
|
|
38554
|
+
collectOrderedFields(stmt.where);
|
|
38555
|
+
collectOrderedFields(stmt.having);
|
|
38556
|
+
for (const column of stmt.columns) {
|
|
38557
|
+
if (column.type === "CASE_COL") collectOrderedFields(column.expr);
|
|
38558
|
+
}
|
|
38559
|
+
const statusOrdersByApp = /* @__PURE__ */ new Map();
|
|
38560
|
+
await Promise.all([...infosByApp].map(async ([appId, infos]) => {
|
|
38561
|
+
const needsStatus = [...orderedFields].some((field) => infos.get(field)?.fieldType === "STATUS");
|
|
38562
|
+
if (!needsStatus) return;
|
|
38563
|
+
const order = await loadProcessStatusOrder(appId, client, cacheContext);
|
|
38564
|
+
if (order) statusOrdersByApp.set(appId, order);
|
|
38565
|
+
}));
|
|
38566
|
+
const fromPhysical = (table, field) => {
|
|
38567
|
+
if (field === "$id") return withFieldSemanticSource(
|
|
38568
|
+
resolveFieldSemantics({ fieldType: "__ID__" }),
|
|
38569
|
+
table.appId,
|
|
38570
|
+
"$id"
|
|
38571
|
+
);
|
|
38572
|
+
const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field));
|
|
38573
|
+
if (!info) return void 0;
|
|
38574
|
+
const base = info.semantics ?? resolveFieldSemantics(info);
|
|
38575
|
+
const semantics = info.fieldType === "STATUS" && statusOrdersByApp.has(table.appId) ? { ...base, optionOrder: statusOrdersByApp.get(table.appId) } : base;
|
|
38576
|
+
return withFieldSemanticSource(
|
|
38577
|
+
semantics,
|
|
38578
|
+
table.appId,
|
|
38579
|
+
info.code
|
|
38580
|
+
);
|
|
38581
|
+
};
|
|
38582
|
+
return (field) => {
|
|
38583
|
+
if (field.tableAlias !== null) {
|
|
38584
|
+
if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
38585
|
+
return fromPhysical(stmt.from, field.field);
|
|
38586
|
+
}
|
|
38587
|
+
const table = tables.find((candidate) => candidate.alias === field.tableAlias);
|
|
38588
|
+
if (!table) return void 0;
|
|
38589
|
+
if (table.cteName !== null) {
|
|
38590
|
+
return materializedTables?.get(table.cteName)?.columnMeta?.get(field.field)?.semantics ?? syntheticSemantics("string");
|
|
38591
|
+
}
|
|
38592
|
+
return fromPhysical(table, field.field);
|
|
38593
|
+
}
|
|
38594
|
+
if (stmt.joins.length === 0) {
|
|
38595
|
+
if (stmt.from.cteName !== null) {
|
|
38596
|
+
return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(field.field)?.semantics ?? syntheticSemantics("string");
|
|
38597
|
+
}
|
|
38598
|
+
return fromPhysical(stmt.from, field.field);
|
|
38599
|
+
}
|
|
38600
|
+
const matches = tables.flatMap((table) => {
|
|
38601
|
+
const semantics = table.cteName !== null ? materializedTables?.get(table.cteName)?.columnMeta?.get(field.field)?.semantics : fromPhysical(table, field.field);
|
|
38602
|
+
return semantics ? [semantics] : [];
|
|
38603
|
+
});
|
|
38604
|
+
if (matches.length === 1) return matches[0];
|
|
38605
|
+
return matches.length > 1 ? syntheticSemantics("string") : void 0;
|
|
38606
|
+
};
|
|
38607
|
+
}
|
|
38608
|
+
function selectCaseConditionsNeedFieldMetadata(stmt) {
|
|
38609
|
+
return stmt.columns.some((column) => column.type === "CASE_COL" && column.expr.branches.some((branch) => whereNeedsFieldMetadata(branch.condition)));
|
|
38610
|
+
}
|
|
38611
|
+
function buildHavingFieldSemanticsResolver(stmt, rowResolver) {
|
|
38612
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
38613
|
+
for (const column of stmt.columns) {
|
|
38614
|
+
if (!("alias" in column) || !column.alias) continue;
|
|
38615
|
+
let semantics;
|
|
38616
|
+
if (column.type === "FIELD") semantics = rowResolver(aggregateFieldRef(column.field));
|
|
38617
|
+
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
|
|
38618
|
+
semantics = syntheticSemantics("number");
|
|
38619
|
+
} else if (column.type === "AGGREGATE") {
|
|
38620
|
+
if (column.func === "MIN" || column.func === "MAX") {
|
|
38621
|
+
semantics = column.arg.type === "FIELD_REF" ? rowResolver(aggregateFieldRef(column.arg.field)) : syntheticSemantics("number");
|
|
38622
|
+
} else {
|
|
38623
|
+
semantics = column.func === "GROUP_CONCAT" ? syntheticSemantics("string") : syntheticSemantics("number");
|
|
38624
|
+
}
|
|
38625
|
+
} else if (column.type === "STRFUNC_COL") {
|
|
38626
|
+
semantics = stringFunctionColumnMeta(column.expr).semantics;
|
|
38627
|
+
} else if (column.type === "LITERAL_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "CASE_COL") {
|
|
38628
|
+
semantics = syntheticSemantics("string");
|
|
38629
|
+
}
|
|
38630
|
+
if (semantics) aliases.set(column.alias, semantics);
|
|
38631
|
+
}
|
|
38632
|
+
return (field) => field.tableAlias === null && aliases.has(field.field) ? aliases.get(field.field) : rowResolver(field);
|
|
38633
|
+
}
|
|
38634
|
+
async function resolveSelectWhereCapability(stmt, client, cacheContext, materializedTables) {
|
|
38635
|
+
if (stmt.where === null) return classifyWhereCapability(null, () => void 0);
|
|
38636
|
+
const resolver = await buildWhereFieldSemanticsResolver(stmt, client, cacheContext, materializedTables);
|
|
38637
|
+
return classifyWhereCapability(stmt.where, resolver);
|
|
38638
|
+
}
|
|
38639
|
+
function formatWhereCapabilityFailure(result) {
|
|
38640
|
+
const reason = result.reasons.find(
|
|
38641
|
+
(candidate) => candidate.code === "WHERE_FIELD_UNRESOLVED" || candidate.code === "WHERE_OPERATOR_UNSUPPORTED"
|
|
38642
|
+
) ?? result.reasons[0];
|
|
38643
|
+
const details = [
|
|
38644
|
+
reason?.field ? `field=${reason.field}` : null,
|
|
38645
|
+
reason?.fieldType ? `type=${reason.fieldType}` : null,
|
|
38646
|
+
reason?.operator ? `operator=${reason.operator}` : null,
|
|
38647
|
+
reason?.code ? `reason=${reason.code}` : null
|
|
38648
|
+
].filter((value) => value !== null).join(", ");
|
|
38649
|
+
return details || "reason=WHERE_UNSUPPORTED";
|
|
38650
|
+
}
|
|
38651
|
+
function hasCanonicalOrder(stmt) {
|
|
38652
|
+
return stmt.orderBy.length > 0 || stmt.columns.some(
|
|
38653
|
+
(column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
|
|
38654
|
+
);
|
|
38655
|
+
}
|
|
38656
|
+
async function assertDmlWhereCapability(stmt, client, cacheContext) {
|
|
38657
|
+
if (stmt.subtableCode || stmt.type === "UPDATE" && stmt.from != null) return;
|
|
38658
|
+
const fields = whereNeedsFieldMetadata(stmt.where) ? await getFieldsCached(stmt.appId, client, cacheContext) : [];
|
|
38659
|
+
const byCode = new Map(fields.map((field) => [field.code, field]));
|
|
38660
|
+
const result = classifyWhereCapability(stmt.where, (field) => {
|
|
38661
|
+
if (field.field === "$id") return resolveFieldSemantics({ fieldType: "__ID__" });
|
|
38662
|
+
const info = byCode.get(field.field);
|
|
38663
|
+
return info?.semantics ?? (info ? resolveFieldSemantics(info) : void 0);
|
|
38664
|
+
});
|
|
38665
|
+
if (result.capability !== "EXACT_PUSHDOWN") {
|
|
38666
|
+
throw new DmlConvertError(
|
|
38667
|
+
`WHERE predicate cannot be represented by kintone REST (${formatWhereCapabilityFailure(result)})`
|
|
38668
|
+
);
|
|
38669
|
+
}
|
|
38670
|
+
}
|
|
37655
38671
|
async function executeSelect(stmt, client, options, cacheContext, cteCache, captureColumnMeta = false) {
|
|
37656
38672
|
let result;
|
|
37657
38673
|
if (isNoFromSelect(stmt)) {
|
|
@@ -37662,12 +38678,51 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
|
|
|
37662
38678
|
return result;
|
|
37663
38679
|
}
|
|
37664
38680
|
await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
|
|
37665
|
-
const
|
|
37666
|
-
|
|
37667
|
-
|
|
37668
|
-
|
|
37669
|
-
|
|
37670
|
-
|
|
38681
|
+
const whereCapability = await resolveSelectWhereCapability(stmt, client, cacheContext, cteCache);
|
|
38682
|
+
if (whereCapability.capability === "UNSUPPORTED") {
|
|
38683
|
+
throw new Error(`ArgumentError: WHERE predicate is unsupported (${formatWhereCapabilityFailure(whereCapability)}).`);
|
|
38684
|
+
}
|
|
38685
|
+
const staticMode = resolveSelectMode(stmt);
|
|
38686
|
+
const mode = whereCapability.capability === "EXACT_PUSHDOWN" ? staticMode : "FULL_SCAN";
|
|
38687
|
+
const orderMeta = await buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
|
|
38688
|
+
const orderPlan = hasCanonicalOrder(stmt) ? (stmt.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
38689
|
+
stmt,
|
|
38690
|
+
staticMode: mode,
|
|
38691
|
+
whereCapability: whereCapability.capability,
|
|
38692
|
+
orderSemantics: orderMeta.semantics,
|
|
38693
|
+
maxRecords: options.maxRecords ?? 1e4,
|
|
38694
|
+
hasKlike: whereHasKlike(stmt.where)
|
|
38695
|
+
}) : null;
|
|
38696
|
+
await validateSelectFieldCodes(
|
|
38697
|
+
stmt,
|
|
38698
|
+
orderPlan?.kind === "CANONICAL_LOCAL" ? "FULL_SCAN" : mode,
|
|
38699
|
+
client,
|
|
38700
|
+
cacheContext
|
|
38701
|
+
);
|
|
38702
|
+
const completeInputRequired = orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" || orderPlan?.kind === "KORDER_CURSOR" ? requiresCompleteInput({ ...stmt, orderBy: [] }) : requiresCompleteInput(stmt);
|
|
38703
|
+
const truncateWasDisabled = completeInputRequired && options.onLimitReached === "truncate";
|
|
38704
|
+
const effectiveOptions = truncateWasDisabled ? { ...options, onLimitReached: "error" } : options;
|
|
38705
|
+
try {
|
|
38706
|
+
if (mode === "SIMPLE") {
|
|
38707
|
+
result = await executeSimpleSelect(stmt, client, effectiveOptions, cacheContext, orderPlan, orderMeta);
|
|
38708
|
+
} else {
|
|
38709
|
+
result = await executeFullScanSelect(
|
|
38710
|
+
stmt,
|
|
38711
|
+
client,
|
|
38712
|
+
effectiveOptions,
|
|
38713
|
+
cacheContext,
|
|
38714
|
+
cteCache,
|
|
38715
|
+
whereCapability.capability === "EXACT_PUSHDOWN",
|
|
38716
|
+
orderMeta
|
|
38717
|
+
);
|
|
38718
|
+
}
|
|
38719
|
+
} catch (error51) {
|
|
38720
|
+
if (completeInputRequired && error51 instanceof FetchAllLimitError) {
|
|
38721
|
+
throw new FetchAllLimitError(
|
|
38722
|
+
"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
|
|
38723
|
+
);
|
|
38724
|
+
}
|
|
38725
|
+
throw error51;
|
|
37671
38726
|
}
|
|
37672
38727
|
if (captureColumnMeta) {
|
|
37673
38728
|
materializedMetaBySelectResult.set(result, await inferSelectColumnMeta(stmt, result.columns, client, cacheContext, cteCache));
|
|
@@ -37728,19 +38783,41 @@ function executeNoFromSelect(stmt) {
|
|
|
37728
38783
|
const rows = applyLimit(projected, stmt.limit, stmt.offset);
|
|
37729
38784
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [] };
|
|
37730
38785
|
}
|
|
37731
|
-
async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
37732
|
-
const
|
|
38786
|
+
async function executeSimpleSelect(stmt, client, options, cacheContext, orderPlan, orderMeta) {
|
|
38787
|
+
const restStmt = orderPlan?.kind === "CANONICAL_REST_TOP_N" ? withCanonicalRestTie(stmt) : stmt;
|
|
38788
|
+
const params = selectToKintoneParams(restStmt);
|
|
38789
|
+
const fetchFields = orderPlan?.kind === "CANONICAL_LOCAL" ? selectToFetchAllFields(stmt, stmt.from) : params.fields;
|
|
37733
38790
|
const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
|
|
37734
38791
|
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
38792
|
+
const projectionSemanticsResolver = stmt.columns.some((column) => column.type === "CASE_COL") ? await buildWhereFieldSemanticsResolver(
|
|
38793
|
+
stmt,
|
|
38794
|
+
client,
|
|
38795
|
+
cacheContext,
|
|
38796
|
+
void 0,
|
|
38797
|
+
selectCaseConditionsNeedFieldMetadata(stmt)
|
|
38798
|
+
) : void 0;
|
|
37735
38799
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
37736
38800
|
const warnings = /* @__PURE__ */ new Set();
|
|
37737
38801
|
const onLimit2 = options.onLimitReached ?? "error";
|
|
37738
38802
|
const parallel = options.fetchParallel ?? 1;
|
|
37739
|
-
const
|
|
38803
|
+
const useRestWindow = stmt.orderBy.length > 0 ? orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" || orderPlan?.kind === "KORDER_CURSOR" : stmt.limit !== null && stmt.limit <= 500;
|
|
37740
38804
|
const needed = stmt.limit === null ? null : (stmt.offset ?? 0) + stmt.limit;
|
|
37741
38805
|
const stopAfter = stmt.orderBy.length === 0 && needed !== null && needed <= maxRecords2 && !whereHasKlike(stmt.where) ? needed : void 0;
|
|
37742
38806
|
let records;
|
|
37743
|
-
if (
|
|
38807
|
+
if ((orderPlan?.kind === "KORDER_NATIVE" || orderPlan?.kind === "KORDER_CURSOR") && stmt.limit === 0) {
|
|
38808
|
+
records = [];
|
|
38809
|
+
} else if (orderPlan?.kind === "KORDER_CURSOR") {
|
|
38810
|
+
const cursorResult = await executeKorderCursor({
|
|
38811
|
+
client,
|
|
38812
|
+
app: params.app,
|
|
38813
|
+
fields: params.fields,
|
|
38814
|
+
query: buildKorderCursorQuery(stmt),
|
|
38815
|
+
offset: stmt.offset ?? 0,
|
|
38816
|
+
limit: stmt.limit
|
|
38817
|
+
});
|
|
38818
|
+
records = cursorResult.records;
|
|
38819
|
+
if (cursorResult.cleanupWarning) warnings.add(cursorResult.cleanupWarning);
|
|
38820
|
+
} else if (useRestWindow) {
|
|
37744
38821
|
const res = await client.getRecords({
|
|
37745
38822
|
app: params.app,
|
|
37746
38823
|
query: params.query,
|
|
@@ -37753,7 +38830,7 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
|
37753
38830
|
client.getRecords,
|
|
37754
38831
|
params.app,
|
|
37755
38832
|
baseQuery,
|
|
37756
|
-
|
|
38833
|
+
fetchFields,
|
|
37757
38834
|
{
|
|
37758
38835
|
parallel,
|
|
37759
38836
|
maxRecords: maxRecords2,
|
|
@@ -37766,16 +38843,23 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
|
37766
38843
|
);
|
|
37767
38844
|
}
|
|
37768
38845
|
let rows = records.map((r) => flatten(r, null));
|
|
37769
|
-
if (!
|
|
37770
|
-
|
|
37771
|
-
|
|
38846
|
+
if (!useRestWindow) {
|
|
38847
|
+
rows = applyOrderBy(
|
|
38848
|
+
rows,
|
|
38849
|
+
stmt.orderBy,
|
|
38850
|
+
orderMeta.optionOrders,
|
|
38851
|
+
orderMeta.sortKinds,
|
|
38852
|
+
orderMeta.semantics
|
|
38853
|
+
);
|
|
37772
38854
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
37773
38855
|
}
|
|
37774
38856
|
const { rows: projected, columns } = project(
|
|
37775
38857
|
rows,
|
|
37776
38858
|
stmt.columns,
|
|
37777
38859
|
void 0,
|
|
37778
|
-
fieldTypeResolvers.row
|
|
38860
|
+
fieldTypeResolvers.row,
|
|
38861
|
+
void 0,
|
|
38862
|
+
projectionSemanticsResolver
|
|
37779
38863
|
);
|
|
37780
38864
|
return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
|
|
37781
38865
|
}
|
|
@@ -37848,8 +38932,8 @@ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
|
|
|
37848
38932
|
const statusFields = collectCandidateFieldCodes(candidates).filter((fieldCode) => fieldTypes.get(fieldCode) === "STATUS");
|
|
37849
38933
|
if (statusFields.length > 0) {
|
|
37850
38934
|
const process4 = await getProcessStatusesCached(appId, client, cacheContext);
|
|
37851
|
-
if (process4.enable && process4.states.length > 0) {
|
|
37852
|
-
const states = new Set(process4.states);
|
|
38935
|
+
if (process4.enable && process4.states && process4.states.length > 0) {
|
|
38936
|
+
const states = new Set(process4.states.map((state) => state.name));
|
|
37853
38937
|
for (const fieldCode of statusFields) fieldOptions.set(fieldCode, states);
|
|
37854
38938
|
}
|
|
37855
38939
|
}
|
|
@@ -38027,7 +39111,18 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
|
|
|
38027
39111
|
return [appId, new Map(infos.map((info) => [info.code, info]))];
|
|
38028
39112
|
}))
|
|
38029
39113
|
);
|
|
39114
|
+
const statusOrdersByApp = /* @__PURE__ */ new Map();
|
|
39115
|
+
const aggregateFieldNames = new Set(refs.map((ref) => ref.field));
|
|
39116
|
+
await Promise.all([...fieldInfosByApp].map(async ([appId, infos]) => {
|
|
39117
|
+
if (![...aggregateFieldNames].some((field) => infos.get(field)?.fieldType === "STATUS")) return;
|
|
39118
|
+
const order = await loadProcessStatusOrder(appId, client, cacheContext);
|
|
39119
|
+
if (order) statusOrdersByApp.set(appId, order);
|
|
39120
|
+
}));
|
|
38030
39121
|
const tables = [stmt.from, ...stmt.joins.map((join) => join.table)];
|
|
39122
|
+
const semanticsForInfo = (info, appId) => {
|
|
39123
|
+
const base = info.semantics ?? resolveFieldSemantics(info);
|
|
39124
|
+
return info.fieldType === "STATUS" && statusOrdersByApp.has(appId) ? { ...base, optionOrder: statusOrdersByApp.get(appId) } : base;
|
|
39125
|
+
};
|
|
38031
39126
|
return (ref) => {
|
|
38032
39127
|
let info;
|
|
38033
39128
|
if (ref.tableAlias !== null) {
|
|
@@ -38037,40 +39132,130 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
|
|
|
38037
39132
|
const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
|
|
38038
39133
|
if (!table) return void 0;
|
|
38039
39134
|
if (table.cteName !== null) {
|
|
38040
|
-
return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.
|
|
39135
|
+
return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
|
|
38041
39136
|
}
|
|
38042
39137
|
info = fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
38043
39138
|
}
|
|
38044
39139
|
} else if (stmt.joins.length === 0) {
|
|
38045
39140
|
if (stmt.from.cteName !== null) {
|
|
38046
|
-
return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field)?.
|
|
39141
|
+
return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
|
|
38047
39142
|
}
|
|
38048
39143
|
info = fieldInfosByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
|
|
38049
39144
|
} else {
|
|
38050
39145
|
const matches = tables.flatMap((table) => {
|
|
38051
39146
|
if (table.cteName !== null) {
|
|
38052
39147
|
const materialized = materializedTables?.get(table.cteName);
|
|
38053
|
-
return materialized?.columns.includes(ref.field) ? [materialized.columnMeta?.get(ref.field)?.
|
|
39148
|
+
return materialized?.columns.includes(ref.field) ? [materialized.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string")] : [];
|
|
38054
39149
|
}
|
|
38055
39150
|
const candidate = fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
38056
|
-
return candidate ? [
|
|
39151
|
+
return candidate ? [semanticsForInfo(candidate, table.appId)] : [];
|
|
38057
39152
|
});
|
|
38058
39153
|
if (matches.length !== 1) return void 0;
|
|
38059
39154
|
return matches[0];
|
|
38060
39155
|
}
|
|
38061
|
-
|
|
39156
|
+
if (!info) return void 0;
|
|
39157
|
+
const sourceTable = ref.tableAlias !== null ? tables.find((table) => table.alias === ref.tableAlias) : stmt.joins.length === 0 ? stmt.from : void 0;
|
|
39158
|
+
return semanticsForInfo(info, sourceTable?.appId ?? stmt.from.appId);
|
|
38062
39159
|
};
|
|
38063
39160
|
}
|
|
38064
39161
|
function fieldCodeForTypeLookup(table, field) {
|
|
38065
39162
|
if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
|
|
38066
39163
|
return field;
|
|
38067
39164
|
}
|
|
38068
|
-
function materializedMetaFromFieldInfo(info) {
|
|
38069
|
-
|
|
39165
|
+
function materializedMetaFromFieldInfo(info, sourceAppId) {
|
|
39166
|
+
const semantics = info.semantics ?? resolveFieldSemantics(info);
|
|
39167
|
+
return {
|
|
39168
|
+
sortKind: aggregateSortKind(info),
|
|
39169
|
+
fieldType: info.fieldType,
|
|
39170
|
+
semantics: sourceAppId === void 0 ? semantics : withFieldSemanticSource(semantics, sourceAppId, info.code)
|
|
39171
|
+
};
|
|
39172
|
+
}
|
|
39173
|
+
function withCanonicalRestTie(stmt) {
|
|
39174
|
+
const hasId = stmt.orderBy.some(
|
|
39175
|
+
(item) => item.key.type === "FIELD_NAME" && item.key.name === "$id"
|
|
39176
|
+
);
|
|
39177
|
+
return hasId ? stmt : {
|
|
39178
|
+
...stmt,
|
|
39179
|
+
orderBy: [...stmt.orderBy, { key: { type: "FIELD_NAME", name: "$id" }, direction: "ASC" }]
|
|
39180
|
+
};
|
|
39181
|
+
}
|
|
39182
|
+
function syntheticColumnMeta(compareMode) {
|
|
39183
|
+
return { sortKind: compareMode, semantics: syntheticSemantics(compareMode) };
|
|
39184
|
+
}
|
|
39185
|
+
function unknownStringColumnMeta() {
|
|
39186
|
+
return { semantics: syntheticSemantics("string", "KSQL_UNKNOWN") };
|
|
39187
|
+
}
|
|
39188
|
+
function unsupportedColumnMeta(fieldType = "KSQL_ARRAY") {
|
|
39189
|
+
return {
|
|
39190
|
+
semantics: { fieldType, compareMode: "unsupported", inSubtable: false, requiresCollectionOperators: false }
|
|
39191
|
+
};
|
|
39192
|
+
}
|
|
39193
|
+
function systemColumnMeta(field) {
|
|
39194
|
+
if (field === "$id" || field === "_rid" || field === "_pid") {
|
|
39195
|
+
return {
|
|
39196
|
+
sortKind: "number",
|
|
39197
|
+
fieldType: "__ID__",
|
|
39198
|
+
semantics: resolveFieldSemantics({ fieldType: "__ID__" })
|
|
39199
|
+
};
|
|
39200
|
+
}
|
|
39201
|
+
if (field === "$revision") return syntheticColumnMeta("number");
|
|
39202
|
+
return void 0;
|
|
39203
|
+
}
|
|
39204
|
+
var NUMBER_RETURNING_STRING_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
39205
|
+
"LENGTH",
|
|
39206
|
+
"INSTR",
|
|
39207
|
+
"ROUND",
|
|
39208
|
+
"FLOOR",
|
|
39209
|
+
"CEIL",
|
|
39210
|
+
"TRUNCATE",
|
|
39211
|
+
"YEAR",
|
|
39212
|
+
"MONTH",
|
|
39213
|
+
"DAY",
|
|
39214
|
+
"DATEDIFF",
|
|
39215
|
+
"ABS",
|
|
39216
|
+
"MOD",
|
|
39217
|
+
"POWER",
|
|
39218
|
+
"SQRT"
|
|
39219
|
+
]);
|
|
39220
|
+
function stringFunctionColumnMeta(expr) {
|
|
39221
|
+
if (expr.func === "CAST") {
|
|
39222
|
+
const target = expr.args[1];
|
|
39223
|
+
return target?.type === "STRING" && target.value === "NUMBER" ? syntheticColumnMeta("number") : syntheticColumnMeta("string");
|
|
39224
|
+
}
|
|
39225
|
+
return NUMBER_RETURNING_STRING_FUNCTIONS.has(expr.func) ? syntheticColumnMeta("number") : syntheticColumnMeta("string");
|
|
39226
|
+
}
|
|
39227
|
+
function caseResultColumnMeta(result, resolveField2) {
|
|
39228
|
+
if (result.type === "STRING") return syntheticColumnMeta("string");
|
|
39229
|
+
if (result.type === "ARRAY") return unsupportedColumnMeta();
|
|
39230
|
+
if (result.type === "NUMBER" || result.type === "ARITH") return syntheticColumnMeta("number");
|
|
39231
|
+
if (result.type === "STRING_FUNC") return stringFunctionColumnMeta(result);
|
|
39232
|
+
const source = resolveField2(aggregateFieldRef(result.field));
|
|
39233
|
+
return source ?? unknownStringColumnMeta();
|
|
39234
|
+
}
|
|
39235
|
+
function mergeExpressionColumnMeta(candidates) {
|
|
39236
|
+
if (candidates.length === 0) return unknownStringColumnMeta();
|
|
39237
|
+
const first = candidates[0];
|
|
39238
|
+
const withoutSource = (semantics) => {
|
|
39239
|
+
if (!semantics) return void 0;
|
|
39240
|
+
const { source: _source, ...rest } = semantics;
|
|
39241
|
+
return rest;
|
|
39242
|
+
};
|
|
39243
|
+
if (candidates.every(
|
|
39244
|
+
(candidate) => candidate.sortKind === first.sortKind && candidate.fieldType === first.fieldType && fieldSemanticsEqual(withoutSource(candidate.semantics), withoutSource(first.semantics))
|
|
39245
|
+
)) {
|
|
39246
|
+
const sameSource = candidates.every(
|
|
39247
|
+
(candidate) => fieldSemanticsEqual(candidate.semantics, first.semantics)
|
|
39248
|
+
);
|
|
39249
|
+
return sameSource ? first : { ...first, semantics: withoutSource(first.semantics) };
|
|
39250
|
+
}
|
|
39251
|
+
if (candidates.some((candidate) => candidate.semantics?.compareMode === "unsupported")) {
|
|
39252
|
+
return unsupportedColumnMeta("KSQL_MIXED_UNSUPPORTED");
|
|
39253
|
+
}
|
|
39254
|
+
return unknownStringColumnMeta();
|
|
38070
39255
|
}
|
|
38071
39256
|
function selectNeedsSourceColumnMeta(stmt) {
|
|
38072
39257
|
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"
|
|
39258
|
+
(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
39259
|
);
|
|
38075
39260
|
}
|
|
38076
39261
|
async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables) {
|
|
@@ -38087,18 +39272,18 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
38087
39272
|
if (ref.tableAlias !== null) {
|
|
38088
39273
|
if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
38089
39274
|
const info2 = physicalInfos.get(stmt.from.appId)?.get(ref.field);
|
|
38090
|
-
return info2 ? materializedMetaFromFieldInfo(info2) : void 0;
|
|
39275
|
+
return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
|
|
38091
39276
|
}
|
|
38092
39277
|
const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
|
|
38093
39278
|
if (!table) return void 0;
|
|
38094
39279
|
if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
|
|
38095
39280
|
const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
38096
|
-
return info ? materializedMetaFromFieldInfo(info) :
|
|
39281
|
+
return info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
|
|
38097
39282
|
}
|
|
38098
39283
|
if (stmt.joins.length === 0) {
|
|
38099
39284
|
if (stmt.from.cteName !== null) return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field);
|
|
38100
39285
|
const info = physicalInfos.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
|
|
38101
|
-
return info ? materializedMetaFromFieldInfo(info) :
|
|
39286
|
+
return info ? materializedMetaFromFieldInfo(info, stmt.from.appId) : systemColumnMeta(ref.field);
|
|
38102
39287
|
}
|
|
38103
39288
|
const matches = tables.flatMap((table) => {
|
|
38104
39289
|
if (table.cteName !== null) {
|
|
@@ -38107,7 +39292,8 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
38107
39292
|
return [materialized.columnMeta?.get(ref.field)];
|
|
38108
39293
|
}
|
|
38109
39294
|
const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
38110
|
-
|
|
39295
|
+
const meta3 = info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
|
|
39296
|
+
return meta3 ? [meta3] : [];
|
|
38111
39297
|
});
|
|
38112
39298
|
return matches.length === 1 ? matches[0] : void 0;
|
|
38113
39299
|
};
|
|
@@ -38137,19 +39323,27 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
38137
39323
|
meta3 = resolveField2(aggregateFieldRef(column.field));
|
|
38138
39324
|
} else if (column.type === "AGGREGATE") {
|
|
38139
39325
|
if (column.func === "GROUP_CONCAT") {
|
|
38140
|
-
meta3 =
|
|
39326
|
+
meta3 = syntheticColumnMeta("string");
|
|
38141
39327
|
} else if (column.func === "COUNT" || column.func === "SUM" || column.func === "AVG") {
|
|
38142
|
-
meta3 =
|
|
39328
|
+
meta3 = syntheticColumnMeta("number");
|
|
38143
39329
|
} else if ((column.func === "MIN" || column.func === "MAX") && column.arg.type === "FIELD_REF") {
|
|
38144
39330
|
const source = resolveField2(aggregateFieldRef(column.arg.field));
|
|
38145
|
-
if (source
|
|
39331
|
+
if (source) meta3 = source;
|
|
38146
39332
|
}
|
|
38147
39333
|
} else if (column.type === "ARITH_AGG_COL" || column.type === "ARITH_COL") {
|
|
38148
|
-
meta3 =
|
|
39334
|
+
meta3 = syntheticColumnMeta("number");
|
|
38149
39335
|
} else if (column.type === "LITERAL_COL") {
|
|
38150
|
-
meta3 =
|
|
39336
|
+
meta3 = syntheticColumnMeta("string");
|
|
39337
|
+
} else if (column.type === "STRFUNC_COL") {
|
|
39338
|
+
meta3 = stringFunctionColumnMeta(column.expr);
|
|
38151
39339
|
} else if (column.type === "WINDOW_COL") {
|
|
38152
|
-
meta3 =
|
|
39340
|
+
meta3 = syntheticColumnMeta("number");
|
|
39341
|
+
} else if (column.type === "CASE_COL") {
|
|
39342
|
+
const results = column.expr.branches.map((branch) => caseResultColumnMeta(branch.result, resolveField2));
|
|
39343
|
+
if (column.expr.elseResult) results.push(caseResultColumnMeta(column.expr.elseResult, resolveField2));
|
|
39344
|
+
meta3 = mergeExpressionColumnMeta(results);
|
|
39345
|
+
} else if (column.type === "SCALAR_SUBQUERY_COL") {
|
|
39346
|
+
meta3 = unknownStringColumnMeta();
|
|
38153
39347
|
}
|
|
38154
39348
|
if (meta3) inferred.set(output, meta3);
|
|
38155
39349
|
});
|
|
@@ -38163,7 +39357,8 @@ function mergeUnionColumnMeta(left, right) {
|
|
|
38163
39357
|
const a = leftMeta?.get(column);
|
|
38164
39358
|
const rightColumn = right.columns[index];
|
|
38165
39359
|
const b = rightColumn === void 0 ? void 0 : rightMeta?.get(rightColumn);
|
|
38166
|
-
if (a && b
|
|
39360
|
+
if (a && b) merged.set(column, mergeExpressionColumnMeta([a, b]));
|
|
39361
|
+
else if (a || b) merged.set(column, unknownStringColumnMeta());
|
|
38167
39362
|
});
|
|
38168
39363
|
return merged;
|
|
38169
39364
|
}
|
|
@@ -38200,7 +39395,7 @@ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
|
|
|
38200
39395
|
};
|
|
38201
39396
|
return { row, having };
|
|
38202
39397
|
}
|
|
38203
|
-
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
|
|
39398
|
+
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache, allowOriginalWherePushdown = true, preloadedOrderMeta) {
|
|
38204
39399
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
38205
39400
|
const warnings = /* @__PURE__ */ new Set();
|
|
38206
39401
|
const parallel = options.fetchParallel ?? 1;
|
|
@@ -38214,6 +39409,14 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
38214
39409
|
loadAggregateSortKindResolver(stmt, client, cacheContext, cteCache)
|
|
38215
39410
|
]);
|
|
38216
39411
|
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
39412
|
+
const fieldSemanticsResolver = await buildWhereFieldSemanticsResolver(
|
|
39413
|
+
stmt,
|
|
39414
|
+
client,
|
|
39415
|
+
cacheContext,
|
|
39416
|
+
cteCache,
|
|
39417
|
+
whereNeedsFieldMetadata(stmt.having) || selectCaseConditionsNeedFieldMetadata(stmt)
|
|
39418
|
+
);
|
|
39419
|
+
const havingFieldSemanticsResolver = buildHavingFieldSemanticsResolver(stmt, fieldSemanticsResolver);
|
|
38217
39420
|
const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
|
|
38218
39421
|
validateKlikePushdownPlan(pushdownPlan);
|
|
38219
39422
|
const mainPushDown = pushdownPlan.mainCondition;
|
|
@@ -38227,7 +39430,8 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
38227
39430
|
true,
|
|
38228
39431
|
options.onLimitReached ?? "error",
|
|
38229
39432
|
warnings,
|
|
38230
|
-
mainPushDown
|
|
39433
|
+
mainPushDown,
|
|
39434
|
+
allowOriginalWherePushdown
|
|
38231
39435
|
);
|
|
38232
39436
|
const parallelJoins = [];
|
|
38233
39437
|
const onOptJoins = [];
|
|
@@ -38253,7 +39457,7 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
38253
39457
|
}
|
|
38254
39458
|
}
|
|
38255
39459
|
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
38256
|
-
const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
|
|
39460
|
+
const orderByMetaPromise = preloadedOrderMeta ? Promise.resolve(preloadedOrderMeta) : buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
|
|
38257
39461
|
scalarCachePromise.catch(() => {
|
|
38258
39462
|
});
|
|
38259
39463
|
orderByMetaPromise.catch(() => {
|
|
@@ -38290,15 +39494,18 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
38290
39494
|
tables.set(join.table.alias, joinRecords);
|
|
38291
39495
|
}));
|
|
38292
39496
|
const scalarCache = await scalarCachePromise;
|
|
38293
|
-
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
39497
|
+
const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
|
|
38294
39498
|
const { rows, columns } = runFullScan({
|
|
38295
39499
|
tables,
|
|
38296
39500
|
stmt,
|
|
38297
39501
|
scalarCache,
|
|
38298
39502
|
optionOrders,
|
|
38299
39503
|
sortKinds,
|
|
39504
|
+
orderSemantics: semantics,
|
|
38300
39505
|
fieldTypeResolver: fieldTypeResolvers.row,
|
|
39506
|
+
fieldSemanticsResolver,
|
|
38301
39507
|
havingFieldTypeResolver: fieldTypeResolvers.having,
|
|
39508
|
+
havingFieldSemanticsResolver,
|
|
38302
39509
|
aggregateSortKindResolver,
|
|
38303
39510
|
appliedKlikes: pushdownPlan.appliedKlikes
|
|
38304
39511
|
});
|
|
@@ -38395,16 +39602,39 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
38395
39602
|
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache),
|
|
38396
39603
|
resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache)
|
|
38397
39604
|
]);
|
|
39605
|
+
const whereCapability = await resolveSelectWhereCapability(stmt, client, cacheContext, cteCache);
|
|
39606
|
+
if (whereCapability.capability === "UNSUPPORTED") {
|
|
39607
|
+
throw new Error(`ArgumentError: WHERE predicate is unsupported (${formatWhereCapabilityFailure(whereCapability)}).`);
|
|
39608
|
+
}
|
|
39609
|
+
const orderMeta = await buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
|
|
39610
|
+
if (hasCanonicalOrder(stmt)) {
|
|
39611
|
+
(stmt.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
39612
|
+
stmt,
|
|
39613
|
+
staticMode: "FULL_SCAN",
|
|
39614
|
+
whereCapability: whereCapability.capability,
|
|
39615
|
+
orderSemantics: orderMeta.semantics,
|
|
39616
|
+
maxRecords: maxRecords2,
|
|
39617
|
+
hasKlike: whereHasKlike(stmt.where)
|
|
39618
|
+
});
|
|
39619
|
+
}
|
|
38398
39620
|
const [pushdownMeta, typedInFieldTypes, aggregateSortKindResolver] = await Promise.all([
|
|
38399
39621
|
loadTypedPushdownMeta(stmt, client, cacheContext),
|
|
38400
39622
|
loadTypedInFieldTypes(stmt, client, cacheContext),
|
|
38401
39623
|
loadAggregateSortKindResolver(stmt, client, cacheContext, cteCache)
|
|
38402
39624
|
]);
|
|
38403
39625
|
const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
|
|
39626
|
+
const fieldSemanticsResolver = await buildWhereFieldSemanticsResolver(
|
|
39627
|
+
stmt,
|
|
39628
|
+
client,
|
|
39629
|
+
cacheContext,
|
|
39630
|
+
cteCache,
|
|
39631
|
+
whereNeedsFieldMetadata(stmt.having) || selectCaseConditionsNeedFieldMetadata(stmt)
|
|
39632
|
+
);
|
|
39633
|
+
const havingFieldSemanticsResolver = buildHavingFieldSemanticsResolver(stmt, fieldSemanticsResolver);
|
|
38404
39634
|
const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
|
|
38405
39635
|
validateKlikePushdownPlan(pushdownPlan);
|
|
38406
39636
|
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
38407
|
-
const orderByMetaPromise =
|
|
39637
|
+
const orderByMetaPromise = Promise.resolve(orderMeta);
|
|
38408
39638
|
scalarCachePromise.catch(() => {
|
|
38409
39639
|
});
|
|
38410
39640
|
orderByMetaPromise.catch(() => {
|
|
@@ -38423,7 +39653,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
38423
39653
|
true,
|
|
38424
39654
|
options.onLimitReached ?? "error",
|
|
38425
39655
|
warnings,
|
|
38426
|
-
pushdownPlan.mainCondition
|
|
39656
|
+
pushdownPlan.mainCondition,
|
|
39657
|
+
whereCapability.capability === "EXACT_PUSHDOWN"
|
|
38427
39658
|
);
|
|
38428
39659
|
tables.set(stmt.from.alias, mainRecords);
|
|
38429
39660
|
}
|
|
@@ -38460,7 +39691,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
38460
39691
|
});
|
|
38461
39692
|
await Promise.all(joinFetches);
|
|
38462
39693
|
const scalarCache = await scalarCachePromise;
|
|
38463
|
-
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
39694
|
+
const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
|
|
38464
39695
|
const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? cteCache.get(stmt.from.cteName)?.columns : void 0;
|
|
38465
39696
|
const { rows, columns } = runFullScan({
|
|
38466
39697
|
tables,
|
|
@@ -38468,8 +39699,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
38468
39699
|
scalarCache,
|
|
38469
39700
|
optionOrders,
|
|
38470
39701
|
sortKinds,
|
|
39702
|
+
orderSemantics: semantics,
|
|
38471
39703
|
fieldTypeResolver: fieldTypeResolvers.row,
|
|
39704
|
+
fieldSemanticsResolver,
|
|
38472
39705
|
havingFieldTypeResolver: fieldTypeResolvers.having,
|
|
39706
|
+
havingFieldSemanticsResolver,
|
|
38473
39707
|
aggregateSortKindResolver,
|
|
38474
39708
|
appliedKlikes: pushdownPlan.appliedKlikes,
|
|
38475
39709
|
sourceColumns
|
|
@@ -38481,13 +39715,13 @@ function processRowToKintoneRecord(row) {
|
|
|
38481
39715
|
Object.entries(row).map(([k, v]) => [k, { value: v ?? "" }])
|
|
38482
39716
|
);
|
|
38483
39717
|
}
|
|
38484
|
-
async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords2, parallel, isMainTable, onLimit2, warnings, pushDownCond = null) {
|
|
39718
|
+
async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords2, parallel, isMainTable, onLimit2, warnings, pushDownCond = null, allowOriginalWherePushdown = true) {
|
|
38485
39719
|
const fields = selectToFetchAllFields(stmt, table);
|
|
38486
39720
|
const onTruncate = (max) => {
|
|
38487
39721
|
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
39722
|
};
|
|
38489
39723
|
if (!table.subtableCode) {
|
|
38490
|
-
const baseQuery = isMainTable ? selectToFetchAllParams(stmt, table.appId).query : "";
|
|
39724
|
+
const baseQuery = isMainTable && allowOriginalWherePushdown ? selectToFetchAllParams(stmt, table.appId).query : "";
|
|
38491
39725
|
const pushQuery = pushDownCond !== null ? whereToKintone(pushDownCond) : "";
|
|
38492
39726
|
const query = baseQuery && pushQuery ? `(${baseQuery}) and (${pushQuery})` : baseQuery || pushQuery;
|
|
38493
39727
|
const resolved = await fetchRecordsForSharedPlan(client.getRecords, table.appId, query, fields, {
|
|
@@ -38691,6 +39925,10 @@ async function getProcessStatusesCached(appId, client, cacheContext) {
|
|
|
38691
39925
|
setScopedCacheValue(processStatusCache, cacheContext, appId, loading);
|
|
38692
39926
|
return loading;
|
|
38693
39927
|
}
|
|
39928
|
+
async function loadProcessStatusOrder(appId, client, cacheContext) {
|
|
39929
|
+
const process4 = await getProcessStatusesCached(appId, client, cacheContext);
|
|
39930
|
+
return process4.enable && process4.states !== null ? new Map(process4.states.map((state) => [state.name, state.index])) : void 0;
|
|
39931
|
+
}
|
|
38694
39932
|
async function getFieldTypeMap(appId, client, cacheContext) {
|
|
38695
39933
|
const cached2 = getScopedCacheValue(fieldTypeCache, cacheContext, appId);
|
|
38696
39934
|
if (cached2) return cached2;
|
|
@@ -38734,18 +39972,118 @@ async function getSortKindMapByApp(appId, client, cacheContext) {
|
|
|
38734
39972
|
setScopedCacheValue(sortKindCache, cacheContext, appId, map2);
|
|
38735
39973
|
return map2;
|
|
38736
39974
|
}
|
|
38737
|
-
|
|
39975
|
+
function orderByFieldNames(stmt) {
|
|
39976
|
+
const items = [
|
|
39977
|
+
...stmt.orderBy,
|
|
39978
|
+
...stmt.columns.flatMap((column) => column.type === "WINDOW_COL" ? column.orderBy : [])
|
|
39979
|
+
];
|
|
39980
|
+
return [...new Set(items.flatMap(
|
|
39981
|
+
(item) => item.key.type === "FIELD_NAME" ? [item.key.name] : []
|
|
39982
|
+
))];
|
|
39983
|
+
}
|
|
39984
|
+
async function buildOrderSemanticsForSelect(stmt, client, cacheContext, materializedTables) {
|
|
39985
|
+
const names = orderByFieldNames(stmt);
|
|
39986
|
+
if (names.length === 0) return /* @__PURE__ */ new Map();
|
|
39987
|
+
const tables = [stmt.from, ...stmt.joins.map((join) => join.table)];
|
|
39988
|
+
const ambiguousFields = /* @__PURE__ */ new Set();
|
|
39989
|
+
const infosByApp = new Map(
|
|
39990
|
+
await Promise.all([...new Set(
|
|
39991
|
+
tables.filter((table) => table.cteName === null).map((table) => table.appId)
|
|
39992
|
+
)].map(async (appId) => {
|
|
39993
|
+
const infos = await getFieldsCached(appId, client, cacheContext);
|
|
39994
|
+
return [appId, new Map(infos.map((info) => [info.code, info]))];
|
|
39995
|
+
}))
|
|
39996
|
+
);
|
|
39997
|
+
const resolveField2 = (ref) => {
|
|
39998
|
+
if (ref.tableAlias !== null) {
|
|
39999
|
+
if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
40000
|
+
const info2 = infosByApp.get(stmt.from.appId)?.get(ref.field);
|
|
40001
|
+
return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
|
|
40002
|
+
}
|
|
40003
|
+
const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
|
|
40004
|
+
if (!table) return void 0;
|
|
40005
|
+
if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
|
|
40006
|
+
const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
40007
|
+
return info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
|
|
40008
|
+
}
|
|
40009
|
+
if (stmt.joins.length === 0) {
|
|
40010
|
+
if (stmt.from.cteName !== null) return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field);
|
|
40011
|
+
const info = infosByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
|
|
40012
|
+
return info ? materializedMetaFromFieldInfo(info, stmt.from.appId) : systemColumnMeta(ref.field);
|
|
40013
|
+
}
|
|
40014
|
+
const matches = tables.flatMap((table) => {
|
|
40015
|
+
if (table.cteName !== null) {
|
|
40016
|
+
const materialized = materializedTables?.get(table.cteName);
|
|
40017
|
+
const meta4 = materialized?.columns.includes(ref.field) ? materialized.columnMeta?.get(ref.field) : void 0;
|
|
40018
|
+
return meta4 ? [meta4] : [];
|
|
40019
|
+
}
|
|
40020
|
+
const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
40021
|
+
const meta3 = info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
|
|
40022
|
+
return meta3 ? [meta3] : [];
|
|
40023
|
+
});
|
|
40024
|
+
if (matches.length > 1) ambiguousFields.add(ref.field);
|
|
40025
|
+
return matches.length === 1 ? matches[0] : void 0;
|
|
40026
|
+
};
|
|
40027
|
+
const aliasSemantics = /* @__PURE__ */ new Map();
|
|
40028
|
+
for (const column of stmt.columns) {
|
|
40029
|
+
if (!("alias" in column) || !column.alias) continue;
|
|
40030
|
+
let meta3;
|
|
40031
|
+
if (column.type === "FIELD") meta3 = resolveField2(aggregateFieldRef(column.field));
|
|
40032
|
+
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
|
|
40033
|
+
meta3 = syntheticColumnMeta("number");
|
|
40034
|
+
} else if (column.type === "LITERAL_COL") meta3 = syntheticColumnMeta("string");
|
|
40035
|
+
else if (column.type === "STRFUNC_COL") meta3 = stringFunctionColumnMeta(column.expr);
|
|
40036
|
+
else if (column.type === "SCALAR_SUBQUERY_COL") meta3 = unknownStringColumnMeta();
|
|
40037
|
+
else if (column.type === "CASE_COL") {
|
|
40038
|
+
const candidates = column.expr.branches.map((branch) => caseResultColumnMeta(branch.result, resolveField2));
|
|
40039
|
+
if (column.expr.elseResult) candidates.push(caseResultColumnMeta(column.expr.elseResult, resolveField2));
|
|
40040
|
+
meta3 = mergeExpressionColumnMeta(candidates);
|
|
40041
|
+
} else if (column.type === "AGGREGATE") {
|
|
40042
|
+
if (column.func === "MIN" || column.func === "MAX") {
|
|
40043
|
+
meta3 = column.arg.type === "FIELD_REF" ? resolveField2(aggregateFieldRef(column.arg.field)) : syntheticColumnMeta("number");
|
|
40044
|
+
} else {
|
|
40045
|
+
meta3 = column.func === "GROUP_CONCAT" ? syntheticColumnMeta("string") : syntheticColumnMeta("number");
|
|
40046
|
+
}
|
|
40047
|
+
}
|
|
40048
|
+
if (meta3?.semantics) aliasSemantics.set(column.alias, meta3.semantics);
|
|
40049
|
+
}
|
|
40050
|
+
const result = /* @__PURE__ */ new Map();
|
|
40051
|
+
for (const name of names) {
|
|
40052
|
+
const base = aliasSemantics.get(name) ?? resolveField2(aggregateFieldRef(name))?.semantics;
|
|
40053
|
+
if (!base) {
|
|
40054
|
+
const ref = aggregateFieldRef(name);
|
|
40055
|
+
if (ref.tableAlias === null && ambiguousFields.has(ref.field)) {
|
|
40056
|
+
result.set(name, resolveFieldSemantics({ fieldType: "KSQL_AMBIGUOUS" }));
|
|
40057
|
+
}
|
|
40058
|
+
continue;
|
|
40059
|
+
}
|
|
40060
|
+
let semantics = base;
|
|
40061
|
+
if (base.fieldType === "STATUS" && base.source && stmt.orderMode !== "KINTONE_NATIVE") {
|
|
40062
|
+
const process4 = await getProcessStatusesCached(base.source.appId, client, cacheContext);
|
|
40063
|
+
if (process4.enable && process4.states !== null) {
|
|
40064
|
+
semantics = {
|
|
40065
|
+
...base,
|
|
40066
|
+
optionOrder: new Map(process4.states.map((state) => [state.name, state.index]))
|
|
40067
|
+
};
|
|
40068
|
+
}
|
|
40069
|
+
}
|
|
40070
|
+
result.set(name, semantics);
|
|
40071
|
+
}
|
|
40072
|
+
return result;
|
|
40073
|
+
}
|
|
40074
|
+
async function buildOrderByMetaForSelect(stmt, client, cacheContext, materializedTables) {
|
|
38738
40075
|
const hasWindowOrderBy = stmt.columns.some(
|
|
38739
40076
|
(column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
|
|
38740
40077
|
);
|
|
38741
40078
|
if (stmt.orderBy.length === 0 && !hasWindowOrderBy) {
|
|
38742
|
-
return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map() };
|
|
40079
|
+
return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map(), semantics: /* @__PURE__ */ new Map() };
|
|
38743
40080
|
}
|
|
38744
|
-
const [optionOrders, sortKinds] = await Promise.all([
|
|
40081
|
+
const [optionOrders, sortKinds, semantics] = await Promise.all([
|
|
38745
40082
|
buildOptionOrdersForSelect(stmt, client, cacheContext),
|
|
38746
|
-
buildSortKindsForSelect(stmt, client, cacheContext)
|
|
40083
|
+
buildSortKindsForSelect(stmt, client, cacheContext),
|
|
40084
|
+
buildOrderSemanticsForSelect(stmt, client, cacheContext, materializedTables)
|
|
38747
40085
|
]);
|
|
38748
|
-
return { optionOrders, sortKinds };
|
|
40086
|
+
return { optionOrders, sortKinds, semantics };
|
|
38749
40087
|
}
|
|
38750
40088
|
async function buildOptionOrdersForSelect(stmt, client, cacheContext) {
|
|
38751
40089
|
const optionOrders = /* @__PURE__ */ new Map();
|
|
@@ -38843,6 +40181,9 @@ var RejectLimitExceededError = class extends Error {
|
|
|
38843
40181
|
}
|
|
38844
40182
|
};
|
|
38845
40183
|
async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
|
|
40184
|
+
if (stmt.type === "UPDATE") {
|
|
40185
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
40186
|
+
}
|
|
38846
40187
|
const operation = stmt.type === "UPDATE" ? "UPDATE" : stmt.type.startsWith("UPSERT") ? "UPSERT" : "INSERT";
|
|
38847
40188
|
const payloadFields = stmt.type === "UPDATE" ? ["$id", ...stmt.assignments.map((a) => a.field)] : [...stmt.fields];
|
|
38848
40189
|
if (new Set(payloadFields).size !== payloadFields.length) {
|
|
@@ -38882,18 +40223,22 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
|
|
|
38882
40223
|
const columnMeta = /* @__PURE__ */ new Map();
|
|
38883
40224
|
for (const column of payloadFields) {
|
|
38884
40225
|
if (column === "$id") {
|
|
38885
|
-
columnMeta.set(column, {
|
|
40226
|
+
columnMeta.set(column, {
|
|
40227
|
+
sortKind: "number",
|
|
40228
|
+
fieldType: "RECORD_NUMBER",
|
|
40229
|
+
semantics: resolveFieldSemantics({ fieldType: "RECORD_NUMBER" })
|
|
40230
|
+
});
|
|
38886
40231
|
continue;
|
|
38887
40232
|
}
|
|
38888
40233
|
const info = infoByCode.get(column);
|
|
38889
|
-
if (info) columnMeta.set(column, materializedMetaFromFieldInfo(info));
|
|
38890
|
-
}
|
|
38891
|
-
columnMeta.set("$err_statement",
|
|
38892
|
-
columnMeta.set("$err_operation",
|
|
38893
|
-
columnMeta.set("$err_row",
|
|
38894
|
-
columnMeta.set("$err_field",
|
|
38895
|
-
columnMeta.set("$err_code",
|
|
38896
|
-
columnMeta.set("$err_message",
|
|
40234
|
+
if (info) columnMeta.set(column, materializedMetaFromFieldInfo(info, stmt.appId));
|
|
40235
|
+
}
|
|
40236
|
+
columnMeta.set("$err_statement", syntheticColumnMeta("number"));
|
|
40237
|
+
columnMeta.set("$err_operation", syntheticColumnMeta("string"));
|
|
40238
|
+
columnMeta.set("$err_row", syntheticColumnMeta("number"));
|
|
40239
|
+
columnMeta.set("$err_field", syntheticColumnMeta("string"));
|
|
40240
|
+
columnMeta.set("$err_code", syntheticColumnMeta("string"));
|
|
40241
|
+
columnMeta.set("$err_message", syntheticColumnMeta("string"));
|
|
38897
40242
|
materializedMetaByValidationResult.set(result, columnMeta);
|
|
38898
40243
|
return { result, candidates, invalidRowNumbers, columnMeta };
|
|
38899
40244
|
}
|
|
@@ -39279,6 +40624,7 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
|
|
|
39279
40624
|
};
|
|
39280
40625
|
}
|
|
39281
40626
|
async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
|
|
40627
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
39282
40628
|
if (stmt.subtableCode) {
|
|
39283
40629
|
return executeUpdateSubtable(stmt, client, options, cacheContext);
|
|
39284
40630
|
}
|
|
@@ -39356,6 +40702,7 @@ function collectUpdateFromTargetFields(stmt) {
|
|
|
39356
40702
|
return [...fields];
|
|
39357
40703
|
}
|
|
39358
40704
|
async function executeDelete(stmt, client, options, cacheContext) {
|
|
40705
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
39359
40706
|
if (stmt.subtableCode) {
|
|
39360
40707
|
return executeDeleteSubtable(stmt, client, options, cacheContext);
|
|
39361
40708
|
}
|
|
@@ -39728,6 +41075,18 @@ async function executeReorder(stmt, client, options, cacheContext) {
|
|
|
39728
41075
|
client,
|
|
39729
41076
|
cacheContext
|
|
39730
41077
|
);
|
|
41078
|
+
const reorderFields = await getFieldsCached(stmt.appId, client, cacheContext);
|
|
41079
|
+
const reorderSemanticsByCode = new Map(reorderFields.map((field) => [
|
|
41080
|
+
field.code,
|
|
41081
|
+
field.semantics ?? resolveFieldSemantics(field)
|
|
41082
|
+
]));
|
|
41083
|
+
const resolveReorderSemantics = (field) => {
|
|
41084
|
+
if (field.field === "_idx" || field.field === "_pid" || field.field === "_rid") {
|
|
41085
|
+
return syntheticSemantics("number");
|
|
41086
|
+
}
|
|
41087
|
+
const code = field.field.startsWith("_p.") ? field.field.slice(3) : field.field;
|
|
41088
|
+
return reorderSemanticsByCode.get(code) ?? syntheticSemantics("string");
|
|
41089
|
+
};
|
|
39731
41090
|
const parents = await fetchAll(
|
|
39732
41091
|
client.getRecords,
|
|
39733
41092
|
stmt.appId,
|
|
@@ -39736,7 +41095,13 @@ async function executeReorder(stmt, client, options, cacheContext) {
|
|
|
39736
41095
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
39737
41096
|
);
|
|
39738
41097
|
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(
|
|
41098
|
+
const targetParentIds = stmt.all ? new Set(parents.map((p) => String(p["$id"]?.value ?? "")).filter((id) => id !== "")) : new Set(expanded.filter((r) => stmt.where && evalWhere(
|
|
41099
|
+
stmt.where,
|
|
41100
|
+
r.flat,
|
|
41101
|
+
resolveFieldType,
|
|
41102
|
+
void 0,
|
|
41103
|
+
resolveReorderSemantics
|
|
41104
|
+
)).map((r) => r.parentId));
|
|
39740
41105
|
if (options.confirm) {
|
|
39741
41106
|
const ok = await options.confirm(targetParentIds.size, "UPDATE");
|
|
39742
41107
|
if (!ok) throw new OperationCancelledError("UPDATE", targetParentIds.size);
|
|
@@ -39747,7 +41112,7 @@ async function executeReorder(stmt, client, options, cacheContext) {
|
|
|
39747
41112
|
if (!parent) continue;
|
|
39748
41113
|
const rows = getMutableTableRows(parent, stmt.subtableCode);
|
|
39749
41114
|
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));
|
|
41115
|
+
sortable.sort((a, b) => compareByOrder(a.flat, b.flat, stmt.by, resolveReorderSemantics));
|
|
39751
41116
|
const orderedRowIds = sortable.map((x) => x.row.id ?? "");
|
|
39752
41117
|
await client.putRecords(buildSubtableReorderPutParams(stmt.appId, pid, getRevision(parent), stmt.subtableCode, orderedRowIds));
|
|
39753
41118
|
}
|
|
@@ -39768,14 +41133,12 @@ function buildFlatRowForSort(parent, subtableCode, row, idx) {
|
|
|
39768
41133
|
}
|
|
39769
41134
|
return flat;
|
|
39770
41135
|
}
|
|
39771
|
-
function compareByOrder(a, b, orderBy) {
|
|
41136
|
+
function compareByOrder(a, b, orderBy, resolveSemantics) {
|
|
39772
41137
|
for (const item of orderBy) {
|
|
39773
41138
|
const av = evalOrderKeyForRow(item.key, a);
|
|
39774
41139
|
const bv = evalOrderKeyForRow(item.key, b);
|
|
39775
|
-
const
|
|
39776
|
-
const
|
|
39777
|
-
const numeric = !Number.isNaN(an) && !Number.isNaN(bn);
|
|
39778
|
-
const cmp = numeric ? an - bn : av.localeCompare(bv, "ja");
|
|
41140
|
+
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");
|
|
41141
|
+
const cmp = compareCanonicalValues(av, bv, semantics ?? syntheticSemantics("string"));
|
|
39779
41142
|
if (cmp !== 0) return item.direction === "ASC" ? cmp : -cmp;
|
|
39780
41143
|
}
|
|
39781
41144
|
return 0;
|
|
@@ -39972,35 +41335,140 @@ async function resolveScalarColumns(columns, client, options, cacheContext, cteC
|
|
|
39972
41335
|
pending.forEach(([i], idx) => cache.set(i, values[idx]));
|
|
39973
41336
|
return cache;
|
|
39974
41337
|
}
|
|
39975
|
-
function
|
|
41338
|
+
async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords2 = 1e4) {
|
|
41339
|
+
const fieldApps = /* @__PURE__ */ new Set();
|
|
41340
|
+
const processStatusApps = /* @__PURE__ */ new Set();
|
|
41341
|
+
const tracedClient = {
|
|
41342
|
+
...client,
|
|
41343
|
+
getFields: async (appId) => {
|
|
41344
|
+
fieldApps.add(appId);
|
|
41345
|
+
return client.getFields(appId);
|
|
41346
|
+
},
|
|
41347
|
+
getProcessStatuses: async (appId) => {
|
|
41348
|
+
processStatusApps.add(appId);
|
|
41349
|
+
return client.getProcessStatuses(appId);
|
|
41350
|
+
}
|
|
41351
|
+
};
|
|
41352
|
+
const capabilities = /* @__PURE__ */ new Map();
|
|
41353
|
+
const orderPlans = /* @__PURE__ */ new Map();
|
|
41354
|
+
const seen = /* @__PURE__ */ new Set();
|
|
41355
|
+
const visit = async (node) => {
|
|
41356
|
+
if (node === null || typeof node !== "object") return;
|
|
41357
|
+
if (seen.has(node)) return;
|
|
41358
|
+
seen.add(node);
|
|
41359
|
+
if (Array.isArray(node)) {
|
|
41360
|
+
await Promise.all(node.map(visit));
|
|
41361
|
+
return;
|
|
41362
|
+
}
|
|
41363
|
+
const typed = node;
|
|
41364
|
+
if (typed["type"] === "SELECT") {
|
|
41365
|
+
const select = node;
|
|
41366
|
+
const physicalApps = [select.from, ...select.joins.map((join) => join.table)].filter((table) => table.cteName === null).map((table) => table.appId);
|
|
41367
|
+
const needsWhereSchema = whereNeedsFieldMetadata(select.where);
|
|
41368
|
+
if (needsWhereSchema || select.orderBy.length > 0 || select.columns.some((column) => column.type === "WINDOW_COL" && column.orderBy.length > 0)) {
|
|
41369
|
+
physicalApps.forEach((appId) => fieldApps.add(appId));
|
|
41370
|
+
}
|
|
41371
|
+
const capability = await resolveSelectWhereCapability(select, tracedClient, cacheContext);
|
|
41372
|
+
if (capability.capability === "UNSUPPORTED") {
|
|
41373
|
+
throw new Error(`ArgumentError: WHERE predicate is unsupported (${formatWhereCapabilityFailure(capability)}).`);
|
|
41374
|
+
}
|
|
41375
|
+
capabilities.set(select, capability);
|
|
41376
|
+
if (select.orderBy.length > 0 || select.columns.some((column) => column.type === "WINDOW_COL" && column.orderBy.length > 0)) {
|
|
41377
|
+
const meta3 = await buildOrderByMetaForSelect(select, tracedClient, cacheContext);
|
|
41378
|
+
if (select.orderMode !== "KINTONE_NATIVE") {
|
|
41379
|
+
for (const semantics of meta3.semantics.values()) {
|
|
41380
|
+
if (semantics.fieldType === "STATUS" && semantics.source) {
|
|
41381
|
+
processStatusApps.add(semantics.source.appId);
|
|
41382
|
+
}
|
|
41383
|
+
}
|
|
41384
|
+
}
|
|
41385
|
+
const hasUnmaterializedSource = [select.from, ...select.joins.map((join) => join.table)].some((table) => table.cteName !== null);
|
|
41386
|
+
if (hasCanonicalOrder(select) && !hasUnmaterializedSource) {
|
|
41387
|
+
const mode = capability.capability === "EXACT_PUSHDOWN" ? resolveSelectMode(select) : "FULL_SCAN";
|
|
41388
|
+
orderPlans.set(select, (select.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
41389
|
+
stmt: select,
|
|
41390
|
+
staticMode: mode,
|
|
41391
|
+
whereCapability: capability.capability,
|
|
41392
|
+
orderSemantics: meta3.semantics,
|
|
41393
|
+
maxRecords: maxRecords2,
|
|
41394
|
+
hasKlike: whereHasKlike(select.where)
|
|
41395
|
+
}));
|
|
41396
|
+
}
|
|
41397
|
+
}
|
|
41398
|
+
} else if (typed["type"] === "UPDATE" || typed["type"] === "DELETE") {
|
|
41399
|
+
fieldApps.add(node.appId);
|
|
41400
|
+
await assertDmlWhereCapability(
|
|
41401
|
+
node,
|
|
41402
|
+
tracedClient,
|
|
41403
|
+
cacheContext
|
|
41404
|
+
);
|
|
41405
|
+
}
|
|
41406
|
+
await Promise.all(Object.values(typed).map(visit));
|
|
41407
|
+
};
|
|
41408
|
+
await visit(query);
|
|
41409
|
+
if (typeof query === "object" && query !== null && query.type === "WITH" && canInlineSingleCte(query)) {
|
|
41410
|
+
const inlined = buildInlinedQuery(query);
|
|
41411
|
+
const capability = await resolveSelectWhereCapability(inlined, tracedClient, cacheContext);
|
|
41412
|
+
if (capability.capability === "UNSUPPORTED") {
|
|
41413
|
+
throw new Error(`ArgumentError: WHERE predicate is unsupported (${formatWhereCapabilityFailure(capability)}).`);
|
|
41414
|
+
}
|
|
41415
|
+
capabilities.set(inlined, capability);
|
|
41416
|
+
if (hasCanonicalOrder(inlined)) {
|
|
41417
|
+
const meta3 = await buildOrderByMetaForSelect(inlined, tracedClient, cacheContext);
|
|
41418
|
+
orderPlans.set(inlined, (inlined.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
41419
|
+
stmt: inlined,
|
|
41420
|
+
staticMode: capability.capability === "EXACT_PUSHDOWN" ? resolveSelectMode(inlined) : "FULL_SCAN",
|
|
41421
|
+
whereCapability: capability.capability,
|
|
41422
|
+
orderSemantics: meta3.semantics,
|
|
41423
|
+
maxRecords: maxRecords2,
|
|
41424
|
+
hasKlike: whereHasKlike(inlined.where)
|
|
41425
|
+
}));
|
|
41426
|
+
}
|
|
41427
|
+
}
|
|
41428
|
+
return { capabilities, orderPlans, fieldApps, processStatusApps };
|
|
41429
|
+
}
|
|
41430
|
+
function explainMetadataLines(analysis) {
|
|
41431
|
+
return [
|
|
41432
|
+
...[...analysis.fieldApps].sort((a, b) => a - b).map((appId) => ` metadata API: form definition APP${appId}`),
|
|
41433
|
+
...[...analysis.processStatusApps].sort((a, b) => a - b).map((appId) => ` metadata API: process status APP${appId}`)
|
|
41434
|
+
];
|
|
41435
|
+
}
|
|
41436
|
+
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords2 = 1e4, cursorMaxActive2 = 2) {
|
|
39976
41437
|
const statements = parseSqlBatch(sql);
|
|
39977
41438
|
const analysis = analyzeBatch(statements);
|
|
39978
41439
|
validateDeclaredBatchVariables(statements, injectedVariables);
|
|
39979
41440
|
const variables = /* @__PURE__ */ new Map();
|
|
39980
|
-
|
|
39981
|
-
|
|
39982
|
-
|
|
39983
|
-
|
|
39984
|
-
|
|
39985
|
-
|
|
39986
|
-
|
|
39987
|
-
|
|
39988
|
-
|
|
39989
|
-
|
|
39990
|
-
|
|
39991
|
-
|
|
39992
|
-
|
|
39993
|
-
|
|
39994
|
-
|
|
39995
|
-
|
|
41441
|
+
const plans = [];
|
|
41442
|
+
for (let i = 0; i < statements.length; i++) {
|
|
41443
|
+
const stmt = statements[i];
|
|
41444
|
+
const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveVariableRefs(stmt.expr, variables) } : stmt : resolveVariableRefs(stmt, variables);
|
|
41445
|
+
validateKlikeStatement(planStmt);
|
|
41446
|
+
const whereAnalysis = await buildExplainWhereAnalysis(planStmt, client, cacheContext, maxRecords2);
|
|
41447
|
+
const statementPlan = addCursorConcurrency(buildBatchStatementPlan(
|
|
41448
|
+
planStmt,
|
|
41449
|
+
analysis.statements[i],
|
|
41450
|
+
whereAnalysis.capabilities,
|
|
41451
|
+
whereAnalysis.orderPlans
|
|
41452
|
+
), cursorMaxActive2);
|
|
41453
|
+
const metadataPlan = explainMetadataLines(whereAnalysis);
|
|
41454
|
+
plans.push({
|
|
41455
|
+
index: i,
|
|
41456
|
+
type: analysis.statements[i].statementType,
|
|
41457
|
+
plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
|
|
41458
|
+
});
|
|
41459
|
+
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
41460
|
+
variables.set(stmt.name, { type: "string", value: `@${stmt.name}` });
|
|
41461
|
+
}
|
|
41462
|
+
}
|
|
41463
|
+
return { statementCount: statements.length, statements: plans };
|
|
39996
41464
|
}
|
|
39997
|
-
function buildBatchStatementPlan(stmt, info) {
|
|
41465
|
+
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans) {
|
|
39998
41466
|
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
39999
41467
|
return [
|
|
40000
41468
|
`CREATE TEMP TABLE ${stmt.name}`,
|
|
40001
41469
|
` scope: batch\uFF08\u30D0\u30C3\u30C1\u7D42\u4E86\u6642\u306B\u81EA\u52D5\u7834\u68C4\uFF09`,
|
|
40002
41470
|
` 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}`)
|
|
41471
|
+
...buildPlanForBatchQuery(stmt.query, info, capabilities, orderPlans).map((l) => ` ${l}`)
|
|
40004
41472
|
];
|
|
40005
41473
|
}
|
|
40006
41474
|
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
@@ -40016,7 +41484,7 @@ function buildBatchStatementPlan(stmt, info) {
|
|
|
40016
41484
|
`SET @${stmt.name} = (SELECT ...)`,
|
|
40017
41485
|
" 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
41486
|
" subquery:",
|
|
40019
|
-
...buildPlanForBatchQuery(stmt.expr.query, subInfo).map((l) => ` ${l}`)
|
|
41487
|
+
...buildPlanForBatchQuery(stmt.expr.query, subInfo, capabilities, orderPlans).map((l) => ` ${l}`)
|
|
40020
41488
|
];
|
|
40021
41489
|
}
|
|
40022
41490
|
return [
|
|
@@ -40032,7 +41500,7 @@ function buildBatchStatementPlan(stmt, info) {
|
|
|
40032
41500
|
}
|
|
40033
41501
|
if (stmt.type === "SHOW_APPS") return ["SHOW APPS\uFF08\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\uFF09"];
|
|
40034
41502
|
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);
|
|
41503
|
+
if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info, capabilities, orderPlans);
|
|
40036
41504
|
if (stmt.type === "ASSERT") {
|
|
40037
41505
|
const lines = [
|
|
40038
41506
|
`ASSERT ${stmt.text}`,
|
|
@@ -40044,11 +41512,11 @@ function buildBatchStatementPlan(stmt, info) {
|
|
|
40044
41512
|
subqueries.forEach((sq, i) => {
|
|
40045
41513
|
lines.push(subqueries.length > 1 ? ` subquery[${i + 1}]:` : " subquery:");
|
|
40046
41514
|
const subInfo = hasTempTableRef(sq.query) ? info : { ...info, tempTablesReferenced: [] };
|
|
40047
|
-
lines.push(...buildPlanForBatchQuery(sq.query, subInfo).map((l) => ` ${l}`));
|
|
41515
|
+
lines.push(...buildPlanForBatchQuery(sq.query, subInfo, capabilities, orderPlans).map((l) => ` ${l}`));
|
|
40048
41516
|
});
|
|
40049
41517
|
return lines;
|
|
40050
41518
|
}
|
|
40051
|
-
return buildPlanForBatchQuery(stmt, info);
|
|
41519
|
+
return buildPlanForBatchQuery(stmt, info, capabilities, orderPlans);
|
|
40052
41520
|
}
|
|
40053
41521
|
function hasTempTableRef(node) {
|
|
40054
41522
|
if (Array.isArray(node)) return node.some(hasTempTableRef);
|
|
@@ -40060,9 +41528,9 @@ function hasTempTableRef(node) {
|
|
|
40060
41528
|
}
|
|
40061
41529
|
return false;
|
|
40062
41530
|
}
|
|
40063
|
-
function buildPlanForBatchQuery(query, info) {
|
|
41531
|
+
function buildPlanForBatchQuery(query, info, capabilities, orderPlans) {
|
|
40064
41532
|
if (info.tempTablesReferenced.length === 0) {
|
|
40065
|
-
return buildExplainPlan(query);
|
|
41533
|
+
return buildExplainPlan(query, void 0, capabilities, orderPlans);
|
|
40066
41534
|
}
|
|
40067
41535
|
const lines = [];
|
|
40068
41536
|
if (query.type === "INSERT_SELECT") {
|
|
@@ -40087,8 +41555,15 @@ function buildPlanForBatchQuery(query, info) {
|
|
|
40087
41555
|
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
41556
|
return lines;
|
|
40089
41557
|
}
|
|
40090
|
-
function executeExplain(stmt) {
|
|
40091
|
-
const
|
|
41558
|
+
async function executeExplain(stmt, client, cacheContext, maxRecords2, cursorMaxActive2) {
|
|
41559
|
+
const analysis = await buildExplainWhereAnalysis(stmt.query, client, cacheContext, maxRecords2);
|
|
41560
|
+
const lines = [
|
|
41561
|
+
...explainMetadataLines(analysis),
|
|
41562
|
+
...addCursorConcurrency(
|
|
41563
|
+
buildExplainPlan(stmt.query, void 0, analysis.capabilities, analysis.orderPlans),
|
|
41564
|
+
cursorMaxActive2
|
|
41565
|
+
)
|
|
41566
|
+
];
|
|
40092
41567
|
return {
|
|
40093
41568
|
type: "SELECT",
|
|
40094
41569
|
columns: ["plan"],
|
|
@@ -40096,31 +41571,64 @@ function executeExplain(stmt) {
|
|
|
40096
41571
|
rowCount: lines.length
|
|
40097
41572
|
};
|
|
40098
41573
|
}
|
|
40099
|
-
function
|
|
40100
|
-
|
|
40101
|
-
|
|
41574
|
+
function addCursorConcurrency(lines, cursorMaxActive2) {
|
|
41575
|
+
const result = [];
|
|
41576
|
+
for (const line of lines) {
|
|
41577
|
+
result.push(line);
|
|
41578
|
+
if (line.trim() === "cursor page size: 500") {
|
|
41579
|
+
const indent = line.match(/^\s*/)?.[0] ?? "";
|
|
41580
|
+
result.push(`${indent}cursor concurrency: ${cursorMaxActive2} per domain (process-local)`);
|
|
41581
|
+
}
|
|
41582
|
+
}
|
|
41583
|
+
return result;
|
|
41584
|
+
}
|
|
41585
|
+
function buildExplainPlan(query, label, capabilities, orderPlans) {
|
|
41586
|
+
if (query.type === "UNION") return buildUnionPlan(query, capabilities, orderPlans);
|
|
41587
|
+
if (query.type === "WITH") return buildWithPlan(query, capabilities, orderPlans);
|
|
40102
41588
|
if (query.type === "INSERT") return buildInsertPlan(query, label);
|
|
40103
|
-
if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label);
|
|
41589
|
+
if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label, capabilities, orderPlans);
|
|
40104
41590
|
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);
|
|
41591
|
+
if (query.type === "UPSERT_SELECT") return buildUpsertSelectPlan(query, label, capabilities, orderPlans);
|
|
41592
|
+
if (query.type === "UPDATE") return buildUpdatePlan(query, label, capabilities, orderPlans);
|
|
40107
41593
|
if (query.type === "DELETE") return buildDeletePlan(query, label);
|
|
40108
41594
|
if (query.type === "REORDER") return buildReorderPlan(query, label);
|
|
40109
|
-
return buildSelectPlan(query, label);
|
|
41595
|
+
return buildSelectPlan(query, label, capabilities, orderPlans);
|
|
40110
41596
|
}
|
|
40111
|
-
function buildSelectPlan(stmt, label) {
|
|
40112
|
-
const
|
|
41597
|
+
function buildSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
41598
|
+
const whereCapability = capabilities?.get(stmt) ?? (capabilities ? [...capabilities].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
41599
|
+
const orderPlan = orderPlans?.get(stmt) ?? (orderPlans ? [...orderPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
41600
|
+
const mode = orderPlan?.kind === "CANONICAL_LOCAL" ? "FULL_SCAN" : whereCapability && whereCapability.capability !== "EXACT_PUSHDOWN" ? "FULL_SCAN" : resolveSelectMode(stmt);
|
|
40113
41601
|
const reasons = collectFullScanReasons(stmt);
|
|
41602
|
+
if (whereCapability && whereCapability.capability !== "EXACT_PUSHDOWN") {
|
|
41603
|
+
reasons.push(...whereCapability.reasons.map((reason) => reason.code));
|
|
41604
|
+
}
|
|
40114
41605
|
const lines = [];
|
|
40115
41606
|
if (label) lines.push(label);
|
|
40116
41607
|
lines.push(` mode: ${mode}`);
|
|
41608
|
+
if (orderPlan) {
|
|
41609
|
+
lines.push(` order plan: ${orderPlan.kind}`);
|
|
41610
|
+
if (orderPlan.reasonCodes.length > 0) lines.push(` order reason: ${orderPlan.reasonCodes.join(", ")}`);
|
|
41611
|
+
if (orderPlan.kind === "KORDER_NATIVE") {
|
|
41612
|
+
lines.push(" order semantics: kintone native (not kSQL canonical)");
|
|
41613
|
+
lines.push(" REST execution: single GET");
|
|
41614
|
+
} else if (orderPlan.kind === "KORDER_CURSOR") {
|
|
41615
|
+
lines.push(" order semantics: kintone native (not kSQL canonical)");
|
|
41616
|
+
lines.push(" fetch API: POST/GET/DELETE records/cursor.json");
|
|
41617
|
+
lines.push(" cursor page size: 500");
|
|
41618
|
+
lines.push(` scan rows: ${orderPlan.scanRows}`);
|
|
41619
|
+
}
|
|
41620
|
+
}
|
|
41621
|
+
if (orderPlan?.requiresCompleteInput ?? requiresCompleteInput(stmt)) {
|
|
41622
|
+
lines.push(" complete input: required (ORDER BY / window ORDER BY; onLimit=truncate disabled)");
|
|
41623
|
+
}
|
|
40117
41624
|
if (mode === "FULL_SCAN" && reasons.length > 0) {
|
|
40118
41625
|
lines.push(` reason: ${reasons.join(", ")}`);
|
|
40119
41626
|
}
|
|
40120
41627
|
if (mode === "SIMPLE") {
|
|
40121
|
-
const params = selectToKintoneParams(stmt);
|
|
41628
|
+
const params = selectToKintoneParams(orderPlan?.kind === "CANONICAL_REST_TOP_N" ? withCanonicalRestTie(stmt) : stmt);
|
|
40122
41629
|
lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);
|
|
40123
|
-
|
|
41630
|
+
const displayedQuery = orderPlan?.kind === "KORDER_CURSOR" ? buildKorderCursorQuery(stmt) : params.query;
|
|
41631
|
+
lines.push(` kintone query: ${displayedQuery || "(\u306A\u3057)"}`);
|
|
40124
41632
|
lines.push(` fields: ${params.fields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : params.fields.join(", ")}`);
|
|
40125
41633
|
} else {
|
|
40126
41634
|
const pushdownPlan = buildKlikePushdownPlan(stmt);
|
|
@@ -40128,7 +41636,8 @@ function buildSelectPlan(stmt, label) {
|
|
|
40128
41636
|
const mainAliasStr = stmt.from.alias ? ` AS ${stmt.from.alias}` : "";
|
|
40129
41637
|
const mainPushDown = pushdownPlan.mainCondition;
|
|
40130
41638
|
const mainCandidate = extractMainTypedPushdownCandidate(stmt);
|
|
40131
|
-
const
|
|
41639
|
+
const exactOriginalWhere = stmt.joins.length === 0 && whereCapability?.capability === "EXACT_PUSHDOWN" && stmt.where !== null && !whereRequiresJsEval(stmt.where) ? whereToKintone(stmt.where) : "";
|
|
41640
|
+
const mainQ = mainPushDown !== null ? whereToKintone(mainPushDown) : exactOriginalWhere || "(\u5168\u4EF6\u53D6\u5F97)";
|
|
40132
41641
|
lines.push(` app: APP${stmt.from.appId}${mainAliasStr} (${stmt.from.appId})`);
|
|
40133
41642
|
lines.push(` kintone query: ${mainQ}`);
|
|
40134
41643
|
if (mainCandidate !== null) {
|
|
@@ -40150,10 +41659,10 @@ function buildSelectPlan(stmt, label) {
|
|
|
40150
41659
|
lines.push(` fields: ${joinFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : joinFields.join(", ")}`);
|
|
40151
41660
|
}
|
|
40152
41661
|
}
|
|
40153
|
-
lines.push(...collectSubqueryPlans(stmt));
|
|
41662
|
+
lines.push(...collectSubqueryPlans(stmt, capabilities, orderPlans));
|
|
40154
41663
|
return lines;
|
|
40155
41664
|
}
|
|
40156
|
-
function buildUnionPlan(stmt) {
|
|
41665
|
+
function buildUnionPlan(stmt, capabilities, orderPlans) {
|
|
40157
41666
|
const selects = [];
|
|
40158
41667
|
const collect = (u) => {
|
|
40159
41668
|
if (u.type === "SELECT") {
|
|
@@ -40167,24 +41676,25 @@ function buildUnionPlan(stmt) {
|
|
|
40167
41676
|
const lines = [];
|
|
40168
41677
|
selects.forEach((sel, i) => {
|
|
40169
41678
|
if (i > 0) lines.push("");
|
|
40170
|
-
lines.push(...buildSelectPlan(sel, `[union:${i + 1}]
|
|
41679
|
+
lines.push(...buildSelectPlan(sel, `[union:${i + 1}]`, capabilities, orderPlans));
|
|
40171
41680
|
});
|
|
40172
41681
|
return lines;
|
|
40173
41682
|
}
|
|
40174
|
-
function buildWithPlan(stmt) {
|
|
41683
|
+
function buildWithPlan(stmt, capabilities, orderPlans) {
|
|
40175
41684
|
const lines = [];
|
|
40176
41685
|
for (const cte of stmt.ctes) {
|
|
40177
41686
|
if (cte.query.type === "SELECT") {
|
|
40178
|
-
lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]
|
|
41687
|
+
lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]`, capabilities, orderPlans));
|
|
40179
41688
|
lines.push("");
|
|
40180
41689
|
}
|
|
40181
41690
|
}
|
|
40182
41691
|
if (stmt.query.type === "SELECT" || stmt.query.type === "UNION") {
|
|
40183
|
-
lines.push(...buildExplainPlan(stmt.query, "[main]"));
|
|
41692
|
+
lines.push(...buildExplainPlan(stmt.query, "[main]", capabilities, orderPlans));
|
|
40184
41693
|
}
|
|
40185
41694
|
if (canInlineSingleCte(stmt)) {
|
|
40186
41695
|
lines.push("");
|
|
40187
|
-
|
|
41696
|
+
const inlined = buildInlinedQuery(stmt);
|
|
41697
|
+
lines.push(...buildSelectPlan(inlined, "[effective: inlined CTE]", capabilities, orderPlans));
|
|
40188
41698
|
}
|
|
40189
41699
|
return lines;
|
|
40190
41700
|
}
|
|
@@ -40212,7 +41722,7 @@ function collectFullScanReasons(stmt) {
|
|
|
40212
41722
|
r.push("ORDER BY \u306B\u5F0F");
|
|
40213
41723
|
return r;
|
|
40214
41724
|
}
|
|
40215
|
-
function collectSubqueryPlans(stmt) {
|
|
41725
|
+
function collectSubqueryPlans(stmt, capabilities, orderPlans) {
|
|
40216
41726
|
const lines = [];
|
|
40217
41727
|
let idx = 1;
|
|
40218
41728
|
const visitWhere = (w) => {
|
|
@@ -40221,16 +41731,16 @@ function collectSubqueryPlans(stmt) {
|
|
|
40221
41731
|
case "BINARY":
|
|
40222
41732
|
if (w.right.type === "SCALAR_SUBQUERY") {
|
|
40223
41733
|
lines.push("");
|
|
40224
|
-
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]
|
|
41734
|
+
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
40225
41735
|
}
|
|
40226
41736
|
if (w.right.type === "SUBQUERY_IN_LIST") {
|
|
40227
41737
|
lines.push("");
|
|
40228
|
-
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]
|
|
41738
|
+
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
40229
41739
|
}
|
|
40230
41740
|
break;
|
|
40231
41741
|
case "EXISTS":
|
|
40232
41742
|
lines.push("");
|
|
40233
|
-
lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]
|
|
41743
|
+
lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
40234
41744
|
break;
|
|
40235
41745
|
case "LOGICAL":
|
|
40236
41746
|
visitWhere(w.left);
|
|
@@ -40248,7 +41758,7 @@ function collectSubqueryPlans(stmt) {
|
|
|
40248
41758
|
for (const col of stmt.columns) {
|
|
40249
41759
|
if (col.type === "SCALAR_SUBQUERY_COL") {
|
|
40250
41760
|
lines.push("");
|
|
40251
|
-
lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]
|
|
41761
|
+
lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
40252
41762
|
}
|
|
40253
41763
|
}
|
|
40254
41764
|
if (stmt.having) visitWhere(stmt.having);
|
|
@@ -40266,7 +41776,7 @@ function buildInsertPlan(stmt, label) {
|
|
|
40266
41776
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
40267
41777
|
return lines;
|
|
40268
41778
|
}
|
|
40269
|
-
function buildInsertSelectPlan(stmt, label) {
|
|
41779
|
+
function buildInsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
40270
41780
|
const lines = [];
|
|
40271
41781
|
if (label) lines.push(label);
|
|
40272
41782
|
lines.push(` [INSERT SELECT]`);
|
|
@@ -40274,10 +41784,10 @@ function buildInsertSelectPlan(stmt, label) {
|
|
|
40274
41784
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
40275
41785
|
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
41786
|
lines.push("");
|
|
40277
|
-
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]"));
|
|
41787
|
+
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans));
|
|
40278
41788
|
return lines;
|
|
40279
41789
|
}
|
|
40280
|
-
function buildUpdatePlan(stmt, label) {
|
|
41790
|
+
function buildUpdatePlan(stmt, label, capabilities, orderPlans) {
|
|
40281
41791
|
const isArith = hasArithAssignment(stmt);
|
|
40282
41792
|
const isSubq = stmt.assignments.some((a) => a.value.type === "SCALAR_SUBQUERY");
|
|
40283
41793
|
const lines = [];
|
|
@@ -40311,7 +41821,7 @@ function buildUpdatePlan(stmt, label) {
|
|
|
40311
41821
|
for (const a of stmt.assignments) {
|
|
40312
41822
|
if (a.value.type === "SCALAR_SUBQUERY") {
|
|
40313
41823
|
lines.push("");
|
|
40314
|
-
lines.push(...buildSelectPlan(a.value.query, `[subquery: ${a.field}]
|
|
41824
|
+
lines.push(...buildSelectPlan(a.value.query, `[subquery: ${a.field}]`, capabilities, orderPlans));
|
|
40315
41825
|
}
|
|
40316
41826
|
}
|
|
40317
41827
|
return lines;
|
|
@@ -40338,7 +41848,7 @@ function buildUpsertPlan(stmt, label) {
|
|
|
40338
41848
|
` 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
41849
|
];
|
|
40340
41850
|
}
|
|
40341
|
-
function buildUpsertSelectPlan(stmt, label) {
|
|
41851
|
+
function buildUpsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
40342
41852
|
const lines = [
|
|
40343
41853
|
...label ? [label] : [],
|
|
40344
41854
|
` [UPSERT SELECT]`,
|
|
@@ -40348,7 +41858,7 @@ function buildUpsertSelectPlan(stmt, label) {
|
|
|
40348
41858
|
` 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
41859
|
``
|
|
40350
41860
|
];
|
|
40351
|
-
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]"));
|
|
41861
|
+
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans));
|
|
40352
41862
|
return lines;
|
|
40353
41863
|
}
|
|
40354
41864
|
function buildReorderPlan(stmt, label) {
|
|
@@ -40661,6 +42171,12 @@ function validateKsqlConfig(config2) {
|
|
|
40661
42171
|
}
|
|
40662
42172
|
const logicalApps = normalizeLogicalApps(profileName, profile2.logicalApps);
|
|
40663
42173
|
if (logicalApps !== void 0) profile2.logicalApps = logicalApps;
|
|
42174
|
+
if (profile2.query?.cursorMaxActive !== void 0) {
|
|
42175
|
+
const value = profile2.query.cursorMaxActive;
|
|
42176
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > 5) {
|
|
42177
|
+
throw argumentError(`query.cursorMaxActive for profile "${profileName}" must be an integer from 1 to 5.`);
|
|
42178
|
+
}
|
|
42179
|
+
}
|
|
40664
42180
|
}
|
|
40665
42181
|
return config2;
|
|
40666
42182
|
}
|
|
@@ -40823,6 +42339,10 @@ var RequestGate = class {
|
|
|
40823
42339
|
async runMutation(fn) {
|
|
40824
42340
|
return this.withSlot(fn);
|
|
40825
42341
|
}
|
|
42342
|
+
/** Cursor Create/Get/Delete: セマフォのみ。GETでも位置を進めるため再試行しない。 */
|
|
42343
|
+
async runCursorStep(fn) {
|
|
42344
|
+
return this.withSlot(fn);
|
|
42345
|
+
}
|
|
40826
42346
|
async withSlot(fn) {
|
|
40827
42347
|
await this.acquire();
|
|
40828
42348
|
try {
|
|
@@ -40854,6 +42374,14 @@ var RequestGate = class {
|
|
|
40854
42374
|
function withRequestGate(client, gate) {
|
|
40855
42375
|
return {
|
|
40856
42376
|
getRecords: (params) => gate.runReadOnly(() => client.getRecords(params)),
|
|
42377
|
+
openCursor: async (params) => {
|
|
42378
|
+
const handle = await gate.runCursorStep(() => client.openCursor(params));
|
|
42379
|
+
return {
|
|
42380
|
+
totalCount: handle.totalCount,
|
|
42381
|
+
nextPage: () => gate.runCursorStep(() => handle.nextPage()),
|
|
42382
|
+
close: () => gate.runCursorStep(() => handle.close())
|
|
42383
|
+
};
|
|
42384
|
+
},
|
|
40857
42385
|
getApps: () => gate.runReadOnly(() => client.getApps()),
|
|
40858
42386
|
getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
|
|
40859
42387
|
getProcessStatuses: (appId) => gate.runReadOnly(() => client.getProcessStatuses(appId)),
|
|
@@ -40883,12 +42411,14 @@ function flattenFormFieldProperties(properties) {
|
|
|
40883
42411
|
function flattenFields(properties, lookupCopyFields, inSubtable = false) {
|
|
40884
42412
|
const out = [];
|
|
40885
42413
|
for (const field of Object.values(properties)) {
|
|
40886
|
-
|
|
42414
|
+
const optionOrder = toOptionOrderMap(field.options);
|
|
42415
|
+
const sortKind = detectSortKind(field.type, field.format);
|
|
42416
|
+
const info = {
|
|
40887
42417
|
code: field.code,
|
|
40888
42418
|
label: field.label,
|
|
40889
42419
|
fieldType: field.type,
|
|
40890
|
-
optionOrder
|
|
40891
|
-
sortKind
|
|
42420
|
+
optionOrder,
|
|
42421
|
+
sortKind,
|
|
40892
42422
|
required: field.required,
|
|
40893
42423
|
minValue: normalizeConstraintValue(field.minValue),
|
|
40894
42424
|
maxValue: normalizeConstraintValue(field.maxValue),
|
|
@@ -40897,7 +42427,9 @@ function flattenFields(properties, lookupCopyFields, inSubtable = false) {
|
|
|
40897
42427
|
defaultValue: field.defaultValue,
|
|
40898
42428
|
inSubtable,
|
|
40899
42429
|
writable: !lookupCopyFields.has(field.code) && !NON_WRITABLE_FIELD_TYPES2.has(field.type)
|
|
40900
|
-
}
|
|
42430
|
+
};
|
|
42431
|
+
info.semantics = resolveFieldSemantics(info);
|
|
42432
|
+
out.push(info);
|
|
40901
42433
|
if (field.fields) out.push(...flattenFields(field.fields, lookupCopyFields, true));
|
|
40902
42434
|
}
|
|
40903
42435
|
return out;
|
|
@@ -40952,7 +42484,230 @@ function detectSortKind(fieldType, calcFormat) {
|
|
|
40952
42484
|
return void 0;
|
|
40953
42485
|
}
|
|
40954
42486
|
|
|
42487
|
+
// src/core/processStatus.ts
|
|
42488
|
+
function normalizeProcessStatusStates(states) {
|
|
42489
|
+
if (states === null) return null;
|
|
42490
|
+
return Object.values(states).map((state) => {
|
|
42491
|
+
const index = Number(state.index);
|
|
42492
|
+
if (!Number.isSafeInteger(index) || index < 0) {
|
|
42493
|
+
throw new Error(`ArgumentError: invalid process status index: ${String(state.index)}`);
|
|
42494
|
+
}
|
|
42495
|
+
return { name: state.name, index };
|
|
42496
|
+
});
|
|
42497
|
+
}
|
|
42498
|
+
|
|
42499
|
+
// src/api/kintoneCursor.ts
|
|
42500
|
+
function isAlreadyReleasedCursorError(error51) {
|
|
42501
|
+
const shaped = error51;
|
|
42502
|
+
return shaped?.status === 404 && shaped.code === "GAIA_CN01";
|
|
42503
|
+
}
|
|
42504
|
+
async function deleteCursorWithConfirmation(deleteCursor, sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)), isAlreadyReleased = isAlreadyReleasedCursorError) {
|
|
42505
|
+
try {
|
|
42506
|
+
await deleteCursor();
|
|
42507
|
+
return;
|
|
42508
|
+
} catch (firstError) {
|
|
42509
|
+
if (isAlreadyReleased(firstError)) return;
|
|
42510
|
+
}
|
|
42511
|
+
await sleep(250);
|
|
42512
|
+
try {
|
|
42513
|
+
await deleteCursor();
|
|
42514
|
+
} catch (confirmationError) {
|
|
42515
|
+
if (isAlreadyReleased(confirmationError)) return;
|
|
42516
|
+
throw confirmationError;
|
|
42517
|
+
}
|
|
42518
|
+
}
|
|
42519
|
+
async function withTimeout(promise2, timeoutMs) {
|
|
42520
|
+
let timer;
|
|
42521
|
+
const timeout2 = new Promise((_resolve, reject) => {
|
|
42522
|
+
timer = setTimeout(() => reject(new Error(`CursorCleanupTimeoutError: cleanup exceeded ${timeoutMs}ms.`)), timeoutMs);
|
|
42523
|
+
timer.unref?.();
|
|
42524
|
+
});
|
|
42525
|
+
try {
|
|
42526
|
+
return await Promise.race([promise2, timeout2]);
|
|
42527
|
+
} finally {
|
|
42528
|
+
if (timer) clearTimeout(timer);
|
|
42529
|
+
}
|
|
42530
|
+
}
|
|
42531
|
+
function createKintoneCursorHandle(totalCount, operations) {
|
|
42532
|
+
let released = false;
|
|
42533
|
+
let closing = false;
|
|
42534
|
+
let pageTail = Promise.resolve();
|
|
42535
|
+
let closePromise = null;
|
|
42536
|
+
const nextPage = () => {
|
|
42537
|
+
if (closing || released) return Promise.resolve({ records: [], next: false });
|
|
42538
|
+
const result = pageTail.then(async () => {
|
|
42539
|
+
if (closing || released) return { records: [], next: false };
|
|
42540
|
+
const page = await operations.get();
|
|
42541
|
+
if (!page.next) {
|
|
42542
|
+
released = true;
|
|
42543
|
+
operations.onReleased?.();
|
|
42544
|
+
}
|
|
42545
|
+
return page;
|
|
42546
|
+
});
|
|
42547
|
+
pageTail = result.then(() => void 0, () => void 0);
|
|
42548
|
+
return result;
|
|
42549
|
+
};
|
|
42550
|
+
const close = () => {
|
|
42551
|
+
if (released) return Promise.resolve();
|
|
42552
|
+
if (closePromise) return closePromise;
|
|
42553
|
+
closing = true;
|
|
42554
|
+
closePromise = pageTail.then(async () => {
|
|
42555
|
+
if (released) return;
|
|
42556
|
+
try {
|
|
42557
|
+
await withTimeout(
|
|
42558
|
+
deleteCursorWithConfirmation(
|
|
42559
|
+
operations.delete,
|
|
42560
|
+
operations.sleep,
|
|
42561
|
+
operations.isAlreadyReleasedError
|
|
42562
|
+
),
|
|
42563
|
+
operations.cleanupTimeoutMs ?? 5e3
|
|
42564
|
+
);
|
|
42565
|
+
released = true;
|
|
42566
|
+
operations.onReleased?.();
|
|
42567
|
+
} catch (error51) {
|
|
42568
|
+
operations.onReleaseUnknown?.();
|
|
42569
|
+
throw error51;
|
|
42570
|
+
}
|
|
42571
|
+
});
|
|
42572
|
+
return closePromise;
|
|
42573
|
+
};
|
|
42574
|
+
return { totalCount, nextPage, close };
|
|
42575
|
+
}
|
|
42576
|
+
|
|
42577
|
+
// src/api/cursorLeaseManager.ts
|
|
42578
|
+
var DEFAULT_MAX_ACTIVE = 2;
|
|
42579
|
+
var MAX_ACTIVE = 5;
|
|
42580
|
+
var DEFAULT_WAIT_MS = 3e4;
|
|
42581
|
+
var DEFAULT_QUARANTINE_MS = 10 * 6e4 + 3e4;
|
|
42582
|
+
var CursorLeaseManager = class {
|
|
42583
|
+
constructor(host, options = {}) {
|
|
42584
|
+
this.host = host;
|
|
42585
|
+
this.active = 0;
|
|
42586
|
+
this.peak = 0;
|
|
42587
|
+
this.quarantined = 0;
|
|
42588
|
+
this.waiters = [];
|
|
42589
|
+
this.createTail = Promise.resolve();
|
|
42590
|
+
const maxActive = options.maxActive ?? DEFAULT_MAX_ACTIVE;
|
|
42591
|
+
if (!Number.isSafeInteger(maxActive) || maxActive < 1 || maxActive > MAX_ACTIVE) {
|
|
42592
|
+
throw new Error(`ArgumentError: cursorMaxActive must be an integer from 1 to ${MAX_ACTIVE}.`);
|
|
42593
|
+
}
|
|
42594
|
+
this.maxActive = maxActive;
|
|
42595
|
+
this.waitTimeoutMs = options.waitTimeoutMs ?? DEFAULT_WAIT_MS;
|
|
42596
|
+
this.quarantineMs = options.quarantineMs ?? DEFAULT_QUARANTINE_MS;
|
|
42597
|
+
}
|
|
42598
|
+
acquire() {
|
|
42599
|
+
if (this.active < this.maxActive) {
|
|
42600
|
+
this.active += 1;
|
|
42601
|
+
this.peak = Math.max(this.peak, this.active);
|
|
42602
|
+
return Promise.resolve(this.makeLease());
|
|
42603
|
+
}
|
|
42604
|
+
return new Promise((resolve2, reject) => {
|
|
42605
|
+
const waiter = {};
|
|
42606
|
+
waiter.resolve = resolve2;
|
|
42607
|
+
waiter.reject = reject;
|
|
42608
|
+
waiter.timer = setTimeout(() => {
|
|
42609
|
+
const index = this.waiters.indexOf(waiter);
|
|
42610
|
+
if (index >= 0) this.waiters.splice(index, 1);
|
|
42611
|
+
reject(new CursorCapacityError(this.host, this.maxActive, this.waitTimeoutMs));
|
|
42612
|
+
}, this.waitTimeoutMs);
|
|
42613
|
+
waiter.timer.unref?.();
|
|
42614
|
+
this.waiters.push(waiter);
|
|
42615
|
+
});
|
|
42616
|
+
}
|
|
42617
|
+
/**
|
|
42618
|
+
* 同一hostを共有する後続surfaceの設定を反映する。
|
|
42619
|
+
* 縮小時は既存leaseを強制終了せず、activeが新上限を下回るまで新規取得だけを止める。
|
|
42620
|
+
*/
|
|
42621
|
+
setMaxActive(maxActive) {
|
|
42622
|
+
this.validateMaxActive(maxActive);
|
|
42623
|
+
if (this.maxActive === maxActive) return;
|
|
42624
|
+
this.maxActive = maxActive;
|
|
42625
|
+
this.dispatchWaiters();
|
|
42626
|
+
}
|
|
42627
|
+
async runCreate(fn) {
|
|
42628
|
+
const previous = this.createTail;
|
|
42629
|
+
let unlock;
|
|
42630
|
+
this.createTail = new Promise((resolve2) => {
|
|
42631
|
+
unlock = resolve2;
|
|
42632
|
+
});
|
|
42633
|
+
await previous;
|
|
42634
|
+
try {
|
|
42635
|
+
return await fn();
|
|
42636
|
+
} finally {
|
|
42637
|
+
unlock();
|
|
42638
|
+
}
|
|
42639
|
+
}
|
|
42640
|
+
snapshot() {
|
|
42641
|
+
return {
|
|
42642
|
+
active: this.active,
|
|
42643
|
+
peak: this.peak,
|
|
42644
|
+
quarantined: this.quarantined,
|
|
42645
|
+
waiting: this.waiters.length,
|
|
42646
|
+
limit: this.maxActive
|
|
42647
|
+
};
|
|
42648
|
+
}
|
|
42649
|
+
makeLease() {
|
|
42650
|
+
let done = false;
|
|
42651
|
+
return {
|
|
42652
|
+
release: () => {
|
|
42653
|
+
if (done) return;
|
|
42654
|
+
done = true;
|
|
42655
|
+
this.returnPermit();
|
|
42656
|
+
},
|
|
42657
|
+
quarantine: (durationMs = this.quarantineMs) => {
|
|
42658
|
+
if (done) return;
|
|
42659
|
+
done = true;
|
|
42660
|
+
this.quarantined += 1;
|
|
42661
|
+
const timer = setTimeout(() => {
|
|
42662
|
+
this.quarantined -= 1;
|
|
42663
|
+
this.returnPermit();
|
|
42664
|
+
}, durationMs);
|
|
42665
|
+
timer.unref?.();
|
|
42666
|
+
}
|
|
42667
|
+
};
|
|
42668
|
+
}
|
|
42669
|
+
returnPermit() {
|
|
42670
|
+
this.active -= 1;
|
|
42671
|
+
this.dispatchWaiters();
|
|
42672
|
+
}
|
|
42673
|
+
dispatchWaiters() {
|
|
42674
|
+
while (this.active < this.maxActive) {
|
|
42675
|
+
const waiter = this.waiters.shift();
|
|
42676
|
+
if (!waiter) return;
|
|
42677
|
+
clearTimeout(waiter.timer);
|
|
42678
|
+
this.active += 1;
|
|
42679
|
+
this.peak = Math.max(this.peak, this.active);
|
|
42680
|
+
waiter.resolve(this.makeLease());
|
|
42681
|
+
}
|
|
42682
|
+
}
|
|
42683
|
+
validateMaxActive(maxActive) {
|
|
42684
|
+
if (!Number.isSafeInteger(maxActive) || maxActive < 1 || maxActive > MAX_ACTIVE) {
|
|
42685
|
+
throw new Error(`ArgumentError: cursorMaxActive must be an integer from 1 to ${MAX_ACTIVE}.`);
|
|
42686
|
+
}
|
|
42687
|
+
}
|
|
42688
|
+
};
|
|
42689
|
+
var managers = /* @__PURE__ */ new Map();
|
|
42690
|
+
function getCursorLeaseManager(host, maxActive = DEFAULT_MAX_ACTIVE) {
|
|
42691
|
+
const key = host.toLowerCase();
|
|
42692
|
+
let manager = managers.get(key);
|
|
42693
|
+
if (!manager) {
|
|
42694
|
+
manager = new CursorLeaseManager(key, { maxActive });
|
|
42695
|
+
managers.set(key, manager);
|
|
42696
|
+
} else {
|
|
42697
|
+
manager.setMaxActive(maxActive);
|
|
42698
|
+
}
|
|
42699
|
+
return manager;
|
|
42700
|
+
}
|
|
42701
|
+
|
|
40955
42702
|
// src/cli/nodeKintoneClient.ts
|
|
42703
|
+
var KintoneApiError = class extends Error {
|
|
42704
|
+
constructor(status, code, bodyText) {
|
|
42705
|
+
super(`kintone API error ${status}: ${bodyText}`);
|
|
42706
|
+
this.status = status;
|
|
42707
|
+
this.code = code;
|
|
42708
|
+
this.name = "KintoneApiError";
|
|
42709
|
+
}
|
|
42710
|
+
};
|
|
40956
42711
|
var SEARCH_ABORTED_HEADER_VALUE = "Filter aborted because of too many search results";
|
|
40957
42712
|
function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
40958
42713
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
@@ -41000,7 +42755,13 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
41000
42755
|
if (tokenResolver.debug) {
|
|
41001
42756
|
tokenResolver.log?.(`[debug] response status=${res.status} body=${bodyText}`);
|
|
41002
42757
|
}
|
|
41003
|
-
|
|
42758
|
+
let code;
|
|
42759
|
+
try {
|
|
42760
|
+
const body = JSON.parse(bodyText);
|
|
42761
|
+
if (typeof body.code === "string") code = body.code;
|
|
42762
|
+
} catch {
|
|
42763
|
+
}
|
|
42764
|
+
throw new KintoneApiError(res.status, code, bodyText);
|
|
41004
42765
|
}
|
|
41005
42766
|
if (tokenResolver.debug) {
|
|
41006
42767
|
tokenResolver.log?.(`[debug] response status=${res.status}`);
|
|
@@ -41067,6 +42828,48 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
41067
42828
|
return response.searchAborted ? { ...response.body, searchAborted: true } : response.body;
|
|
41068
42829
|
}
|
|
41069
42830
|
},
|
|
42831
|
+
async openCursor(params) {
|
|
42832
|
+
const manager = getCursorLeaseManager(new URL(normalizedBaseUrl).host, tokenResolver.cursorMaxActive);
|
|
42833
|
+
const lease = await manager.acquire();
|
|
42834
|
+
let created;
|
|
42835
|
+
try {
|
|
42836
|
+
created = await manager.runCreate(() => requestJson(
|
|
42837
|
+
`${apiBasePath}/records/cursor.json`,
|
|
42838
|
+
{
|
|
42839
|
+
method: "POST",
|
|
42840
|
+
body: JSON.stringify({
|
|
42841
|
+
app: params.app,
|
|
42842
|
+
query: params.query,
|
|
42843
|
+
size: params.size,
|
|
42844
|
+
fields: params.fields && params.fields.length > 0 ? params.fields : void 0
|
|
42845
|
+
})
|
|
42846
|
+
},
|
|
42847
|
+
params.app
|
|
42848
|
+
));
|
|
42849
|
+
} catch (error51) {
|
|
42850
|
+
if (error51 instanceof KintoneApiError) {
|
|
42851
|
+
lease.release();
|
|
42852
|
+
throw error51;
|
|
42853
|
+
}
|
|
42854
|
+
lease.quarantine();
|
|
42855
|
+
throw new CursorCreateOutcomeUnknownError(error51);
|
|
42856
|
+
}
|
|
42857
|
+
const cursorId = created.id;
|
|
42858
|
+
return createKintoneCursorHandle(Number(created.totalCount), {
|
|
42859
|
+
get: () => requestJson(
|
|
42860
|
+
`${apiBasePath}/records/cursor.json?id=${encodeURIComponent(cursorId)}`,
|
|
42861
|
+
{ method: "GET" },
|
|
42862
|
+
params.app
|
|
42863
|
+
),
|
|
42864
|
+
delete: () => requestJson(
|
|
42865
|
+
`${apiBasePath}/records/cursor.json`,
|
|
42866
|
+
{ method: "DELETE", body: JSON.stringify({ id: cursorId }) },
|
|
42867
|
+
params.app
|
|
42868
|
+
),
|
|
42869
|
+
onReleased: () => lease.release(),
|
|
42870
|
+
onReleaseUnknown: () => lease.quarantine()
|
|
42871
|
+
});
|
|
42872
|
+
},
|
|
41070
42873
|
async postRecords(_params) {
|
|
41071
42874
|
const res = await requestJson(
|
|
41072
42875
|
`${apiBasePath}/records.json`,
|
|
@@ -41149,7 +42952,7 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
41149
42952
|
const res = await requestJson(`${apiBasePath}/app/status.json?${qs.toString()}`, { method: "GET" }, appId);
|
|
41150
42953
|
return {
|
|
41151
42954
|
enable: res.enable,
|
|
41152
|
-
states:
|
|
42955
|
+
states: normalizeProcessStatusStates(res.states)
|
|
41153
42956
|
};
|
|
41154
42957
|
}
|
|
41155
42958
|
};
|
|
@@ -41533,6 +43336,10 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
41533
43336
|
const onLimit2 = input.onLimit ?? envOnLimit("KSQL_ON_LIMIT") ?? profile2.query?.onLimit ?? "error";
|
|
41534
43337
|
const timeout2 = input.timeout ?? envInt("KSQL_TIMEOUT") ?? profile2.query?.timeout ?? 3e4;
|
|
41535
43338
|
const tempTableMaxRows2 = input.tempTableMaxRows ?? envInt("KSQL_TEMP_TABLE_MAX_ROWS") ?? profile2.query?.tempTableMaxRows;
|
|
43339
|
+
const cursorMaxActive2 = input.cursorMaxActive ?? envInt("KSQL_CURSOR_MAX_ACTIVE") ?? profile2.query?.cursorMaxActive ?? 2;
|
|
43340
|
+
if (!Number.isSafeInteger(cursorMaxActive2) || cursorMaxActive2 < 1 || cursorMaxActive2 > 5) {
|
|
43341
|
+
throw new Error("ArgumentError: cursorMaxActive must be an integer from 1 to 5.");
|
|
43342
|
+
}
|
|
41536
43343
|
const appIds = extractAppIds(sql);
|
|
41537
43344
|
const defaultApp = envInt("KSQL_APP") ?? profile2.app ?? null;
|
|
41538
43345
|
if (appIds.length === 0 && defaultApp !== null) appIds.push(defaultApp);
|
|
@@ -41570,6 +43377,7 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
41570
43377
|
}
|
|
41571
43378
|
profileClientMap.set(pName, createNodeKintoneClient(baseUrl, {
|
|
41572
43379
|
guestSpaceId,
|
|
43380
|
+
cursorMaxActive: cursorMaxActive2,
|
|
41573
43381
|
timeoutMs: timeout2,
|
|
41574
43382
|
debug: input.debug,
|
|
41575
43383
|
debugHeaders: input.debugHeaders,
|
|
@@ -41601,6 +43409,7 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
41601
43409
|
}
|
|
41602
43410
|
profileClientMap.set(pName, createNodeKintoneClient(baseUrl, {
|
|
41603
43411
|
guestSpaceId,
|
|
43412
|
+
cursorMaxActive: cursorMaxActive2,
|
|
41604
43413
|
timeoutMs: timeout2,
|
|
41605
43414
|
debug: input.debug,
|
|
41606
43415
|
debugHeaders: input.debugHeaders,
|
|
@@ -41634,6 +43443,12 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
41634
43443
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
41635
43444
|
return routed.getRecords({ ...params, app: binding.appId });
|
|
41636
43445
|
},
|
|
43446
|
+
openCursor: (params) => {
|
|
43447
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
43448
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
43449
|
+
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
43450
|
+
return routed.openCursor({ ...params, app: binding.appId });
|
|
43451
|
+
},
|
|
41637
43452
|
postRecords: (params) => {
|
|
41638
43453
|
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
41639
43454
|
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
@@ -41684,6 +43499,7 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
41684
43499
|
fetchParallel: fetchParallel2,
|
|
41685
43500
|
onLimit: onLimit2,
|
|
41686
43501
|
timeout: timeout2,
|
|
43502
|
+
cursorMaxActive: cursorMaxActive2,
|
|
41687
43503
|
tempTableMaxRows: tempTableMaxRows2
|
|
41688
43504
|
};
|
|
41689
43505
|
}
|
|
@@ -41884,6 +43700,7 @@ function noOpClient() {
|
|
|
41884
43700
|
};
|
|
41885
43701
|
return {
|
|
41886
43702
|
getRecords: fail,
|
|
43703
|
+
openCursor: fail,
|
|
41887
43704
|
postRecords: fail,
|
|
41888
43705
|
putRecords: fail,
|
|
41889
43706
|
deleteRecords: fail,
|
|
@@ -42156,8 +43973,26 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42156
43973
|
} catch (err) {
|
|
42157
43974
|
throw restoreSqlContextError(err, normalized.sourceSql, normalized.sqlContext);
|
|
42158
43975
|
}
|
|
43976
|
+
const needsAppMetadata = normalized.appBindingByMappedApp.size > 0 && statements.some(explainNeedsAppMetadata);
|
|
43977
|
+
const runtime = needsAppMetadata ? await createRuntime(serverOptions, {
|
|
43978
|
+
sql: input.sql,
|
|
43979
|
+
sqlContext: normalized.sqlContext,
|
|
43980
|
+
profile: input.profile,
|
|
43981
|
+
maxRecords: input.maxRecords,
|
|
43982
|
+
cursorMaxActive: input.cursorMaxActive
|
|
43983
|
+
}) : null;
|
|
43984
|
+
const explainClient = runtime?.client ?? noOpClient();
|
|
43985
|
+
const explainCacheContext = runtime?.cacheContext ?? normalized.cacheContext;
|
|
43986
|
+
const explainSourceSql = runtime?.sql ?? normalized.normalizedSql;
|
|
42159
43987
|
if (statements.length > 1) {
|
|
42160
|
-
const plans = buildBatchExplainPlans(
|
|
43988
|
+
const plans = await buildBatchExplainPlans(
|
|
43989
|
+
explainSourceSql,
|
|
43990
|
+
explainClient,
|
|
43991
|
+
void 0,
|
|
43992
|
+
explainCacheContext,
|
|
43993
|
+
runtime?.maxRecords ?? input.maxRecords,
|
|
43994
|
+
runtime?.cursorMaxActive ?? input.cursorMaxActive ?? 2
|
|
43995
|
+
);
|
|
42161
43996
|
return {
|
|
42162
43997
|
ok: true,
|
|
42163
43998
|
batch: true,
|
|
@@ -42166,8 +44001,10 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42166
44001
|
appBindings
|
|
42167
44002
|
};
|
|
42168
44003
|
}
|
|
42169
|
-
const result = await executeSql(explainSql(
|
|
42170
|
-
cacheContext:
|
|
44004
|
+
const result = await executeSql(explainSql(explainSourceSql), explainClient, {
|
|
44005
|
+
cacheContext: explainCacheContext,
|
|
44006
|
+
maxRecords: runtime?.maxRecords ?? input.maxRecords,
|
|
44007
|
+
cursorMaxActive: runtime?.cursorMaxActive ?? input.cursorMaxActive ?? 2
|
|
42171
44008
|
});
|
|
42172
44009
|
if (result.type !== "SELECT") {
|
|
42173
44010
|
throw new Error(`ArgumentError: EXPLAIN returned unexpected result type ${result.type}.`);
|
|
@@ -42192,9 +44029,10 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42192
44029
|
profile: input.profile,
|
|
42193
44030
|
maxRecords: input.maxRecords,
|
|
42194
44031
|
fetchParallel: input.fetchParallel,
|
|
42195
|
-
onLimit: validation.
|
|
44032
|
+
onLimit: validation.containsValidationOnly ? "error" : input.onLimit,
|
|
42196
44033
|
timeout: input.timeout,
|
|
42197
|
-
tempTableMaxRows: input.tempTableMaxRows
|
|
44034
|
+
tempTableMaxRows: input.tempTableMaxRows,
|
|
44035
|
+
cursorMaxActive: input.cursorMaxActive
|
|
42198
44036
|
});
|
|
42199
44037
|
const batchResult = await executeBatchSql(runtime2.sql, runtime2.client, {
|
|
42200
44038
|
maxRecords: runtime2.maxRecords,
|
|
@@ -42209,6 +44047,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42209
44047
|
// runtime.timeout は env / profile / 既定 30000ms を解決済みの値で、
|
|
42210
44048
|
// HTTP クライアント側の per-request タイムアウトと同値になる
|
|
42211
44049
|
timeoutMs: runtime2.timeout,
|
|
44050
|
+
cursorMaxActive: runtime2.cursorMaxActive ?? input.cursorMaxActive ?? 2,
|
|
42212
44051
|
variables: input.variables
|
|
42213
44052
|
});
|
|
42214
44053
|
return { ...buildBatchEnvelope(batchResult, { maxTotalRecords: input.maxTotalRecords }) };
|
|
@@ -42237,14 +44076,16 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42237
44076
|
profile: input.profile,
|
|
42238
44077
|
maxRecords: input.maxRecords,
|
|
42239
44078
|
fetchParallel: input.fetchParallel,
|
|
42240
|
-
onLimit: validation.
|
|
42241
|
-
timeout: input.timeout
|
|
44079
|
+
onLimit: validation.containsValidationOnly ? "error" : input.onLimit,
|
|
44080
|
+
timeout: input.timeout,
|
|
44081
|
+
cursorMaxActive: input.cursorMaxActive
|
|
42242
44082
|
});
|
|
42243
44083
|
const result = await executeSql(runtime.sql, runtime.client, {
|
|
42244
44084
|
maxRecords: runtime.maxRecords,
|
|
42245
44085
|
fetchParallel: runtime.fetchParallel,
|
|
42246
44086
|
onLimitReached: runtime.onLimit,
|
|
42247
|
-
cacheContext: runtime.cacheContext
|
|
44087
|
+
cacheContext: runtime.cacheContext,
|
|
44088
|
+
cursorMaxActive: runtime.cursorMaxActive ?? input.cursorMaxActive ?? 2
|
|
42248
44089
|
});
|
|
42249
44090
|
if (result.type === "ASSERT") return toAssertPayload(result);
|
|
42250
44091
|
if (result.type === "VALIDATION") return toDmlValidationPayload(result);
|
|
@@ -42288,7 +44129,8 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42288
44129
|
fetchParallel: input.fetchParallel,
|
|
42289
44130
|
onLimit: DEFAULT_ON_LIMIT,
|
|
42290
44131
|
timeout: input.timeout,
|
|
42291
|
-
tempTableMaxRows: input.tempTableMaxRows
|
|
44132
|
+
tempTableMaxRows: input.tempTableMaxRows,
|
|
44133
|
+
cursorMaxActive: input.cursorMaxActive
|
|
42292
44134
|
});
|
|
42293
44135
|
let totalAffected = staticInsertTotal;
|
|
42294
44136
|
const batchResult = await executeBatchSql(runtime.sql, runtime.client, {
|
|
@@ -42300,6 +44142,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42300
44142
|
tempTableMaxRows: runtime.tempTableMaxRows,
|
|
42301
44143
|
// 合計タイムアウト(解決済みの runtime.timeout。per-request と同値)
|
|
42302
44144
|
timeoutMs: runtime.timeout,
|
|
44145
|
+
cursorMaxActive: runtime.cursorMaxActive ?? input.cursorMaxActive ?? 2,
|
|
42303
44146
|
variables: input.variables,
|
|
42304
44147
|
confirm: async (count, operation) => {
|
|
42305
44148
|
if (count > dmlMaxRows) {
|
|
@@ -42355,7 +44198,8 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42355
44198
|
maxRecords: resolveMutateRuntimeMaxRecords(validation.statements, dmlMaxRows),
|
|
42356
44199
|
fetchParallel: input.fetchParallel,
|
|
42357
44200
|
onLimit: DEFAULT_ON_LIMIT,
|
|
42358
|
-
timeout: input.timeout
|
|
44201
|
+
timeout: input.timeout,
|
|
44202
|
+
cursorMaxActive: input.cursorMaxActive
|
|
42359
44203
|
});
|
|
42360
44204
|
let result;
|
|
42361
44205
|
try {
|
|
@@ -42364,6 +44208,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42364
44208
|
fetchParallel: runtime.fetchParallel,
|
|
42365
44209
|
onLimitReached: runtime.onLimit,
|
|
42366
44210
|
cacheContext: runtime.cacheContext,
|
|
44211
|
+
cursorMaxActive: runtime.cursorMaxActive ?? input.cursorMaxActive ?? 2,
|
|
42367
44212
|
confirm: async (count, operation) => {
|
|
42368
44213
|
if (count > dmlMaxRows) {
|
|
42369
44214
|
throw new Error(`ArgumentError: ${operation} affected rows (${count}) exceed dmlMaxRows (${dmlMaxRows}).`);
|
|
@@ -42533,9 +44378,10 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42533
44378
|
var profile = external_exports.string().min(1).describe("kintone connection profile name from ksql.config.json (default: the server's default profile).").optional();
|
|
42534
44379
|
var maxRecords = external_exports.number().int().positive().describe("Maximum records fetched per SELECT (default 500).").optional();
|
|
42535
44380
|
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').
|
|
44381
|
+
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
44382
|
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
44383
|
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();
|
|
44384
|
+
var cursorMaxActive = external_exports.number().int().min(1).max(5).describe("Maximum active Cursor API handles per kintone host in this process (1-5, default 2). Later calls update the host limit; lowering it keeps existing cursors and delays new ones until active usage falls below the new limit. Create/Get are never automatically retried; capacity waits up to 30 seconds.").optional();
|
|
42539
44385
|
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).");
|
|
42540
44386
|
var savedQueryTags = external_exports.array(external_exports.string().min(1)).describe("Tags for organizing saved queries.").optional();
|
|
42541
44387
|
var validateInputSchema = external_exports.object({
|
|
@@ -42544,7 +44390,9 @@ var validateInputSchema = external_exports.object({
|
|
|
42544
44390
|
});
|
|
42545
44391
|
var explainInputSchema = external_exports.object({
|
|
42546
44392
|
sql: external_exports.string().min(1).describe("kSQL text to explain. May contain multiple ;-separated statements (batch) and temp tables (#name)."),
|
|
42547
|
-
profile
|
|
44393
|
+
profile,
|
|
44394
|
+
maxRecords,
|
|
44395
|
+
cursorMaxActive
|
|
42548
44396
|
});
|
|
42549
44397
|
var queryInputSchema = external_exports.object({
|
|
42550
44398
|
sql: external_exports.string().min(1).describe("Read-only kSQL text. May contain multiple ;-separated statements (batch) with temp tables, e.g. CREATE TEMP TABLE #t AS SELECT ...; SELECT ... FROM #t;"),
|
|
@@ -42554,6 +44402,7 @@ var queryInputSchema = external_exports.object({
|
|
|
42554
44402
|
onLimit,
|
|
42555
44403
|
tempTableMaxRows,
|
|
42556
44404
|
timeout,
|
|
44405
|
+
cursorMaxActive,
|
|
42557
44406
|
continueOnError: external_exports.boolean().describe("Batch (multi-statement) only: keep executing subsequent statements after a runtime error (default false = fail-fast).").optional(),
|
|
42558
44407
|
maxTotalRecords: external_exports.number().int().positive().describe("Batch (multi-statement) only: cap on total rows returned across all result sets (default: unlimited).").optional(),
|
|
42559
44408
|
variables: external_exports.record(external_exports.string(), external_exports.string()).describe("Batch only: string values for variables declared with DECLARE. Keys omit @ and are case-insensitive.").optional()
|
|
@@ -42567,6 +44416,7 @@ var mutateInputSchema = external_exports.object({
|
|
|
42567
44416
|
fetchParallel,
|
|
42568
44417
|
tempTableMaxRows,
|
|
42569
44418
|
timeout,
|
|
44419
|
+
cursorMaxActive,
|
|
42570
44420
|
dmlTotalMaxRows: external_exports.number().int().positive().describe("Batch (multi-statement) only: cap on total affected rows across the whole batch (default: per-statement dmlMaxRows only). DML batches always run fail-fast.").optional(),
|
|
42571
44421
|
variables: external_exports.record(external_exports.string(), external_exports.string()).describe("Batch only: string values for variables declared with DECLARE. Keys omit @ and are case-insensitive.").optional()
|
|
42572
44422
|
});
|
|
@@ -42657,7 +44507,7 @@ Options:
|
|
|
42657
44507
|
-h, --help Show help
|
|
42658
44508
|
`);
|
|
42659
44509
|
}
|
|
42660
|
-
var SERVER_VERSION = true ? "
|
|
44510
|
+
var SERVER_VERSION = true ? "3.1.0" : "0.0.0-dev";
|
|
42661
44511
|
function createServer(args) {
|
|
42662
44512
|
const server = new McpServer({
|
|
42663
44513
|
name: "ksql-mcp",
|
|
@@ -42674,12 +44524,12 @@ function createServer(args) {
|
|
|
42674
44524
|
}, tools.validateTool);
|
|
42675
44525
|
server.registerTool("ksql_explain", {
|
|
42676
44526
|
title: "Explain kSQL",
|
|
42677
|
-
description: "Return the kSQL execution plan
|
|
44527
|
+
description: "Return the schema-aware kSQL execution plan. Reads form metadata and, when needed, process status metadata; never reads or writes records.",
|
|
42678
44528
|
inputSchema: explainInputShape
|
|
42679
44529
|
}, tools.explainTool);
|
|
42680
44530
|
server.registerTool("ksql_query", {
|
|
42681
44531
|
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.
|
|
44532
|
+
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
44533
|
inputSchema: queryInputShape
|
|
42684
44534
|
}, tools.queryTool);
|
|
42685
44535
|
server.registerTool("ksql_mutate", {
|