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