@rex0220/kintone-sql-tools 3.0.0 → 3.2.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 +1 -0
- package/dist-cli/ksql.js +771 -56
- package/dist-mcp/ksql-mcp.js +771 -63
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -31029,6 +31029,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31029
31029
|
["LTRIM", "LTRIM" /* LTRIM */],
|
|
31030
31030
|
["RTRIM", "RTRIM" /* RTRIM */],
|
|
31031
31031
|
["LENGTH", "LENGTH" /* LENGTH */],
|
|
31032
|
+
["LENGTH_CHAR", "LENGTH_CHAR" /* LENGTH_CHAR */],
|
|
31032
31033
|
["SUBSTRING", "SUBSTRING" /* SUBSTRING */],
|
|
31033
31034
|
["SUBSTR", "SUBSTR" /* SUBSTR */],
|
|
31034
31035
|
["CONCAT", "CONCAT" /* CONCAT */],
|
|
@@ -31041,6 +31042,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31041
31042
|
["LEAST", "LEAST" /* LEAST */],
|
|
31042
31043
|
["LPAD", "LPAD" /* LPAD */],
|
|
31043
31044
|
["RPAD", "RPAD" /* RPAD */],
|
|
31045
|
+
["TRANSLATE", "TRANSLATE" /* TRANSLATE */],
|
|
31044
31046
|
["CAST", "CAST" /* CAST */],
|
|
31045
31047
|
["CONVERT", "CONVERT" /* CONVERT */],
|
|
31046
31048
|
["FORMAT", "FORMAT" /* FORMAT */],
|
|
@@ -31400,10 +31402,12 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
|
|
|
31400
31402
|
"LTRIM" /* LTRIM */,
|
|
31401
31403
|
"RTRIM" /* RTRIM */,
|
|
31402
31404
|
"LENGTH" /* LENGTH */,
|
|
31405
|
+
"LENGTH_CHAR" /* LENGTH_CHAR */,
|
|
31403
31406
|
"SUBSTRING" /* SUBSTRING */,
|
|
31404
31407
|
"SUBSTR" /* SUBSTR */,
|
|
31405
31408
|
"CONCAT" /* CONCAT */,
|
|
31406
31409
|
"REPLACE" /* REPLACE */,
|
|
31410
|
+
"TRANSLATE" /* TRANSLATE */,
|
|
31407
31411
|
"COALESCE" /* COALESCE */,
|
|
31408
31412
|
"NULLIF" /* NULLIF */,
|
|
31409
31413
|
"ISNULL" /* ISNULL */,
|
|
@@ -31455,6 +31459,7 @@ var ParseError = class extends Error {
|
|
|
31455
31459
|
var Parser = class {
|
|
31456
31460
|
constructor(tokens) {
|
|
31457
31461
|
this.tokens = tokens;
|
|
31462
|
+
this.allowUnaryPlusNumber = false;
|
|
31458
31463
|
this.pos = 0;
|
|
31459
31464
|
/** WITH 句で定義された CTE 名のセット(parseTableRef で参照) */
|
|
31460
31465
|
this.cteNames = /* @__PURE__ */ new Set();
|
|
@@ -32223,8 +32228,16 @@ var Parser = class {
|
|
|
32223
32228
|
this.expect(")" /* RPAREN */);
|
|
32224
32229
|
return expr;
|
|
32225
32230
|
}
|
|
32231
|
+
if (this.allowUnaryPlusNumber && this.peek().kind === "+" /* PLUS */) {
|
|
32232
|
+
this.advance();
|
|
32233
|
+
const number4 = this.expect("NUMBER" /* NUMBER */, "\u5358\u9805 + \u306E\u76F4\u5F8C\u306B\u306F\u6570\u5024\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059");
|
|
32234
|
+
return { type: "NUMBER", value: Number(number4.value) };
|
|
32235
|
+
}
|
|
32226
32236
|
if (this.peek().kind === "-" /* MINUS */) {
|
|
32227
32237
|
this.advance();
|
|
32238
|
+
if (this.peek().kind === "-" /* MINUS */ || this.peek().kind === "+" /* PLUS */) {
|
|
32239
|
+
throw new ParseError("\u5358\u9805\u7B26\u53F7\u3092\u91CD\u306D\u3066\u6307\u5B9A\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
32240
|
+
}
|
|
32228
32241
|
const operand = this.parseArithPrimary();
|
|
32229
32242
|
if (operand.type === "NUMBER") return { type: "NUMBER", value: -operand.value };
|
|
32230
32243
|
return { type: "ARITH", left: { type: "NUMBER", value: 0 }, op: "-", right: operand };
|
|
@@ -32334,10 +32347,12 @@ var Parser = class {
|
|
|
32334
32347
|
["LTRIM" /* LTRIM */]: "LTRIM",
|
|
32335
32348
|
["RTRIM" /* RTRIM */]: "RTRIM",
|
|
32336
32349
|
["LENGTH" /* LENGTH */]: "LENGTH",
|
|
32350
|
+
["LENGTH_CHAR" /* LENGTH_CHAR */]: "LENGTH_CHAR",
|
|
32337
32351
|
["SUBSTRING" /* SUBSTRING */]: "SUBSTRING",
|
|
32338
32352
|
["SUBSTR" /* SUBSTR */]: "SUBSTRING",
|
|
32339
32353
|
["CONCAT" /* CONCAT */]: "CONCAT",
|
|
32340
32354
|
["REPLACE" /* REPLACE */]: "REPLACE",
|
|
32355
|
+
["TRANSLATE" /* TRANSLATE */]: "TRANSLATE",
|
|
32341
32356
|
["COALESCE" /* COALESCE */]: "COALESCE",
|
|
32342
32357
|
["NULLIF" /* NULLIF */]: "NULLIF",
|
|
32343
32358
|
["ISNULL" /* ISNULL */]: "ISNULL",
|
|
@@ -33098,6 +33113,11 @@ var Parser = class {
|
|
|
33098
33113
|
} else if (this.peek().kind === "IF" /* IF */) {
|
|
33099
33114
|
const expr = this.parseIfExpr();
|
|
33100
33115
|
row.push({ type: "CASE_VALUE", expr });
|
|
33116
|
+
} else if (this.peek().kind === "-" /* MINUS */ || this.peek().kind === "+" /* PLUS */) {
|
|
33117
|
+
const sign = this.advance();
|
|
33118
|
+
const number4 = this.expect("NUMBER" /* NUMBER */, "INSERT \u306E\u5358\u9805\u7B26\u53F7\u306E\u76F4\u5F8C\u306B\u306F\u6570\u5024\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059");
|
|
33119
|
+
const value = Number(number4.value);
|
|
33120
|
+
row.push({ type: "NUMBER", value: sign.kind === "-" /* MINUS */ ? -value : value });
|
|
33101
33121
|
} else {
|
|
33102
33122
|
const tok = this.advance();
|
|
33103
33123
|
if (tok.kind === "STRING" /* STRING */) {
|
|
@@ -33127,6 +33147,12 @@ var Parser = class {
|
|
|
33127
33147
|
const { appId, subtableCode } = extractTableRef(name, this.prev());
|
|
33128
33148
|
this.expect("SET" /* SET */);
|
|
33129
33149
|
const assignments = this.parseAssignments();
|
|
33150
|
+
if (subtableCode && assignments.some((a) => a.value.type === "STRING_FUNC")) {
|
|
33151
|
+
throw new ParseError(
|
|
33152
|
+
"\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093",
|
|
33153
|
+
this.prev()
|
|
33154
|
+
);
|
|
33155
|
+
}
|
|
33130
33156
|
let from = null;
|
|
33131
33157
|
if (this.consume("FROM" /* FROM */)) {
|
|
33132
33158
|
const table = this.parseTableRef();
|
|
@@ -33170,7 +33196,14 @@ var Parser = class {
|
|
|
33170
33196
|
from.targetFilter = decomposed.targetFilter;
|
|
33171
33197
|
} else if (assignments.some((a) => a.value.type === "SOURCE_FIELD")) {
|
|
33172
33198
|
throw new ParseError(
|
|
33173
|
-
"SET \u306E\u5024\u306B\
|
|
33199
|
+
"SET \u306E\u5024\u306B\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u3092\u5358\u72EC\u3067\u6307\u5B9A\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093",
|
|
33200
|
+
whereTok
|
|
33201
|
+
);
|
|
33202
|
+
} else if (assignments.some(
|
|
33203
|
+
(a) => a.value.type === "STRING_FUNC" && this.nodeContainsAnyQualifier(a.value)
|
|
33204
|
+
)) {
|
|
33205
|
+
throw new ParseError(
|
|
33206
|
+
"UPDATE SET \u306E\u6587\u5B57\u5217\u95A2\u6570\u3067\u306F\u66F4\u65B0\u5148\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u4FEE\u98FE\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044",
|
|
33174
33207
|
whereTok
|
|
33175
33208
|
);
|
|
33176
33209
|
}
|
|
@@ -33237,6 +33270,12 @@ var Parser = class {
|
|
|
33237
33270
|
}
|
|
33238
33271
|
validateUpdateFromAssignments(assignments, sourceAlias, tok) {
|
|
33239
33272
|
for (const assignment of assignments) {
|
|
33273
|
+
if (assignment.value.type === "STRING_FUNC") {
|
|
33274
|
+
throw new ParseError(
|
|
33275
|
+
"UPDATE ... FROM \u306E SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093",
|
|
33276
|
+
tok
|
|
33277
|
+
);
|
|
33278
|
+
}
|
|
33240
33279
|
if (assignment.value.type === "SOURCE_FIELD") {
|
|
33241
33280
|
if (assignment.value.alias.toLowerCase() !== sourceAlias.toLowerCase()) {
|
|
33242
33281
|
throw new ParseError(`UPDATE ... FROM \u306E SET \u53C2\u7167\u306F\u30BD\u30FC\u30B9 alias ${sourceAlias} \u3067\u4FEE\u98FE\u3057\u3066\u304F\u3060\u3055\u3044`, tok);
|
|
@@ -33376,9 +33415,17 @@ var Parser = class {
|
|
|
33376
33415
|
this.expect(")" /* RPAREN */);
|
|
33377
33416
|
return { type: "SCALAR_SUBQUERY", query };
|
|
33378
33417
|
}
|
|
33379
|
-
const
|
|
33418
|
+
const previousAllowUnaryPlusNumber = this.allowUnaryPlusNumber;
|
|
33419
|
+
this.allowUnaryPlusNumber = true;
|
|
33420
|
+
let node;
|
|
33421
|
+
try {
|
|
33422
|
+
node = this.parseArithAddSub();
|
|
33423
|
+
} finally {
|
|
33424
|
+
this.allowUnaryPlusNumber = previousAllowUnaryPlusNumber;
|
|
33425
|
+
}
|
|
33380
33426
|
if (node.type === "NUMBER") return node;
|
|
33381
33427
|
if (node.type === "ARITH") return node;
|
|
33428
|
+
if (node.type === "STRING_FUNC") return node;
|
|
33382
33429
|
if (node.type === "FIELD_REF") {
|
|
33383
33430
|
const dot = node.field.indexOf(".");
|
|
33384
33431
|
if (dot > 0 && dot < node.field.length - 1) {
|
|
@@ -33386,7 +33433,7 @@ var Parser = class {
|
|
|
33386
33433
|
}
|
|
33387
33434
|
}
|
|
33388
33435
|
throw new ParseError(
|
|
33389
|
-
"SET \u306E\u5024\u306B\
|
|
33436
|
+
"SET \u306E\u5024\u306B\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u3092\u5358\u72EC\u3067\u6307\u5B9A\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093",
|
|
33390
33437
|
tok
|
|
33391
33438
|
);
|
|
33392
33439
|
}
|
|
@@ -35399,6 +35446,43 @@ function applyRoundOp(op, num, digits) {
|
|
|
35399
35446
|
if (digits > 0) return String(parseFloat(raw.toFixed(digits)));
|
|
35400
35447
|
return String(raw);
|
|
35401
35448
|
}
|
|
35449
|
+
function isHighSurrogate(codeUnit) {
|
|
35450
|
+
return codeUnit >= 55296 && codeUnit <= 56319;
|
|
35451
|
+
}
|
|
35452
|
+
function isLowSurrogate(codeUnit) {
|
|
35453
|
+
return codeUnit >= 56320 && codeUnit <= 57343;
|
|
35454
|
+
}
|
|
35455
|
+
function splitsSurrogatePair(value, index) {
|
|
35456
|
+
return index > 0 && index < value.length && isHighSurrogate(value.charCodeAt(index - 1)) && isLowSurrogate(value.charCodeAt(index));
|
|
35457
|
+
}
|
|
35458
|
+
function normalizeSliceIndex(index, length) {
|
|
35459
|
+
if (Number.isNaN(index) || index === Number.NEGATIVE_INFINITY) return 0;
|
|
35460
|
+
if (index === Number.POSITIVE_INFINITY) return length;
|
|
35461
|
+
const integer2 = Math.trunc(index);
|
|
35462
|
+
return integer2 < 0 ? Math.max(length + integer2, 0) : Math.min(integer2, length);
|
|
35463
|
+
}
|
|
35464
|
+
function sliceSafePrefix(value, budget) {
|
|
35465
|
+
let end = Math.min(Math.max(0, budget), value.length);
|
|
35466
|
+
if (splitsSurrogatePair(value, end)) end -= 1;
|
|
35467
|
+
return value.slice(0, end);
|
|
35468
|
+
}
|
|
35469
|
+
function sliceSafeSuffix(value, budget) {
|
|
35470
|
+
let start = Math.max(0, value.length - budget);
|
|
35471
|
+
if (splitsSurrogatePair(value, start)) start += 1;
|
|
35472
|
+
return value.slice(start);
|
|
35473
|
+
}
|
|
35474
|
+
function sliceSafeRange(value, rawStart, rawEnd) {
|
|
35475
|
+
let start = normalizeSliceIndex(rawStart, value.length);
|
|
35476
|
+
let end = normalizeSliceIndex(rawEnd, value.length);
|
|
35477
|
+
if (end <= start) return "";
|
|
35478
|
+
if (splitsSurrogatePair(value, start)) start += 1;
|
|
35479
|
+
if (splitsSurrogatePair(value, end)) end -= 1;
|
|
35480
|
+
return value.slice(start, Math.max(start, end));
|
|
35481
|
+
}
|
|
35482
|
+
function makeSafePadding(pad, gap) {
|
|
35483
|
+
const repeated = pad.repeat(Math.ceil(gap / pad.length));
|
|
35484
|
+
return sliceSafePrefix(repeated, gap);
|
|
35485
|
+
}
|
|
35402
35486
|
function evalStringFunc(expr, row) {
|
|
35403
35487
|
const args = expr.args.map((a) => evalStringFuncArg(a, row));
|
|
35404
35488
|
switch (expr.func) {
|
|
@@ -35414,23 +35498,26 @@ function evalStringFunc(expr, row) {
|
|
|
35414
35498
|
return (args[0] ?? "").trimEnd();
|
|
35415
35499
|
case "LENGTH":
|
|
35416
35500
|
return String((args[0] ?? "").length);
|
|
35501
|
+
case "LENGTH_CHAR":
|
|
35502
|
+
assertArity("LENGTH_CHAR", args, 1, 1);
|
|
35503
|
+
return String([...args[0] ?? ""].length);
|
|
35417
35504
|
case "SUBSTRING": {
|
|
35418
35505
|
const str = args[0] ?? "";
|
|
35419
35506
|
const start = Math.max(0, Number(args[1] ?? "1") - 1);
|
|
35420
35507
|
const len = args[2] !== void 0 ? Number(args[2]) : void 0;
|
|
35421
|
-
return len !== void 0 ?
|
|
35508
|
+
return sliceSafeRange(str, start, len !== void 0 ? start + len : str.length);
|
|
35422
35509
|
}
|
|
35423
35510
|
case "LEFT": {
|
|
35424
35511
|
assertArity("LEFT", args, 2, 2);
|
|
35425
35512
|
const str = args[0];
|
|
35426
35513
|
const n = Math.trunc(Number(args[1]));
|
|
35427
|
-
return Number.isNaN(n) || n <= 0 ? "" : str
|
|
35514
|
+
return Number.isNaN(n) || n <= 0 ? "" : sliceSafePrefix(str, n);
|
|
35428
35515
|
}
|
|
35429
35516
|
case "RIGHT": {
|
|
35430
35517
|
assertArity("RIGHT", args, 2, 2);
|
|
35431
35518
|
const str = args[0];
|
|
35432
35519
|
const n = Math.trunc(Number(args[1]));
|
|
35433
|
-
return Number.isNaN(n) || n <= 0 ? "" : str
|
|
35520
|
+
return Number.isNaN(n) || n <= 0 ? "" : sliceSafeSuffix(str, n);
|
|
35434
35521
|
}
|
|
35435
35522
|
case "INSTR":
|
|
35436
35523
|
assertArity("INSTR", args, 2, 2);
|
|
@@ -35441,10 +35528,11 @@ function evalStringFunc(expr, row) {
|
|
|
35441
35528
|
const str = args[0];
|
|
35442
35529
|
const n = Math.trunc(Number(args[1]));
|
|
35443
35530
|
if (Number.isNaN(n) || n <= 0) return "";
|
|
35444
|
-
if (str.length >= n) return str
|
|
35531
|
+
if (str.length >= n) return sliceSafePrefix(str, n);
|
|
35445
35532
|
const pad = args[2] ?? " ";
|
|
35446
35533
|
if (pad === "") return str;
|
|
35447
|
-
|
|
35534
|
+
const padding = makeSafePadding(pad, n - str.length);
|
|
35535
|
+
return expr.func === "LPAD" ? padding + str : str + padding;
|
|
35448
35536
|
}
|
|
35449
35537
|
case "GREATEST":
|
|
35450
35538
|
case "LEAST":
|
|
@@ -35458,6 +35546,21 @@ function evalStringFunc(expr, row) {
|
|
|
35458
35546
|
const to = args[2] ?? "";
|
|
35459
35547
|
return from === "" ? str : str.split(from).join(to);
|
|
35460
35548
|
}
|
|
35549
|
+
case "TRANSLATE": {
|
|
35550
|
+
assertArity("TRANSLATE", args, 3, 3);
|
|
35551
|
+
const from = [...args[1]];
|
|
35552
|
+
const to = [...args[2]];
|
|
35553
|
+
if (from.length !== to.length) {
|
|
35554
|
+
throw new Error(
|
|
35555
|
+
`ArgumentError: TRANSLATE \u306E from \u3068 to \u306F\u540C\u3058\u6587\u5B57\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08from=${from.length}, to=${to.length}\uFF09`
|
|
35556
|
+
);
|
|
35557
|
+
}
|
|
35558
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
35559
|
+
from.forEach((ch, i) => {
|
|
35560
|
+
if (!map2.has(ch)) map2.set(ch, to[i]);
|
|
35561
|
+
});
|
|
35562
|
+
return [...args[0]].map((ch) => map2.get(ch) ?? ch).join("");
|
|
35563
|
+
}
|
|
35461
35564
|
case "COALESCE":
|
|
35462
35565
|
return args.find((a) => a !== "") ?? "";
|
|
35463
35566
|
case "NULLIF":
|
|
@@ -35695,6 +35798,7 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType, semantics
|
|
|
35695
35798
|
}
|
|
35696
35799
|
var NUMERIC_STRING_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
35697
35800
|
"LENGTH",
|
|
35801
|
+
"LENGTH_CHAR",
|
|
35698
35802
|
"INSTR",
|
|
35699
35803
|
"ROUND",
|
|
35700
35804
|
"FLOOR",
|
|
@@ -35942,7 +36046,7 @@ function updateToPutBatches(stmt, ids, fieldTypes = /* @__PURE__ */ new Map()) {
|
|
|
35942
36046
|
function buildUpdateRecord(assignments, fieldTypes) {
|
|
35943
36047
|
const record2 = {};
|
|
35944
36048
|
for (const { field, value } of assignments) {
|
|
35945
|
-
if (value.type === "ARITH" || value.type === "CASE_VALUE" || value.type === "SOURCE_FIELD") continue;
|
|
36049
|
+
if (value.type === "ARITH" || value.type === "CASE_VALUE" || value.type === "STRING_FUNC" || value.type === "SOURCE_FIELD") continue;
|
|
35946
36050
|
record2[field] = { value: toKintoneValue(value, fieldTypes.get(field)) };
|
|
35947
36051
|
}
|
|
35948
36052
|
return record2;
|
|
@@ -35952,12 +36056,19 @@ function hasArithAssignment(stmt) {
|
|
|
35952
36056
|
(a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE"
|
|
35953
36057
|
);
|
|
35954
36058
|
}
|
|
36059
|
+
function hasRowDependentAssignment(stmt) {
|
|
36060
|
+
return stmt.assignments.some(
|
|
36061
|
+
(a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE" || a.value.type === "STRING_FUNC"
|
|
36062
|
+
);
|
|
36063
|
+
}
|
|
35955
36064
|
function updateToGetQueryForArith(stmt) {
|
|
35956
36065
|
assertDmlWhereIsSafe(stmt.where);
|
|
35957
36066
|
const refFields = /* @__PURE__ */ new Set();
|
|
35958
36067
|
for (const { value } of stmt.assignments) {
|
|
35959
36068
|
if (value.type === "ARITH") {
|
|
35960
36069
|
collectArithFields2(value, refFields);
|
|
36070
|
+
} else if (value.type === "STRING_FUNC") {
|
|
36071
|
+
collectStringFuncFields2(value, refFields);
|
|
35961
36072
|
} else if (value.type === "CASE_VALUE") {
|
|
35962
36073
|
collectCaseFields(value.expr, refFields);
|
|
35963
36074
|
}
|
|
@@ -36044,6 +36155,8 @@ function updateToPutBatchesArith(stmt, records, fieldTypes = /* @__PURE__ */ new
|
|
|
36044
36155
|
for (const { field, value } of stmt.assignments) {
|
|
36045
36156
|
if (value.type === "ARITH") {
|
|
36046
36157
|
record2[field] = { value: String(evalArith(value, raw)) };
|
|
36158
|
+
} else if (value.type === "STRING_FUNC") {
|
|
36159
|
+
record2[field] = { value: evalStringFunc(value, row) };
|
|
36047
36160
|
} else if (value.type === "CASE_VALUE") {
|
|
36048
36161
|
record2[field] = { value: evalCaseWhenValue(value.expr, row, fieldTypes.get(field)) };
|
|
36049
36162
|
} else if (value.type === "SOURCE_FIELD") {
|
|
@@ -36092,6 +36205,8 @@ function updateFromToPutBatches(stmt, matched, fieldTypes = /* @__PURE__ */ new
|
|
|
36092
36205
|
throw new DmlConvertError(`\u6570\u5024\u30D5\u30A3\u30FC\u30EB\u30C9 ${field} \u306B\u5909\u63DB\u3067\u304D\u306A\u3044\u5024\u3067\u3059: ${raw}`);
|
|
36093
36206
|
}
|
|
36094
36207
|
record2[field] = { value: toKintoneValue({ type: "STRING", value: raw }, fieldType) };
|
|
36208
|
+
} else if (value.type === "STRING_FUNC") {
|
|
36209
|
+
throw new DmlConvertError("UPDATE ... FROM \u306E SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
|
|
36095
36210
|
} else if (value.type === "ARITH") {
|
|
36096
36211
|
record2[field] = { value: String(evalArith(value, target)) };
|
|
36097
36212
|
} else if (value.type === "CASE_VALUE") {
|
|
@@ -36543,7 +36658,7 @@ var KORDER_NATIVE_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
36543
36658
|
"CREATOR",
|
|
36544
36659
|
"MODIFIER"
|
|
36545
36660
|
]);
|
|
36546
|
-
function
|
|
36661
|
+
function planKorder(input) {
|
|
36547
36662
|
const { stmt } = input;
|
|
36548
36663
|
const reasons = [];
|
|
36549
36664
|
if (stmt.orderMode !== "KINTONE_NATIVE") reasons.push("KORDER_MODE_REQUIRED");
|
|
@@ -36573,29 +36688,120 @@ function planKorderNative(input) {
|
|
|
36573
36688
|
reasons.push(`KORDER_TYPE_UNSUPPORTED(field=${name}, type=${semantics.fieldType})`);
|
|
36574
36689
|
}
|
|
36575
36690
|
}
|
|
36576
|
-
if (stmt.limit === null || stmt.limit
|
|
36691
|
+
if (stmt.limit === null || !Number.isSafeInteger(stmt.limit) || stmt.limit < 0) {
|
|
36577
36692
|
reasons.push(`KORDER_LIMIT_INVALID(limit=${String(stmt.limit)})`);
|
|
36578
36693
|
}
|
|
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
36694
|
const offset = stmt.offset ?? 0;
|
|
36583
|
-
if (offset
|
|
36695
|
+
if (!Number.isSafeInteger(offset) || offset < 0) {
|
|
36696
|
+
reasons.push(`KORDER_OFFSET_INVALID(offset=${offset})`);
|
|
36697
|
+
}
|
|
36698
|
+
const scanRows = stmt.limit === null ? Number.NaN : offset + stmt.limit;
|
|
36699
|
+
if (stmt.limit !== null && !Number.isSafeInteger(scanRows)) {
|
|
36700
|
+
reasons.push(`KORDER_SCAN_ROWS_INVALID(offset=${offset}, limit=${stmt.limit})`);
|
|
36701
|
+
}
|
|
36584
36702
|
const unique = [...new Set(reasons)];
|
|
36585
36703
|
if (unique.length > 0) {
|
|
36586
36704
|
throw new Error(
|
|
36587
36705
|
`ArgumentError: KORDER BY cannot be executed (mode=KINTONE_NATIVE; ${unique.join(", ")}). Use ORDER BY for canonical local ordering or simplify the query.`
|
|
36588
36706
|
);
|
|
36589
36707
|
}
|
|
36708
|
+
const native = stmt.limit <= 500 && offset <= 1e4 && stmt.limit <= input.maxRecords;
|
|
36709
|
+
if (!native && scanRows > input.maxRecords) {
|
|
36710
|
+
throw new Error(
|
|
36711
|
+
`ArgumentError: KORDER BY cannot be executed (mode=KINTONE_NATIVE; KORDER_SCAN_ROWS_EXCEEDS_MAX_RECORDS(scanRows=${scanRows}, maxRecords=${input.maxRecords})). Use ORDER BY for canonical local ordering, raise maxRecords, or reduce LIMIT/OFFSET.`
|
|
36712
|
+
);
|
|
36713
|
+
}
|
|
36590
36714
|
return {
|
|
36591
|
-
kind: "KORDER_NATIVE",
|
|
36715
|
+
kind: native ? "KORDER_NATIVE" : "KORDER_CURSOR",
|
|
36592
36716
|
requiresCompleteInput: false,
|
|
36593
36717
|
localOrderBy: false,
|
|
36594
36718
|
applyLocalOffsetLimit: false,
|
|
36595
|
-
reasonCodes: []
|
|
36719
|
+
reasonCodes: [],
|
|
36720
|
+
scanRows
|
|
36596
36721
|
};
|
|
36597
36722
|
}
|
|
36598
36723
|
|
|
36724
|
+
// src/core/errors/cursorErrors.ts
|
|
36725
|
+
var CursorCapacityError = class extends Error {
|
|
36726
|
+
constructor(host, limit, waitMs) {
|
|
36727
|
+
super(`CursorCapacityError: host=${host} \u306E active cursor \u4E0A\u9650 ${limit} \u306B ${waitMs}ms \u4EE5\u5185\u3067\u7A7A\u304D\u304C\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002`);
|
|
36728
|
+
this.name = "CursorCapacityError";
|
|
36729
|
+
}
|
|
36730
|
+
};
|
|
36731
|
+
var CursorCreateOutcomeUnknownError = class extends Error {
|
|
36732
|
+
constructor(cause) {
|
|
36733
|
+
super("CursorCreateOutcomeUnknownError: Create Cursor \u306E\u6210\u5426\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002\u81EA\u52D5\u518D\u8A66\u884C\u305B\u305A\u3001\u6700\u592710\u5206+\u5B89\u5168\u4F59\u88D5\u306E\u9593\u306F\u67A0\u3092\u9694\u96E2\u3057\u307E\u3059\u3002");
|
|
36734
|
+
this.name = "CursorCreateOutcomeUnknownError";
|
|
36735
|
+
this.cause = cause;
|
|
36736
|
+
}
|
|
36737
|
+
};
|
|
36738
|
+
var CursorCleanupWarning = class extends Error {
|
|
36739
|
+
constructor(cause) {
|
|
36740
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
36741
|
+
super(`CursorCleanupWarning: Cursor \u306E\u89E3\u653E\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002\u7D50\u679C\u306F\u6709\u52B9\u3067\u3059\u304C\u3001\u6700\u592710\u5206+\u5B89\u5168\u4F59\u88D5\u306E\u9593\u306F\u67A0\u3092\u9694\u96E2\u3057\u307E\u3059\u3002\u8A73\u7D30: ${detail}`);
|
|
36742
|
+
this.name = "CursorCleanupWarning";
|
|
36743
|
+
this.cause = cause;
|
|
36744
|
+
}
|
|
36745
|
+
};
|
|
36746
|
+
|
|
36747
|
+
// src/core/optimization/korderCursorExecutor.ts
|
|
36748
|
+
async function executeKorderCursor(input) {
|
|
36749
|
+
const handle = await input.client.openCursor({
|
|
36750
|
+
app: input.app,
|
|
36751
|
+
fields: input.fields.length > 0 ? input.fields : void 0,
|
|
36752
|
+
query: input.query,
|
|
36753
|
+
size: 500
|
|
36754
|
+
});
|
|
36755
|
+
const records = [];
|
|
36756
|
+
let seen = 0;
|
|
36757
|
+
let primaryError;
|
|
36758
|
+
let cleanupWarning;
|
|
36759
|
+
try {
|
|
36760
|
+
if (handle.totalCount > input.offset) {
|
|
36761
|
+
while (records.length < input.limit) {
|
|
36762
|
+
const page = await handle.nextPage();
|
|
36763
|
+
for (const record2 of page.records) {
|
|
36764
|
+
if (seen < input.offset) seen += 1;
|
|
36765
|
+
else if (records.length < input.limit) records.push(record2);
|
|
36766
|
+
else break;
|
|
36767
|
+
}
|
|
36768
|
+
if (!page.next) break;
|
|
36769
|
+
}
|
|
36770
|
+
}
|
|
36771
|
+
} catch (error51) {
|
|
36772
|
+
primaryError = error51;
|
|
36773
|
+
throw error51;
|
|
36774
|
+
} finally {
|
|
36775
|
+
try {
|
|
36776
|
+
await handle.close();
|
|
36777
|
+
} catch (cleanupError) {
|
|
36778
|
+
if (primaryError && primaryError instanceof Error) {
|
|
36779
|
+
Object.defineProperty(primaryError, "cursorCleanupError", {
|
|
36780
|
+
value: cleanupError,
|
|
36781
|
+
configurable: true
|
|
36782
|
+
});
|
|
36783
|
+
} else {
|
|
36784
|
+
cleanupWarning = new CursorCleanupWarning(cleanupError).message;
|
|
36785
|
+
}
|
|
36786
|
+
}
|
|
36787
|
+
}
|
|
36788
|
+
return { records, cleanupWarning };
|
|
36789
|
+
}
|
|
36790
|
+
|
|
36791
|
+
// src/converter/korderCursorQuery.ts
|
|
36792
|
+
function buildKorderCursorQuery(stmt) {
|
|
36793
|
+
const parts = [];
|
|
36794
|
+
if (stmt.where) parts.push(whereToKintone(stmt.where));
|
|
36795
|
+
const order = stmt.orderBy.map((item) => {
|
|
36796
|
+
if (item.key.type !== "FIELD_NAME") {
|
|
36797
|
+
throw new Error("ArgumentError: KORDER cursor key must be a direct field.");
|
|
36798
|
+
}
|
|
36799
|
+
return `${item.key.name} ${item.direction === "ASC" ? "asc" : "desc"}`;
|
|
36800
|
+
});
|
|
36801
|
+
parts.push(`order by ${order.join(", ")}`);
|
|
36802
|
+
return parts.join(" ");
|
|
36803
|
+
}
|
|
36804
|
+
|
|
36599
36805
|
// src/engine/process.ts
|
|
36600
36806
|
function flatten(record2, alias) {
|
|
36601
36807
|
const row = {};
|
|
@@ -36892,6 +37098,7 @@ function compareSortKeys(a, b, meta3) {
|
|
|
36892
37098
|
}
|
|
36893
37099
|
var NUMERIC_ORDER_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
36894
37100
|
"LENGTH",
|
|
37101
|
+
"LENGTH_CHAR",
|
|
36895
37102
|
"INSTR",
|
|
36896
37103
|
"ROUND",
|
|
36897
37104
|
"FLOOR",
|
|
@@ -37736,6 +37943,15 @@ function createEmptyMetrics() {
|
|
|
37736
37943
|
fieldCalls: 0,
|
|
37737
37944
|
appsCalls: 0,
|
|
37738
37945
|
processStatusCalls: 0,
|
|
37946
|
+
cursorCreateCalls: 0,
|
|
37947
|
+
cursorGetCalls: 0,
|
|
37948
|
+
cursorDeleteCalls: 0,
|
|
37949
|
+
cursorRecordsScanned: 0,
|
|
37950
|
+
cursorActiveCurrent: 0,
|
|
37951
|
+
cursorActivePeak: 0,
|
|
37952
|
+
cursorCleanupFailures: 0,
|
|
37953
|
+
cursorCreateOutcomeUnknown: 0,
|
|
37954
|
+
cursorQuarantinedCurrent: 0,
|
|
37739
37955
|
fetchedRows: 0,
|
|
37740
37956
|
elapsedMs: 0
|
|
37741
37957
|
};
|
|
@@ -37748,6 +37964,48 @@ function wrapClientWithMetrics(client, metrics) {
|
|
|
37748
37964
|
metrics.fetchedRows += res.records.length;
|
|
37749
37965
|
return res;
|
|
37750
37966
|
},
|
|
37967
|
+
openCursor: async (params) => {
|
|
37968
|
+
metrics.cursorCreateCalls += 1;
|
|
37969
|
+
let handle;
|
|
37970
|
+
try {
|
|
37971
|
+
handle = await client.openCursor(params);
|
|
37972
|
+
} catch (error51) {
|
|
37973
|
+
if (error51 instanceof Error && error51.name === "CursorCreateOutcomeUnknownError") {
|
|
37974
|
+
metrics.cursorCreateOutcomeUnknown += 1;
|
|
37975
|
+
metrics.cursorQuarantinedCurrent += 1;
|
|
37976
|
+
}
|
|
37977
|
+
throw error51;
|
|
37978
|
+
}
|
|
37979
|
+
metrics.cursorActiveCurrent += 1;
|
|
37980
|
+
metrics.cursorActivePeak = Math.max(metrics.cursorActivePeak, metrics.cursorActiveCurrent);
|
|
37981
|
+
let released = false;
|
|
37982
|
+
const markReleased = () => {
|
|
37983
|
+
if (released) return;
|
|
37984
|
+
released = true;
|
|
37985
|
+
metrics.cursorActiveCurrent -= 1;
|
|
37986
|
+
};
|
|
37987
|
+
return {
|
|
37988
|
+
totalCount: handle.totalCount,
|
|
37989
|
+
nextPage: async () => {
|
|
37990
|
+
metrics.cursorGetCalls += 1;
|
|
37991
|
+
const page = await handle.nextPage();
|
|
37992
|
+
metrics.cursorRecordsScanned += page.records.length;
|
|
37993
|
+
if (!page.next) markReleased();
|
|
37994
|
+
return page;
|
|
37995
|
+
},
|
|
37996
|
+
close: async () => {
|
|
37997
|
+
if (!released) metrics.cursorDeleteCalls += 1;
|
|
37998
|
+
try {
|
|
37999
|
+
await handle.close();
|
|
38000
|
+
markReleased();
|
|
38001
|
+
} catch (error51) {
|
|
38002
|
+
metrics.cursorCleanupFailures += 1;
|
|
38003
|
+
metrics.cursorQuarantinedCurrent += 1;
|
|
38004
|
+
throw error51;
|
|
38005
|
+
}
|
|
38006
|
+
}
|
|
38007
|
+
};
|
|
38008
|
+
},
|
|
37751
38009
|
postRecords: (params) => {
|
|
37752
38010
|
metrics.postCalls += 1;
|
|
37753
38011
|
return client.postRecords(params);
|
|
@@ -37787,6 +38045,37 @@ function wrapClientWithSearchAbort(client, collector, failClosed) {
|
|
|
37787
38045
|
}
|
|
37788
38046
|
};
|
|
37789
38047
|
}
|
|
38048
|
+
function wrapClientWithCursorScope(client) {
|
|
38049
|
+
const active = /* @__PURE__ */ new Set();
|
|
38050
|
+
return {
|
|
38051
|
+
client: {
|
|
38052
|
+
...client,
|
|
38053
|
+
openCursor: async (params) => {
|
|
38054
|
+
const handle = await client.openCursor(params);
|
|
38055
|
+
active.add(handle);
|
|
38056
|
+
const remove = () => active.delete(handle);
|
|
38057
|
+
return {
|
|
38058
|
+
totalCount: handle.totalCount,
|
|
38059
|
+
async nextPage() {
|
|
38060
|
+
const page = await handle.nextPage();
|
|
38061
|
+
if (!page.next) remove();
|
|
38062
|
+
return page;
|
|
38063
|
+
},
|
|
38064
|
+
async close() {
|
|
38065
|
+
try {
|
|
38066
|
+
await handle.close();
|
|
38067
|
+
} finally {
|
|
38068
|
+
remove();
|
|
38069
|
+
}
|
|
38070
|
+
}
|
|
38071
|
+
};
|
|
38072
|
+
}
|
|
38073
|
+
},
|
|
38074
|
+
closeActive: async () => {
|
|
38075
|
+
await Promise.all([...active].map((handle) => handle.close().catch(() => void 0)));
|
|
38076
|
+
}
|
|
38077
|
+
};
|
|
38078
|
+
}
|
|
37790
38079
|
function isSelectLikeStatement(stmt) {
|
|
37791
38080
|
return stmt.type === "SELECT" || stmt.type === "UNION" || stmt.type === "WITH";
|
|
37792
38081
|
}
|
|
@@ -37837,7 +38126,13 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
37837
38126
|
case "DESCRIBE":
|
|
37838
38127
|
return executeDescribe(stmt, client, cacheContext);
|
|
37839
38128
|
case "EXPLAIN":
|
|
37840
|
-
return executeExplain(
|
|
38129
|
+
return executeExplain(
|
|
38130
|
+
stmt,
|
|
38131
|
+
client,
|
|
38132
|
+
cacheContext,
|
|
38133
|
+
options.maxRecords ?? 1e4,
|
|
38134
|
+
options.cursorMaxActive ?? 2
|
|
38135
|
+
);
|
|
37841
38136
|
// 一時テーブルはバッチスコープのため単文実行では拒否する(executeBatch を使う)
|
|
37842
38137
|
case "CREATE_TEMP_TABLE":
|
|
37843
38138
|
throw new Error("ArgumentError: CREATE TEMP TABLE requires a batch (temp tables are batch-scoped).");
|
|
@@ -37944,9 +38239,11 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
37944
38239
|
searchAbortCollector,
|
|
37945
38240
|
info.statementType !== "SELECT" && info.statementType !== "UNION" && info.statementType !== "WITH"
|
|
37946
38241
|
);
|
|
38242
|
+
const cursorScope = wrapClientWithCursorScope(statementClient);
|
|
37947
38243
|
const outcome = await runWithDeadline(
|
|
37948
|
-
executeBatchStatement(statements[i], info,
|
|
37949
|
-
remaining
|
|
38244
|
+
executeBatchStatement(statements[i], info, cursorScope.client, stmtOptions, cacheContext, tempTables, variables),
|
|
38245
|
+
remaining,
|
|
38246
|
+
cursorScope.closeActive
|
|
37950
38247
|
);
|
|
37951
38248
|
if (outcome.result) {
|
|
37952
38249
|
outcome.result = attachSearchAbortWarning(outcome.result, searchAbortCollector);
|
|
@@ -38104,19 +38401,47 @@ async function runSelectLike(query, client, options, cacheContext, tempTables) {
|
|
|
38104
38401
|
}
|
|
38105
38402
|
return executeQueryWithCte(query, client, options, tempTables, cacheContext, true);
|
|
38106
38403
|
}
|
|
38107
|
-
async function runWithDeadline(work, remainingMs) {
|
|
38404
|
+
async function runWithDeadline(work, remainingMs, onTimeout) {
|
|
38108
38405
|
if (remainingMs === null) return work;
|
|
38109
38406
|
if (remainingMs <= 0) {
|
|
38407
|
+
if (onTimeout) await onTimeout();
|
|
38110
38408
|
void work.catch(() => {
|
|
38111
38409
|
});
|
|
38112
38410
|
throw new BatchTimeoutError();
|
|
38113
38411
|
}
|
|
38114
38412
|
let timer;
|
|
38413
|
+
let timedOut = false;
|
|
38414
|
+
const guardedWork = work.then(
|
|
38415
|
+
(value) => timedOut ? new Promise(() => void 0) : value,
|
|
38416
|
+
(error51) => {
|
|
38417
|
+
if (timedOut) return new Promise(() => void 0);
|
|
38418
|
+
throw error51;
|
|
38419
|
+
}
|
|
38420
|
+
);
|
|
38115
38421
|
try {
|
|
38116
38422
|
return await Promise.race([
|
|
38117
|
-
|
|
38423
|
+
guardedWork,
|
|
38118
38424
|
new Promise((_, reject) => {
|
|
38119
|
-
timer = setTimeout(() =>
|
|
38425
|
+
timer = setTimeout(() => {
|
|
38426
|
+
timedOut = true;
|
|
38427
|
+
void (async () => {
|
|
38428
|
+
if (onTimeout) {
|
|
38429
|
+
let cleanupTimer;
|
|
38430
|
+
try {
|
|
38431
|
+
await Promise.race([
|
|
38432
|
+
onTimeout(),
|
|
38433
|
+
new Promise((resolve2) => {
|
|
38434
|
+
cleanupTimer = setTimeout(resolve2, 5e3);
|
|
38435
|
+
cleanupTimer.unref?.();
|
|
38436
|
+
})
|
|
38437
|
+
]);
|
|
38438
|
+
} finally {
|
|
38439
|
+
if (cleanupTimer) clearTimeout(cleanupTimer);
|
|
38440
|
+
}
|
|
38441
|
+
}
|
|
38442
|
+
reject(new BatchTimeoutError());
|
|
38443
|
+
})();
|
|
38444
|
+
}, remainingMs);
|
|
38120
38445
|
})
|
|
38121
38446
|
]);
|
|
38122
38447
|
} catch (e) {
|
|
@@ -38476,7 +38801,7 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
|
|
|
38476
38801
|
const staticMode = resolveSelectMode(stmt);
|
|
38477
38802
|
const mode = whereCapability.capability === "EXACT_PUSHDOWN" ? staticMode : "FULL_SCAN";
|
|
38478
38803
|
const orderMeta = await buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
|
|
38479
|
-
const orderPlan = hasCanonicalOrder(stmt) ? (stmt.orderMode === "KINTONE_NATIVE" ?
|
|
38804
|
+
const orderPlan = hasCanonicalOrder(stmt) ? (stmt.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
38480
38805
|
stmt,
|
|
38481
38806
|
staticMode: mode,
|
|
38482
38807
|
whereCapability: whereCapability.capability,
|
|
@@ -38490,7 +38815,7 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
|
|
|
38490
38815
|
client,
|
|
38491
38816
|
cacheContext
|
|
38492
38817
|
);
|
|
38493
|
-
const completeInputRequired = orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" ? requiresCompleteInput({ ...stmt, orderBy: [] }) : requiresCompleteInput(stmt);
|
|
38818
|
+
const completeInputRequired = orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" || orderPlan?.kind === "KORDER_CURSOR" ? requiresCompleteInput({ ...stmt, orderBy: [] }) : requiresCompleteInput(stmt);
|
|
38494
38819
|
const truncateWasDisabled = completeInputRequired && options.onLimitReached === "truncate";
|
|
38495
38820
|
const effectiveOptions = truncateWasDisabled ? { ...options, onLimitReached: "error" } : options;
|
|
38496
38821
|
try {
|
|
@@ -38591,12 +38916,23 @@ async function executeSimpleSelect(stmt, client, options, cacheContext, orderPla
|
|
|
38591
38916
|
const warnings = /* @__PURE__ */ new Set();
|
|
38592
38917
|
const onLimit2 = options.onLimitReached ?? "error";
|
|
38593
38918
|
const parallel = options.fetchParallel ?? 1;
|
|
38594
|
-
const useRestWindow = stmt.orderBy.length > 0 ? orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" : stmt.limit !== null && stmt.limit <= 500;
|
|
38919
|
+
const useRestWindow = stmt.orderBy.length > 0 ? orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" || orderPlan?.kind === "KORDER_CURSOR" : stmt.limit !== null && stmt.limit <= 500;
|
|
38595
38920
|
const needed = stmt.limit === null ? null : (stmt.offset ?? 0) + stmt.limit;
|
|
38596
38921
|
const stopAfter = stmt.orderBy.length === 0 && needed !== null && needed <= maxRecords2 && !whereHasKlike(stmt.where) ? needed : void 0;
|
|
38597
38922
|
let records;
|
|
38598
|
-
if (orderPlan?.kind === "KORDER_NATIVE" && stmt.limit === 0) {
|
|
38923
|
+
if ((orderPlan?.kind === "KORDER_NATIVE" || orderPlan?.kind === "KORDER_CURSOR") && stmt.limit === 0) {
|
|
38599
38924
|
records = [];
|
|
38925
|
+
} else if (orderPlan?.kind === "KORDER_CURSOR") {
|
|
38926
|
+
const cursorResult = await executeKorderCursor({
|
|
38927
|
+
client,
|
|
38928
|
+
app: params.app,
|
|
38929
|
+
fields: params.fields,
|
|
38930
|
+
query: buildKorderCursorQuery(stmt),
|
|
38931
|
+
offset: stmt.offset ?? 0,
|
|
38932
|
+
limit: stmt.limit
|
|
38933
|
+
});
|
|
38934
|
+
records = cursorResult.records;
|
|
38935
|
+
if (cursorResult.cleanupWarning) warnings.add(cursorResult.cleanupWarning);
|
|
38600
38936
|
} else if (useRestWindow) {
|
|
38601
38937
|
const res = await client.getRecords({
|
|
38602
38938
|
app: params.app,
|
|
@@ -38983,6 +39319,7 @@ function systemColumnMeta(field) {
|
|
|
38983
39319
|
}
|
|
38984
39320
|
var NUMBER_RETURNING_STRING_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
38985
39321
|
"LENGTH",
|
|
39322
|
+
"LENGTH_CHAR",
|
|
38986
39323
|
"INSTR",
|
|
38987
39324
|
"ROUND",
|
|
38988
39325
|
"FLOOR",
|
|
@@ -39388,7 +39725,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
39388
39725
|
}
|
|
39389
39726
|
const orderMeta = await buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
|
|
39390
39727
|
if (hasCanonicalOrder(stmt)) {
|
|
39391
|
-
(stmt.orderMode === "KINTONE_NATIVE" ?
|
|
39728
|
+
(stmt.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
39392
39729
|
stmt,
|
|
39393
39730
|
staticMode: "FULL_SCAN",
|
|
39394
39731
|
whereCapability: whereCapability.capability,
|
|
@@ -39950,6 +40287,28 @@ var NON_WRITABLE_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
39950
40287
|
"CATEGORY",
|
|
39951
40288
|
"REFERENCE_TABLE"
|
|
39952
40289
|
]);
|
|
40290
|
+
function assertWritableTopLevelDmlFields(appId, targetFields, fieldInfos) {
|
|
40291
|
+
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
40292
|
+
for (const code of targetFields) {
|
|
40293
|
+
const info = infoByCode.get(code);
|
|
40294
|
+
if (!info) {
|
|
40295
|
+
throw new Error(`ArgumentError: DML target field ${code} does not exist.`);
|
|
40296
|
+
}
|
|
40297
|
+
if (info.inSubtable) {
|
|
40298
|
+
throw new Error(
|
|
40299
|
+
`ArgumentError: DML target field ${code} is inside a subtable. Use subtable DML syntax (for example, APP${appId}$\u30C6\u30FC\u30D6\u30EB).`
|
|
40300
|
+
);
|
|
40301
|
+
}
|
|
40302
|
+
if (info.writable === false || NON_WRITABLE_FIELD_TYPES.has(info.fieldType)) {
|
|
40303
|
+
throw new Error(`ArgumentError: DML target field ${code} is not writable (${info.fieldType}).`);
|
|
40304
|
+
}
|
|
40305
|
+
}
|
|
40306
|
+
}
|
|
40307
|
+
async function loadWritableTopLevelDmlFields(appId, targetFields, client, cacheContext) {
|
|
40308
|
+
const fieldInfos = await getFieldsCached(appId, client, cacheContext);
|
|
40309
|
+
assertWritableTopLevelDmlFields(appId, targetFields, fieldInfos);
|
|
40310
|
+
return fieldInfos;
|
|
40311
|
+
}
|
|
39953
40312
|
async function executeDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
|
|
39954
40313
|
return (await prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber)).result;
|
|
39955
40314
|
}
|
|
@@ -39961,24 +40320,22 @@ var RejectLimitExceededError = class extends Error {
|
|
|
39961
40320
|
}
|
|
39962
40321
|
};
|
|
39963
40322
|
async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
|
|
39964
|
-
if (stmt.type === "UPDATE") {
|
|
39965
|
-
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
39966
|
-
}
|
|
39967
40323
|
const operation = stmt.type === "UPDATE" ? "UPDATE" : stmt.type.startsWith("UPSERT") ? "UPSERT" : "INSERT";
|
|
39968
40324
|
const payloadFields = stmt.type === "UPDATE" ? ["$id", ...stmt.assignments.map((a) => a.field)] : [...stmt.fields];
|
|
39969
40325
|
if (new Set(payloadFields).size !== payloadFields.length) {
|
|
39970
40326
|
throw new Error("ArgumentError: DML target fields contain duplicates.");
|
|
39971
40327
|
}
|
|
39972
|
-
const fieldInfos = await getFieldsCached(stmt.appId, client, cacheContext);
|
|
39973
|
-
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
39974
40328
|
const targetFields = stmt.type === "UPDATE" ? stmt.assignments.map((a) => a.field) : stmt.fields;
|
|
39975
|
-
|
|
39976
|
-
|
|
39977
|
-
|
|
39978
|
-
|
|
39979
|
-
|
|
39980
|
-
|
|
40329
|
+
const fieldInfos = await loadWritableTopLevelDmlFields(
|
|
40330
|
+
stmt.appId,
|
|
40331
|
+
targetFields,
|
|
40332
|
+
client,
|
|
40333
|
+
cacheContext
|
|
40334
|
+
);
|
|
40335
|
+
if (stmt.type === "UPDATE") {
|
|
40336
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
39981
40337
|
}
|
|
40338
|
+
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
39982
40339
|
const candidates = await materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode);
|
|
39983
40340
|
const { errors, invalidRows, invalidRowNumbers } = validateDmlCandidates(
|
|
39984
40341
|
candidates,
|
|
@@ -40147,7 +40504,7 @@ async function materializeUpdateValidationCandidates(stmt, client, options, cach
|
|
|
40147
40504
|
await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
|
|
40148
40505
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
40149
40506
|
let records;
|
|
40150
|
-
if (
|
|
40507
|
+
if (hasRowDependentAssignment(stmt)) {
|
|
40151
40508
|
const getParams = updateToGetQueryForArith(stmt);
|
|
40152
40509
|
const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [...getParams.fields], {
|
|
40153
40510
|
maxRecords: options.maxRecords ?? 1e4,
|
|
@@ -40356,6 +40713,7 @@ async function executeInsert(stmt, client, options, cacheContext) {
|
|
|
40356
40713
|
if (stmt.subtableCode) {
|
|
40357
40714
|
return executeInsertSubtable(stmt, client, options, cacheContext);
|
|
40358
40715
|
}
|
|
40716
|
+
await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
40359
40717
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
40360
40718
|
const batches = insertToPostBatches(stmt, fieldTypes);
|
|
40361
40719
|
const createdIds = [];
|
|
@@ -40370,6 +40728,7 @@ async function executeInsert(stmt, client, options, cacheContext) {
|
|
|
40370
40728
|
};
|
|
40371
40729
|
}
|
|
40372
40730
|
async function executeInsertSelect(stmt, client, options, cacheContext, cteCache) {
|
|
40731
|
+
await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
40373
40732
|
const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
|
|
40374
40733
|
const { rows, columns } = selectResult;
|
|
40375
40734
|
if (columns.length !== stmt.fields.length) {
|
|
@@ -40404,17 +40763,24 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
|
|
|
40404
40763
|
};
|
|
40405
40764
|
}
|
|
40406
40765
|
async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
|
|
40407
|
-
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
40408
40766
|
if (stmt.subtableCode) {
|
|
40767
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
40409
40768
|
return executeUpdateSubtable(stmt, client, options, cacheContext);
|
|
40410
40769
|
}
|
|
40770
|
+
await loadWritableTopLevelDmlFields(
|
|
40771
|
+
stmt.appId,
|
|
40772
|
+
stmt.assignments.map((assignment) => assignment.field),
|
|
40773
|
+
client,
|
|
40774
|
+
cacheContext
|
|
40775
|
+
);
|
|
40776
|
+
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
40411
40777
|
if (stmt.from != null) {
|
|
40412
40778
|
return executeUpdateFrom(stmt, stmt.from, client, options, cacheContext, tempTables);
|
|
40413
40779
|
}
|
|
40414
40780
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
40415
40781
|
await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
|
|
40416
40782
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
40417
|
-
if (
|
|
40783
|
+
if (hasRowDependentAssignment(stmt)) {
|
|
40418
40784
|
const getParams2 = updateToGetQueryForArith(stmt);
|
|
40419
40785
|
const resolved2 = await fetchRecordsForSharedPlan(
|
|
40420
40786
|
client.getRecords,
|
|
@@ -40508,6 +40874,7 @@ async function executeDelete(stmt, client, options, cacheContext) {
|
|
|
40508
40874
|
return { type: "DELETE", deletedCount: ids.length };
|
|
40509
40875
|
}
|
|
40510
40876
|
async function executeUpsert(stmt, client, options, cacheContext) {
|
|
40877
|
+
await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
40511
40878
|
const toInsert = [];
|
|
40512
40879
|
const toUpdate = [];
|
|
40513
40880
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
@@ -40934,6 +41301,7 @@ function evalOrderKeyForRow(key, row) {
|
|
|
40934
41301
|
}
|
|
40935
41302
|
}
|
|
40936
41303
|
async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache) {
|
|
41304
|
+
await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
40937
41305
|
const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
|
|
40938
41306
|
const { rows, columns } = selectResult;
|
|
40939
41307
|
if (columns.length !== stmt.fields.length) {
|
|
@@ -41165,7 +41533,7 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
41165
41533
|
const hasUnmaterializedSource = [select.from, ...select.joins.map((join) => join.table)].some((table) => table.cteName !== null);
|
|
41166
41534
|
if (hasCanonicalOrder(select) && !hasUnmaterializedSource) {
|
|
41167
41535
|
const mode = capability.capability === "EXACT_PUSHDOWN" ? resolveSelectMode(select) : "FULL_SCAN";
|
|
41168
|
-
orderPlans.set(select, (select.orderMode === "KINTONE_NATIVE" ?
|
|
41536
|
+
orderPlans.set(select, (select.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
41169
41537
|
stmt: select,
|
|
41170
41538
|
staticMode: mode,
|
|
41171
41539
|
whereCapability: capability.capability,
|
|
@@ -41195,7 +41563,7 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
41195
41563
|
capabilities.set(inlined, capability);
|
|
41196
41564
|
if (hasCanonicalOrder(inlined)) {
|
|
41197
41565
|
const meta3 = await buildOrderByMetaForSelect(inlined, tracedClient, cacheContext);
|
|
41198
|
-
orderPlans.set(inlined, (inlined.orderMode === "KINTONE_NATIVE" ?
|
|
41566
|
+
orderPlans.set(inlined, (inlined.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
41199
41567
|
stmt: inlined,
|
|
41200
41568
|
staticMode: capability.capability === "EXACT_PUSHDOWN" ? resolveSelectMode(inlined) : "FULL_SCAN",
|
|
41201
41569
|
whereCapability: capability.capability,
|
|
@@ -41213,7 +41581,7 @@ function explainMetadataLines(analysis) {
|
|
|
41213
41581
|
...[...analysis.processStatusApps].sort((a, b) => a - b).map((appId) => ` metadata API: process status APP${appId}`)
|
|
41214
41582
|
];
|
|
41215
41583
|
}
|
|
41216
|
-
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords2 = 1e4) {
|
|
41584
|
+
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords2 = 1e4, cursorMaxActive2 = 2) {
|
|
41217
41585
|
const statements = parseSqlBatch(sql);
|
|
41218
41586
|
const analysis = analyzeBatch(statements);
|
|
41219
41587
|
validateDeclaredBatchVariables(statements, injectedVariables);
|
|
@@ -41224,12 +41592,12 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
41224
41592
|
const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveVariableRefs(stmt.expr, variables) } : stmt : resolveVariableRefs(stmt, variables);
|
|
41225
41593
|
validateKlikeStatement(planStmt);
|
|
41226
41594
|
const whereAnalysis = await buildExplainWhereAnalysis(planStmt, client, cacheContext, maxRecords2);
|
|
41227
|
-
const statementPlan = buildBatchStatementPlan(
|
|
41595
|
+
const statementPlan = addCursorConcurrency(buildBatchStatementPlan(
|
|
41228
41596
|
planStmt,
|
|
41229
41597
|
analysis.statements[i],
|
|
41230
41598
|
whereAnalysis.capabilities,
|
|
41231
41599
|
whereAnalysis.orderPlans
|
|
41232
|
-
);
|
|
41600
|
+
), cursorMaxActive2);
|
|
41233
41601
|
const metadataPlan = explainMetadataLines(whereAnalysis);
|
|
41234
41602
|
plans.push({
|
|
41235
41603
|
index: i,
|
|
@@ -41335,11 +41703,14 @@ function buildPlanForBatchQuery(query, info, capabilities, orderPlans) {
|
|
|
41335
41703
|
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");
|
|
41336
41704
|
return lines;
|
|
41337
41705
|
}
|
|
41338
|
-
async function executeExplain(stmt, client, cacheContext, maxRecords2) {
|
|
41706
|
+
async function executeExplain(stmt, client, cacheContext, maxRecords2, cursorMaxActive2) {
|
|
41339
41707
|
const analysis = await buildExplainWhereAnalysis(stmt.query, client, cacheContext, maxRecords2);
|
|
41340
41708
|
const lines = [
|
|
41341
41709
|
...explainMetadataLines(analysis),
|
|
41342
|
-
...
|
|
41710
|
+
...addCursorConcurrency(
|
|
41711
|
+
buildExplainPlan(stmt.query, void 0, analysis.capabilities, analysis.orderPlans),
|
|
41712
|
+
cursorMaxActive2
|
|
41713
|
+
)
|
|
41343
41714
|
];
|
|
41344
41715
|
return {
|
|
41345
41716
|
type: "SELECT",
|
|
@@ -41348,6 +41719,17 @@ async function executeExplain(stmt, client, cacheContext, maxRecords2) {
|
|
|
41348
41719
|
rowCount: lines.length
|
|
41349
41720
|
};
|
|
41350
41721
|
}
|
|
41722
|
+
function addCursorConcurrency(lines, cursorMaxActive2) {
|
|
41723
|
+
const result = [];
|
|
41724
|
+
for (const line of lines) {
|
|
41725
|
+
result.push(line);
|
|
41726
|
+
if (line.trim() === "cursor page size: 500") {
|
|
41727
|
+
const indent = line.match(/^\s*/)?.[0] ?? "";
|
|
41728
|
+
result.push(`${indent}cursor concurrency: ${cursorMaxActive2} per domain (process-local)`);
|
|
41729
|
+
}
|
|
41730
|
+
}
|
|
41731
|
+
return result;
|
|
41732
|
+
}
|
|
41351
41733
|
function buildExplainPlan(query, label, capabilities, orderPlans) {
|
|
41352
41734
|
if (query.type === "UNION") return buildUnionPlan(query, capabilities, orderPlans);
|
|
41353
41735
|
if (query.type === "WITH") return buildWithPlan(query, capabilities, orderPlans);
|
|
@@ -41377,6 +41759,11 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
41377
41759
|
if (orderPlan.kind === "KORDER_NATIVE") {
|
|
41378
41760
|
lines.push(" order semantics: kintone native (not kSQL canonical)");
|
|
41379
41761
|
lines.push(" REST execution: single GET");
|
|
41762
|
+
} else if (orderPlan.kind === "KORDER_CURSOR") {
|
|
41763
|
+
lines.push(" order semantics: kintone native (not kSQL canonical)");
|
|
41764
|
+
lines.push(" fetch API: POST/GET/DELETE records/cursor.json");
|
|
41765
|
+
lines.push(" cursor page size: 500");
|
|
41766
|
+
lines.push(` scan rows: ${orderPlan.scanRows}`);
|
|
41380
41767
|
}
|
|
41381
41768
|
}
|
|
41382
41769
|
if (orderPlan?.requiresCompleteInput ?? requiresCompleteInput(stmt)) {
|
|
@@ -41388,7 +41775,8 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
41388
41775
|
if (mode === "SIMPLE") {
|
|
41389
41776
|
const params = selectToKintoneParams(orderPlan?.kind === "CANONICAL_REST_TOP_N" ? withCanonicalRestTie(stmt) : stmt);
|
|
41390
41777
|
lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);
|
|
41391
|
-
|
|
41778
|
+
const displayedQuery = orderPlan?.kind === "KORDER_CURSOR" ? buildKorderCursorQuery(stmt) : params.query;
|
|
41779
|
+
lines.push(` kintone query: ${displayedQuery || "(\u306A\u3057)"}`);
|
|
41392
41780
|
lines.push(` fields: ${params.fields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : params.fields.join(", ")}`);
|
|
41393
41781
|
} else {
|
|
41394
41782
|
const pushdownPlan = buildKlikePushdownPlan(stmt);
|
|
@@ -41549,6 +41937,8 @@ function buildInsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
41549
41937
|
}
|
|
41550
41938
|
function buildUpdatePlan(stmt, label, capabilities, orderPlans) {
|
|
41551
41939
|
const isArith = hasArithAssignment(stmt);
|
|
41940
|
+
const isStringFunc = stmt.assignments.some((a) => a.value.type === "STRING_FUNC");
|
|
41941
|
+
const isRowDependent = hasRowDependentAssignment(stmt);
|
|
41552
41942
|
const isSubq = stmt.assignments.some((a) => a.value.type === "SCALAR_SUBQUERY");
|
|
41553
41943
|
const lines = [];
|
|
41554
41944
|
if (label) lines.push(label);
|
|
@@ -41565,10 +41955,11 @@ function buildUpdatePlan(stmt, label, capabilities, orderPlans) {
|
|
|
41565
41955
|
lines.push(` api: GET /k/v1/records.json \u2192 PUT /k/v1/records.json`);
|
|
41566
41956
|
const setTypes = [];
|
|
41567
41957
|
if (isArith) setTypes.push("\u7B97\u8853 SET\uFF08\u73FE\u5728\u5024\u3092\u53D6\u5F97\u3057\u3066\u8A08\u7B97\uFF09");
|
|
41958
|
+
if (isStringFunc) setTypes.push("\u6587\u5B57\u5217\u95A2\u6570 SET\uFF08\u73FE\u5728\u5024\u3092\u53D6\u5F97\u3057\u3066\u8A55\u4FA1\uFF09");
|
|
41568
41959
|
if (isSubq) setTypes.push("\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA SET");
|
|
41569
|
-
if (!
|
|
41960
|
+
if (!isRowDependent && !isSubq) setTypes.push("\u5358\u7D14 SET");
|
|
41570
41961
|
lines.push(` set type: ${setTypes.join(", ")}`);
|
|
41571
|
-
if (
|
|
41962
|
+
if (isRowDependent) {
|
|
41572
41963
|
const refFields = collectArithRefFields(stmt);
|
|
41573
41964
|
if (refFields.length > 0) {
|
|
41574
41965
|
lines.push(` ref fields: ${refFields.join(", ")}\uFF08GET \u306B\u542B\u3081\u308B\uFF09`);
|
|
@@ -41654,6 +42045,7 @@ function collectArithRefFields(stmt) {
|
|
|
41654
42045
|
const refs = /* @__PURE__ */ new Set();
|
|
41655
42046
|
for (const { value } of stmt.assignments) {
|
|
41656
42047
|
if (value.type === "ARITH") collectArithNodeRefs(value, refs);
|
|
42048
|
+
if (value.type === "STRING_FUNC") collectArithNodeRefs(value, refs);
|
|
41657
42049
|
}
|
|
41658
42050
|
return [...refs];
|
|
41659
42051
|
}
|
|
@@ -41666,6 +42058,13 @@ function collectArithNodeRefs(node, out) {
|
|
|
41666
42058
|
collectArithNodeRefs(node.left, out);
|
|
41667
42059
|
collectArithNodeRefs(node.right, out);
|
|
41668
42060
|
}
|
|
42061
|
+
if (node.type === "STRING_FUNC") {
|
|
42062
|
+
for (const arg of node.args) {
|
|
42063
|
+
if (arg.type !== "STRING" && arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") {
|
|
42064
|
+
collectArithNodeRefs(arg, out);
|
|
42065
|
+
}
|
|
42066
|
+
}
|
|
42067
|
+
}
|
|
41669
42068
|
}
|
|
41670
42069
|
function formatAssignment(a) {
|
|
41671
42070
|
const v = a.value;
|
|
@@ -41673,6 +42072,7 @@ function formatAssignment(a) {
|
|
|
41673
42072
|
if (v.type === "NUMBER") return `${a.field} = ${v.value}`;
|
|
41674
42073
|
if (v.type === "ARITH") return `${a.field} = ${formatArithExprStr(v)}`;
|
|
41675
42074
|
if (v.type === "CASE_VALUE") return `${a.field} = CASE WHEN ...`;
|
|
42075
|
+
if (v.type === "STRING_FUNC") return `${a.field} = ${v.func}(...)`;
|
|
41676
42076
|
if (v.type === "SCALAR_SUBQUERY") return `${a.field} = (SELECT ...)`;
|
|
41677
42077
|
if (v.type === "SOURCE_FIELD") return `${a.field} = ${v.alias}.${v.field}`;
|
|
41678
42078
|
return `${a.field} = (${v.type})`;
|
|
@@ -41931,6 +42331,12 @@ function validateKsqlConfig(config2) {
|
|
|
41931
42331
|
}
|
|
41932
42332
|
const logicalApps = normalizeLogicalApps(profileName, profile2.logicalApps);
|
|
41933
42333
|
if (logicalApps !== void 0) profile2.logicalApps = logicalApps;
|
|
42334
|
+
if (profile2.query?.cursorMaxActive !== void 0) {
|
|
42335
|
+
const value = profile2.query.cursorMaxActive;
|
|
42336
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > 5) {
|
|
42337
|
+
throw argumentError(`query.cursorMaxActive for profile "${profileName}" must be an integer from 1 to 5.`);
|
|
42338
|
+
}
|
|
42339
|
+
}
|
|
41934
42340
|
}
|
|
41935
42341
|
return config2;
|
|
41936
42342
|
}
|
|
@@ -42093,6 +42499,10 @@ var RequestGate = class {
|
|
|
42093
42499
|
async runMutation(fn) {
|
|
42094
42500
|
return this.withSlot(fn);
|
|
42095
42501
|
}
|
|
42502
|
+
/** Cursor Create/Get/Delete: セマフォのみ。GETでも位置を進めるため再試行しない。 */
|
|
42503
|
+
async runCursorStep(fn) {
|
|
42504
|
+
return this.withSlot(fn);
|
|
42505
|
+
}
|
|
42096
42506
|
async withSlot(fn) {
|
|
42097
42507
|
await this.acquire();
|
|
42098
42508
|
try {
|
|
@@ -42124,6 +42534,14 @@ var RequestGate = class {
|
|
|
42124
42534
|
function withRequestGate(client, gate) {
|
|
42125
42535
|
return {
|
|
42126
42536
|
getRecords: (params) => gate.runReadOnly(() => client.getRecords(params)),
|
|
42537
|
+
openCursor: async (params) => {
|
|
42538
|
+
const handle = await gate.runCursorStep(() => client.openCursor(params));
|
|
42539
|
+
return {
|
|
42540
|
+
totalCount: handle.totalCount,
|
|
42541
|
+
nextPage: () => gate.runCursorStep(() => handle.nextPage()),
|
|
42542
|
+
close: () => gate.runCursorStep(() => handle.close())
|
|
42543
|
+
};
|
|
42544
|
+
},
|
|
42127
42545
|
getApps: () => gate.runReadOnly(() => client.getApps()),
|
|
42128
42546
|
getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
|
|
42129
42547
|
getProcessStatuses: (appId) => gate.runReadOnly(() => client.getProcessStatuses(appId)),
|
|
@@ -42238,7 +42656,218 @@ function normalizeProcessStatusStates(states) {
|
|
|
42238
42656
|
});
|
|
42239
42657
|
}
|
|
42240
42658
|
|
|
42659
|
+
// src/api/kintoneCursor.ts
|
|
42660
|
+
function isAlreadyReleasedCursorError(error51) {
|
|
42661
|
+
const shaped = error51;
|
|
42662
|
+
return shaped?.status === 404 && shaped.code === "GAIA_CN01";
|
|
42663
|
+
}
|
|
42664
|
+
async function deleteCursorWithConfirmation(deleteCursor, sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)), isAlreadyReleased = isAlreadyReleasedCursorError) {
|
|
42665
|
+
try {
|
|
42666
|
+
await deleteCursor();
|
|
42667
|
+
return;
|
|
42668
|
+
} catch (firstError) {
|
|
42669
|
+
if (isAlreadyReleased(firstError)) return;
|
|
42670
|
+
}
|
|
42671
|
+
await sleep(250);
|
|
42672
|
+
try {
|
|
42673
|
+
await deleteCursor();
|
|
42674
|
+
} catch (confirmationError) {
|
|
42675
|
+
if (isAlreadyReleased(confirmationError)) return;
|
|
42676
|
+
throw confirmationError;
|
|
42677
|
+
}
|
|
42678
|
+
}
|
|
42679
|
+
async function withTimeout(promise2, timeoutMs) {
|
|
42680
|
+
let timer;
|
|
42681
|
+
const timeout2 = new Promise((_resolve, reject) => {
|
|
42682
|
+
timer = setTimeout(() => reject(new Error(`CursorCleanupTimeoutError: cleanup exceeded ${timeoutMs}ms.`)), timeoutMs);
|
|
42683
|
+
timer.unref?.();
|
|
42684
|
+
});
|
|
42685
|
+
try {
|
|
42686
|
+
return await Promise.race([promise2, timeout2]);
|
|
42687
|
+
} finally {
|
|
42688
|
+
if (timer) clearTimeout(timer);
|
|
42689
|
+
}
|
|
42690
|
+
}
|
|
42691
|
+
function createKintoneCursorHandle(totalCount, operations) {
|
|
42692
|
+
let released = false;
|
|
42693
|
+
let closing = false;
|
|
42694
|
+
let pageTail = Promise.resolve();
|
|
42695
|
+
let closePromise = null;
|
|
42696
|
+
const nextPage = () => {
|
|
42697
|
+
if (closing || released) return Promise.resolve({ records: [], next: false });
|
|
42698
|
+
const result = pageTail.then(async () => {
|
|
42699
|
+
if (closing || released) return { records: [], next: false };
|
|
42700
|
+
const page = await operations.get();
|
|
42701
|
+
if (!page.next) {
|
|
42702
|
+
released = true;
|
|
42703
|
+
operations.onReleased?.();
|
|
42704
|
+
}
|
|
42705
|
+
return page;
|
|
42706
|
+
});
|
|
42707
|
+
pageTail = result.then(() => void 0, () => void 0);
|
|
42708
|
+
return result;
|
|
42709
|
+
};
|
|
42710
|
+
const close = () => {
|
|
42711
|
+
if (released) return Promise.resolve();
|
|
42712
|
+
if (closePromise) return closePromise;
|
|
42713
|
+
closing = true;
|
|
42714
|
+
closePromise = pageTail.then(async () => {
|
|
42715
|
+
if (released) return;
|
|
42716
|
+
try {
|
|
42717
|
+
await withTimeout(
|
|
42718
|
+
deleteCursorWithConfirmation(
|
|
42719
|
+
operations.delete,
|
|
42720
|
+
operations.sleep,
|
|
42721
|
+
operations.isAlreadyReleasedError
|
|
42722
|
+
),
|
|
42723
|
+
operations.cleanupTimeoutMs ?? 5e3
|
|
42724
|
+
);
|
|
42725
|
+
released = true;
|
|
42726
|
+
operations.onReleased?.();
|
|
42727
|
+
} catch (error51) {
|
|
42728
|
+
operations.onReleaseUnknown?.();
|
|
42729
|
+
throw error51;
|
|
42730
|
+
}
|
|
42731
|
+
});
|
|
42732
|
+
return closePromise;
|
|
42733
|
+
};
|
|
42734
|
+
return { totalCount, nextPage, close };
|
|
42735
|
+
}
|
|
42736
|
+
|
|
42737
|
+
// src/api/cursorLeaseManager.ts
|
|
42738
|
+
var DEFAULT_MAX_ACTIVE = 2;
|
|
42739
|
+
var MAX_ACTIVE = 5;
|
|
42740
|
+
var DEFAULT_WAIT_MS = 3e4;
|
|
42741
|
+
var DEFAULT_QUARANTINE_MS = 10 * 6e4 + 3e4;
|
|
42742
|
+
var CursorLeaseManager = class {
|
|
42743
|
+
constructor(host, options = {}) {
|
|
42744
|
+
this.host = host;
|
|
42745
|
+
this.active = 0;
|
|
42746
|
+
this.peak = 0;
|
|
42747
|
+
this.quarantined = 0;
|
|
42748
|
+
this.waiters = [];
|
|
42749
|
+
this.createTail = Promise.resolve();
|
|
42750
|
+
const maxActive = options.maxActive ?? DEFAULT_MAX_ACTIVE;
|
|
42751
|
+
if (!Number.isSafeInteger(maxActive) || maxActive < 1 || maxActive > MAX_ACTIVE) {
|
|
42752
|
+
throw new Error(`ArgumentError: cursorMaxActive must be an integer from 1 to ${MAX_ACTIVE}.`);
|
|
42753
|
+
}
|
|
42754
|
+
this.maxActive = maxActive;
|
|
42755
|
+
this.waitTimeoutMs = options.waitTimeoutMs ?? DEFAULT_WAIT_MS;
|
|
42756
|
+
this.quarantineMs = options.quarantineMs ?? DEFAULT_QUARANTINE_MS;
|
|
42757
|
+
}
|
|
42758
|
+
acquire() {
|
|
42759
|
+
if (this.active < this.maxActive) {
|
|
42760
|
+
this.active += 1;
|
|
42761
|
+
this.peak = Math.max(this.peak, this.active);
|
|
42762
|
+
return Promise.resolve(this.makeLease());
|
|
42763
|
+
}
|
|
42764
|
+
return new Promise((resolve2, reject) => {
|
|
42765
|
+
const waiter = {};
|
|
42766
|
+
waiter.resolve = resolve2;
|
|
42767
|
+
waiter.reject = reject;
|
|
42768
|
+
waiter.timer = setTimeout(() => {
|
|
42769
|
+
const index = this.waiters.indexOf(waiter);
|
|
42770
|
+
if (index >= 0) this.waiters.splice(index, 1);
|
|
42771
|
+
reject(new CursorCapacityError(this.host, this.maxActive, this.waitTimeoutMs));
|
|
42772
|
+
}, this.waitTimeoutMs);
|
|
42773
|
+
waiter.timer.unref?.();
|
|
42774
|
+
this.waiters.push(waiter);
|
|
42775
|
+
});
|
|
42776
|
+
}
|
|
42777
|
+
/**
|
|
42778
|
+
* 同一hostを共有する後続surfaceの設定を反映する。
|
|
42779
|
+
* 縮小時は既存leaseを強制終了せず、activeが新上限を下回るまで新規取得だけを止める。
|
|
42780
|
+
*/
|
|
42781
|
+
setMaxActive(maxActive) {
|
|
42782
|
+
this.validateMaxActive(maxActive);
|
|
42783
|
+
if (this.maxActive === maxActive) return;
|
|
42784
|
+
this.maxActive = maxActive;
|
|
42785
|
+
this.dispatchWaiters();
|
|
42786
|
+
}
|
|
42787
|
+
async runCreate(fn) {
|
|
42788
|
+
const previous = this.createTail;
|
|
42789
|
+
let unlock;
|
|
42790
|
+
this.createTail = new Promise((resolve2) => {
|
|
42791
|
+
unlock = resolve2;
|
|
42792
|
+
});
|
|
42793
|
+
await previous;
|
|
42794
|
+
try {
|
|
42795
|
+
return await fn();
|
|
42796
|
+
} finally {
|
|
42797
|
+
unlock();
|
|
42798
|
+
}
|
|
42799
|
+
}
|
|
42800
|
+
snapshot() {
|
|
42801
|
+
return {
|
|
42802
|
+
active: this.active,
|
|
42803
|
+
peak: this.peak,
|
|
42804
|
+
quarantined: this.quarantined,
|
|
42805
|
+
waiting: this.waiters.length,
|
|
42806
|
+
limit: this.maxActive
|
|
42807
|
+
};
|
|
42808
|
+
}
|
|
42809
|
+
makeLease() {
|
|
42810
|
+
let done = false;
|
|
42811
|
+
return {
|
|
42812
|
+
release: () => {
|
|
42813
|
+
if (done) return;
|
|
42814
|
+
done = true;
|
|
42815
|
+
this.returnPermit();
|
|
42816
|
+
},
|
|
42817
|
+
quarantine: (durationMs = this.quarantineMs) => {
|
|
42818
|
+
if (done) return;
|
|
42819
|
+
done = true;
|
|
42820
|
+
this.quarantined += 1;
|
|
42821
|
+
const timer = setTimeout(() => {
|
|
42822
|
+
this.quarantined -= 1;
|
|
42823
|
+
this.returnPermit();
|
|
42824
|
+
}, durationMs);
|
|
42825
|
+
timer.unref?.();
|
|
42826
|
+
}
|
|
42827
|
+
};
|
|
42828
|
+
}
|
|
42829
|
+
returnPermit() {
|
|
42830
|
+
this.active -= 1;
|
|
42831
|
+
this.dispatchWaiters();
|
|
42832
|
+
}
|
|
42833
|
+
dispatchWaiters() {
|
|
42834
|
+
while (this.active < this.maxActive) {
|
|
42835
|
+
const waiter = this.waiters.shift();
|
|
42836
|
+
if (!waiter) return;
|
|
42837
|
+
clearTimeout(waiter.timer);
|
|
42838
|
+
this.active += 1;
|
|
42839
|
+
this.peak = Math.max(this.peak, this.active);
|
|
42840
|
+
waiter.resolve(this.makeLease());
|
|
42841
|
+
}
|
|
42842
|
+
}
|
|
42843
|
+
validateMaxActive(maxActive) {
|
|
42844
|
+
if (!Number.isSafeInteger(maxActive) || maxActive < 1 || maxActive > MAX_ACTIVE) {
|
|
42845
|
+
throw new Error(`ArgumentError: cursorMaxActive must be an integer from 1 to ${MAX_ACTIVE}.`);
|
|
42846
|
+
}
|
|
42847
|
+
}
|
|
42848
|
+
};
|
|
42849
|
+
var managers = /* @__PURE__ */ new Map();
|
|
42850
|
+
function getCursorLeaseManager(host, maxActive = DEFAULT_MAX_ACTIVE) {
|
|
42851
|
+
const key = host.toLowerCase();
|
|
42852
|
+
let manager = managers.get(key);
|
|
42853
|
+
if (!manager) {
|
|
42854
|
+
manager = new CursorLeaseManager(key, { maxActive });
|
|
42855
|
+
managers.set(key, manager);
|
|
42856
|
+
} else {
|
|
42857
|
+
manager.setMaxActive(maxActive);
|
|
42858
|
+
}
|
|
42859
|
+
return manager;
|
|
42860
|
+
}
|
|
42861
|
+
|
|
42241
42862
|
// src/cli/nodeKintoneClient.ts
|
|
42863
|
+
var KintoneApiError = class extends Error {
|
|
42864
|
+
constructor(status, code, bodyText) {
|
|
42865
|
+
super(`kintone API error ${status}: ${bodyText}`);
|
|
42866
|
+
this.status = status;
|
|
42867
|
+
this.code = code;
|
|
42868
|
+
this.name = "KintoneApiError";
|
|
42869
|
+
}
|
|
42870
|
+
};
|
|
42242
42871
|
var SEARCH_ABORTED_HEADER_VALUE = "Filter aborted because of too many search results";
|
|
42243
42872
|
function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
42244
42873
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
@@ -42286,7 +42915,13 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
42286
42915
|
if (tokenResolver.debug) {
|
|
42287
42916
|
tokenResolver.log?.(`[debug] response status=${res.status} body=${bodyText}`);
|
|
42288
42917
|
}
|
|
42289
|
-
|
|
42918
|
+
let code;
|
|
42919
|
+
try {
|
|
42920
|
+
const body = JSON.parse(bodyText);
|
|
42921
|
+
if (typeof body.code === "string") code = body.code;
|
|
42922
|
+
} catch {
|
|
42923
|
+
}
|
|
42924
|
+
throw new KintoneApiError(res.status, code, bodyText);
|
|
42290
42925
|
}
|
|
42291
42926
|
if (tokenResolver.debug) {
|
|
42292
42927
|
tokenResolver.log?.(`[debug] response status=${res.status}`);
|
|
@@ -42353,6 +42988,48 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
42353
42988
|
return response.searchAborted ? { ...response.body, searchAborted: true } : response.body;
|
|
42354
42989
|
}
|
|
42355
42990
|
},
|
|
42991
|
+
async openCursor(params) {
|
|
42992
|
+
const manager = getCursorLeaseManager(new URL(normalizedBaseUrl).host, tokenResolver.cursorMaxActive);
|
|
42993
|
+
const lease = await manager.acquire();
|
|
42994
|
+
let created;
|
|
42995
|
+
try {
|
|
42996
|
+
created = await manager.runCreate(() => requestJson(
|
|
42997
|
+
`${apiBasePath}/records/cursor.json`,
|
|
42998
|
+
{
|
|
42999
|
+
method: "POST",
|
|
43000
|
+
body: JSON.stringify({
|
|
43001
|
+
app: params.app,
|
|
43002
|
+
query: params.query,
|
|
43003
|
+
size: params.size,
|
|
43004
|
+
fields: params.fields && params.fields.length > 0 ? params.fields : void 0
|
|
43005
|
+
})
|
|
43006
|
+
},
|
|
43007
|
+
params.app
|
|
43008
|
+
));
|
|
43009
|
+
} catch (error51) {
|
|
43010
|
+
if (error51 instanceof KintoneApiError) {
|
|
43011
|
+
lease.release();
|
|
43012
|
+
throw error51;
|
|
43013
|
+
}
|
|
43014
|
+
lease.quarantine();
|
|
43015
|
+
throw new CursorCreateOutcomeUnknownError(error51);
|
|
43016
|
+
}
|
|
43017
|
+
const cursorId = created.id;
|
|
43018
|
+
return createKintoneCursorHandle(Number(created.totalCount), {
|
|
43019
|
+
get: () => requestJson(
|
|
43020
|
+
`${apiBasePath}/records/cursor.json?id=${encodeURIComponent(cursorId)}`,
|
|
43021
|
+
{ method: "GET" },
|
|
43022
|
+
params.app
|
|
43023
|
+
),
|
|
43024
|
+
delete: () => requestJson(
|
|
43025
|
+
`${apiBasePath}/records/cursor.json`,
|
|
43026
|
+
{ method: "DELETE", body: JSON.stringify({ id: cursorId }) },
|
|
43027
|
+
params.app
|
|
43028
|
+
),
|
|
43029
|
+
onReleased: () => lease.release(),
|
|
43030
|
+
onReleaseUnknown: () => lease.quarantine()
|
|
43031
|
+
});
|
|
43032
|
+
},
|
|
42356
43033
|
async postRecords(_params) {
|
|
42357
43034
|
const res = await requestJson(
|
|
42358
43035
|
`${apiBasePath}/records.json`,
|
|
@@ -42819,6 +43496,10 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
42819
43496
|
const onLimit2 = input.onLimit ?? envOnLimit("KSQL_ON_LIMIT") ?? profile2.query?.onLimit ?? "error";
|
|
42820
43497
|
const timeout2 = input.timeout ?? envInt("KSQL_TIMEOUT") ?? profile2.query?.timeout ?? 3e4;
|
|
42821
43498
|
const tempTableMaxRows2 = input.tempTableMaxRows ?? envInt("KSQL_TEMP_TABLE_MAX_ROWS") ?? profile2.query?.tempTableMaxRows;
|
|
43499
|
+
const cursorMaxActive2 = input.cursorMaxActive ?? envInt("KSQL_CURSOR_MAX_ACTIVE") ?? profile2.query?.cursorMaxActive ?? 2;
|
|
43500
|
+
if (!Number.isSafeInteger(cursorMaxActive2) || cursorMaxActive2 < 1 || cursorMaxActive2 > 5) {
|
|
43501
|
+
throw new Error("ArgumentError: cursorMaxActive must be an integer from 1 to 5.");
|
|
43502
|
+
}
|
|
42822
43503
|
const appIds = extractAppIds(sql);
|
|
42823
43504
|
const defaultApp = envInt("KSQL_APP") ?? profile2.app ?? null;
|
|
42824
43505
|
if (appIds.length === 0 && defaultApp !== null) appIds.push(defaultApp);
|
|
@@ -42856,6 +43537,7 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
42856
43537
|
}
|
|
42857
43538
|
profileClientMap.set(pName, createNodeKintoneClient(baseUrl, {
|
|
42858
43539
|
guestSpaceId,
|
|
43540
|
+
cursorMaxActive: cursorMaxActive2,
|
|
42859
43541
|
timeoutMs: timeout2,
|
|
42860
43542
|
debug: input.debug,
|
|
42861
43543
|
debugHeaders: input.debugHeaders,
|
|
@@ -42887,6 +43569,7 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
42887
43569
|
}
|
|
42888
43570
|
profileClientMap.set(pName, createNodeKintoneClient(baseUrl, {
|
|
42889
43571
|
guestSpaceId,
|
|
43572
|
+
cursorMaxActive: cursorMaxActive2,
|
|
42890
43573
|
timeoutMs: timeout2,
|
|
42891
43574
|
debug: input.debug,
|
|
42892
43575
|
debugHeaders: input.debugHeaders,
|
|
@@ -42920,6 +43603,12 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
42920
43603
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
42921
43604
|
return routed.getRecords({ ...params, app: binding.appId });
|
|
42922
43605
|
},
|
|
43606
|
+
openCursor: (params) => {
|
|
43607
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
43608
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
43609
|
+
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
43610
|
+
return routed.openCursor({ ...params, app: binding.appId });
|
|
43611
|
+
},
|
|
42923
43612
|
postRecords: (params) => {
|
|
42924
43613
|
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
42925
43614
|
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
@@ -42970,6 +43659,7 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
42970
43659
|
fetchParallel: fetchParallel2,
|
|
42971
43660
|
onLimit: onLimit2,
|
|
42972
43661
|
timeout: timeout2,
|
|
43662
|
+
cursorMaxActive: cursorMaxActive2,
|
|
42973
43663
|
tempTableMaxRows: tempTableMaxRows2
|
|
42974
43664
|
};
|
|
42975
43665
|
}
|
|
@@ -43170,6 +43860,7 @@ function noOpClient() {
|
|
|
43170
43860
|
};
|
|
43171
43861
|
return {
|
|
43172
43862
|
getRecords: fail,
|
|
43863
|
+
openCursor: fail,
|
|
43173
43864
|
postRecords: fail,
|
|
43174
43865
|
putRecords: fail,
|
|
43175
43866
|
deleteRecords: fail,
|
|
@@ -43446,7 +44137,9 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43446
44137
|
const runtime = needsAppMetadata ? await createRuntime(serverOptions, {
|
|
43447
44138
|
sql: input.sql,
|
|
43448
44139
|
sqlContext: normalized.sqlContext,
|
|
43449
|
-
profile: input.profile
|
|
44140
|
+
profile: input.profile,
|
|
44141
|
+
maxRecords: input.maxRecords,
|
|
44142
|
+
cursorMaxActive: input.cursorMaxActive
|
|
43450
44143
|
}) : null;
|
|
43451
44144
|
const explainClient = runtime?.client ?? noOpClient();
|
|
43452
44145
|
const explainCacheContext = runtime?.cacheContext ?? normalized.cacheContext;
|
|
@@ -43457,7 +44150,8 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43457
44150
|
explainClient,
|
|
43458
44151
|
void 0,
|
|
43459
44152
|
explainCacheContext,
|
|
43460
|
-
runtime?.maxRecords
|
|
44153
|
+
runtime?.maxRecords ?? input.maxRecords,
|
|
44154
|
+
runtime?.cursorMaxActive ?? input.cursorMaxActive ?? 2
|
|
43461
44155
|
);
|
|
43462
44156
|
return {
|
|
43463
44157
|
ok: true,
|
|
@@ -43469,7 +44163,8 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43469
44163
|
}
|
|
43470
44164
|
const result = await executeSql(explainSql(explainSourceSql), explainClient, {
|
|
43471
44165
|
cacheContext: explainCacheContext,
|
|
43472
|
-
maxRecords: runtime?.maxRecords
|
|
44166
|
+
maxRecords: runtime?.maxRecords ?? input.maxRecords,
|
|
44167
|
+
cursorMaxActive: runtime?.cursorMaxActive ?? input.cursorMaxActive ?? 2
|
|
43473
44168
|
});
|
|
43474
44169
|
if (result.type !== "SELECT") {
|
|
43475
44170
|
throw new Error(`ArgumentError: EXPLAIN returned unexpected result type ${result.type}.`);
|
|
@@ -43496,7 +44191,8 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43496
44191
|
fetchParallel: input.fetchParallel,
|
|
43497
44192
|
onLimit: validation.containsValidationOnly ? "error" : input.onLimit,
|
|
43498
44193
|
timeout: input.timeout,
|
|
43499
|
-
tempTableMaxRows: input.tempTableMaxRows
|
|
44194
|
+
tempTableMaxRows: input.tempTableMaxRows,
|
|
44195
|
+
cursorMaxActive: input.cursorMaxActive
|
|
43500
44196
|
});
|
|
43501
44197
|
const batchResult = await executeBatchSql(runtime2.sql, runtime2.client, {
|
|
43502
44198
|
maxRecords: runtime2.maxRecords,
|
|
@@ -43511,6 +44207,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43511
44207
|
// runtime.timeout は env / profile / 既定 30000ms を解決済みの値で、
|
|
43512
44208
|
// HTTP クライアント側の per-request タイムアウトと同値になる
|
|
43513
44209
|
timeoutMs: runtime2.timeout,
|
|
44210
|
+
cursorMaxActive: runtime2.cursorMaxActive ?? input.cursorMaxActive ?? 2,
|
|
43514
44211
|
variables: input.variables
|
|
43515
44212
|
});
|
|
43516
44213
|
return { ...buildBatchEnvelope(batchResult, { maxTotalRecords: input.maxTotalRecords }) };
|
|
@@ -43540,13 +44237,15 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43540
44237
|
maxRecords: input.maxRecords,
|
|
43541
44238
|
fetchParallel: input.fetchParallel,
|
|
43542
44239
|
onLimit: validation.containsValidationOnly ? "error" : input.onLimit,
|
|
43543
|
-
timeout: input.timeout
|
|
44240
|
+
timeout: input.timeout,
|
|
44241
|
+
cursorMaxActive: input.cursorMaxActive
|
|
43544
44242
|
});
|
|
43545
44243
|
const result = await executeSql(runtime.sql, runtime.client, {
|
|
43546
44244
|
maxRecords: runtime.maxRecords,
|
|
43547
44245
|
fetchParallel: runtime.fetchParallel,
|
|
43548
44246
|
onLimitReached: runtime.onLimit,
|
|
43549
|
-
cacheContext: runtime.cacheContext
|
|
44247
|
+
cacheContext: runtime.cacheContext,
|
|
44248
|
+
cursorMaxActive: runtime.cursorMaxActive ?? input.cursorMaxActive ?? 2
|
|
43550
44249
|
});
|
|
43551
44250
|
if (result.type === "ASSERT") return toAssertPayload(result);
|
|
43552
44251
|
if (result.type === "VALIDATION") return toDmlValidationPayload(result);
|
|
@@ -43590,7 +44289,8 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43590
44289
|
fetchParallel: input.fetchParallel,
|
|
43591
44290
|
onLimit: DEFAULT_ON_LIMIT,
|
|
43592
44291
|
timeout: input.timeout,
|
|
43593
|
-
tempTableMaxRows: input.tempTableMaxRows
|
|
44292
|
+
tempTableMaxRows: input.tempTableMaxRows,
|
|
44293
|
+
cursorMaxActive: input.cursorMaxActive
|
|
43594
44294
|
});
|
|
43595
44295
|
let totalAffected = staticInsertTotal;
|
|
43596
44296
|
const batchResult = await executeBatchSql(runtime.sql, runtime.client, {
|
|
@@ -43602,6 +44302,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43602
44302
|
tempTableMaxRows: runtime.tempTableMaxRows,
|
|
43603
44303
|
// 合計タイムアウト(解決済みの runtime.timeout。per-request と同値)
|
|
43604
44304
|
timeoutMs: runtime.timeout,
|
|
44305
|
+
cursorMaxActive: runtime.cursorMaxActive ?? input.cursorMaxActive ?? 2,
|
|
43605
44306
|
variables: input.variables,
|
|
43606
44307
|
confirm: async (count, operation) => {
|
|
43607
44308
|
if (count > dmlMaxRows) {
|
|
@@ -43657,7 +44358,8 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43657
44358
|
maxRecords: resolveMutateRuntimeMaxRecords(validation.statements, dmlMaxRows),
|
|
43658
44359
|
fetchParallel: input.fetchParallel,
|
|
43659
44360
|
onLimit: DEFAULT_ON_LIMIT,
|
|
43660
|
-
timeout: input.timeout
|
|
44361
|
+
timeout: input.timeout,
|
|
44362
|
+
cursorMaxActive: input.cursorMaxActive
|
|
43661
44363
|
});
|
|
43662
44364
|
let result;
|
|
43663
44365
|
try {
|
|
@@ -43666,6 +44368,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
43666
44368
|
fetchParallel: runtime.fetchParallel,
|
|
43667
44369
|
onLimitReached: runtime.onLimit,
|
|
43668
44370
|
cacheContext: runtime.cacheContext,
|
|
44371
|
+
cursorMaxActive: runtime.cursorMaxActive ?? input.cursorMaxActive ?? 2,
|
|
43669
44372
|
confirm: async (count, operation) => {
|
|
43670
44373
|
if (count > dmlMaxRows) {
|
|
43671
44374
|
throw new Error(`ArgumentError: ${operation} affected rows (${count}) exceed dmlMaxRows (${dmlMaxRows}).`);
|
|
@@ -43838,6 +44541,7 @@ var fetchParallel = external_exports.number().int().min(1).max(10).describe("Num
|
|
|
43838
44541
|
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();
|
|
43839
44542
|
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();
|
|
43840
44543
|
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();
|
|
44544
|
+
var cursorMaxActive = external_exports.number().int().min(1).max(5).describe("Maximum active Cursor API handles per kintone host in this process (1-5, default 2). Later calls update the host limit; lowering it keeps existing cursors and delays new ones until active usage falls below the new limit. Create/Get are never automatically retried; capacity waits up to 30 seconds.").optional();
|
|
43841
44545
|
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).");
|
|
43842
44546
|
var savedQueryTags = external_exports.array(external_exports.string().min(1)).describe("Tags for organizing saved queries.").optional();
|
|
43843
44547
|
var validateInputSchema = external_exports.object({
|
|
@@ -43846,7 +44550,9 @@ var validateInputSchema = external_exports.object({
|
|
|
43846
44550
|
});
|
|
43847
44551
|
var explainInputSchema = external_exports.object({
|
|
43848
44552
|
sql: external_exports.string().min(1).describe("kSQL text to explain. May contain multiple ;-separated statements (batch) and temp tables (#name)."),
|
|
43849
|
-
profile
|
|
44553
|
+
profile,
|
|
44554
|
+
maxRecords,
|
|
44555
|
+
cursorMaxActive
|
|
43850
44556
|
});
|
|
43851
44557
|
var queryInputSchema = external_exports.object({
|
|
43852
44558
|
sql: external_exports.string().min(1).describe("Read-only kSQL text. May contain multiple ;-separated statements (batch) with temp tables, e.g. CREATE TEMP TABLE #t AS SELECT ...; SELECT ... FROM #t;"),
|
|
@@ -43856,6 +44562,7 @@ var queryInputSchema = external_exports.object({
|
|
|
43856
44562
|
onLimit,
|
|
43857
44563
|
tempTableMaxRows,
|
|
43858
44564
|
timeout,
|
|
44565
|
+
cursorMaxActive,
|
|
43859
44566
|
continueOnError: external_exports.boolean().describe("Batch (multi-statement) only: keep executing subsequent statements after a runtime error (default false = fail-fast).").optional(),
|
|
43860
44567
|
maxTotalRecords: external_exports.number().int().positive().describe("Batch (multi-statement) only: cap on total rows returned across all result sets (default: unlimited).").optional(),
|
|
43861
44568
|
variables: external_exports.record(external_exports.string(), external_exports.string()).describe("Batch only: string values for variables declared with DECLARE. Keys omit @ and are case-insensitive.").optional()
|
|
@@ -43869,6 +44576,7 @@ var mutateInputSchema = external_exports.object({
|
|
|
43869
44576
|
fetchParallel,
|
|
43870
44577
|
tempTableMaxRows,
|
|
43871
44578
|
timeout,
|
|
44579
|
+
cursorMaxActive,
|
|
43872
44580
|
dmlTotalMaxRows: external_exports.number().int().positive().describe("Batch (multi-statement) only: cap on total affected rows across the whole batch (default: per-statement dmlMaxRows only). DML batches always run fail-fast.").optional(),
|
|
43873
44581
|
variables: external_exports.record(external_exports.string(), external_exports.string()).describe("Batch only: string values for variables declared with DECLARE. Keys omit @ and are case-insensitive.").optional()
|
|
43874
44582
|
});
|
|
@@ -43959,7 +44667,7 @@ Options:
|
|
|
43959
44667
|
-h, --help Show help
|
|
43960
44668
|
`);
|
|
43961
44669
|
}
|
|
43962
|
-
var SERVER_VERSION = true ? "3.
|
|
44670
|
+
var SERVER_VERSION = true ? "3.2.0" : "0.0.0-dev";
|
|
43963
44671
|
function createServer(args) {
|
|
43964
44672
|
const server = new McpServer({
|
|
43965
44673
|
name: "ksql-mcp",
|