@rex0220/kintone-sql-tools 2.16.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 +1689 -299
- package/dist-mcp/ksql-mcp.js +1678 -273
- 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 */],
|
|
@@ -31035,6 +31036,11 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31035
31036
|
["COALESCE", "COALESCE" /* COALESCE */],
|
|
31036
31037
|
["NULLIF", "NULLIF" /* NULLIF */],
|
|
31037
31038
|
["ISNULL", "ISNULL" /* ISNULL */],
|
|
31039
|
+
["INSTR", "INSTR" /* INSTR */],
|
|
31040
|
+
["GREATEST", "GREATEST" /* GREATEST */],
|
|
31041
|
+
["LEAST", "LEAST" /* LEAST */],
|
|
31042
|
+
["LPAD", "LPAD" /* LPAD */],
|
|
31043
|
+
["RPAD", "RPAD" /* RPAD */],
|
|
31038
31044
|
["CAST", "CAST" /* CAST */],
|
|
31039
31045
|
["CONVERT", "CONVERT" /* CONVERT */],
|
|
31040
31046
|
["FORMAT", "FORMAT" /* FORMAT */],
|
|
@@ -31042,6 +31048,8 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31042
31048
|
["FLOOR", "FLOOR" /* FLOOR */],
|
|
31043
31049
|
["CEIL", "CEIL" /* CEIL */],
|
|
31044
31050
|
["CEILING", "CEILING" /* CEILING */],
|
|
31051
|
+
["TRUNCATE", "TRUNCATE" /* TRUNCATE */],
|
|
31052
|
+
["TRUNC", "TRUNC" /* TRUNC */],
|
|
31045
31053
|
["ABS", "ABS" /* ABS */],
|
|
31046
31054
|
["MOD", "MOD" /* MOD */],
|
|
31047
31055
|
["POWER", "POWER" /* POWER */],
|
|
@@ -31053,6 +31061,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31053
31061
|
["DATE_FORMAT", "DATE_FORMAT" /* DATE_FORMAT */],
|
|
31054
31062
|
["DATEDIFF", "DATEDIFF" /* DATEDIFF */],
|
|
31055
31063
|
["DATE_ADD", "DATE_ADD" /* DATE_ADD */],
|
|
31064
|
+
["LAST_DAY", "LAST_DAY" /* LAST_DAY */],
|
|
31056
31065
|
["IF", "IF" /* IF */]
|
|
31057
31066
|
]);
|
|
31058
31067
|
|
|
@@ -31398,6 +31407,13 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
|
|
|
31398
31407
|
"COALESCE" /* COALESCE */,
|
|
31399
31408
|
"NULLIF" /* NULLIF */,
|
|
31400
31409
|
"ISNULL" /* ISNULL */,
|
|
31410
|
+
"LEFT" /* LEFT */,
|
|
31411
|
+
"RIGHT" /* RIGHT */,
|
|
31412
|
+
"INSTR" /* INSTR */,
|
|
31413
|
+
"GREATEST" /* GREATEST */,
|
|
31414
|
+
"LEAST" /* LEAST */,
|
|
31415
|
+
"LPAD" /* LPAD */,
|
|
31416
|
+
"RPAD" /* RPAD */,
|
|
31401
31417
|
"CAST" /* CAST */,
|
|
31402
31418
|
"CONVERT" /* CONVERT */,
|
|
31403
31419
|
"FORMAT" /* FORMAT */,
|
|
@@ -31405,6 +31421,8 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
|
|
|
31405
31421
|
"FLOOR" /* FLOOR */,
|
|
31406
31422
|
"CEIL" /* CEIL */,
|
|
31407
31423
|
"CEILING" /* CEILING */,
|
|
31424
|
+
"TRUNCATE" /* TRUNCATE */,
|
|
31425
|
+
"TRUNC" /* TRUNC */,
|
|
31408
31426
|
"ABS" /* ABS */,
|
|
31409
31427
|
"MOD" /* MOD */,
|
|
31410
31428
|
"POWER" /* POWER */,
|
|
@@ -31416,6 +31434,7 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
|
|
|
31416
31434
|
"DATE_FORMAT" /* DATE_FORMAT */,
|
|
31417
31435
|
"DATEDIFF" /* DATEDIFF */,
|
|
31418
31436
|
"DATE_ADD" /* DATE_ADD */,
|
|
31437
|
+
"LAST_DAY" /* LAST_DAY */,
|
|
31419
31438
|
"IF" /* IF */
|
|
31420
31439
|
]);
|
|
31421
31440
|
function needsSpaceBetween(prev, cur) {
|
|
@@ -31497,7 +31516,7 @@ var Parser = class {
|
|
|
31497
31516
|
case "WITH" /* WITH */:
|
|
31498
31517
|
return this.parseWith();
|
|
31499
31518
|
case "SELECT" /* SELECT */:
|
|
31500
|
-
return this.tryParseUnionChain(this.parseSelect());
|
|
31519
|
+
return this.tryParseUnionChain(this.parseSelect(true));
|
|
31501
31520
|
case "INSERT" /* INSERT */:
|
|
31502
31521
|
return this.parseInsert();
|
|
31503
31522
|
case "UPDATE" /* UPDATE */:
|
|
@@ -31687,7 +31706,7 @@ var Parser = class {
|
|
|
31687
31706
|
}
|
|
31688
31707
|
query = w;
|
|
31689
31708
|
} else if (tok.kind === "SELECT" /* SELECT */) {
|
|
31690
|
-
const sel = this.parseSelect();
|
|
31709
|
+
const sel = this.parseSelect(true);
|
|
31691
31710
|
const chained = this.tryParseUnionChain(sel);
|
|
31692
31711
|
query = chained;
|
|
31693
31712
|
} else if (tok.kind === "INSERT" /* INSERT */) {
|
|
@@ -31880,7 +31899,7 @@ var Parser = class {
|
|
|
31880
31899
|
// ----------------------------------------------------------
|
|
31881
31900
|
// SELECT
|
|
31882
31901
|
// ----------------------------------------------------------
|
|
31883
|
-
parseSelect() {
|
|
31902
|
+
parseSelect(allowKorder = false) {
|
|
31884
31903
|
this.expect("SELECT" /* SELECT */);
|
|
31885
31904
|
const distinct = this.consume("DISTINCT" /* DISTINCT */);
|
|
31886
31905
|
const columns = this.parseSelectColumns();
|
|
@@ -31897,7 +31916,19 @@ var Parser = class {
|
|
|
31897
31916
|
having = this.parseWhereExpr();
|
|
31898
31917
|
}
|
|
31899
31918
|
}
|
|
31900
|
-
|
|
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
|
+
}
|
|
31901
31932
|
const limit = this.consume("LIMIT" /* LIMIT */) ? this.parseUnsignedInt() : null;
|
|
31902
31933
|
const offset = this.consume("OFFSET" /* OFFSET */) ? this.parseUnsignedInt() : null;
|
|
31903
31934
|
const hasWindow = columns.some((column) => column.type === "WINDOW_COL");
|
|
@@ -31914,6 +31945,7 @@ var Parser = class {
|
|
|
31914
31945
|
where,
|
|
31915
31946
|
groupBy,
|
|
31916
31947
|
having,
|
|
31948
|
+
orderMode,
|
|
31917
31949
|
orderBy,
|
|
31918
31950
|
limit,
|
|
31919
31951
|
offset
|
|
@@ -31951,6 +31983,9 @@ var Parser = class {
|
|
|
31951
31983
|
// ----------------------------------------------------------
|
|
31952
31984
|
tryParseUnionChain(left) {
|
|
31953
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
|
+
}
|
|
31954
31989
|
this.advance();
|
|
31955
31990
|
const all = this.consume("ALL" /* ALL */);
|
|
31956
31991
|
const right = this.parseSelect();
|
|
@@ -32288,6 +32323,10 @@ var Parser = class {
|
|
|
32288
32323
|
// arg: 文字列リテラル / 算術式(フィールド参照・数値含む)/ ネスト文字列関数
|
|
32289
32324
|
// ──────────────────────────────────────────────────
|
|
32290
32325
|
tryStringFuncName() {
|
|
32326
|
+
if (this.peekAt(1).kind === "(" /* LPAREN */) {
|
|
32327
|
+
if (this.peek().kind === "LEFT" /* LEFT */) return "LEFT";
|
|
32328
|
+
if (this.peek().kind === "RIGHT" /* RIGHT */) return "RIGHT";
|
|
32329
|
+
}
|
|
32291
32330
|
const map2 = {
|
|
32292
32331
|
["UPPER" /* UPPER */]: "UPPER",
|
|
32293
32332
|
["LOWER" /* LOWER */]: "LOWER",
|
|
@@ -32302,6 +32341,11 @@ var Parser = class {
|
|
|
32302
32341
|
["COALESCE" /* COALESCE */]: "COALESCE",
|
|
32303
32342
|
["NULLIF" /* NULLIF */]: "NULLIF",
|
|
32304
32343
|
["ISNULL" /* ISNULL */]: "ISNULL",
|
|
32344
|
+
["INSTR" /* INSTR */]: "INSTR",
|
|
32345
|
+
["GREATEST" /* GREATEST */]: "GREATEST",
|
|
32346
|
+
["LEAST" /* LEAST */]: "LEAST",
|
|
32347
|
+
["LPAD" /* LPAD */]: "LPAD",
|
|
32348
|
+
["RPAD" /* RPAD */]: "RPAD",
|
|
32305
32349
|
["CAST" /* CAST */]: "CAST",
|
|
32306
32350
|
["CONVERT" /* CONVERT */]: "CAST",
|
|
32307
32351
|
// CONVERT → CAST に正規化
|
|
@@ -32311,12 +32355,16 @@ var Parser = class {
|
|
|
32311
32355
|
["CEIL" /* CEIL */]: "CEIL",
|
|
32312
32356
|
["CEILING" /* CEILING */]: "CEIL",
|
|
32313
32357
|
// CEILING → CEIL に正規化
|
|
32358
|
+
["TRUNCATE" /* TRUNCATE */]: "TRUNCATE",
|
|
32359
|
+
["TRUNC" /* TRUNC */]: "TRUNCATE",
|
|
32360
|
+
// TRUNC → TRUNCATE に正規化
|
|
32314
32361
|
["YEAR" /* YEAR */]: "YEAR",
|
|
32315
32362
|
["MONTH" /* MONTH */]: "MONTH",
|
|
32316
32363
|
["DAY" /* DAY */]: "DAY",
|
|
32317
32364
|
["DATE_FORMAT" /* DATE_FORMAT */]: "DATE_FORMAT",
|
|
32318
32365
|
["DATEDIFF" /* DATEDIFF */]: "DATEDIFF",
|
|
32319
32366
|
["DATE_ADD" /* DATE_ADD */]: "DATE_ADD",
|
|
32367
|
+
["LAST_DAY" /* LAST_DAY */]: "LAST_DAY",
|
|
32320
32368
|
["ABS" /* ABS */]: "ABS",
|
|
32321
32369
|
["MOD" /* MOD */]: "MOD",
|
|
32322
32370
|
["POWER" /* POWER */]: "POWER",
|
|
@@ -33591,7 +33639,50 @@ function isReadOnlyStatement(stmt) {
|
|
|
33591
33639
|
return !writesKintone(stmt) && (isReadOnlyType(stmt.type) || isDmlType(stmt.type));
|
|
33592
33640
|
}
|
|
33593
33641
|
function requiresCompleteInput(stmt) {
|
|
33594
|
-
|
|
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
|
+
}
|
|
33595
33686
|
}
|
|
33596
33687
|
function hasWhereClause(stmt) {
|
|
33597
33688
|
if (!stmt || typeof stmt !== "object") return false;
|
|
@@ -34394,6 +34485,7 @@ function buildInlinedQuery(stmt) {
|
|
|
34394
34485
|
where,
|
|
34395
34486
|
groupBy: [],
|
|
34396
34487
|
having: null,
|
|
34488
|
+
orderMode: "CANONICAL",
|
|
34397
34489
|
orderBy: final.orderBy.length > 0 ? final.orderBy : cteBody.orderBy,
|
|
34398
34490
|
limit: final.limit ?? cteBody.limit,
|
|
34399
34491
|
offset: final.offset ?? cteBody.offset,
|
|
@@ -34988,6 +35080,72 @@ function analyzeBatch(statements) {
|
|
|
34988
35080
|
};
|
|
34989
35081
|
}
|
|
34990
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
|
+
|
|
34991
35149
|
// src/core/batchVariables.ts
|
|
34992
35150
|
var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
34993
35151
|
function normalizeBatchVariableName(name) {
|
|
@@ -35023,26 +35181,197 @@ function validateDeclaredBatchVariables(statements, input) {
|
|
|
35023
35181
|
}
|
|
35024
35182
|
|
|
35025
35183
|
// src/core/scalarCompare.ts
|
|
35026
|
-
function
|
|
35027
|
-
|
|
35028
|
-
|
|
35029
|
-
|
|
35030
|
-
|
|
35031
|
-
|
|
35032
|
-
|
|
35033
|
-
|
|
35034
|
-
|
|
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);
|
|
35035
35293
|
switch (op) {
|
|
35294
|
+
case "=":
|
|
35295
|
+
return cmp === 0;
|
|
35296
|
+
case "!=":
|
|
35297
|
+
case "<>":
|
|
35298
|
+
return cmp !== 0;
|
|
35036
35299
|
case ">":
|
|
35037
|
-
return
|
|
35300
|
+
return cmp > 0;
|
|
35038
35301
|
case "<":
|
|
35039
|
-
return
|
|
35302
|
+
return cmp < 0;
|
|
35040
35303
|
case ">=":
|
|
35041
|
-
return
|
|
35304
|
+
return cmp >= 0;
|
|
35042
35305
|
case "<=":
|
|
35043
|
-
return
|
|
35306
|
+
return cmp <= 0;
|
|
35044
35307
|
}
|
|
35045
35308
|
}
|
|
35309
|
+
function selectScalarExtreme(values, extreme) {
|
|
35310
|
+
if (extreme === "least" && values.includes("")) return "";
|
|
35311
|
+
const candidates = extreme === "greatest" ? values.filter((value) => value !== "") : [...values];
|
|
35312
|
+
if (candidates.length === 0) return "";
|
|
35313
|
+
const numeric = candidates.every((value) => !Number.isNaN(Number(value)));
|
|
35314
|
+
const compare = (left, right) => {
|
|
35315
|
+
if (numeric) {
|
|
35316
|
+
const numericCmp = triCompare(Number(left), Number(right));
|
|
35317
|
+
if (numericCmp !== 0) return numericCmp;
|
|
35318
|
+
}
|
|
35319
|
+
return compareCodePointStrings(left, right);
|
|
35320
|
+
};
|
|
35321
|
+
return candidates.reduce((best, candidate) => {
|
|
35322
|
+
const cmp = compare(candidate, best);
|
|
35323
|
+
return extreme === "greatest" ? cmp > 0 ? candidate : best : cmp < 0 ? candidate : best;
|
|
35324
|
+
});
|
|
35325
|
+
}
|
|
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
|
+
}
|
|
35046
35375
|
|
|
35047
35376
|
// src/engine/evalFunc.ts
|
|
35048
35377
|
function evalArithExpr(expr, row) {
|
|
@@ -35091,6 +35420,36 @@ function evalStringFunc(expr, row) {
|
|
|
35091
35420
|
const len = args[2] !== void 0 ? Number(args[2]) : void 0;
|
|
35092
35421
|
return len !== void 0 ? str.slice(start, start + len) : str.slice(start);
|
|
35093
35422
|
}
|
|
35423
|
+
case "LEFT": {
|
|
35424
|
+
assertArity("LEFT", args, 2, 2);
|
|
35425
|
+
const str = args[0];
|
|
35426
|
+
const n = Math.trunc(Number(args[1]));
|
|
35427
|
+
return Number.isNaN(n) || n <= 0 ? "" : str.slice(0, n);
|
|
35428
|
+
}
|
|
35429
|
+
case "RIGHT": {
|
|
35430
|
+
assertArity("RIGHT", args, 2, 2);
|
|
35431
|
+
const str = args[0];
|
|
35432
|
+
const n = Math.trunc(Number(args[1]));
|
|
35433
|
+
return Number.isNaN(n) || n <= 0 ? "" : str.slice(Math.max(0, str.length - n));
|
|
35434
|
+
}
|
|
35435
|
+
case "INSTR":
|
|
35436
|
+
assertArity("INSTR", args, 2, 2);
|
|
35437
|
+
return String(args[0].indexOf(args[1]) + 1);
|
|
35438
|
+
case "LPAD":
|
|
35439
|
+
case "RPAD": {
|
|
35440
|
+
assertArity(expr.func, args, 2, 3);
|
|
35441
|
+
const str = args[0];
|
|
35442
|
+
const n = Math.trunc(Number(args[1]));
|
|
35443
|
+
if (Number.isNaN(n) || n <= 0) return "";
|
|
35444
|
+
if (str.length >= n) return str.slice(0, n);
|
|
35445
|
+
const pad = args[2] ?? " ";
|
|
35446
|
+
if (pad === "") return str;
|
|
35447
|
+
return expr.func === "LPAD" ? str.padStart(n, pad) : str.padEnd(n, pad);
|
|
35448
|
+
}
|
|
35449
|
+
case "GREATEST":
|
|
35450
|
+
case "LEAST":
|
|
35451
|
+
assertArity(expr.func, args, 2);
|
|
35452
|
+
return selectScalarExtreme(args, expr.func === "GREATEST" ? "greatest" : "least");
|
|
35094
35453
|
case "CONCAT":
|
|
35095
35454
|
return args.join("");
|
|
35096
35455
|
case "REPLACE": {
|
|
@@ -35111,6 +35470,9 @@ function evalStringFunc(expr, row) {
|
|
|
35111
35470
|
return applyRoundOp("floor", Number(args[0] ?? "0"), Number(args[1] ?? "0"));
|
|
35112
35471
|
case "CEIL":
|
|
35113
35472
|
return applyRoundOp("ceil", Number(args[0] ?? "0"), Number(args[1] ?? "0"));
|
|
35473
|
+
case "TRUNCATE":
|
|
35474
|
+
assertArity("TRUNCATE", args, 1, 2);
|
|
35475
|
+
return applyRoundOp("trunc", Number(args[0]), Number(args[1] ?? "0"));
|
|
35114
35476
|
case "CAST": {
|
|
35115
35477
|
const val = args[0] ?? "";
|
|
35116
35478
|
const castType = args[1] ?? "TEXT";
|
|
@@ -35143,6 +35505,9 @@ function evalStringFunc(expr, row) {
|
|
|
35143
35505
|
return applyDateDiff(args[0] ?? "", args[1] ?? "");
|
|
35144
35506
|
case "DATE_ADD":
|
|
35145
35507
|
return applyDateAdd(args[0] ?? "", Number(args[1] ?? "0"), (args[2] ?? "DAY").toUpperCase());
|
|
35508
|
+
case "LAST_DAY":
|
|
35509
|
+
assertArity("LAST_DAY", args, 1, 1);
|
|
35510
|
+
return applyLastDay(args[0]);
|
|
35146
35511
|
case "ABS":
|
|
35147
35512
|
return String(Math.abs(Number(args[0] ?? "0")));
|
|
35148
35513
|
case "MOD": {
|
|
@@ -35165,6 +35530,11 @@ function evalStringFunc(expr, row) {
|
|
|
35165
35530
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
35166
35531
|
}
|
|
35167
35532
|
}
|
|
35533
|
+
function assertArity(func, args, min, max = Number.POSITIVE_INFINITY) {
|
|
35534
|
+
if (args.length >= min && args.length <= max) return;
|
|
35535
|
+
const expected = min === max ? String(min) : max === Number.POSITIVE_INFINITY ? `${min} or more` : `${min} to ${max}`;
|
|
35536
|
+
throw new Error(`ArgumentError: ${func} expects ${expected} argument(s).`);
|
|
35537
|
+
}
|
|
35168
35538
|
function parseDateParts(s) {
|
|
35169
35539
|
return {
|
|
35170
35540
|
y: s.slice(0, 4) || "0000",
|
|
@@ -35189,6 +35559,9 @@ function applyDateDiff(date1, date22) {
|
|
|
35189
35559
|
return String(Math.round((d1 - d2) / 864e5));
|
|
35190
35560
|
}
|
|
35191
35561
|
function applyDateAdd(dateStr, n, unit) {
|
|
35562
|
+
if (unit !== "YEAR" && unit !== "MONTH" && unit !== "DAY") {
|
|
35563
|
+
throw new Error("ArgumentError: DATE_ADD unit must be YEAR, MONTH, or DAY.");
|
|
35564
|
+
}
|
|
35192
35565
|
if (!dateStr || dateStr.length < 10) return dateStr;
|
|
35193
35566
|
const { y, mo, d } = parseDateParts(dateStr);
|
|
35194
35567
|
const dt = new Date(Date.UTC(+y, +mo - 1, +d));
|
|
@@ -35199,7 +35572,7 @@ function applyDateAdd(dateStr, n, unit) {
|
|
|
35199
35572
|
case "MONTH":
|
|
35200
35573
|
dt.setUTCMonth(dt.getUTCMonth() + n);
|
|
35201
35574
|
break;
|
|
35202
|
-
|
|
35575
|
+
case "DAY":
|
|
35203
35576
|
dt.setUTCDate(dt.getUTCDate() + n);
|
|
35204
35577
|
break;
|
|
35205
35578
|
}
|
|
@@ -35208,6 +35581,15 @@ function applyDateAdd(dateStr, n, unit) {
|
|
|
35208
35581
|
const rd = String(dt.getUTCDate()).padStart(2, "0");
|
|
35209
35582
|
return `${ry}-${rmo}-${rd}`;
|
|
35210
35583
|
}
|
|
35584
|
+
function applyLastDay(dateStr) {
|
|
35585
|
+
if (!dateStr || dateStr.length < 10) return dateStr;
|
|
35586
|
+
const { y, mo } = parseDateParts(dateStr);
|
|
35587
|
+
const dt = new Date(Date.UTC(+y, +mo, 0));
|
|
35588
|
+
const ry = String(dt.getUTCFullYear()).padStart(4, "0");
|
|
35589
|
+
const rmo = String(dt.getUTCMonth() + 1).padStart(2, "0");
|
|
35590
|
+
const rd = String(dt.getUTCDate()).padStart(2, "0");
|
|
35591
|
+
return `${ry}-${rmo}-${rd}`;
|
|
35592
|
+
}
|
|
35211
35593
|
function applyFormat(num, pattern) {
|
|
35212
35594
|
if (/^-?\d+$/.test(pattern.trim())) {
|
|
35213
35595
|
return formatWithComma(num, Math.max(0, Number(pattern)));
|
|
@@ -35255,34 +35637,35 @@ function resolveFieldRef(row, field) {
|
|
|
35255
35637
|
}
|
|
35256
35638
|
|
|
35257
35639
|
// src/engine/evalWhere.ts
|
|
35258
|
-
function evalWhere(expr, row, resolveFieldType, appliedKlikes) {
|
|
35640
|
+
function evalWhere(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
|
|
35259
35641
|
switch (expr.type) {
|
|
35260
35642
|
case "BINARY":
|
|
35261
|
-
return evalBinary(expr, row, resolveFieldType, appliedKlikes);
|
|
35643
|
+
return evalBinary(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
|
|
35262
35644
|
case "NULL_CHECK":
|
|
35263
35645
|
return evalNullCheck(expr, row);
|
|
35264
35646
|
case "LOGICAL":
|
|
35265
|
-
return evalLogical(expr, row, resolveFieldType, appliedKlikes);
|
|
35647
|
+
return evalLogical(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
|
|
35266
35648
|
case "NOT":
|
|
35267
|
-
return !evalWhere(expr.expr, row, resolveFieldType, appliedKlikes);
|
|
35649
|
+
return !evalWhere(expr.expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
|
|
35268
35650
|
case "GROUP":
|
|
35269
|
-
return evalWhere(expr.expr, row, resolveFieldType, appliedKlikes);
|
|
35651
|
+
return evalWhere(expr.expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2);
|
|
35270
35652
|
case "EXISTS": {
|
|
35271
35653
|
const exists = expr.resolved;
|
|
35272
35654
|
return expr.not ? !exists : exists;
|
|
35273
35655
|
}
|
|
35274
35656
|
}
|
|
35275
35657
|
}
|
|
35276
|
-
function evalBinary(expr, row, resolveFieldType, appliedKlikes) {
|
|
35658
|
+
function evalBinary(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
|
|
35277
35659
|
if (expr.op === "KLIKE" || expr.op === "NOT_KLIKE") {
|
|
35278
35660
|
if (appliedKlikes?.has(expr)) return true;
|
|
35279
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");
|
|
35280
35662
|
}
|
|
35281
|
-
const left = resolveField(expr.left, row, resolveFieldType);
|
|
35663
|
+
const left = resolveField(expr.left, row, resolveFieldType, resolveFieldSemantics2);
|
|
35282
35664
|
const fieldType = expr.left.type === "FIELD" ? resolveFieldType?.(expr.left) : void 0;
|
|
35283
|
-
|
|
35665
|
+
const semantics = semanticsForLeft(expr.left, fieldType, resolveFieldSemantics2);
|
|
35666
|
+
return evalOp(expr.op, left, expr.right, row, fieldType, resolveFieldType, semantics, resolveFieldSemantics2);
|
|
35284
35667
|
}
|
|
35285
|
-
function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
|
|
35668
|
+
function evalOp(op, leftStr, right, row, fieldType, resolveFieldType, semantics = syntheticSemantics("string"), resolveFieldSemantics2) {
|
|
35286
35669
|
if (op === "IN" || op === "NOT_IN") {
|
|
35287
35670
|
let values = null;
|
|
35288
35671
|
if (right.type === "IN_LIST") {
|
|
@@ -35307,8 +35690,53 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
|
|
|
35307
35690
|
if (op === "KLIKE" || op === "NOT_KLIKE") {
|
|
35308
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");
|
|
35309
35692
|
}
|
|
35310
|
-
const rightStr = resolveValue(right, row, resolveFieldType);
|
|
35311
|
-
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");
|
|
35312
35740
|
}
|
|
35313
35741
|
var STRING_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
|
|
35314
35742
|
var OBJECT_ARRAY_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -35359,20 +35787,20 @@ function evalNullCheck(expr, row) {
|
|
|
35359
35787
|
const val = resolveField(expr.field, row);
|
|
35360
35788
|
return expr.not ? val !== "" : val === "";
|
|
35361
35789
|
}
|
|
35362
|
-
function evalLogical(expr, row, resolveFieldType, appliedKlikes) {
|
|
35790
|
+
function evalLogical(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
|
|
35363
35791
|
if (expr.op === "AND") {
|
|
35364
|
-
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);
|
|
35365
35793
|
}
|
|
35366
|
-
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);
|
|
35367
35795
|
}
|
|
35368
|
-
function resolveField(field, row, resolveFieldType) {
|
|
35796
|
+
function resolveField(field, row, resolveFieldType, resolveFieldSemantics2) {
|
|
35369
35797
|
if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
|
|
35370
35798
|
if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
|
|
35371
|
-
if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType);
|
|
35799
|
+
if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType, resolveFieldSemantics2);
|
|
35372
35800
|
const key = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
|
|
35373
35801
|
return resolveFieldRef(row, key);
|
|
35374
35802
|
}
|
|
35375
|
-
function resolveValue(value, row, resolveFieldType) {
|
|
35803
|
+
function resolveValue(value, row, resolveFieldType, resolveFieldSemantics2) {
|
|
35376
35804
|
switch (value.type) {
|
|
35377
35805
|
case "VARIABLE":
|
|
35378
35806
|
throw new Error(`ParseError: unresolved batch variable @${value.name}.`);
|
|
@@ -35395,14 +35823,14 @@ function resolveValue(value, row, resolveFieldType) {
|
|
|
35395
35823
|
if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
|
|
35396
35824
|
return String(evalArithExpr(value.expr, row));
|
|
35397
35825
|
case "CASE_VALUE":
|
|
35398
|
-
return evalCaseWhen(value.expr, row, resolveFieldType);
|
|
35826
|
+
return evalCaseWhen(value.expr, row, resolveFieldType, resolveFieldSemantics2);
|
|
35399
35827
|
case "ARRAY":
|
|
35400
35828
|
return value.elements.map((e) => e.value).join(",");
|
|
35401
35829
|
}
|
|
35402
35830
|
}
|
|
35403
|
-
function evalCaseWhen(expr, row, resolveFieldType) {
|
|
35831
|
+
function evalCaseWhen(expr, row, resolveFieldType, resolveFieldSemantics2) {
|
|
35404
35832
|
for (const branch of expr.branches) {
|
|
35405
|
-
if (evalWhere(branch.condition, row, resolveFieldType)) {
|
|
35833
|
+
if (evalWhere(branch.condition, row, resolveFieldType, void 0, resolveFieldSemantics2)) {
|
|
35406
35834
|
return evalCaseResult(branch.result, row);
|
|
35407
35835
|
}
|
|
35408
35836
|
}
|
|
@@ -36033,6 +36461,141 @@ async function resolveDmlTargetIds(getRecords, app, query, options) {
|
|
|
36033
36461
|
};
|
|
36034
36462
|
}
|
|
36035
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
|
+
|
|
36036
36599
|
// src/engine/process.ts
|
|
36037
36600
|
function flatten(record2, alias) {
|
|
36038
36601
|
const row = {};
|
|
@@ -36097,9 +36660,9 @@ function applyJoin(leftRows, rightRows, join) {
|
|
|
36097
36660
|
}
|
|
36098
36661
|
return result;
|
|
36099
36662
|
}
|
|
36100
|
-
function applyFilter(rows, where, resolveFieldType, appliedKlikes) {
|
|
36663
|
+
function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
|
|
36101
36664
|
if (where === null) return rows;
|
|
36102
|
-
return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes));
|
|
36665
|
+
return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2));
|
|
36103
36666
|
}
|
|
36104
36667
|
function hasAggregateColumns(columns) {
|
|
36105
36668
|
return columns.some(
|
|
@@ -36160,7 +36723,7 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
36160
36723
|
let strVal;
|
|
36161
36724
|
if (arg.type === "FIELD_REF") {
|
|
36162
36725
|
const raw = row[arg.field];
|
|
36163
|
-
if (raw === void 0 || raw === "") continue;
|
|
36726
|
+
if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") continue;
|
|
36164
36727
|
strVal = raw;
|
|
36165
36728
|
} else {
|
|
36166
36729
|
const n = evalArithExpr(arg, row);
|
|
@@ -36172,10 +36735,16 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
36172
36735
|
const eff = distinct ? [...new Set(strValues)] : strValues;
|
|
36173
36736
|
if (func === "COUNT") return eff.length;
|
|
36174
36737
|
if (func === "GROUP_CONCAT") return eff.join(separator ?? ",");
|
|
36175
|
-
const
|
|
36176
|
-
if (
|
|
36177
|
-
if (eff.length === 0) return
|
|
36178
|
-
|
|
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;
|
|
36179
36748
|
}
|
|
36180
36749
|
const nums = eff.map(Number);
|
|
36181
36750
|
switch (func) {
|
|
@@ -36183,37 +36752,12 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
36183
36752
|
return nums.reduce((a, b) => a + b, 0);
|
|
36184
36753
|
case "AVG":
|
|
36185
36754
|
return nums.length === 0 ? 0 : nums.reduce((a, b) => a + b, 0) / nums.length;
|
|
36186
|
-
// Math.max(...nums) は要素数が多いと RangeError になるためループで求める
|
|
36187
|
-
case "MAX":
|
|
36188
|
-
return nums.length === 0 ? 0 : maxOf(nums);
|
|
36189
|
-
case "MIN":
|
|
36190
|
-
return nums.length === 0 ? 0 : minOf(nums);
|
|
36191
36755
|
}
|
|
36192
36756
|
}
|
|
36193
36757
|
function toAggregateFieldRef(field) {
|
|
36194
36758
|
const dot = field.indexOf(".");
|
|
36195
36759
|
return dot > 0 ? { type: "FIELD", tableAlias: field.slice(0, dot), field: field.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field };
|
|
36196
36760
|
}
|
|
36197
|
-
function maxStringOf(values) {
|
|
36198
|
-
let value = values[0];
|
|
36199
|
-
for (const candidate of values) if (candidate > value) value = candidate;
|
|
36200
|
-
return value;
|
|
36201
|
-
}
|
|
36202
|
-
function minStringOf(values) {
|
|
36203
|
-
let value = values[0];
|
|
36204
|
-
for (const candidate of values) if (candidate < value) value = candidate;
|
|
36205
|
-
return value;
|
|
36206
|
-
}
|
|
36207
|
-
function maxOf(nums) {
|
|
36208
|
-
let m = nums[0];
|
|
36209
|
-
for (const n of nums) if (n > m) m = n;
|
|
36210
|
-
return m;
|
|
36211
|
-
}
|
|
36212
|
-
function minOf(nums) {
|
|
36213
|
-
let m = nums[0];
|
|
36214
|
-
for (const n of nums) if (n < m) m = n;
|
|
36215
|
-
return m;
|
|
36216
|
-
}
|
|
36217
36761
|
function evalAggArithExpr(node, rows, resolveAggSortKind) {
|
|
36218
36762
|
if (node.type === "NUMBER") return node.value;
|
|
36219
36763
|
if (node.type === "AGG_REF") return Number(evalAggregate(node.func, node.distinct, node.arg, node.separator, rows, resolveAggSortKind));
|
|
@@ -36245,9 +36789,9 @@ function aggregateSyntheticName2(func, distinct, arg) {
|
|
|
36245
36789
|
const argStr = aggregateArgLabel(arg);
|
|
36246
36790
|
return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
|
|
36247
36791
|
}
|
|
36248
|
-
function applyHaving(rows, having, resolveFieldType) {
|
|
36792
|
+
function applyHaving(rows, having, resolveFieldType, resolveFieldSemantics2) {
|
|
36249
36793
|
if (having === null) return rows;
|
|
36250
|
-
return rows.filter((row) => evalWhere(having, row, resolveFieldType));
|
|
36794
|
+
return rows.filter((row) => evalWhere(having, row, resolveFieldType, void 0, resolveFieldSemantics2));
|
|
36251
36795
|
}
|
|
36252
36796
|
function applyDistinct(rows, columns) {
|
|
36253
36797
|
if (rows.length === 0) return rows;
|
|
@@ -36299,27 +36843,37 @@ function buildDistinctKeyBuilder(rows, columns) {
|
|
|
36299
36843
|
return JSON.stringify(values);
|
|
36300
36844
|
};
|
|
36301
36845
|
}
|
|
36302
|
-
function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
|
|
36846
|
+
function applyOrderBy(rows, orderBy, optionOrders, sortKinds, fieldSemantics2) {
|
|
36303
36847
|
if (orderBy.length === 0) return rows;
|
|
36304
|
-
return sortDecoratedRows(rows, orderBy, optionOrders, sortKinds).rows.map((item) => item.row);
|
|
36305
|
-
}
|
|
36306
|
-
function sortDecoratedRows(rows, orderBy, optionOrders, sortKinds) {
|
|
36307
|
-
const keyMeta = orderBy.map(({ key }) =>
|
|
36308
|
-
|
|
36309
|
-
|
|
36310
|
-
|
|
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
|
+
});
|
|
36311
36872
|
const decorated = rows.map((row) => ({
|
|
36312
36873
|
row,
|
|
36313
36874
|
keys: orderBy.map(({ key }, i) => {
|
|
36314
36875
|
const s = evalOrderKey(key, row);
|
|
36315
|
-
|
|
36316
|
-
const orderMap = keyMeta[i].orderMap;
|
|
36317
|
-
return {
|
|
36318
|
-
s,
|
|
36319
|
-
n,
|
|
36320
|
-
isNum: !Number.isNaN(n),
|
|
36321
|
-
rank: orderMap ? minChoiceIndex(parseChoiceValues(s), orderMap) : 0
|
|
36322
|
-
};
|
|
36876
|
+
return { s };
|
|
36323
36877
|
})
|
|
36324
36878
|
}));
|
|
36325
36879
|
const compare = (a, b) => compareDecoratedRows(a, b, orderBy, keyMeta);
|
|
@@ -36334,15 +36888,24 @@ function compareDecoratedRows(a, b, orderBy, keyMeta) {
|
|
|
36334
36888
|
return 0;
|
|
36335
36889
|
}
|
|
36336
36890
|
function compareSortKeys(a, b, meta3) {
|
|
36337
|
-
|
|
36338
|
-
|
|
36339
|
-
|
|
36340
|
-
|
|
36341
|
-
|
|
36342
|
-
|
|
36343
|
-
|
|
36344
|
-
|
|
36345
|
-
|
|
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
|
+
]);
|
|
36346
36909
|
function evalOrderKey(key, row) {
|
|
36347
36910
|
switch (key.type) {
|
|
36348
36911
|
case "FIELD_NAME":
|
|
@@ -36353,30 +36916,7 @@ function evalOrderKey(key, row) {
|
|
|
36353
36916
|
return evalStringFunc(key.expr, row);
|
|
36354
36917
|
}
|
|
36355
36918
|
}
|
|
36356
|
-
function
|
|
36357
|
-
const trimmed = raw.trim();
|
|
36358
|
-
if (trimmed === "") return [""];
|
|
36359
|
-
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
36360
|
-
try {
|
|
36361
|
-
const arr = JSON.parse(trimmed);
|
|
36362
|
-
if (Array.isArray(arr)) {
|
|
36363
|
-
return arr.map((v) => String(v ?? ""));
|
|
36364
|
-
}
|
|
36365
|
-
} catch {
|
|
36366
|
-
}
|
|
36367
|
-
}
|
|
36368
|
-
return [trimmed];
|
|
36369
|
-
}
|
|
36370
|
-
function minChoiceIndex(values, orderMap) {
|
|
36371
|
-
let min = Number.MAX_SAFE_INTEGER;
|
|
36372
|
-
for (const value of values) {
|
|
36373
|
-
const idx = orderMap.get(value);
|
|
36374
|
-
const rank = idx ?? Number.MAX_SAFE_INTEGER;
|
|
36375
|
-
if (rank < min) min = rank;
|
|
36376
|
-
}
|
|
36377
|
-
return min;
|
|
36378
|
-
}
|
|
36379
|
-
function applyWindow(rows, columns, optionOrders, sortKinds) {
|
|
36919
|
+
function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
|
|
36380
36920
|
const windows = columns.filter((column) => column.type === "WINDOW_COL");
|
|
36381
36921
|
if (rows.length === 0 || windows.length === 0) return rows;
|
|
36382
36922
|
for (const window of windows) {
|
|
@@ -36388,7 +36928,7 @@ function applyWindow(rows, columns, optionOrders, sortKinds) {
|
|
|
36388
36928
|
else partitions.set(key, [row]);
|
|
36389
36929
|
}
|
|
36390
36930
|
for (const partition of partitions.values()) {
|
|
36391
|
-
const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds);
|
|
36931
|
+
const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds, fieldSemantics2);
|
|
36392
36932
|
const sorted = sortedResult.rows;
|
|
36393
36933
|
let rank = 1;
|
|
36394
36934
|
let denseRank = 1;
|
|
@@ -36413,7 +36953,7 @@ function applyLimit(rows, limit, offset) {
|
|
|
36413
36953
|
if (limit === null) return rows.slice(start);
|
|
36414
36954
|
return rows.slice(start, start + limit);
|
|
36415
36955
|
}
|
|
36416
|
-
function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
|
|
36956
|
+
function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2) {
|
|
36417
36957
|
if (columns.length === 1 && columns[0].type === "WILDCARD") {
|
|
36418
36958
|
const projected2 = rows.map((row) => stripParentShortcutColumns(row));
|
|
36419
36959
|
const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
|
|
@@ -36477,7 +37017,7 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
|
|
|
36477
37017
|
}
|
|
36478
37018
|
case "CASE_COL": {
|
|
36479
37019
|
const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
|
|
36480
|
-
out[key] = evalCaseWhen(col.expr, row, resolveFieldType);
|
|
37020
|
+
out[key] = evalCaseWhen(col.expr, row, resolveFieldType, resolveFieldSemantics2);
|
|
36481
37021
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
36482
37022
|
break;
|
|
36483
37023
|
}
|
|
@@ -36632,6 +37172,26 @@ function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
|
|
|
36632
37172
|
args: expr.args.map((arg) => resolveAggInStringFuncArg(arg, rows, resolveAggSortKind))
|
|
36633
37173
|
};
|
|
36634
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
|
+
}
|
|
36635
37195
|
function runFullScan(input) {
|
|
36636
37196
|
const {
|
|
36637
37197
|
stmt,
|
|
@@ -36639,12 +37199,17 @@ function runFullScan(input) {
|
|
|
36639
37199
|
scalarCache,
|
|
36640
37200
|
optionOrders,
|
|
36641
37201
|
sortKinds,
|
|
37202
|
+
orderSemantics,
|
|
36642
37203
|
fieldTypeResolver,
|
|
37204
|
+
fieldSemanticsResolver,
|
|
36643
37205
|
havingFieldTypeResolver,
|
|
37206
|
+
havingFieldSemanticsResolver,
|
|
36644
37207
|
aggregateSortKindResolver,
|
|
36645
37208
|
appliedKlikes,
|
|
36646
37209
|
sourceColumns
|
|
36647
37210
|
} = input;
|
|
37211
|
+
const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
|
|
37212
|
+
for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
|
|
36648
37213
|
let rows = [];
|
|
36649
37214
|
const mainAlias = stmt.from.alias;
|
|
36650
37215
|
const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
|
|
@@ -36655,18 +37220,18 @@ function runFullScan(input) {
|
|
|
36655
37220
|
const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
|
|
36656
37221
|
rows = applyJoin(rows, rightRows, join);
|
|
36657
37222
|
}
|
|
36658
|
-
rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes);
|
|
37223
|
+
rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes, fieldSemanticsResolver);
|
|
36659
37224
|
if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
|
|
36660
37225
|
rows = applyGroupBy(rows, stmt.groupBy, stmt.columns, aggregateSortKindResolver);
|
|
36661
37226
|
}
|
|
36662
|
-
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
|
|
36663
|
-
rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds);
|
|
37227
|
+
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, havingFieldSemanticsResolver);
|
|
37228
|
+
rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds, effectiveOrderSemantics);
|
|
36664
37229
|
if (stmt.distinct) {
|
|
36665
37230
|
rows = applyDistinct(rows, stmt.columns);
|
|
36666
37231
|
}
|
|
36667
|
-
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds);
|
|
37232
|
+
rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds, effectiveOrderSemantics);
|
|
36668
37233
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
36669
|
-
return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns);
|
|
37234
|
+
return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns, fieldSemanticsResolver);
|
|
36670
37235
|
}
|
|
36671
37236
|
|
|
36672
37237
|
// src/converter/subtableAdapter.ts
|
|
@@ -36934,6 +37499,192 @@ function renderValidationValue(value) {
|
|
|
36934
37499
|
return String(value);
|
|
36935
37500
|
}
|
|
36936
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
|
+
|
|
36937
37688
|
// src/execute.ts
|
|
36938
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";
|
|
36939
37690
|
var SearchAbortedError = class extends Error {
|
|
@@ -36944,8 +37695,20 @@ var SearchAbortedError = class extends Error {
|
|
|
36944
37695
|
};
|
|
36945
37696
|
var materializedMetaBySelectResult = /* @__PURE__ */ new WeakMap();
|
|
36946
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
|
+
}
|
|
36947
37709
|
async function execute(sql, client, options = {}) {
|
|
36948
37710
|
const startedAt = Date.now();
|
|
37711
|
+
const cacheContext = resolveCacheContext(client, options.cacheContext);
|
|
36949
37712
|
const stmt = parseSql(sql);
|
|
36950
37713
|
const metrics = createEmptyMetrics();
|
|
36951
37714
|
const countedClient = wrapClientWithMetrics(client, metrics);
|
|
@@ -36959,7 +37722,7 @@ async function execute(sql, client, options = {}) {
|
|
|
36959
37722
|
stmt,
|
|
36960
37723
|
guardedClient,
|
|
36961
37724
|
options,
|
|
36962
|
-
|
|
37725
|
+
cacheContext
|
|
36963
37726
|
);
|
|
36964
37727
|
metrics.elapsedMs = Date.now() - startedAt;
|
|
36965
37728
|
return { ...attachSearchAbortWarning(result, collector), metrics };
|
|
@@ -37074,7 +37837,7 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
37074
37837
|
case "DESCRIBE":
|
|
37075
37838
|
return executeDescribe(stmt, client, cacheContext);
|
|
37076
37839
|
case "EXPLAIN":
|
|
37077
|
-
return executeExplain(stmt);
|
|
37840
|
+
return executeExplain(stmt, client, cacheContext, options.maxRecords ?? 1e4);
|
|
37078
37841
|
// 一時テーブルはバッチスコープのため単文実行では拒否する(executeBatch を使う)
|
|
37079
37842
|
case "CREATE_TEMP_TABLE":
|
|
37080
37843
|
throw new Error("ArgumentError: CREATE TEMP TABLE requires a batch (temp tables are batch-scoped).");
|
|
@@ -37105,7 +37868,7 @@ function materializedColumnMetaEqual(left, right) {
|
|
|
37105
37868
|
if (!left || !right || left.size !== right.size) return false;
|
|
37106
37869
|
for (const [column, meta3] of left) {
|
|
37107
37870
|
const candidate = right.get(column);
|
|
37108
|
-
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;
|
|
37109
37872
|
}
|
|
37110
37873
|
return true;
|
|
37111
37874
|
}
|
|
@@ -37136,7 +37899,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
37136
37899
|
const countedClient = wrapClientWithMetrics(client, metrics);
|
|
37137
37900
|
const startedAt = Date.now();
|
|
37138
37901
|
const deadline = options.timeoutMs != null ? startedAt + options.timeoutMs : null;
|
|
37139
|
-
const cacheContext = options.cacheContext
|
|
37902
|
+
const cacheContext = resolveCacheContext(client, options.cacheContext);
|
|
37140
37903
|
const tempTables = /* @__PURE__ */ new Map();
|
|
37141
37904
|
const variables = /* @__PURE__ */ new Map();
|
|
37142
37905
|
const results = [];
|
|
@@ -37230,7 +37993,10 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
37230
37993
|
cacheContext,
|
|
37231
37994
|
tempTables
|
|
37232
37995
|
);
|
|
37233
|
-
|
|
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 });
|
|
37234
38000
|
} catch (e) {
|
|
37235
38001
|
if (e instanceof ScalarSubqueryError) {
|
|
37236
38002
|
throw new Error(`ArgumentError: ${e.message}`);
|
|
@@ -37461,13 +38227,14 @@ var ScalarSubqueryError = class extends Error {
|
|
|
37461
38227
|
};
|
|
37462
38228
|
async function executeAssert(stmt, client, options, cacheContext, tempTables) {
|
|
37463
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");
|
|
37464
38231
|
if (stmt.op === "BETWEEN") {
|
|
37465
38232
|
if (stmt.low === null || stmt.high === null) {
|
|
37466
38233
|
throw new Error("ArgumentError: malformed ASSERT statement.");
|
|
37467
38234
|
}
|
|
37468
38235
|
const low = await evalAssertOperand(stmt.low, client, options, cacheContext, tempTables);
|
|
37469
38236
|
const high = await evalAssertOperand(stmt.high, client, options, cacheContext, tempTables);
|
|
37470
|
-
if (!compareScalarValues(">=", left, low) || !compareScalarValues("<=", left, high)) {
|
|
38237
|
+
if (!compareScalarValues(">=", left, low, semantics) || !compareScalarValues("<=", left, high, semantics)) {
|
|
37471
38238
|
throw new AssertError(`assertion failed: ${stmt.text} (actual: ${left}).`);
|
|
37472
38239
|
}
|
|
37473
38240
|
return { type: "ASSERT", condition: stmt.text };
|
|
@@ -37476,7 +38243,7 @@ async function executeAssert(stmt, client, options, cacheContext, tempTables) {
|
|
|
37476
38243
|
throw new Error("ArgumentError: malformed ASSERT statement.");
|
|
37477
38244
|
}
|
|
37478
38245
|
const right = await evalAssertOperand(stmt.right, client, options, cacheContext, tempTables);
|
|
37479
|
-
if (!compareScalarValues(stmt.op, left, right)) {
|
|
38246
|
+
if (!compareScalarValues(stmt.op, left, right, semantics)) {
|
|
37480
38247
|
throw new AssertError(`assertion failed: ${stmt.text} (actual: ${left}).`);
|
|
37481
38248
|
}
|
|
37482
38249
|
return { type: "ASSERT", condition: stmt.text };
|
|
@@ -37549,6 +38316,149 @@ function evalAssertArith(node) {
|
|
|
37549
38316
|
}
|
|
37550
38317
|
throw new Error(`ArgumentError: unsupported operand in ASSERT expression: ${node.type}`);
|
|
37551
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
|
+
}
|
|
37552
38462
|
async function executeSelect(stmt, client, options, cacheContext, cteCache, captureColumnMeta = false) {
|
|
37553
38463
|
let result;
|
|
37554
38464
|
if (isNoFromSelect(stmt)) {
|
|
@@ -37559,12 +38469,51 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
|
|
|
37559
38469
|
return result;
|
|
37560
38470
|
}
|
|
37561
38471
|
await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
|
|
37562
|
-
const
|
|
37563
|
-
|
|
37564
|
-
|
|
37565
|
-
|
|
37566
|
-
|
|
37567
|
-
|
|
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;
|
|
37568
38517
|
}
|
|
37569
38518
|
if (captureColumnMeta) {
|
|
37570
38519
|
materializedMetaBySelectResult.set(result, await inferSelectColumnMeta(stmt, result.columns, client, cacheContext, cteCache));
|
|
@@ -37625,19 +38574,30 @@ function executeNoFromSelect(stmt) {
|
|
|
37625
38574
|
const rows = applyLimit(projected, stmt.limit, stmt.offset);
|
|
37626
38575
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [] };
|
|
37627
38576
|
}
|
|
37628
|
-
async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
37629
|
-
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;
|
|
37630
38581
|
const typedInFieldTypes = await loadTypedInFieldTypes(stmt, client, cacheContext);
|
|
37631
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;
|
|
37632
38590
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
37633
38591
|
const warnings = /* @__PURE__ */ new Set();
|
|
37634
38592
|
const onLimit2 = options.onLimitReached ?? "error";
|
|
37635
38593
|
const parallel = options.fetchParallel ?? 1;
|
|
37636
|
-
const
|
|
38594
|
+
const useRestWindow = stmt.orderBy.length > 0 ? orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" : stmt.limit !== null && stmt.limit <= 500;
|
|
37637
38595
|
const needed = stmt.limit === null ? null : (stmt.offset ?? 0) + stmt.limit;
|
|
37638
38596
|
const stopAfter = stmt.orderBy.length === 0 && needed !== null && needed <= maxRecords2 && !whereHasKlike(stmt.where) ? needed : void 0;
|
|
37639
38597
|
let records;
|
|
37640
|
-
if (
|
|
38598
|
+
if (orderPlan?.kind === "KORDER_NATIVE" && stmt.limit === 0) {
|
|
38599
|
+
records = [];
|
|
38600
|
+
} else if (useRestWindow) {
|
|
37641
38601
|
const res = await client.getRecords({
|
|
37642
38602
|
app: params.app,
|
|
37643
38603
|
query: params.query,
|
|
@@ -37650,7 +38610,7 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
|
37650
38610
|
client.getRecords,
|
|
37651
38611
|
params.app,
|
|
37652
38612
|
baseQuery,
|
|
37653
|
-
|
|
38613
|
+
fetchFields,
|
|
37654
38614
|
{
|
|
37655
38615
|
parallel,
|
|
37656
38616
|
maxRecords: maxRecords2,
|
|
@@ -37663,16 +38623,23 @@ async function executeSimpleSelect(stmt, client, options, cacheContext) {
|
|
|
37663
38623
|
);
|
|
37664
38624
|
}
|
|
37665
38625
|
let rows = records.map((r) => flatten(r, null));
|
|
37666
|
-
if (!
|
|
37667
|
-
|
|
37668
|
-
|
|
38626
|
+
if (!useRestWindow) {
|
|
38627
|
+
rows = applyOrderBy(
|
|
38628
|
+
rows,
|
|
38629
|
+
stmt.orderBy,
|
|
38630
|
+
orderMeta.optionOrders,
|
|
38631
|
+
orderMeta.sortKinds,
|
|
38632
|
+
orderMeta.semantics
|
|
38633
|
+
);
|
|
37669
38634
|
rows = applyLimit(rows, stmt.limit, stmt.offset);
|
|
37670
38635
|
}
|
|
37671
38636
|
const { rows: projected, columns } = project(
|
|
37672
38637
|
rows,
|
|
37673
38638
|
stmt.columns,
|
|
37674
38639
|
void 0,
|
|
37675
|
-
fieldTypeResolvers.row
|
|
38640
|
+
fieldTypeResolvers.row,
|
|
38641
|
+
void 0,
|
|
38642
|
+
projectionSemanticsResolver
|
|
37676
38643
|
);
|
|
37677
38644
|
return { type: "SELECT", rows: projected, columns, rowCount: projected.length, warnings: [...warnings] };
|
|
37678
38645
|
}
|
|
@@ -37745,8 +38712,8 @@ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
|
|
|
37745
38712
|
const statusFields = collectCandidateFieldCodes(candidates).filter((fieldCode) => fieldTypes.get(fieldCode) === "STATUS");
|
|
37746
38713
|
if (statusFields.length > 0) {
|
|
37747
38714
|
const process4 = await getProcessStatusesCached(appId, client, cacheContext);
|
|
37748
|
-
if (process4.enable && process4.states.length > 0) {
|
|
37749
|
-
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));
|
|
37750
38717
|
for (const fieldCode of statusFields) fieldOptions.set(fieldCode, states);
|
|
37751
38718
|
}
|
|
37752
38719
|
}
|
|
@@ -37924,7 +38891,18 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
|
|
|
37924
38891
|
return [appId, new Map(infos.map((info) => [info.code, info]))];
|
|
37925
38892
|
}))
|
|
37926
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
|
+
}));
|
|
37927
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
|
+
};
|
|
37928
38906
|
return (ref) => {
|
|
37929
38907
|
let info;
|
|
37930
38908
|
if (ref.tableAlias !== null) {
|
|
@@ -37934,40 +38912,130 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
|
|
|
37934
38912
|
const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
|
|
37935
38913
|
if (!table) return void 0;
|
|
37936
38914
|
if (table.cteName !== null) {
|
|
37937
|
-
return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.
|
|
38915
|
+
return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
|
|
37938
38916
|
}
|
|
37939
38917
|
info = fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
37940
38918
|
}
|
|
37941
38919
|
} else if (stmt.joins.length === 0) {
|
|
37942
38920
|
if (stmt.from.cteName !== null) {
|
|
37943
|
-
return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field)?.
|
|
38921
|
+
return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
|
|
37944
38922
|
}
|
|
37945
38923
|
info = fieldInfosByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
|
|
37946
38924
|
} else {
|
|
37947
38925
|
const matches = tables.flatMap((table) => {
|
|
37948
38926
|
if (table.cteName !== null) {
|
|
37949
38927
|
const materialized = materializedTables?.get(table.cteName);
|
|
37950
|
-
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")] : [];
|
|
37951
38929
|
}
|
|
37952
38930
|
const candidate = fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
37953
|
-
return candidate ? [
|
|
38931
|
+
return candidate ? [semanticsForInfo(candidate, table.appId)] : [];
|
|
37954
38932
|
});
|
|
37955
38933
|
if (matches.length !== 1) return void 0;
|
|
37956
38934
|
return matches[0];
|
|
37957
38935
|
}
|
|
37958
|
-
|
|
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);
|
|
37959
38939
|
};
|
|
37960
38940
|
}
|
|
37961
38941
|
function fieldCodeForTypeLookup(table, field) {
|
|
37962
38942
|
if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
|
|
37963
38943
|
return field;
|
|
37964
38944
|
}
|
|
37965
|
-
function materializedMetaFromFieldInfo(info) {
|
|
37966
|
-
|
|
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();
|
|
37967
39035
|
}
|
|
37968
39036
|
function selectNeedsSourceColumnMeta(stmt) {
|
|
37969
39037
|
return stmt.columns.some(
|
|
37970
|
-
(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"
|
|
37971
39039
|
);
|
|
37972
39040
|
}
|
|
37973
39041
|
async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables) {
|
|
@@ -37984,18 +39052,18 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
37984
39052
|
if (ref.tableAlias !== null) {
|
|
37985
39053
|
if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
37986
39054
|
const info2 = physicalInfos.get(stmt.from.appId)?.get(ref.field);
|
|
37987
|
-
return info2 ? materializedMetaFromFieldInfo(info2) : void 0;
|
|
39055
|
+
return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
|
|
37988
39056
|
}
|
|
37989
39057
|
const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
|
|
37990
39058
|
if (!table) return void 0;
|
|
37991
39059
|
if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
|
|
37992
39060
|
const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
37993
|
-
return info ? materializedMetaFromFieldInfo(info) :
|
|
39061
|
+
return info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
|
|
37994
39062
|
}
|
|
37995
39063
|
if (stmt.joins.length === 0) {
|
|
37996
39064
|
if (stmt.from.cteName !== null) return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field);
|
|
37997
39065
|
const info = physicalInfos.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
|
|
37998
|
-
return info ? materializedMetaFromFieldInfo(info) :
|
|
39066
|
+
return info ? materializedMetaFromFieldInfo(info, stmt.from.appId) : systemColumnMeta(ref.field);
|
|
37999
39067
|
}
|
|
38000
39068
|
const matches = tables.flatMap((table) => {
|
|
38001
39069
|
if (table.cteName !== null) {
|
|
@@ -38004,7 +39072,8 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
38004
39072
|
return [materialized.columnMeta?.get(ref.field)];
|
|
38005
39073
|
}
|
|
38006
39074
|
const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
|
|
38007
|
-
|
|
39075
|
+
const meta3 = info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(ref.field);
|
|
39076
|
+
return meta3 ? [meta3] : [];
|
|
38008
39077
|
});
|
|
38009
39078
|
return matches.length === 1 ? matches[0] : void 0;
|
|
38010
39079
|
};
|
|
@@ -38034,19 +39103,27 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
38034
39103
|
meta3 = resolveField2(aggregateFieldRef(column.field));
|
|
38035
39104
|
} else if (column.type === "AGGREGATE") {
|
|
38036
39105
|
if (column.func === "GROUP_CONCAT") {
|
|
38037
|
-
meta3 =
|
|
39106
|
+
meta3 = syntheticColumnMeta("string");
|
|
38038
39107
|
} else if (column.func === "COUNT" || column.func === "SUM" || column.func === "AVG") {
|
|
38039
|
-
meta3 =
|
|
39108
|
+
meta3 = syntheticColumnMeta("number");
|
|
38040
39109
|
} else if ((column.func === "MIN" || column.func === "MAX") && column.arg.type === "FIELD_REF") {
|
|
38041
39110
|
const source = resolveField2(aggregateFieldRef(column.arg.field));
|
|
38042
|
-
if (source
|
|
39111
|
+
if (source) meta3 = source;
|
|
38043
39112
|
}
|
|
38044
39113
|
} else if (column.type === "ARITH_AGG_COL" || column.type === "ARITH_COL") {
|
|
38045
|
-
meta3 =
|
|
39114
|
+
meta3 = syntheticColumnMeta("number");
|
|
38046
39115
|
} else if (column.type === "LITERAL_COL") {
|
|
38047
|
-
meta3 =
|
|
39116
|
+
meta3 = syntheticColumnMeta("string");
|
|
39117
|
+
} else if (column.type === "STRFUNC_COL") {
|
|
39118
|
+
meta3 = stringFunctionColumnMeta(column.expr);
|
|
38048
39119
|
} else if (column.type === "WINDOW_COL") {
|
|
38049
|
-
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();
|
|
38050
39127
|
}
|
|
38051
39128
|
if (meta3) inferred.set(output, meta3);
|
|
38052
39129
|
});
|
|
@@ -38060,7 +39137,8 @@ function mergeUnionColumnMeta(left, right) {
|
|
|
38060
39137
|
const a = leftMeta?.get(column);
|
|
38061
39138
|
const rightColumn = right.columns[index];
|
|
38062
39139
|
const b = rightColumn === void 0 ? void 0 : rightMeta?.get(rightColumn);
|
|
38063
|
-
if (a && b
|
|
39140
|
+
if (a && b) merged.set(column, mergeExpressionColumnMeta([a, b]));
|
|
39141
|
+
else if (a || b) merged.set(column, unknownStringColumnMeta());
|
|
38064
39142
|
});
|
|
38065
39143
|
return merged;
|
|
38066
39144
|
}
|
|
@@ -38097,7 +39175,7 @@ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
|
|
|
38097
39175
|
};
|
|
38098
39176
|
return { row, having };
|
|
38099
39177
|
}
|
|
38100
|
-
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
|
|
39178
|
+
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache, allowOriginalWherePushdown = true, preloadedOrderMeta) {
|
|
38101
39179
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
38102
39180
|
const warnings = /* @__PURE__ */ new Set();
|
|
38103
39181
|
const parallel = options.fetchParallel ?? 1;
|
|
@@ -38111,6 +39189,14 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
38111
39189
|
loadAggregateSortKindResolver(stmt, client, cacheContext, cteCache)
|
|
38112
39190
|
]);
|
|
38113
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);
|
|
38114
39200
|
const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
|
|
38115
39201
|
validateKlikePushdownPlan(pushdownPlan);
|
|
38116
39202
|
const mainPushDown = pushdownPlan.mainCondition;
|
|
@@ -38124,7 +39210,8 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
38124
39210
|
true,
|
|
38125
39211
|
options.onLimitReached ?? "error",
|
|
38126
39212
|
warnings,
|
|
38127
|
-
mainPushDown
|
|
39213
|
+
mainPushDown,
|
|
39214
|
+
allowOriginalWherePushdown
|
|
38128
39215
|
);
|
|
38129
39216
|
const parallelJoins = [];
|
|
38130
39217
|
const onOptJoins = [];
|
|
@@ -38150,7 +39237,7 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
38150
39237
|
}
|
|
38151
39238
|
}
|
|
38152
39239
|
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
38153
|
-
const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
|
|
39240
|
+
const orderByMetaPromise = preloadedOrderMeta ? Promise.resolve(preloadedOrderMeta) : buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
|
|
38154
39241
|
scalarCachePromise.catch(() => {
|
|
38155
39242
|
});
|
|
38156
39243
|
orderByMetaPromise.catch(() => {
|
|
@@ -38187,15 +39274,18 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
38187
39274
|
tables.set(join.table.alias, joinRecords);
|
|
38188
39275
|
}));
|
|
38189
39276
|
const scalarCache = await scalarCachePromise;
|
|
38190
|
-
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
39277
|
+
const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
|
|
38191
39278
|
const { rows, columns } = runFullScan({
|
|
38192
39279
|
tables,
|
|
38193
39280
|
stmt,
|
|
38194
39281
|
scalarCache,
|
|
38195
39282
|
optionOrders,
|
|
38196
39283
|
sortKinds,
|
|
39284
|
+
orderSemantics: semantics,
|
|
38197
39285
|
fieldTypeResolver: fieldTypeResolvers.row,
|
|
39286
|
+
fieldSemanticsResolver,
|
|
38198
39287
|
havingFieldTypeResolver: fieldTypeResolvers.having,
|
|
39288
|
+
havingFieldSemanticsResolver,
|
|
38199
39289
|
aggregateSortKindResolver,
|
|
38200
39290
|
appliedKlikes: pushdownPlan.appliedKlikes
|
|
38201
39291
|
});
|
|
@@ -38292,16 +39382,39 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
38292
39382
|
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache),
|
|
38293
39383
|
resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache)
|
|
38294
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
|
+
}
|
|
38295
39400
|
const [pushdownMeta, typedInFieldTypes, aggregateSortKindResolver] = await Promise.all([
|
|
38296
39401
|
loadTypedPushdownMeta(stmt, client, cacheContext),
|
|
38297
39402
|
loadTypedInFieldTypes(stmt, client, cacheContext),
|
|
38298
39403
|
loadAggregateSortKindResolver(stmt, client, cacheContext, cteCache)
|
|
38299
39404
|
]);
|
|
38300
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);
|
|
38301
39414
|
const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
|
|
38302
39415
|
validateKlikePushdownPlan(pushdownPlan);
|
|
38303
39416
|
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
38304
|
-
const orderByMetaPromise =
|
|
39417
|
+
const orderByMetaPromise = Promise.resolve(orderMeta);
|
|
38305
39418
|
scalarCachePromise.catch(() => {
|
|
38306
39419
|
});
|
|
38307
39420
|
orderByMetaPromise.catch(() => {
|
|
@@ -38320,7 +39433,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
38320
39433
|
true,
|
|
38321
39434
|
options.onLimitReached ?? "error",
|
|
38322
39435
|
warnings,
|
|
38323
|
-
pushdownPlan.mainCondition
|
|
39436
|
+
pushdownPlan.mainCondition,
|
|
39437
|
+
whereCapability.capability === "EXACT_PUSHDOWN"
|
|
38324
39438
|
);
|
|
38325
39439
|
tables.set(stmt.from.alias, mainRecords);
|
|
38326
39440
|
}
|
|
@@ -38357,7 +39471,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
38357
39471
|
});
|
|
38358
39472
|
await Promise.all(joinFetches);
|
|
38359
39473
|
const scalarCache = await scalarCachePromise;
|
|
38360
|
-
const { optionOrders, sortKinds } = await orderByMetaPromise;
|
|
39474
|
+
const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
|
|
38361
39475
|
const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? cteCache.get(stmt.from.cteName)?.columns : void 0;
|
|
38362
39476
|
const { rows, columns } = runFullScan({
|
|
38363
39477
|
tables,
|
|
@@ -38365,8 +39479,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
38365
39479
|
scalarCache,
|
|
38366
39480
|
optionOrders,
|
|
38367
39481
|
sortKinds,
|
|
39482
|
+
orderSemantics: semantics,
|
|
38368
39483
|
fieldTypeResolver: fieldTypeResolvers.row,
|
|
39484
|
+
fieldSemanticsResolver,
|
|
38369
39485
|
havingFieldTypeResolver: fieldTypeResolvers.having,
|
|
39486
|
+
havingFieldSemanticsResolver,
|
|
38370
39487
|
aggregateSortKindResolver,
|
|
38371
39488
|
appliedKlikes: pushdownPlan.appliedKlikes,
|
|
38372
39489
|
sourceColumns
|
|
@@ -38378,13 +39495,13 @@ function processRowToKintoneRecord(row) {
|
|
|
38378
39495
|
Object.entries(row).map(([k, v]) => [k, { value: v ?? "" }])
|
|
38379
39496
|
);
|
|
38380
39497
|
}
|
|
38381
|
-
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) {
|
|
38382
39499
|
const fields = selectToFetchAllFields(stmt, table);
|
|
38383
39500
|
const onTruncate = (max) => {
|
|
38384
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`);
|
|
38385
39502
|
};
|
|
38386
39503
|
if (!table.subtableCode) {
|
|
38387
|
-
const baseQuery = isMainTable ? selectToFetchAllParams(stmt, table.appId).query : "";
|
|
39504
|
+
const baseQuery = isMainTable && allowOriginalWherePushdown ? selectToFetchAllParams(stmt, table.appId).query : "";
|
|
38388
39505
|
const pushQuery = pushDownCond !== null ? whereToKintone(pushDownCond) : "";
|
|
38389
39506
|
const query = baseQuery && pushQuery ? `(${baseQuery}) and (${pushQuery})` : baseQuery || pushQuery;
|
|
38390
39507
|
const resolved = await fetchRecordsForSharedPlan(client.getRecords, table.appId, query, fields, {
|
|
@@ -38588,6 +39705,10 @@ async function getProcessStatusesCached(appId, client, cacheContext) {
|
|
|
38588
39705
|
setScopedCacheValue(processStatusCache, cacheContext, appId, loading);
|
|
38589
39706
|
return loading;
|
|
38590
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
|
+
}
|
|
38591
39712
|
async function getFieldTypeMap(appId, client, cacheContext) {
|
|
38592
39713
|
const cached2 = getScopedCacheValue(fieldTypeCache, cacheContext, appId);
|
|
38593
39714
|
if (cached2) return cached2;
|
|
@@ -38631,18 +39752,118 @@ async function getSortKindMapByApp(appId, client, cacheContext) {
|
|
|
38631
39752
|
setScopedCacheValue(sortKindCache, cacheContext, appId, map2);
|
|
38632
39753
|
return map2;
|
|
38633
39754
|
}
|
|
38634
|
-
|
|
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) {
|
|
38635
39855
|
const hasWindowOrderBy = stmt.columns.some(
|
|
38636
39856
|
(column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
|
|
38637
39857
|
);
|
|
38638
39858
|
if (stmt.orderBy.length === 0 && !hasWindowOrderBy) {
|
|
38639
|
-
return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map() };
|
|
39859
|
+
return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map(), semantics: /* @__PURE__ */ new Map() };
|
|
38640
39860
|
}
|
|
38641
|
-
const [optionOrders, sortKinds] = await Promise.all([
|
|
39861
|
+
const [optionOrders, sortKinds, semantics] = await Promise.all([
|
|
38642
39862
|
buildOptionOrdersForSelect(stmt, client, cacheContext),
|
|
38643
|
-
buildSortKindsForSelect(stmt, client, cacheContext)
|
|
39863
|
+
buildSortKindsForSelect(stmt, client, cacheContext),
|
|
39864
|
+
buildOrderSemanticsForSelect(stmt, client, cacheContext, materializedTables)
|
|
38644
39865
|
]);
|
|
38645
|
-
return { optionOrders, sortKinds };
|
|
39866
|
+
return { optionOrders, sortKinds, semantics };
|
|
38646
39867
|
}
|
|
38647
39868
|
async function buildOptionOrdersForSelect(stmt, client, cacheContext) {
|
|
38648
39869
|
const optionOrders = /* @__PURE__ */ new Map();
|
|
@@ -38740,6 +39961,9 @@ var RejectLimitExceededError = class extends Error {
|
|
|
38740
39961
|
}
|
|
38741
39962
|
};
|
|
38742
39963
|
async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
|
|
39964
|
+
if (stmt.type === "UPDATE") {
|
|
39965
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
39966
|
+
}
|
|
38743
39967
|
const operation = stmt.type === "UPDATE" ? "UPDATE" : stmt.type.startsWith("UPSERT") ? "UPSERT" : "INSERT";
|
|
38744
39968
|
const payloadFields = stmt.type === "UPDATE" ? ["$id", ...stmt.assignments.map((a) => a.field)] : [...stmt.fields];
|
|
38745
39969
|
if (new Set(payloadFields).size !== payloadFields.length) {
|
|
@@ -38779,18 +40003,22 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
|
|
|
38779
40003
|
const columnMeta = /* @__PURE__ */ new Map();
|
|
38780
40004
|
for (const column of payloadFields) {
|
|
38781
40005
|
if (column === "$id") {
|
|
38782
|
-
columnMeta.set(column, {
|
|
40006
|
+
columnMeta.set(column, {
|
|
40007
|
+
sortKind: "number",
|
|
40008
|
+
fieldType: "RECORD_NUMBER",
|
|
40009
|
+
semantics: resolveFieldSemantics({ fieldType: "RECORD_NUMBER" })
|
|
40010
|
+
});
|
|
38783
40011
|
continue;
|
|
38784
40012
|
}
|
|
38785
40013
|
const info = infoByCode.get(column);
|
|
38786
|
-
if (info) columnMeta.set(column, materializedMetaFromFieldInfo(info));
|
|
38787
|
-
}
|
|
38788
|
-
columnMeta.set("$err_statement",
|
|
38789
|
-
columnMeta.set("$err_operation",
|
|
38790
|
-
columnMeta.set("$err_row",
|
|
38791
|
-
columnMeta.set("$err_field",
|
|
38792
|
-
columnMeta.set("$err_code",
|
|
38793
|
-
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"));
|
|
38794
40022
|
materializedMetaByValidationResult.set(result, columnMeta);
|
|
38795
40023
|
return { result, candidates, invalidRowNumbers, columnMeta };
|
|
38796
40024
|
}
|
|
@@ -39176,6 +40404,7 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
|
|
|
39176
40404
|
};
|
|
39177
40405
|
}
|
|
39178
40406
|
async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
|
|
40407
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
39179
40408
|
if (stmt.subtableCode) {
|
|
39180
40409
|
return executeUpdateSubtable(stmt, client, options, cacheContext);
|
|
39181
40410
|
}
|
|
@@ -39253,6 +40482,7 @@ function collectUpdateFromTargetFields(stmt) {
|
|
|
39253
40482
|
return [...fields];
|
|
39254
40483
|
}
|
|
39255
40484
|
async function executeDelete(stmt, client, options, cacheContext) {
|
|
40485
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
39256
40486
|
if (stmt.subtableCode) {
|
|
39257
40487
|
return executeDeleteSubtable(stmt, client, options, cacheContext);
|
|
39258
40488
|
}
|
|
@@ -39625,6 +40855,18 @@ async function executeReorder(stmt, client, options, cacheContext) {
|
|
|
39625
40855
|
client,
|
|
39626
40856
|
cacheContext
|
|
39627
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
|
+
};
|
|
39628
40870
|
const parents = await fetchAll(
|
|
39629
40871
|
client.getRecords,
|
|
39630
40872
|
stmt.appId,
|
|
@@ -39633,7 +40875,13 @@ async function executeReorder(stmt, client, options, cacheContext) {
|
|
|
39633
40875
|
{ maxRecords: options.maxRecords ?? 1e4, parallel: options.fetchParallel ?? 1 }
|
|
39634
40876
|
);
|
|
39635
40877
|
const expanded = expandRowsForSubtableDml(parents, stmt.subtableCode);
|
|
39636
|
-
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));
|
|
39637
40885
|
if (options.confirm) {
|
|
39638
40886
|
const ok = await options.confirm(targetParentIds.size, "UPDATE");
|
|
39639
40887
|
if (!ok) throw new OperationCancelledError("UPDATE", targetParentIds.size);
|
|
@@ -39644,7 +40892,7 @@ async function executeReorder(stmt, client, options, cacheContext) {
|
|
|
39644
40892
|
if (!parent) continue;
|
|
39645
40893
|
const rows = getMutableTableRows(parent, stmt.subtableCode);
|
|
39646
40894
|
const sortable = rows.map((row, i) => ({ row, i, flat: buildFlatRowForSort(parent, stmt.subtableCode, row, i) }));
|
|
39647
|
-
sortable.sort((a, b) => compareByOrder(a.flat, b.flat, stmt.by));
|
|
40895
|
+
sortable.sort((a, b) => compareByOrder(a.flat, b.flat, stmt.by, resolveReorderSemantics));
|
|
39648
40896
|
const orderedRowIds = sortable.map((x) => x.row.id ?? "");
|
|
39649
40897
|
await client.putRecords(buildSubtableReorderPutParams(stmt.appId, pid, getRevision(parent), stmt.subtableCode, orderedRowIds));
|
|
39650
40898
|
}
|
|
@@ -39665,14 +40913,12 @@ function buildFlatRowForSort(parent, subtableCode, row, idx) {
|
|
|
39665
40913
|
}
|
|
39666
40914
|
return flat;
|
|
39667
40915
|
}
|
|
39668
|
-
function compareByOrder(a, b, orderBy) {
|
|
40916
|
+
function compareByOrder(a, b, orderBy, resolveSemantics) {
|
|
39669
40917
|
for (const item of orderBy) {
|
|
39670
40918
|
const av = evalOrderKeyForRow(item.key, a);
|
|
39671
40919
|
const bv = evalOrderKeyForRow(item.key, b);
|
|
39672
|
-
const
|
|
39673
|
-
const
|
|
39674
|
-
const numeric = !Number.isNaN(an) && !Number.isNaN(bn);
|
|
39675
|
-
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"));
|
|
39676
40922
|
if (cmp !== 0) return item.direction === "ASC" ? cmp : -cmp;
|
|
39677
40923
|
}
|
|
39678
40924
|
return 0;
|
|
@@ -39869,35 +41115,140 @@ async function resolveScalarColumns(columns, client, options, cacheContext, cteC
|
|
|
39869
41115
|
pending.forEach(([i], idx) => cache.set(i, values[idx]));
|
|
39870
41116
|
return cache;
|
|
39871
41117
|
}
|
|
39872
|
-
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) {
|
|
39873
41217
|
const statements = parseSqlBatch(sql);
|
|
39874
41218
|
const analysis = analyzeBatch(statements);
|
|
39875
41219
|
validateDeclaredBatchVariables(statements, injectedVariables);
|
|
39876
41220
|
const variables = /* @__PURE__ */ new Map();
|
|
39877
|
-
|
|
39878
|
-
|
|
39879
|
-
|
|
39880
|
-
|
|
39881
|
-
|
|
39882
|
-
|
|
39883
|
-
|
|
39884
|
-
|
|
39885
|
-
|
|
39886
|
-
|
|
39887
|
-
|
|
39888
|
-
|
|
39889
|
-
|
|
39890
|
-
|
|
39891
|
-
|
|
39892
|
-
|
|
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 };
|
|
39893
41244
|
}
|
|
39894
|
-
function buildBatchStatementPlan(stmt, info) {
|
|
41245
|
+
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans) {
|
|
39895
41246
|
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
39896
41247
|
return [
|
|
39897
41248
|
`CREATE TEMP TABLE ${stmt.name}`,
|
|
39898
41249
|
` scope: batch\uFF08\u30D0\u30C3\u30C1\u7D42\u4E86\u6642\u306B\u81EA\u52D5\u7834\u68C4\uFF09`,
|
|
39899
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`,
|
|
39900
|
-
...buildPlanForBatchQuery(stmt.query, info).map((l) => ` ${l}`)
|
|
41251
|
+
...buildPlanForBatchQuery(stmt.query, info, capabilities, orderPlans).map((l) => ` ${l}`)
|
|
39901
41252
|
];
|
|
39902
41253
|
}
|
|
39903
41254
|
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
@@ -39913,7 +41264,7 @@ function buildBatchStatementPlan(stmt, info) {
|
|
|
39913
41264
|
`SET @${stmt.name} = (SELECT ...)`,
|
|
39914
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",
|
|
39915
41266
|
" subquery:",
|
|
39916
|
-
...buildPlanForBatchQuery(stmt.expr.query, subInfo).map((l) => ` ${l}`)
|
|
41267
|
+
...buildPlanForBatchQuery(stmt.expr.query, subInfo, capabilities, orderPlans).map((l) => ` ${l}`)
|
|
39917
41268
|
];
|
|
39918
41269
|
}
|
|
39919
41270
|
return [
|
|
@@ -39929,7 +41280,7 @@ function buildBatchStatementPlan(stmt, info) {
|
|
|
39929
41280
|
}
|
|
39930
41281
|
if (stmt.type === "SHOW_APPS") return ["SHOW APPS\uFF08\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\uFF09"];
|
|
39931
41282
|
if (stmt.type === "DESCRIBE") return [`DESCRIBE APP${stmt.appId}\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\uFF09`];
|
|
39932
|
-
if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info);
|
|
41283
|
+
if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info, capabilities, orderPlans);
|
|
39933
41284
|
if (stmt.type === "ASSERT") {
|
|
39934
41285
|
const lines = [
|
|
39935
41286
|
`ASSERT ${stmt.text}`,
|
|
@@ -39941,11 +41292,11 @@ function buildBatchStatementPlan(stmt, info) {
|
|
|
39941
41292
|
subqueries.forEach((sq, i) => {
|
|
39942
41293
|
lines.push(subqueries.length > 1 ? ` subquery[${i + 1}]:` : " subquery:");
|
|
39943
41294
|
const subInfo = hasTempTableRef(sq.query) ? info : { ...info, tempTablesReferenced: [] };
|
|
39944
|
-
lines.push(...buildPlanForBatchQuery(sq.query, subInfo).map((l) => ` ${l}`));
|
|
41295
|
+
lines.push(...buildPlanForBatchQuery(sq.query, subInfo, capabilities, orderPlans).map((l) => ` ${l}`));
|
|
39945
41296
|
});
|
|
39946
41297
|
return lines;
|
|
39947
41298
|
}
|
|
39948
|
-
return buildPlanForBatchQuery(stmt, info);
|
|
41299
|
+
return buildPlanForBatchQuery(stmt, info, capabilities, orderPlans);
|
|
39949
41300
|
}
|
|
39950
41301
|
function hasTempTableRef(node) {
|
|
39951
41302
|
if (Array.isArray(node)) return node.some(hasTempTableRef);
|
|
@@ -39957,9 +41308,9 @@ function hasTempTableRef(node) {
|
|
|
39957
41308
|
}
|
|
39958
41309
|
return false;
|
|
39959
41310
|
}
|
|
39960
|
-
function buildPlanForBatchQuery(query, info) {
|
|
41311
|
+
function buildPlanForBatchQuery(query, info, capabilities, orderPlans) {
|
|
39961
41312
|
if (info.tempTablesReferenced.length === 0) {
|
|
39962
|
-
return buildExplainPlan(query);
|
|
41313
|
+
return buildExplainPlan(query, void 0, capabilities, orderPlans);
|
|
39963
41314
|
}
|
|
39964
41315
|
const lines = [];
|
|
39965
41316
|
if (query.type === "INSERT_SELECT") {
|
|
@@ -39984,8 +41335,12 @@ function buildPlanForBatchQuery(query, info) {
|
|
|
39984
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");
|
|
39985
41336
|
return lines;
|
|
39986
41337
|
}
|
|
39987
|
-
function executeExplain(stmt) {
|
|
39988
|
-
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
|
+
];
|
|
39989
41344
|
return {
|
|
39990
41345
|
type: "SELECT",
|
|
39991
41346
|
columns: ["plan"],
|
|
@@ -39993,29 +41348,45 @@ function executeExplain(stmt) {
|
|
|
39993
41348
|
rowCount: lines.length
|
|
39994
41349
|
};
|
|
39995
41350
|
}
|
|
39996
|
-
function buildExplainPlan(query, label) {
|
|
39997
|
-
if (query.type === "UNION") return buildUnionPlan(query);
|
|
39998
|
-
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);
|
|
39999
41354
|
if (query.type === "INSERT") return buildInsertPlan(query, label);
|
|
40000
|
-
if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label);
|
|
41355
|
+
if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label, capabilities, orderPlans);
|
|
40001
41356
|
if (query.type === "UPSERT") return buildUpsertPlan(query, label);
|
|
40002
|
-
if (query.type === "UPSERT_SELECT") return buildUpsertSelectPlan(query, label);
|
|
40003
|
-
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);
|
|
40004
41359
|
if (query.type === "DELETE") return buildDeletePlan(query, label);
|
|
40005
41360
|
if (query.type === "REORDER") return buildReorderPlan(query, label);
|
|
40006
|
-
return buildSelectPlan(query, label);
|
|
41361
|
+
return buildSelectPlan(query, label, capabilities, orderPlans);
|
|
40007
41362
|
}
|
|
40008
|
-
function buildSelectPlan(stmt, label) {
|
|
40009
|
-
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);
|
|
40010
41367
|
const reasons = collectFullScanReasons(stmt);
|
|
41368
|
+
if (whereCapability && whereCapability.capability !== "EXACT_PUSHDOWN") {
|
|
41369
|
+
reasons.push(...whereCapability.reasons.map((reason) => reason.code));
|
|
41370
|
+
}
|
|
40011
41371
|
const lines = [];
|
|
40012
41372
|
if (label) lines.push(label);
|
|
40013
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
|
+
}
|
|
40014
41385
|
if (mode === "FULL_SCAN" && reasons.length > 0) {
|
|
40015
41386
|
lines.push(` reason: ${reasons.join(", ")}`);
|
|
40016
41387
|
}
|
|
40017
41388
|
if (mode === "SIMPLE") {
|
|
40018
|
-
const params = selectToKintoneParams(stmt);
|
|
41389
|
+
const params = selectToKintoneParams(orderPlan?.kind === "CANONICAL_REST_TOP_N" ? withCanonicalRestTie(stmt) : stmt);
|
|
40019
41390
|
lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);
|
|
40020
41391
|
lines.push(` kintone query: ${params.query || "(\u306A\u3057)"}`);
|
|
40021
41392
|
lines.push(` fields: ${params.fields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : params.fields.join(", ")}`);
|
|
@@ -40025,7 +41396,8 @@ function buildSelectPlan(stmt, label) {
|
|
|
40025
41396
|
const mainAliasStr = stmt.from.alias ? ` AS ${stmt.from.alias}` : "";
|
|
40026
41397
|
const mainPushDown = pushdownPlan.mainCondition;
|
|
40027
41398
|
const mainCandidate = extractMainTypedPushdownCandidate(stmt);
|
|
40028
|
-
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)";
|
|
40029
41401
|
lines.push(` app: APP${stmt.from.appId}${mainAliasStr} (${stmt.from.appId})`);
|
|
40030
41402
|
lines.push(` kintone query: ${mainQ}`);
|
|
40031
41403
|
if (mainCandidate !== null) {
|
|
@@ -40047,10 +41419,10 @@ function buildSelectPlan(stmt, label) {
|
|
|
40047
41419
|
lines.push(` fields: ${joinFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : joinFields.join(", ")}`);
|
|
40048
41420
|
}
|
|
40049
41421
|
}
|
|
40050
|
-
lines.push(...collectSubqueryPlans(stmt));
|
|
41422
|
+
lines.push(...collectSubqueryPlans(stmt, capabilities, orderPlans));
|
|
40051
41423
|
return lines;
|
|
40052
41424
|
}
|
|
40053
|
-
function buildUnionPlan(stmt) {
|
|
41425
|
+
function buildUnionPlan(stmt, capabilities, orderPlans) {
|
|
40054
41426
|
const selects = [];
|
|
40055
41427
|
const collect = (u) => {
|
|
40056
41428
|
if (u.type === "SELECT") {
|
|
@@ -40064,24 +41436,25 @@ function buildUnionPlan(stmt) {
|
|
|
40064
41436
|
const lines = [];
|
|
40065
41437
|
selects.forEach((sel, i) => {
|
|
40066
41438
|
if (i > 0) lines.push("");
|
|
40067
|
-
lines.push(...buildSelectPlan(sel, `[union:${i + 1}]
|
|
41439
|
+
lines.push(...buildSelectPlan(sel, `[union:${i + 1}]`, capabilities, orderPlans));
|
|
40068
41440
|
});
|
|
40069
41441
|
return lines;
|
|
40070
41442
|
}
|
|
40071
|
-
function buildWithPlan(stmt) {
|
|
41443
|
+
function buildWithPlan(stmt, capabilities, orderPlans) {
|
|
40072
41444
|
const lines = [];
|
|
40073
41445
|
for (const cte of stmt.ctes) {
|
|
40074
41446
|
if (cte.query.type === "SELECT") {
|
|
40075
|
-
lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]
|
|
41447
|
+
lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]`, capabilities, orderPlans));
|
|
40076
41448
|
lines.push("");
|
|
40077
41449
|
}
|
|
40078
41450
|
}
|
|
40079
41451
|
if (stmt.query.type === "SELECT" || stmt.query.type === "UNION") {
|
|
40080
|
-
lines.push(...buildExplainPlan(stmt.query, "[main]"));
|
|
41452
|
+
lines.push(...buildExplainPlan(stmt.query, "[main]", capabilities, orderPlans));
|
|
40081
41453
|
}
|
|
40082
41454
|
if (canInlineSingleCte(stmt)) {
|
|
40083
41455
|
lines.push("");
|
|
40084
|
-
|
|
41456
|
+
const inlined = buildInlinedQuery(stmt);
|
|
41457
|
+
lines.push(...buildSelectPlan(inlined, "[effective: inlined CTE]", capabilities, orderPlans));
|
|
40085
41458
|
}
|
|
40086
41459
|
return lines;
|
|
40087
41460
|
}
|
|
@@ -40109,7 +41482,7 @@ function collectFullScanReasons(stmt) {
|
|
|
40109
41482
|
r.push("ORDER BY \u306B\u5F0F");
|
|
40110
41483
|
return r;
|
|
40111
41484
|
}
|
|
40112
|
-
function collectSubqueryPlans(stmt) {
|
|
41485
|
+
function collectSubqueryPlans(stmt, capabilities, orderPlans) {
|
|
40113
41486
|
const lines = [];
|
|
40114
41487
|
let idx = 1;
|
|
40115
41488
|
const visitWhere = (w) => {
|
|
@@ -40118,16 +41491,16 @@ function collectSubqueryPlans(stmt) {
|
|
|
40118
41491
|
case "BINARY":
|
|
40119
41492
|
if (w.right.type === "SCALAR_SUBQUERY") {
|
|
40120
41493
|
lines.push("");
|
|
40121
|
-
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]
|
|
41494
|
+
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
40122
41495
|
}
|
|
40123
41496
|
if (w.right.type === "SUBQUERY_IN_LIST") {
|
|
40124
41497
|
lines.push("");
|
|
40125
|
-
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]
|
|
41498
|
+
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
40126
41499
|
}
|
|
40127
41500
|
break;
|
|
40128
41501
|
case "EXISTS":
|
|
40129
41502
|
lines.push("");
|
|
40130
|
-
lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]
|
|
41503
|
+
lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
40131
41504
|
break;
|
|
40132
41505
|
case "LOGICAL":
|
|
40133
41506
|
visitWhere(w.left);
|
|
@@ -40145,7 +41518,7 @@ function collectSubqueryPlans(stmt) {
|
|
|
40145
41518
|
for (const col of stmt.columns) {
|
|
40146
41519
|
if (col.type === "SCALAR_SUBQUERY_COL") {
|
|
40147
41520
|
lines.push("");
|
|
40148
|
-
lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]
|
|
41521
|
+
lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
40149
41522
|
}
|
|
40150
41523
|
}
|
|
40151
41524
|
if (stmt.having) visitWhere(stmt.having);
|
|
@@ -40163,7 +41536,7 @@ function buildInsertPlan(stmt, label) {
|
|
|
40163
41536
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
40164
41537
|
return lines;
|
|
40165
41538
|
}
|
|
40166
|
-
function buildInsertSelectPlan(stmt, label) {
|
|
41539
|
+
function buildInsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
40167
41540
|
const lines = [];
|
|
40168
41541
|
if (label) lines.push(label);
|
|
40169
41542
|
lines.push(` [INSERT SELECT]`);
|
|
@@ -40171,10 +41544,10 @@ function buildInsertSelectPlan(stmt, label) {
|
|
|
40171
41544
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
40172
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`);
|
|
40173
41546
|
lines.push("");
|
|
40174
|
-
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]"));
|
|
41547
|
+
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans));
|
|
40175
41548
|
return lines;
|
|
40176
41549
|
}
|
|
40177
|
-
function buildUpdatePlan(stmt, label) {
|
|
41550
|
+
function buildUpdatePlan(stmt, label, capabilities, orderPlans) {
|
|
40178
41551
|
const isArith = hasArithAssignment(stmt);
|
|
40179
41552
|
const isSubq = stmt.assignments.some((a) => a.value.type === "SCALAR_SUBQUERY");
|
|
40180
41553
|
const lines = [];
|
|
@@ -40208,7 +41581,7 @@ function buildUpdatePlan(stmt, label) {
|
|
|
40208
41581
|
for (const a of stmt.assignments) {
|
|
40209
41582
|
if (a.value.type === "SCALAR_SUBQUERY") {
|
|
40210
41583
|
lines.push("");
|
|
40211
|
-
lines.push(...buildSelectPlan(a.value.query, `[subquery: ${a.field}]
|
|
41584
|
+
lines.push(...buildSelectPlan(a.value.query, `[subquery: ${a.field}]`, capabilities, orderPlans));
|
|
40212
41585
|
}
|
|
40213
41586
|
}
|
|
40214
41587
|
return lines;
|
|
@@ -40235,7 +41608,7 @@ function buildUpsertPlan(stmt, label) {
|
|
|
40235
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}`
|
|
40236
41609
|
];
|
|
40237
41610
|
}
|
|
40238
|
-
function buildUpsertSelectPlan(stmt, label) {
|
|
41611
|
+
function buildUpsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
40239
41612
|
const lines = [
|
|
40240
41613
|
...label ? [label] : [],
|
|
40241
41614
|
` [UPSERT SELECT]`,
|
|
@@ -40245,7 +41618,7 @@ function buildUpsertSelectPlan(stmt, label) {
|
|
|
40245
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`,
|
|
40246
41619
|
``
|
|
40247
41620
|
];
|
|
40248
|
-
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]"));
|
|
41621
|
+
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans));
|
|
40249
41622
|
return lines;
|
|
40250
41623
|
}
|
|
40251
41624
|
function buildReorderPlan(stmt, label) {
|
|
@@ -40780,12 +42153,14 @@ function flattenFormFieldProperties(properties) {
|
|
|
40780
42153
|
function flattenFields(properties, lookupCopyFields, inSubtable = false) {
|
|
40781
42154
|
const out = [];
|
|
40782
42155
|
for (const field of Object.values(properties)) {
|
|
40783
|
-
|
|
42156
|
+
const optionOrder = toOptionOrderMap(field.options);
|
|
42157
|
+
const sortKind = detectSortKind(field.type, field.format);
|
|
42158
|
+
const info = {
|
|
40784
42159
|
code: field.code,
|
|
40785
42160
|
label: field.label,
|
|
40786
42161
|
fieldType: field.type,
|
|
40787
|
-
optionOrder
|
|
40788
|
-
sortKind
|
|
42162
|
+
optionOrder,
|
|
42163
|
+
sortKind,
|
|
40789
42164
|
required: field.required,
|
|
40790
42165
|
minValue: normalizeConstraintValue(field.minValue),
|
|
40791
42166
|
maxValue: normalizeConstraintValue(field.maxValue),
|
|
@@ -40794,7 +42169,9 @@ function flattenFields(properties, lookupCopyFields, inSubtable = false) {
|
|
|
40794
42169
|
defaultValue: field.defaultValue,
|
|
40795
42170
|
inSubtable,
|
|
40796
42171
|
writable: !lookupCopyFields.has(field.code) && !NON_WRITABLE_FIELD_TYPES2.has(field.type)
|
|
40797
|
-
}
|
|
42172
|
+
};
|
|
42173
|
+
info.semantics = resolveFieldSemantics(info);
|
|
42174
|
+
out.push(info);
|
|
40798
42175
|
if (field.fields) out.push(...flattenFields(field.fields, lookupCopyFields, true));
|
|
40799
42176
|
}
|
|
40800
42177
|
return out;
|
|
@@ -40849,6 +42226,18 @@ function detectSortKind(fieldType, calcFormat) {
|
|
|
40849
42226
|
return void 0;
|
|
40850
42227
|
}
|
|
40851
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
|
+
|
|
40852
42241
|
// src/cli/nodeKintoneClient.ts
|
|
40853
42242
|
var SEARCH_ABORTED_HEADER_VALUE = "Filter aborted because of too many search results";
|
|
40854
42243
|
function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
@@ -41046,7 +42435,7 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
41046
42435
|
const res = await requestJson(`${apiBasePath}/app/status.json?${qs.toString()}`, { method: "GET" }, appId);
|
|
41047
42436
|
return {
|
|
41048
42437
|
enable: res.enable,
|
|
41049
|
-
states:
|
|
42438
|
+
states: normalizeProcessStatusStates(res.states)
|
|
41050
42439
|
};
|
|
41051
42440
|
}
|
|
41052
42441
|
};
|
|
@@ -42053,8 +43442,23 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42053
43442
|
} catch (err) {
|
|
42054
43443
|
throw restoreSqlContextError(err, normalized.sourceSql, normalized.sqlContext);
|
|
42055
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;
|
|
42056
43454
|
if (statements.length > 1) {
|
|
42057
|
-
const plans = buildBatchExplainPlans(
|
|
43455
|
+
const plans = await buildBatchExplainPlans(
|
|
43456
|
+
explainSourceSql,
|
|
43457
|
+
explainClient,
|
|
43458
|
+
void 0,
|
|
43459
|
+
explainCacheContext,
|
|
43460
|
+
runtime?.maxRecords
|
|
43461
|
+
);
|
|
42058
43462
|
return {
|
|
42059
43463
|
ok: true,
|
|
42060
43464
|
batch: true,
|
|
@@ -42063,8 +43467,9 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42063
43467
|
appBindings
|
|
42064
43468
|
};
|
|
42065
43469
|
}
|
|
42066
|
-
const result = await executeSql(explainSql(
|
|
42067
|
-
cacheContext:
|
|
43470
|
+
const result = await executeSql(explainSql(explainSourceSql), explainClient, {
|
|
43471
|
+
cacheContext: explainCacheContext,
|
|
43472
|
+
maxRecords: runtime?.maxRecords
|
|
42068
43473
|
});
|
|
42069
43474
|
if (result.type !== "SELECT") {
|
|
42070
43475
|
throw new Error(`ArgumentError: EXPLAIN returned unexpected result type ${result.type}.`);
|
|
@@ -42089,7 +43494,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42089
43494
|
profile: input.profile,
|
|
42090
43495
|
maxRecords: input.maxRecords,
|
|
42091
43496
|
fetchParallel: input.fetchParallel,
|
|
42092
|
-
onLimit: validation.
|
|
43497
|
+
onLimit: validation.containsValidationOnly ? "error" : input.onLimit,
|
|
42093
43498
|
timeout: input.timeout,
|
|
42094
43499
|
tempTableMaxRows: input.tempTableMaxRows
|
|
42095
43500
|
});
|
|
@@ -42134,7 +43539,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42134
43539
|
profile: input.profile,
|
|
42135
43540
|
maxRecords: input.maxRecords,
|
|
42136
43541
|
fetchParallel: input.fetchParallel,
|
|
42137
|
-
onLimit: validation.
|
|
43542
|
+
onLimit: validation.containsValidationOnly ? "error" : input.onLimit,
|
|
42138
43543
|
timeout: input.timeout
|
|
42139
43544
|
});
|
|
42140
43545
|
const result = await executeSql(runtime.sql, runtime.client, {
|
|
@@ -42430,7 +43835,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
42430
43835
|
var profile = external_exports.string().min(1).describe("kintone connection profile name from ksql.config.json (default: the server's default profile).").optional();
|
|
42431
43836
|
var maxRecords = external_exports.number().int().positive().describe("Maximum records fetched per SELECT (default 500).").optional();
|
|
42432
43837
|
var fetchParallel = external_exports.number().int().min(1).max(10).describe("Number of parallel kintone record-fetch requests (1-10).").optional();
|
|
42433
|
-
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();
|
|
42434
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();
|
|
42435
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();
|
|
42436
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).");
|
|
@@ -42554,7 +43959,7 @@ Options:
|
|
|
42554
43959
|
-h, --help Show help
|
|
42555
43960
|
`);
|
|
42556
43961
|
}
|
|
42557
|
-
var SERVER_VERSION = true ? "
|
|
43962
|
+
var SERVER_VERSION = true ? "3.0.0" : "0.0.0-dev";
|
|
42558
43963
|
function createServer(args) {
|
|
42559
43964
|
const server = new McpServer({
|
|
42560
43965
|
name: "ksql-mcp",
|
|
@@ -42571,12 +43976,12 @@ function createServer(args) {
|
|
|
42571
43976
|
}, tools.validateTool);
|
|
42572
43977
|
server.registerTool("ksql_explain", {
|
|
42573
43978
|
title: "Explain kSQL",
|
|
42574
|
-
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.",
|
|
42575
43980
|
inputSchema: explainInputShape
|
|
42576
43981
|
}, tools.explainTool);
|
|
42577
43982
|
server.registerTool("ksql_query", {
|
|
42578
43983
|
title: "Run read-only kSQL",
|
|
42579
|
-
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.",
|
|
42580
43985
|
inputSchema: queryInputShape
|
|
42581
43986
|
}, tools.queryTool);
|
|
42582
43987
|
server.registerTool("ksql_mutate", {
|