@rex0220/kintone-sql-tools 1.3.0 → 1.4.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 +13 -2
- package/dist-cli/ksql.js +1178 -290
- package/dist-mcp/ksql-mcp.js +953 -97
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -31052,11 +31052,12 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31052
31052
|
|
|
31053
31053
|
// src/lexer/lexer.ts
|
|
31054
31054
|
var LexError = class extends Error {
|
|
31055
|
-
constructor(message, pos, input) {
|
|
31055
|
+
constructor(message, pos, input, unterminated = false) {
|
|
31056
31056
|
const around = input.slice(Math.max(0, pos - 10), pos + 10);
|
|
31057
31057
|
super(`${message}\uFF08\u4F4D\u7F6E ${pos}\u3001\u524D\u5F8C: \u300C${around}\u300D\uFF09`);
|
|
31058
31058
|
this.pos = pos;
|
|
31059
31059
|
this.input = input;
|
|
31060
|
+
this.unterminated = unterminated;
|
|
31060
31061
|
this.name = "LexError";
|
|
31061
31062
|
}
|
|
31062
31063
|
};
|
|
@@ -31093,6 +31094,7 @@ var Lexer = class {
|
|
|
31093
31094
|
const opTok = this.tryReadOperator(start);
|
|
31094
31095
|
if (opTok) return opTok;
|
|
31095
31096
|
if (isIdentStart(ch)) return this.readIdentOrKeyword(start);
|
|
31097
|
+
if (ch === "#") return this.readHashIdent(start);
|
|
31096
31098
|
throw new LexError(
|
|
31097
31099
|
`\u4E88\u671F\u3057\u306A\u3044\u6587\u5B57 \u300C${ch}\u300D \u3067\u3059`,
|
|
31098
31100
|
this.pos,
|
|
@@ -31121,7 +31123,7 @@ var Lexer = class {
|
|
|
31121
31123
|
this.pos++;
|
|
31122
31124
|
}
|
|
31123
31125
|
}
|
|
31124
|
-
throw new LexError("\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u304C\u9589\u3058\u3089\u308C\u3066\u3044\u307E\u305B\u3093", start, this.input);
|
|
31126
|
+
throw new LexError("\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u304C\u9589\u3058\u3089\u308C\u3066\u3044\u307E\u305B\u3093", start, this.input, true);
|
|
31125
31127
|
}
|
|
31126
31128
|
// ----------------------------------------------------------
|
|
31127
31129
|
// バッククォート識別子: `field name`
|
|
@@ -31141,7 +31143,8 @@ var Lexer = class {
|
|
|
31141
31143
|
throw new LexError(
|
|
31142
31144
|
"\u30D0\u30C3\u30AF\u30AF\u30A9\u30FC\u30C8\u8B58\u5225\u5B50\u304C\u9589\u3058\u3089\u308C\u3066\u3044\u307E\u305B\u3093",
|
|
31143
31145
|
start,
|
|
31144
|
-
this.input
|
|
31146
|
+
this.input,
|
|
31147
|
+
true
|
|
31145
31148
|
);
|
|
31146
31149
|
}
|
|
31147
31150
|
// ----------------------------------------------------------
|
|
@@ -31248,6 +31251,30 @@ var Lexer = class {
|
|
|
31248
31251
|
return this.makeToken(kind, value, start);
|
|
31249
31252
|
}
|
|
31250
31253
|
// ----------------------------------------------------------
|
|
31254
|
+
// 一時テーブル識別子: #temp
|
|
31255
|
+
// # は先頭のみ有効。isIdentStart に # を加えると isIdentContinue 経由で
|
|
31256
|
+
// 識別子の途中(APP#x 等)にも許容されてしまうため、専用分岐で読む。
|
|
31257
|
+
// ----------------------------------------------------------
|
|
31258
|
+
readHashIdent(start) {
|
|
31259
|
+
this.pos++;
|
|
31260
|
+
const next = this.input[this.pos] ?? "";
|
|
31261
|
+
if (!isIdentStart(next)) {
|
|
31262
|
+
throw new LexError("\u300C#\u300D \u306E\u76F4\u5F8C\u306B\u306F\u8B58\u5225\u5B50\u304C\u5FC5\u8981\u3067\u3059", start, this.input);
|
|
31263
|
+
}
|
|
31264
|
+
while (this.pos < this.input.length && isIdentContinue(this.input[this.pos])) {
|
|
31265
|
+
this.pos++;
|
|
31266
|
+
}
|
|
31267
|
+
const value = this.input.slice(start, this.pos);
|
|
31268
|
+
if (this.input[this.pos] === "@") {
|
|
31269
|
+
throw new LexError(
|
|
31270
|
+
`@profile is not allowed on temp table ${value}.`,
|
|
31271
|
+
this.pos,
|
|
31272
|
+
this.input
|
|
31273
|
+
);
|
|
31274
|
+
}
|
|
31275
|
+
return this.makeToken("IDENT" /* IDENT */, value, start);
|
|
31276
|
+
}
|
|
31277
|
+
// ----------------------------------------------------------
|
|
31251
31278
|
// 空白・コメントをスキップ
|
|
31252
31279
|
// ----------------------------------------------------------
|
|
31253
31280
|
skipWhitespaceAndComments() {
|
|
@@ -31264,14 +31291,25 @@ var Lexer = class {
|
|
|
31264
31291
|
continue;
|
|
31265
31292
|
}
|
|
31266
31293
|
if (ch === "/" && this.input[this.pos + 1] === "*") {
|
|
31294
|
+
const commentStart = this.pos;
|
|
31267
31295
|
this.pos += 2;
|
|
31296
|
+
let closed = false;
|
|
31268
31297
|
while (this.pos < this.input.length) {
|
|
31269
31298
|
if (this.input[this.pos] === "*" && this.input[this.pos + 1] === "/") {
|
|
31270
31299
|
this.pos += 2;
|
|
31300
|
+
closed = true;
|
|
31271
31301
|
break;
|
|
31272
31302
|
}
|
|
31273
31303
|
this.pos++;
|
|
31274
31304
|
}
|
|
31305
|
+
if (!closed) {
|
|
31306
|
+
throw new LexError(
|
|
31307
|
+
"\u30D6\u30ED\u30C3\u30AF\u30B3\u30E1\u30F3\u30C8\u304C\u9589\u3058\u3089\u308C\u3066\u3044\u307E\u305B\u3093",
|
|
31308
|
+
commentStart,
|
|
31309
|
+
this.input,
|
|
31310
|
+
true
|
|
31311
|
+
);
|
|
31312
|
+
}
|
|
31275
31313
|
continue;
|
|
31276
31314
|
}
|
|
31277
31315
|
break;
|
|
@@ -31305,6 +31343,7 @@ function isJapanese(cp) {
|
|
|
31305
31343
|
}
|
|
31306
31344
|
|
|
31307
31345
|
// src/parser/parser.ts
|
|
31346
|
+
var MAX_BATCH_STATEMENTS = 20;
|
|
31308
31347
|
var ParseError = class extends Error {
|
|
31309
31348
|
constructor(message, token) {
|
|
31310
31349
|
super(`${message}\uFF08\u4F4D\u7F6E ${token.pos}\u3001\u30C8\u30FC\u30AF\u30F3: \u300C${token.value}\u300D\uFF09`);
|
|
@@ -31318,15 +31357,54 @@ var Parser = class {
|
|
|
31318
31357
|
this.pos = 0;
|
|
31319
31358
|
/** WITH 句で定義された CTE 名のセット(parseTableRef で参照) */
|
|
31320
31359
|
this.cteNames = /* @__PURE__ */ new Set();
|
|
31360
|
+
/** パース中に出現した一時テーブル参照(#name)のトークン。単文 API での拒否に使う */
|
|
31361
|
+
this.tempTableRefs = [];
|
|
31321
31362
|
}
|
|
31322
31363
|
// ----------------------------------------------------------
|
|
31323
31364
|
// 公開 API
|
|
31324
31365
|
// ----------------------------------------------------------
|
|
31366
|
+
/** 単文をパースする(従来 API。複文が渡されたらエラー) */
|
|
31325
31367
|
parse() {
|
|
31326
|
-
const
|
|
31327
|
-
if (
|
|
31368
|
+
const stmts = this.parseStatements();
|
|
31369
|
+
if (stmts.length === 0) {
|
|
31370
|
+
throw new ParseError("SQL \u6587\u304C\u3042\u308A\u307E\u305B\u3093", this.peek());
|
|
31371
|
+
}
|
|
31372
|
+
if (stmts.length > 1) {
|
|
31373
|
+
throw new ParseError(
|
|
31374
|
+
"\u3053\u306E API \u306F\u5358\u6587\u306E\u307F\u53D7\u3051\u4ED8\u3051\u307E\u3059\uFF08\u8907\u6587\u306F\u30D0\u30C3\u30C1\u5B9F\u884C API \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\uFF09",
|
|
31375
|
+
this.peek()
|
|
31376
|
+
);
|
|
31377
|
+
}
|
|
31378
|
+
if (this.tempTableRefs.length > 0) {
|
|
31379
|
+
const tok = this.tempTableRefs[0];
|
|
31380
|
+
throw new ParseError(
|
|
31381
|
+
`temp table ${tok.value} is not defined in this batch.`,
|
|
31382
|
+
tok
|
|
31383
|
+
);
|
|
31384
|
+
}
|
|
31385
|
+
return stmts[0];
|
|
31386
|
+
}
|
|
31387
|
+
/** 複文(`;` 区切り)をパースする。空文はスキップする */
|
|
31388
|
+
parseStatements() {
|
|
31389
|
+
const stmts = [];
|
|
31390
|
+
while (true) {
|
|
31391
|
+
while (this.peek().kind === ";" /* SEMICOLON */) this.advance();
|
|
31392
|
+
if (this.peek().kind === "EOF" /* EOF */) break;
|
|
31393
|
+
const startTok = this.peek();
|
|
31394
|
+
stmts.push(this.parseStatement());
|
|
31395
|
+
if (stmts.length > MAX_BATCH_STATEMENTS) {
|
|
31396
|
+
throw new ParseError(
|
|
31397
|
+
`batch exceeds ${MAX_BATCH_STATEMENTS} statements.`,
|
|
31398
|
+
startTok
|
|
31399
|
+
);
|
|
31400
|
+
}
|
|
31401
|
+
const after = this.peek();
|
|
31402
|
+
if (after.kind !== ";" /* SEMICOLON */ && after.kind !== "EOF" /* EOF */) {
|
|
31403
|
+
throw new ParseError("\u6587\u306E\u533A\u5207\u308A\u306B\u306F ; \u304C\u5FC5\u8981\u3067\u3059", after);
|
|
31404
|
+
}
|
|
31405
|
+
}
|
|
31328
31406
|
this.expect("EOF" /* EOF */);
|
|
31329
|
-
return
|
|
31407
|
+
return stmts;
|
|
31330
31408
|
}
|
|
31331
31409
|
// ----------------------------------------------------------
|
|
31332
31410
|
// Statement ディスパッチ
|
|
@@ -31355,12 +31433,63 @@ var Parser = class {
|
|
|
31355
31433
|
return this.parseDescribe();
|
|
31356
31434
|
case "EXPLAIN" /* EXPLAIN */:
|
|
31357
31435
|
return this.parseExplain();
|
|
31436
|
+
case "IDENT" /* IDENT */: {
|
|
31437
|
+
const upper = tok.value.toUpperCase();
|
|
31438
|
+
if (upper === "CREATE") return this.parseCreateTempTable();
|
|
31439
|
+
if (upper === "DROP") return this.parseDropTempTable();
|
|
31440
|
+
break;
|
|
31441
|
+
}
|
|
31358
31442
|
default:
|
|
31359
|
-
|
|
31360
|
-
|
|
31361
|
-
|
|
31362
|
-
|
|
31443
|
+
break;
|
|
31444
|
+
}
|
|
31445
|
+
throw new ParseError(
|
|
31446
|
+
"SELECT / INSERT / UPDATE / DELETE / REORDER / WITH / SHOW / DESCRIBE / EXPLAIN / CREATE TEMP TABLE / DROP TEMP TABLE \u306E\u3044\u305A\u308C\u304B\u3067\u59CB\u307E\u308B SQL \u6587\u304C\u5FC5\u8981\u3067\u3059",
|
|
31447
|
+
tok
|
|
31448
|
+
);
|
|
31449
|
+
}
|
|
31450
|
+
// ----------------------------------------------------------
|
|
31451
|
+
// CREATE TEMP TABLE / DROP TEMP TABLE(バッチ内一時テーブル)
|
|
31452
|
+
// CREATE / DROP / TEMP / TABLE は予約語にしない(ソフトキーワード)
|
|
31453
|
+
// ----------------------------------------------------------
|
|
31454
|
+
parseCreateTempTable() {
|
|
31455
|
+
this.advance();
|
|
31456
|
+
this.expectSoftKeyword("TEMP", "CREATE \u306E\u5F8C\u306B\u306F TEMP TABLE \u304C\u5FC5\u8981\u3067\u3059\uFF08\u4F8B: CREATE TEMP TABLE #temp AS SELECT ...\uFF09");
|
|
31457
|
+
this.expectSoftKeyword("TABLE", "CREATE TEMP \u306E\u5F8C\u306B\u306F TABLE \u304C\u5FC5\u8981\u3067\u3059");
|
|
31458
|
+
const name = this.parseTempTableName();
|
|
31459
|
+
this.expect("AS" /* AS */, "CREATE TEMP TABLE \u306B\u306F AS SELECT \u304C\u5FC5\u8981\u3067\u3059");
|
|
31460
|
+
const tok = this.peek();
|
|
31461
|
+
let query;
|
|
31462
|
+
if (tok.kind === "WITH" /* WITH */) {
|
|
31463
|
+
query = this.parseWith();
|
|
31464
|
+
} else if (tok.kind === "SELECT" /* SELECT */) {
|
|
31465
|
+
query = this.tryParseUnionChain(this.parseSelect());
|
|
31466
|
+
} else {
|
|
31467
|
+
throw new ParseError("CREATE TEMP TABLE ... AS \u306E\u5F8C\u306B\u306F SELECT / WITH \u304C\u5FC5\u8981\u3067\u3059", tok);
|
|
31468
|
+
}
|
|
31469
|
+
return { type: "CREATE_TEMP_TABLE", name, query };
|
|
31470
|
+
}
|
|
31471
|
+
parseDropTempTable() {
|
|
31472
|
+
this.advance();
|
|
31473
|
+
this.expectSoftKeyword("TEMP", "DROP \u306E\u5F8C\u306B\u306F TEMP TABLE \u304C\u5FC5\u8981\u3067\u3059\uFF08\u4F8B: DROP TEMP TABLE #temp\uFF09");
|
|
31474
|
+
this.expectSoftKeyword("TABLE", "DROP TEMP \u306E\u5F8C\u306B\u306F TABLE \u304C\u5FC5\u8981\u3067\u3059");
|
|
31475
|
+
const name = this.parseTempTableName();
|
|
31476
|
+
return { type: "DROP_TEMP_TABLE", name };
|
|
31477
|
+
}
|
|
31478
|
+
expectSoftKeyword(word, msg) {
|
|
31479
|
+
const tok = this.peek();
|
|
31480
|
+
if (tok.kind === "IDENT" /* IDENT */ && tok.value.toUpperCase() === word) {
|
|
31481
|
+
this.advance();
|
|
31482
|
+
return;
|
|
31363
31483
|
}
|
|
31484
|
+
throw new ParseError(msg, tok);
|
|
31485
|
+
}
|
|
31486
|
+
parseTempTableName() {
|
|
31487
|
+
const tok = this.peek();
|
|
31488
|
+
if (tok.kind === "IDENT" /* IDENT */ && tok.value.startsWith("#")) {
|
|
31489
|
+
this.advance();
|
|
31490
|
+
return tok.value;
|
|
31491
|
+
}
|
|
31492
|
+
throw new ParseError("\u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u540D\u306F # \u3067\u59CB\u307E\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08\u4F8B: #temp\uFF09", tok);
|
|
31364
31493
|
}
|
|
31365
31494
|
parseShow() {
|
|
31366
31495
|
this.advance();
|
|
@@ -31917,24 +32046,38 @@ var Parser = class {
|
|
|
31917
32046
|
// FROM / JOIN
|
|
31918
32047
|
// ----------------------------------------------------------
|
|
31919
32048
|
parseTableRef() {
|
|
31920
|
-
const
|
|
32049
|
+
const nameTok = this.peek();
|
|
32050
|
+
const name = this.parseTableName();
|
|
32051
|
+
if (nameTok.kind === "IDENT" /* IDENT */ && name.startsWith("#")) {
|
|
32052
|
+
this.tempTableRefs.push(this.prev());
|
|
32053
|
+
const alias2 = this.consume("AS" /* AS */) ? this.parseTableAliasName() : this.tryParseImplicitAlias();
|
|
32054
|
+
return { appId: 0, alias: alias2, cteName: name };
|
|
32055
|
+
}
|
|
31921
32056
|
if (this.cteNames.has(name)) {
|
|
31922
|
-
const alias2 = this.consume("AS" /* AS */) ? this.
|
|
32057
|
+
const alias2 = this.consume("AS" /* AS */) ? this.parseTableAliasName() : this.tryParseImplicitAlias();
|
|
31923
32058
|
return { appId: 0, alias: alias2, cteName: name };
|
|
31924
32059
|
}
|
|
31925
32060
|
const { appId, subtableCode } = extractTableRef(name, this.prev());
|
|
31926
32061
|
if (subtableCode) {
|
|
31927
|
-
const alias2 = this.consume("AS" /* AS */) ? this.
|
|
32062
|
+
const alias2 = this.consume("AS" /* AS */) ? this.parseTableAliasName() : this.tryParseImplicitAlias();
|
|
31928
32063
|
return { appId, alias: alias2, cteName: null, subtableCode };
|
|
31929
32064
|
}
|
|
31930
32065
|
const implicit = this.tryParseImplicitAlias();
|
|
31931
|
-
const alias = this.consume("AS" /* AS */) ? this.
|
|
32066
|
+
const alias = this.consume("AS" /* AS */) ? this.parseTableAliasName() : implicit ?? name;
|
|
31932
32067
|
return { appId, alias, cteName: null };
|
|
31933
32068
|
}
|
|
32069
|
+
// テーブル alias 名を読む(IDENT / BIDENT)。alias 位置の # は BIDENT でも拒否
|
|
32070
|
+
parseTableAliasName() {
|
|
32071
|
+
const tok = this.peek();
|
|
32072
|
+
if ((tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) && tok.value.startsWith("#")) {
|
|
32073
|
+
throw new ParseError("\u30A8\u30A4\u30EA\u30A2\u30B9\u540D\u306B # \u3067\u59CB\u307E\u308B\u540D\u524D\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
|
|
32074
|
+
}
|
|
32075
|
+
return this.parseIdentifier();
|
|
32076
|
+
}
|
|
31934
32077
|
tryParseImplicitAlias() {
|
|
31935
32078
|
const k = this.peek().kind;
|
|
31936
32079
|
if (k === "IDENT" /* IDENT */ || k === "BIDENT" /* BIDENT */) {
|
|
31937
|
-
return this.
|
|
32080
|
+
return this.parseTableAliasName();
|
|
31938
32081
|
}
|
|
31939
32082
|
return null;
|
|
31940
32083
|
}
|
|
@@ -32339,6 +32482,7 @@ var Parser = class {
|
|
|
32339
32482
|
parseInsert() {
|
|
32340
32483
|
this.expect("INSERT" /* INSERT */);
|
|
32341
32484
|
this.expect("INTO" /* INTO */);
|
|
32485
|
+
this.rejectTempTableDml();
|
|
32342
32486
|
const name = this.parseIdentifier();
|
|
32343
32487
|
const { appId, subtableCode } = extractTableRef(name, this.prev());
|
|
32344
32488
|
this.expect("(" /* LPAREN */);
|
|
@@ -32364,6 +32508,7 @@ var Parser = class {
|
|
|
32364
32508
|
parseUpsert() {
|
|
32365
32509
|
this.expect("UPSERT" /* UPSERT */);
|
|
32366
32510
|
this.expect("INTO" /* INTO */);
|
|
32511
|
+
this.rejectTempTableDml();
|
|
32367
32512
|
const name = this.parseIdentifier();
|
|
32368
32513
|
const { appId, subtableCode } = extractTableRef(name, this.prev());
|
|
32369
32514
|
if (subtableCode) {
|
|
@@ -32448,6 +32593,7 @@ var Parser = class {
|
|
|
32448
32593
|
// ----------------------------------------------------------
|
|
32449
32594
|
parseUpdate() {
|
|
32450
32595
|
this.expect("UPDATE" /* UPDATE */);
|
|
32596
|
+
this.rejectTempTableDml();
|
|
32451
32597
|
const name = this.parseIdentifier();
|
|
32452
32598
|
const { appId, subtableCode } = extractTableRef(name, this.prev());
|
|
32453
32599
|
this.expect("SET" /* SET */);
|
|
@@ -32523,6 +32669,7 @@ var Parser = class {
|
|
|
32523
32669
|
parseDelete() {
|
|
32524
32670
|
this.expect("DELETE" /* DELETE */);
|
|
32525
32671
|
this.expect("FROM" /* FROM */);
|
|
32672
|
+
this.rejectTempTableDml();
|
|
32526
32673
|
const name = this.parseIdentifier();
|
|
32527
32674
|
const { appId, subtableCode } = extractTableRef(name, this.prev());
|
|
32528
32675
|
const whereTok = this.peek();
|
|
@@ -32541,6 +32688,7 @@ var Parser = class {
|
|
|
32541
32688
|
parseReorder() {
|
|
32542
32689
|
this.expect("REORDER" /* REORDER */);
|
|
32543
32690
|
const all = this.consume("ALL" /* ALL */);
|
|
32691
|
+
this.rejectTempTableDml();
|
|
32544
32692
|
const name = this.parseIdentifier();
|
|
32545
32693
|
const { appId, subtableCode } = extractTableRef(name, this.prev());
|
|
32546
32694
|
if (!subtableCode) {
|
|
@@ -32622,8 +32770,29 @@ var Parser = class {
|
|
|
32622
32770
|
}
|
|
32623
32771
|
return n;
|
|
32624
32772
|
}
|
|
32625
|
-
// 識別子(IDENT / BIDENT
|
|
32773
|
+
// 識別子(IDENT / BIDENT)を読む。# 始まりの一時テーブル名は不可
|
|
32774
|
+
//(temp マーカーはレキサが生成する IDENT のみ。`#field` のような
|
|
32775
|
+
// バッククォート識別子は # で始まる通常フィールド名として許容する)
|
|
32626
32776
|
parseIdentifier() {
|
|
32777
|
+
const tok = this.peek();
|
|
32778
|
+
if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
|
|
32779
|
+
if (tok.kind === "IDENT" /* IDENT */ && tok.value.startsWith("#")) {
|
|
32780
|
+
throw new ParseError(
|
|
32781
|
+
"\u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u540D\uFF08# \u3067\u59CB\u307E\u308B\u540D\u524D\uFF09\u306F FROM / JOIN / CREATE / DROP TEMP TABLE \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059",
|
|
32782
|
+
tok
|
|
32783
|
+
);
|
|
32784
|
+
}
|
|
32785
|
+
this.advance();
|
|
32786
|
+
return tok.value;
|
|
32787
|
+
}
|
|
32788
|
+
throw new ParseError(
|
|
32789
|
+
"\u30D5\u30A3\u30FC\u30EB\u30C9\u540D\u307E\u305F\u306F\u30C6\u30FC\u30D6\u30EB\u540D\u304C\u5FC5\u8981\u3067\u3059",
|
|
32790
|
+
tok
|
|
32791
|
+
);
|
|
32792
|
+
}
|
|
32793
|
+
// テーブル名(IDENT / BIDENT)を読む。# 始まりの一時テーブル名を許容する
|
|
32794
|
+
//(一時テーブルを受理してよいのはテーブル参照位置のみ。他は parseIdentifier を使う)
|
|
32795
|
+
parseTableName() {
|
|
32627
32796
|
const tok = this.peek();
|
|
32628
32797
|
if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
|
|
32629
32798
|
this.advance();
|
|
@@ -32634,10 +32803,23 @@ var Parser = class {
|
|
|
32634
32803
|
tok
|
|
32635
32804
|
);
|
|
32636
32805
|
}
|
|
32806
|
+
// DML の対象テーブル位置に一時テーブルが指定されていたら拒否する
|
|
32807
|
+
rejectTempTableDml() {
|
|
32808
|
+
const tok = this.peek();
|
|
32809
|
+
if (tok.kind === "IDENT" /* IDENT */ && tok.value.startsWith("#")) {
|
|
32810
|
+
throw new ParseError(
|
|
32811
|
+
`DML on temp table ${tok.value} is not supported.`,
|
|
32812
|
+
tok
|
|
32813
|
+
);
|
|
32814
|
+
}
|
|
32815
|
+
}
|
|
32637
32816
|
// エイリアス名: IDENT / BIDENT に加え、キーワードも許容する
|
|
32638
32817
|
// 例: SELECT SUM(金額) AS avg → "avg" は AVG キーワードだが alias として有効
|
|
32639
32818
|
parseAliasName() {
|
|
32640
32819
|
const tok = this.peek();
|
|
32820
|
+
if (tok.value.startsWith("#")) {
|
|
32821
|
+
throw new ParseError("\u30A8\u30A4\u30EA\u30A2\u30B9\u540D\u306B # \u3067\u59CB\u307E\u308B\u540D\u524D\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
|
|
32822
|
+
}
|
|
32641
32823
|
if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */ || KEYWORDS.has(tok.value.toUpperCase())) {
|
|
32642
32824
|
this.advance();
|
|
32643
32825
|
return tok.value.toLowerCase();
|
|
@@ -32694,6 +32876,159 @@ function extractTableRef(name, tok) {
|
|
|
32694
32876
|
return { appId: Number(m[1]), subtableCode: m[2] ?? null };
|
|
32695
32877
|
}
|
|
32696
32878
|
|
|
32879
|
+
// src/core/dmlGuard.ts
|
|
32880
|
+
function getStatementType(stmt) {
|
|
32881
|
+
if (!stmt || typeof stmt !== "object") return "UNKNOWN";
|
|
32882
|
+
const obj = stmt;
|
|
32883
|
+
return typeof obj.type === "string" ? obj.type : "UNKNOWN";
|
|
32884
|
+
}
|
|
32885
|
+
function isDmlType(type) {
|
|
32886
|
+
return type === "INSERT" || type === "INSERT_SELECT" || type === "UPDATE" || type === "DELETE" || type === "UPSERT" || type === "UPSERT_SELECT" || type === "REORDER";
|
|
32887
|
+
}
|
|
32888
|
+
function isReadOnlyType(type) {
|
|
32889
|
+
return type === "SELECT" || type === "UNION" || type === "WITH" || type === "EXPLAIN" || type === "SHOW_APPS" || type === "DESCRIBE" || type === "CREATE_TEMP_TABLE" || type === "DROP_TEMP_TABLE";
|
|
32890
|
+
}
|
|
32891
|
+
function hasWhereClause(stmt) {
|
|
32892
|
+
if (!stmt || typeof stmt !== "object") return false;
|
|
32893
|
+
const obj = stmt;
|
|
32894
|
+
return obj.where !== null && obj.where !== void 0;
|
|
32895
|
+
}
|
|
32896
|
+
function isNoFromSelectStatement(stmt) {
|
|
32897
|
+
if (!stmt || typeof stmt !== "object") return false;
|
|
32898
|
+
const obj = stmt;
|
|
32899
|
+
return obj.type === "SELECT" && obj.from?.appId === 0 && obj.from?.cteName === "__NO_FROM__";
|
|
32900
|
+
}
|
|
32901
|
+
function getInsertValuesCount(stmt) {
|
|
32902
|
+
if (!stmt || typeof stmt !== "object") return null;
|
|
32903
|
+
const obj = stmt;
|
|
32904
|
+
if (obj.type !== "INSERT") return null;
|
|
32905
|
+
return Array.isArray(obj.values) ? obj.values.length : null;
|
|
32906
|
+
}
|
|
32907
|
+
|
|
32908
|
+
// src/core/batch.ts
|
|
32909
|
+
var MAX_TEMP_TABLES = 16;
|
|
32910
|
+
var BatchAnalysisError = class extends Error {
|
|
32911
|
+
constructor(message, statementIndex) {
|
|
32912
|
+
super(message);
|
|
32913
|
+
this.statementIndex = statementIndex;
|
|
32914
|
+
}
|
|
32915
|
+
};
|
|
32916
|
+
function collectRefs(node, tempRefs, appIds) {
|
|
32917
|
+
if (Array.isArray(node)) {
|
|
32918
|
+
for (const v of node) collectRefs(v, tempRefs, appIds);
|
|
32919
|
+
return;
|
|
32920
|
+
}
|
|
32921
|
+
if (node !== null && typeof node === "object") {
|
|
32922
|
+
const obj = node;
|
|
32923
|
+
const cte = obj["cteName"];
|
|
32924
|
+
if (typeof cte === "string" && cte.startsWith("#")) tempRefs.add(cte);
|
|
32925
|
+
const appId = obj["appId"];
|
|
32926
|
+
if (typeof appId === "number" && appId > 0) appIds.add(appId);
|
|
32927
|
+
for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
|
|
32928
|
+
}
|
|
32929
|
+
}
|
|
32930
|
+
function analyzeBatch(statements) {
|
|
32931
|
+
if (statements.length === 0) {
|
|
32932
|
+
throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
|
|
32933
|
+
}
|
|
32934
|
+
if (statements.length === 1) {
|
|
32935
|
+
const t = statements[0].type;
|
|
32936
|
+
if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
|
|
32937
|
+
const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
|
|
32938
|
+
throw new BatchAnalysisError(
|
|
32939
|
+
`ArgumentError: ${verb} requires a batch (temp tables are batch-scoped).`,
|
|
32940
|
+
0
|
|
32941
|
+
);
|
|
32942
|
+
}
|
|
32943
|
+
}
|
|
32944
|
+
const defined = /* @__PURE__ */ new Map();
|
|
32945
|
+
const createdOrder = [];
|
|
32946
|
+
const results = [];
|
|
32947
|
+
statements.forEach((stmt, index) => {
|
|
32948
|
+
const statementType = getStatementType(stmt);
|
|
32949
|
+
const created = [];
|
|
32950
|
+
const dropped = [];
|
|
32951
|
+
const refs = /* @__PURE__ */ new Set();
|
|
32952
|
+
const stmtAppIds = /* @__PURE__ */ new Set();
|
|
32953
|
+
const dependsOn = /* @__PURE__ */ new Set();
|
|
32954
|
+
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
32955
|
+
collectRefs(stmt.query, refs, stmtAppIds);
|
|
32956
|
+
} else if (stmt.type === "DROP_TEMP_TABLE") {
|
|
32957
|
+
} else {
|
|
32958
|
+
collectRefs(stmt, refs, stmtAppIds);
|
|
32959
|
+
}
|
|
32960
|
+
let tempOnlySource = false;
|
|
32961
|
+
if (stmt.type === "INSERT_SELECT" || stmt.type === "UPSERT_SELECT") {
|
|
32962
|
+
const srcTemp = /* @__PURE__ */ new Set();
|
|
32963
|
+
const srcApps = /* @__PURE__ */ new Set();
|
|
32964
|
+
collectRefs(stmt.select, srcTemp, srcApps);
|
|
32965
|
+
tempOnlySource = srcTemp.size > 0 && srcApps.size === 0;
|
|
32966
|
+
}
|
|
32967
|
+
for (const name of refs) {
|
|
32968
|
+
const at = defined.get(name);
|
|
32969
|
+
if (at === void 0) {
|
|
32970
|
+
throw new BatchAnalysisError(
|
|
32971
|
+
`ParseError: temp table ${name} is not defined in this batch.`,
|
|
32972
|
+
index
|
|
32973
|
+
);
|
|
32974
|
+
}
|
|
32975
|
+
dependsOn.add(at);
|
|
32976
|
+
}
|
|
32977
|
+
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
32978
|
+
if (defined.has(stmt.name)) {
|
|
32979
|
+
throw new BatchAnalysisError(
|
|
32980
|
+
`ParseError: temp table ${stmt.name} is already defined.`,
|
|
32981
|
+
index
|
|
32982
|
+
);
|
|
32983
|
+
}
|
|
32984
|
+
defined.set(stmt.name, index);
|
|
32985
|
+
createdOrder.push(stmt.name);
|
|
32986
|
+
created.push(stmt.name);
|
|
32987
|
+
if (defined.size > MAX_TEMP_TABLES) {
|
|
32988
|
+
throw new BatchAnalysisError(
|
|
32989
|
+
`ParseError: batch exceeds ${MAX_TEMP_TABLES} temp tables.`,
|
|
32990
|
+
index
|
|
32991
|
+
);
|
|
32992
|
+
}
|
|
32993
|
+
}
|
|
32994
|
+
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
32995
|
+
const at = defined.get(stmt.name);
|
|
32996
|
+
if (at === void 0) {
|
|
32997
|
+
throw new BatchAnalysisError(
|
|
32998
|
+
`ParseError: temp table ${stmt.name} is not defined in this batch.`,
|
|
32999
|
+
index
|
|
33000
|
+
);
|
|
33001
|
+
}
|
|
33002
|
+
dependsOn.add(at);
|
|
33003
|
+
dropped.push(stmt.name);
|
|
33004
|
+
defined.delete(stmt.name);
|
|
33005
|
+
}
|
|
33006
|
+
results.push({
|
|
33007
|
+
index,
|
|
33008
|
+
statementType,
|
|
33009
|
+
isDml: isDmlType(statementType),
|
|
33010
|
+
isReadOnly: isReadOnlyType(statementType),
|
|
33011
|
+
hasWhere: hasWhereClause(stmt),
|
|
33012
|
+
insertValuesCount: getInsertValuesCount(stmt),
|
|
33013
|
+
appIds: [...stmtAppIds].sort((a, b) => a - b),
|
|
33014
|
+
tempTablesCreated: created,
|
|
33015
|
+
tempTablesReferenced: [...refs],
|
|
33016
|
+
tempTablesDropped: dropped,
|
|
33017
|
+
dependsOn: [...dependsOn].sort((a, b) => a - b),
|
|
33018
|
+
tempOnlySource,
|
|
33019
|
+
targetAppId: isDmlType(statementType) && typeof stmt.appId === "number" ? stmt.appId : null
|
|
33020
|
+
});
|
|
33021
|
+
});
|
|
33022
|
+
const containsDml = results.some((r) => r.isDml);
|
|
33023
|
+
return {
|
|
33024
|
+
statementCount: statements.length,
|
|
33025
|
+
isReadOnlyBatch: !containsDml && results.every((r) => r.isReadOnly),
|
|
33026
|
+
containsDml,
|
|
33027
|
+
tempTables: createdOrder,
|
|
33028
|
+
statements: results
|
|
33029
|
+
};
|
|
33030
|
+
}
|
|
33031
|
+
|
|
32697
33032
|
// src/engine/pushDownNot.ts
|
|
32698
33033
|
function pushDownNot(expr) {
|
|
32699
33034
|
switch (expr.type) {
|
|
@@ -34371,8 +34706,10 @@ function applyGroupBy(rows, groupByKeys, columns) {
|
|
|
34371
34706
|
}
|
|
34372
34707
|
for (const col of columns) {
|
|
34373
34708
|
if (col.type === "AGGREGATE") {
|
|
34374
|
-
const
|
|
34375
|
-
|
|
34709
|
+
const syntheticKey = aggregateSyntheticName2(col.func, col.distinct, col.arg);
|
|
34710
|
+
const value = String(evalAggregate(col.func, col.distinct, col.arg, groupRows));
|
|
34711
|
+
outRow[col.alias ?? syntheticKey] = value;
|
|
34712
|
+
if (col.alias) outRow[syntheticKey] = value;
|
|
34376
34713
|
} else if (col.type === "ARITH_AGG_COL") {
|
|
34377
34714
|
const outputKey = col.alias ?? aggArithDefaultKey(col.expr);
|
|
34378
34715
|
outRow[outputKey] = String(evalAggArithExpr(col.expr, groupRows));
|
|
@@ -34883,6 +35220,9 @@ function wrapClientWithMetrics(client, metrics) {
|
|
|
34883
35220
|
async function executeStatement(sql, client, options) {
|
|
34884
35221
|
const cacheContext = options.cacheContext ?? "default";
|
|
34885
35222
|
const stmt = parseSql(sql);
|
|
35223
|
+
return executeParsedStatement(stmt, client, options, cacheContext);
|
|
35224
|
+
}
|
|
35225
|
+
async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
34886
35226
|
switch (stmt.type) {
|
|
34887
35227
|
case "SELECT":
|
|
34888
35228
|
return executeSelect(stmt, client, options, cacheContext);
|
|
@@ -34910,9 +35250,181 @@ async function executeStatement(sql, client, options) {
|
|
|
34910
35250
|
return executeDescribe(stmt, client, cacheContext);
|
|
34911
35251
|
case "EXPLAIN":
|
|
34912
35252
|
return executeExplain(stmt);
|
|
35253
|
+
// 一時テーブルはバッチスコープのため単文実行では拒否する(executeBatch を使う)
|
|
35254
|
+
case "CREATE_TEMP_TABLE":
|
|
35255
|
+
throw new Error("ArgumentError: CREATE TEMP TABLE requires a batch (temp tables are batch-scoped).");
|
|
35256
|
+
case "DROP_TEMP_TABLE":
|
|
35257
|
+
throw new Error("ArgumentError: DROP TEMP TABLE requires a batch (temp tables are batch-scoped).");
|
|
35258
|
+
}
|
|
35259
|
+
}
|
|
35260
|
+
var TEMP_TABLE_MAX_ROWS = 1e4;
|
|
35261
|
+
var BatchTimeoutError = class extends Error {
|
|
35262
|
+
constructor() {
|
|
35263
|
+
super("TimeoutError: batch timeout exceeded.");
|
|
35264
|
+
}
|
|
35265
|
+
};
|
|
35266
|
+
async function executeBatch(sql, client, options = {}) {
|
|
35267
|
+
const statements = parseSqlBatch(sql);
|
|
35268
|
+
const analysis = analyzeBatch(statements);
|
|
35269
|
+
if (options.continueOnError && analysis.containsDml) {
|
|
35270
|
+
throw new Error("ArgumentError: continueOnError is not allowed for batches containing DML.");
|
|
35271
|
+
}
|
|
35272
|
+
for (const s of analysis.statements) {
|
|
35273
|
+
if (!s.isDml || s.tempTablesReferenced.length === 0) continue;
|
|
35274
|
+
if (s.statementType === "INSERT_SELECT" && s.tempOnlySource) continue;
|
|
35275
|
+
throw new BatchAnalysisError(
|
|
35276
|
+
s.statementType === "INSERT_SELECT" ? `ArgumentError: INSERT_SELECT in a batch must select from temp tables only. (statement ${s.index})` : `ArgumentError: temp table references in ${s.statementType} are not supported yet.`,
|
|
35277
|
+
s.index
|
|
35278
|
+
);
|
|
35279
|
+
}
|
|
35280
|
+
const metrics = createEmptyMetrics();
|
|
35281
|
+
const countedClient = wrapClientWithMetrics(client, metrics);
|
|
35282
|
+
const startedAt = Date.now();
|
|
35283
|
+
const deadline = options.timeoutMs != null ? startedAt + options.timeoutMs : null;
|
|
35284
|
+
const cacheContext = options.cacheContext ?? "default";
|
|
35285
|
+
const tempTables = /* @__PURE__ */ new Map();
|
|
35286
|
+
const results = [];
|
|
35287
|
+
const failed = /* @__PURE__ */ new Set();
|
|
35288
|
+
let aborted2 = null;
|
|
35289
|
+
for (let i = 0; i < statements.length; i++) {
|
|
35290
|
+
const info = analysis.statements[i];
|
|
35291
|
+
const base = { index: i, type: info.statementType };
|
|
35292
|
+
if (aborted2) {
|
|
35293
|
+
results.push({ ...base, status: "skipped", skippedReason: aborted2 });
|
|
35294
|
+
failed.add(i);
|
|
35295
|
+
continue;
|
|
35296
|
+
}
|
|
35297
|
+
const brokenDep = info.dependsOn.find((d) => failed.has(d));
|
|
35298
|
+
if (brokenDep !== void 0) {
|
|
35299
|
+
const depName = analysis.statements[brokenDep].tempTablesCreated[0] ?? `statement ${brokenDep}`;
|
|
35300
|
+
results.push({ ...base, status: "skipped", skippedReason: `dependency: ${depName}` });
|
|
35301
|
+
failed.add(i);
|
|
35302
|
+
continue;
|
|
35303
|
+
}
|
|
35304
|
+
if (deadline !== null && Date.now() >= deadline) {
|
|
35305
|
+
results.push({ ...base, status: "skipped", skippedReason: "timeout" });
|
|
35306
|
+
failed.add(i);
|
|
35307
|
+
aborted2 = "timeout";
|
|
35308
|
+
continue;
|
|
35309
|
+
}
|
|
35310
|
+
try {
|
|
35311
|
+
const remaining = deadline !== null ? deadline - Date.now() : null;
|
|
35312
|
+
const outcome = await runWithDeadline(
|
|
35313
|
+
executeBatchStatement(statements[i], info, countedClient, options, cacheContext, tempTables),
|
|
35314
|
+
remaining
|
|
35315
|
+
);
|
|
35316
|
+
results.push({ ...base, status: "success", ...outcome });
|
|
35317
|
+
} catch (e) {
|
|
35318
|
+
results.push({ ...base, status: "error", error: toBatchStatementError(e) });
|
|
35319
|
+
failed.add(i);
|
|
35320
|
+
if (e instanceof BatchTimeoutError) {
|
|
35321
|
+
aborted2 = "timeout";
|
|
35322
|
+
} else if (!options.continueOnError) {
|
|
35323
|
+
aborted2 = "fail-fast";
|
|
35324
|
+
}
|
|
35325
|
+
}
|
|
35326
|
+
}
|
|
35327
|
+
metrics.elapsedMs = Date.now() - startedAt;
|
|
35328
|
+
return {
|
|
35329
|
+
ok: results.every((r) => r.status === "success"),
|
|
35330
|
+
statementCount: statements.length,
|
|
35331
|
+
statements: results,
|
|
35332
|
+
analysis,
|
|
35333
|
+
metrics
|
|
35334
|
+
};
|
|
35335
|
+
}
|
|
35336
|
+
async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables) {
|
|
35337
|
+
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
35338
|
+
const materializeOptions = {
|
|
35339
|
+
...options,
|
|
35340
|
+
maxRecords: options.tempTableMaxRows ?? TEMP_TABLE_MAX_ROWS,
|
|
35341
|
+
onLimitReached: "error"
|
|
35342
|
+
};
|
|
35343
|
+
const result = await runSelectLike(stmt.query, client, materializeOptions, cacheContext, tempTables);
|
|
35344
|
+
tempTables.set(stmt.name, result.rows);
|
|
35345
|
+
return { tempTable: stmt.name, rowCount: result.rows.length };
|
|
35346
|
+
}
|
|
35347
|
+
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
35348
|
+
tempTables.delete(stmt.name);
|
|
35349
|
+
return { tempTable: stmt.name };
|
|
35350
|
+
}
|
|
35351
|
+
if (stmt.type === "EXPLAIN") {
|
|
35352
|
+
return { result: await executeParsedStatement(stmt, client, options, cacheContext) };
|
|
35353
|
+
}
|
|
35354
|
+
if (info.tempTablesReferenced.length > 0) {
|
|
35355
|
+
if (stmt.type === "SELECT" || stmt.type === "UNION") {
|
|
35356
|
+
return { result: await executeQueryWithCte(stmt, client, options, tempTables, cacheContext) };
|
|
35357
|
+
}
|
|
35358
|
+
if (stmt.type === "WITH") {
|
|
35359
|
+
return { result: await executeWith(stmt, client, options, cacheContext, tempTables) };
|
|
35360
|
+
}
|
|
35361
|
+
if (stmt.type === "INSERT_SELECT") {
|
|
35362
|
+
return { result: await executeInsertSelect(stmt, client, options, cacheContext, tempTables) };
|
|
35363
|
+
}
|
|
35364
|
+
throw new Error(`ArgumentError: temp table references in ${stmt.type} are not supported yet.`);
|
|
35365
|
+
}
|
|
35366
|
+
return { result: await executeParsedStatement(stmt, client, options, cacheContext) };
|
|
35367
|
+
}
|
|
35368
|
+
async function runSelectLike(query, client, options, cacheContext, tempTables) {
|
|
35369
|
+
if (query.type === "WITH") {
|
|
35370
|
+
return executeWith(query, client, options, cacheContext, tempTables);
|
|
34913
35371
|
}
|
|
35372
|
+
return executeQueryWithCte(query, client, options, tempTables, cacheContext);
|
|
34914
35373
|
}
|
|
34915
|
-
async function
|
|
35374
|
+
async function runWithDeadline(work, remainingMs) {
|
|
35375
|
+
if (remainingMs === null) return work;
|
|
35376
|
+
if (remainingMs <= 0) {
|
|
35377
|
+
void work.catch(() => {
|
|
35378
|
+
});
|
|
35379
|
+
throw new BatchTimeoutError();
|
|
35380
|
+
}
|
|
35381
|
+
let timer;
|
|
35382
|
+
try {
|
|
35383
|
+
return await Promise.race([
|
|
35384
|
+
work,
|
|
35385
|
+
new Promise((_, reject) => {
|
|
35386
|
+
timer = setTimeout(() => reject(new BatchTimeoutError()), remainingMs);
|
|
35387
|
+
})
|
|
35388
|
+
]);
|
|
35389
|
+
} catch (e) {
|
|
35390
|
+
if (e instanceof BatchTimeoutError) {
|
|
35391
|
+
void work.catch(() => {
|
|
35392
|
+
});
|
|
35393
|
+
}
|
|
35394
|
+
throw e;
|
|
35395
|
+
} finally {
|
|
35396
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
35397
|
+
}
|
|
35398
|
+
}
|
|
35399
|
+
function toBatchStatementError(e) {
|
|
35400
|
+
if (e instanceof Error) {
|
|
35401
|
+
const name = e.name !== "Error" ? e.name : null;
|
|
35402
|
+
return { code: name ?? codeFromMessagePrefix(e.message), message: e.message };
|
|
35403
|
+
}
|
|
35404
|
+
if (e !== null && typeof e === "object") {
|
|
35405
|
+
const obj = e;
|
|
35406
|
+
const message2 = typeof obj.message === "string" && obj.message.length > 0 ? obj.message : safeJsonStringify(e);
|
|
35407
|
+
const code = typeof obj.code === "string" && obj.code.length > 0 ? obj.code : codeFromMessagePrefix(message2);
|
|
35408
|
+
return { code, message: message2 };
|
|
35409
|
+
}
|
|
35410
|
+
const message = String(e);
|
|
35411
|
+
return { code: codeFromMessagePrefix(message), message };
|
|
35412
|
+
}
|
|
35413
|
+
function codeFromMessagePrefix(message) {
|
|
35414
|
+
return message.match(/^([A-Za-z]+Error):/)?.[1] ?? "Error";
|
|
35415
|
+
}
|
|
35416
|
+
function safeJsonStringify(v) {
|
|
35417
|
+
try {
|
|
35418
|
+
return JSON.stringify(v) ?? String(v);
|
|
35419
|
+
} catch {
|
|
35420
|
+
return String(v);
|
|
35421
|
+
}
|
|
35422
|
+
}
|
|
35423
|
+
function parseSqlBatch(sql) {
|
|
35424
|
+
const tokens = new Lexer(sql).tokenize();
|
|
35425
|
+
return new Parser(tokens).parseStatements();
|
|
35426
|
+
}
|
|
35427
|
+
async function executeSelect(stmt, client, options, cacheContext, cteCache) {
|
|
34916
35428
|
if (isNoFromSelect(stmt)) {
|
|
34917
35429
|
return executeNoFromSelect(stmt);
|
|
34918
35430
|
}
|
|
@@ -34921,7 +35433,7 @@ async function executeSelect(stmt, client, options, cacheContext) {
|
|
|
34921
35433
|
if (mode === "SIMPLE") {
|
|
34922
35434
|
return executeSimpleSelect(stmt, client, options, cacheContext);
|
|
34923
35435
|
} else {
|
|
34924
|
-
return executeFullScanSelect(stmt, client, options, cacheContext);
|
|
35436
|
+
return executeFullScanSelect(stmt, client, options, cacheContext, cteCache);
|
|
34925
35437
|
}
|
|
34926
35438
|
}
|
|
34927
35439
|
function isNoFromSelect(stmt) {
|
|
@@ -35045,13 +35557,13 @@ async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
|
35045
35557
|
}
|
|
35046
35558
|
}
|
|
35047
35559
|
}
|
|
35048
|
-
async function executeFullScanSelect(stmt, client, options, cacheContext) {
|
|
35560
|
+
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache) {
|
|
35049
35561
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
35050
35562
|
const warnings = /* @__PURE__ */ new Set();
|
|
35051
35563
|
const parallel = options.fetchParallel ?? 1;
|
|
35052
35564
|
await Promise.all([
|
|
35053
|
-
resolveSubqueries(stmt.where, client, options, cacheContext),
|
|
35054
|
-
resolveSubqueries(stmt.having, client, options, cacheContext)
|
|
35565
|
+
resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
|
|
35566
|
+
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
|
|
35055
35567
|
]);
|
|
35056
35568
|
const tableConditions = /* @__PURE__ */ new Map();
|
|
35057
35569
|
if (stmt.where !== null) {
|
|
@@ -35101,7 +35613,7 @@ async function executeFullScanSelect(stmt, client, options, cacheContext) {
|
|
|
35101
35613
|
onOptJoins.push(join);
|
|
35102
35614
|
}
|
|
35103
35615
|
}
|
|
35104
|
-
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext);
|
|
35616
|
+
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
35105
35617
|
const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
|
|
35106
35618
|
scalarCachePromise.catch(() => {
|
|
35107
35619
|
});
|
|
@@ -35170,11 +35682,11 @@ function deduplicateRows(rows, columns) {
|
|
|
35170
35682
|
return true;
|
|
35171
35683
|
});
|
|
35172
35684
|
}
|
|
35173
|
-
async function executeWith(stmt, client, options, cacheContext) {
|
|
35174
|
-
if (canInlineSingleCte(stmt)) {
|
|
35685
|
+
async function executeWith(stmt, client, options, cacheContext, seed) {
|
|
35686
|
+
if ((seed == null || seed.size === 0) && canInlineSingleCte(stmt)) {
|
|
35175
35687
|
return executeSelect(buildInlinedQuery(stmt), client, options, cacheContext);
|
|
35176
35688
|
}
|
|
35177
|
-
const cteCache =
|
|
35689
|
+
const cteCache = new Map(seed ?? []);
|
|
35178
35690
|
for (const cte of stmt.ctes) {
|
|
35179
35691
|
let result;
|
|
35180
35692
|
if (cte.query.type === "SHOW_APPS") {
|
|
@@ -35286,7 +35798,7 @@ async function executeQueryWithCte(query, client, options, cteCache, cacheContex
|
|
|
35286
35798
|
}
|
|
35287
35799
|
const hasCteRef = query.from.cteName != null || query.joins.some((j) => j.table.cteName != null);
|
|
35288
35800
|
if (!hasCteRef) {
|
|
35289
|
-
return executeSelect(query, client, options, cacheContext);
|
|
35801
|
+
return executeSelect(query, client, options, cacheContext, cteCache);
|
|
35290
35802
|
}
|
|
35291
35803
|
return executeFullScanWithCte(query, client, options, cteCache, cacheContext);
|
|
35292
35804
|
}
|
|
@@ -35295,10 +35807,10 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
35295
35807
|
const warnings = /* @__PURE__ */ new Set();
|
|
35296
35808
|
const parallel = options.fetchParallel ?? 1;
|
|
35297
35809
|
await Promise.all([
|
|
35298
|
-
resolveSubqueries(stmt.where, client, options, cacheContext),
|
|
35299
|
-
resolveSubqueries(stmt.having, client, options, cacheContext)
|
|
35810
|
+
resolveSubqueries(stmt.where, client, options, cacheContext, cteCache),
|
|
35811
|
+
resolveSubqueries(stmt.having, client, options, cacheContext, cteCache)
|
|
35300
35812
|
]);
|
|
35301
|
-
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext);
|
|
35813
|
+
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
35302
35814
|
const orderByMetaPromise = buildOrderByMetaForSelect(stmt, client, cacheContext);
|
|
35303
35815
|
scalarCachePromise.catch(() => {
|
|
35304
35816
|
});
|
|
@@ -35696,14 +36208,18 @@ async function executeInsert(stmt, client, options, cacheContext) {
|
|
|
35696
36208
|
insertedCount: createdIds.flat().length
|
|
35697
36209
|
};
|
|
35698
36210
|
}
|
|
35699
|
-
async function executeInsertSelect(stmt, client, options, cacheContext) {
|
|
35700
|
-
const selectResult = await executeSelect(stmt.select, client, options, cacheContext);
|
|
36211
|
+
async function executeInsertSelect(stmt, client, options, cacheContext, cteCache) {
|
|
36212
|
+
const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
|
|
35701
36213
|
const { rows, columns } = selectResult;
|
|
35702
36214
|
if (columns.length !== stmt.fields.length) {
|
|
35703
36215
|
throw new Error(
|
|
35704
36216
|
`SELECT \u306E\u5217\u6570\uFF08${columns.length}\uFF09\u3068 INSERT \u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u6570\uFF08${stmt.fields.length}\uFF09\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093`
|
|
35705
36217
|
);
|
|
35706
36218
|
}
|
|
36219
|
+
if (options.confirm) {
|
|
36220
|
+
const ok = await options.confirm(rows.length, "INSERT");
|
|
36221
|
+
if (!ok) throw new OperationCancelledError("INSERT", rows.length);
|
|
36222
|
+
}
|
|
35707
36223
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
35708
36224
|
const allRecords = rows.map((row) => {
|
|
35709
36225
|
const record2 = {};
|
|
@@ -36251,24 +36767,30 @@ function parseSql(sql) {
|
|
|
36251
36767
|
throw e;
|
|
36252
36768
|
}
|
|
36253
36769
|
}
|
|
36254
|
-
async function resolveSubqueries(where, client, options, cacheContext) {
|
|
36770
|
+
async function resolveSubqueries(where, client, options, cacheContext, cteCache) {
|
|
36255
36771
|
const tasks = [];
|
|
36256
|
-
collectSubqueryTasks(where, client, options, cacheContext, tasks);
|
|
36772
|
+
collectSubqueryTasks(where, client, options, cacheContext, tasks, cteCache);
|
|
36257
36773
|
await Promise.all(tasks);
|
|
36258
36774
|
}
|
|
36259
|
-
function
|
|
36775
|
+
function runSubquery(query, client, options, cacheContext, cteCache) {
|
|
36776
|
+
if (cteCache !== void 0 && cteCache.size > 0) {
|
|
36777
|
+
return executeQueryWithCte(query, client, options, cteCache, cacheContext);
|
|
36778
|
+
}
|
|
36779
|
+
return executeSelect(query, client, options, cacheContext);
|
|
36780
|
+
}
|
|
36781
|
+
function collectSubqueryTasks(where, client, options, cacheContext, tasks, cteCache) {
|
|
36260
36782
|
if (where === null) return;
|
|
36261
36783
|
switch (where.type) {
|
|
36262
36784
|
case "BINARY": {
|
|
36263
36785
|
const right = where.right;
|
|
36264
36786
|
if (right.type === "SUBQUERY_IN_LIST") {
|
|
36265
|
-
tasks.push(
|
|
36787
|
+
tasks.push(runSubquery(right.query, client, options, cacheContext, cteCache).then((result) => {
|
|
36266
36788
|
const col = right.column ?? (result.columns[0] ?? "");
|
|
36267
36789
|
right.resolved = new Set(result.rows.map((r) => r[col] ?? ""));
|
|
36268
36790
|
}));
|
|
36269
36791
|
}
|
|
36270
36792
|
if (right.type === "SCALAR_SUBQUERY") {
|
|
36271
|
-
tasks.push(
|
|
36793
|
+
tasks.push(runSubquery(right.query, client, options, cacheContext, cteCache).then((result) => {
|
|
36272
36794
|
if (result.rowCount === 0) throw new Error("\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u304C\u5024\u3092\u8FD4\u3057\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
36273
36795
|
if (result.rowCount > 1) throw new Error("\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u304C\u8907\u6570\u884C\u3092\u8FD4\u3057\u307E\u3057\u305F\uFF081\u884C\u306E\u307F\u8A31\u53EF\uFF09");
|
|
36274
36796
|
const col = result.columns[0] ?? "";
|
|
@@ -36278,16 +36800,16 @@ function collectSubqueryTasks(where, client, options, cacheContext, tasks) {
|
|
|
36278
36800
|
break;
|
|
36279
36801
|
}
|
|
36280
36802
|
case "LOGICAL":
|
|
36281
|
-
collectSubqueryTasks(where.left, client, options, cacheContext, tasks);
|
|
36282
|
-
collectSubqueryTasks(where.right, client, options, cacheContext, tasks);
|
|
36803
|
+
collectSubqueryTasks(where.left, client, options, cacheContext, tasks, cteCache);
|
|
36804
|
+
collectSubqueryTasks(where.right, client, options, cacheContext, tasks, cteCache);
|
|
36283
36805
|
break;
|
|
36284
36806
|
case "NOT":
|
|
36285
36807
|
case "GROUP":
|
|
36286
|
-
collectSubqueryTasks(where.expr, client, options, cacheContext, tasks);
|
|
36808
|
+
collectSubqueryTasks(where.expr, client, options, cacheContext, tasks, cteCache);
|
|
36287
36809
|
break;
|
|
36288
36810
|
case "EXISTS": {
|
|
36289
36811
|
const node = where;
|
|
36290
|
-
tasks.push(
|
|
36812
|
+
tasks.push(runSubquery(node.query, client, options, cacheContext, cteCache).then((result) => {
|
|
36291
36813
|
node.resolved = result.rowCount > 0;
|
|
36292
36814
|
}));
|
|
36293
36815
|
break;
|
|
@@ -36305,7 +36827,7 @@ async function resolveSetSubqueries(assignments, client, options, cacheContext)
|
|
|
36305
36827
|
a.value = { type: "STRING", value: resolved };
|
|
36306
36828
|
}
|
|
36307
36829
|
}
|
|
36308
|
-
async function resolveScalarColumns(columns, client, options, cacheContext) {
|
|
36830
|
+
async function resolveScalarColumns(columns, client, options, cacheContext, cteCache) {
|
|
36309
36831
|
const byQuery = /* @__PURE__ */ new Map();
|
|
36310
36832
|
const pending = [];
|
|
36311
36833
|
for (let i = 0; i < columns.length; i++) {
|
|
@@ -36314,7 +36836,7 @@ async function resolveScalarColumns(columns, client, options, cacheContext) {
|
|
|
36314
36836
|
const key = JSON.stringify(col.query);
|
|
36315
36837
|
let promise2 = byQuery.get(key);
|
|
36316
36838
|
if (!promise2) {
|
|
36317
|
-
promise2 =
|
|
36839
|
+
promise2 = runSubquery(col.query, client, options, cacheContext, cteCache).then((result) => {
|
|
36318
36840
|
if (result.rowCount === 0) throw new Error("\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u304C\u5024\u3092\u8FD4\u3057\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
36319
36841
|
if (result.rowCount > 1) throw new Error("\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u304C\u8907\u6570\u884C\u3092\u8FD4\u3057\u307E\u3057\u305F\uFF081\u884C\u306E\u307F\u8A31\u53EF\uFF09");
|
|
36320
36842
|
const firstCol = result.columns[0] ?? "";
|
|
@@ -36329,6 +36851,59 @@ async function resolveScalarColumns(columns, client, options, cacheContext) {
|
|
|
36329
36851
|
pending.forEach(([i], idx) => cache.set(i, values[idx]));
|
|
36330
36852
|
return cache;
|
|
36331
36853
|
}
|
|
36854
|
+
function buildBatchExplainPlans(sql) {
|
|
36855
|
+
const statements = parseSqlBatch(sql);
|
|
36856
|
+
const analysis = analyzeBatch(statements);
|
|
36857
|
+
return {
|
|
36858
|
+
statementCount: statements.length,
|
|
36859
|
+
statements: statements.map((stmt, i) => ({
|
|
36860
|
+
index: i,
|
|
36861
|
+
type: analysis.statements[i].statementType,
|
|
36862
|
+
plan: buildBatchStatementPlan(stmt, analysis.statements[i])
|
|
36863
|
+
}))
|
|
36864
|
+
};
|
|
36865
|
+
}
|
|
36866
|
+
function buildBatchStatementPlan(stmt, info) {
|
|
36867
|
+
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
36868
|
+
return [
|
|
36869
|
+
`CREATE TEMP TABLE ${stmt.name}`,
|
|
36870
|
+
` scope: batch\uFF08\u30D0\u30C3\u30C1\u7D42\u4E86\u6642\u306B\u81EA\u52D5\u7834\u68C4\uFF09`,
|
|
36871
|
+
` rows: \u5B9F\u4F53\u5316\u524D\u306E\u305F\u3081\u4E0D\u660E\uFF08\u4E0A\u9650 ${TEMP_TABLE_MAX_ROWS} \u884C\u3001\u8D85\u904E\u306F\u30A8\u30E9\u30FC\uFF09`,
|
|
36872
|
+
...buildPlanForBatchQuery(stmt.query, info).map((l) => ` ${l}`)
|
|
36873
|
+
];
|
|
36874
|
+
}
|
|
36875
|
+
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
36876
|
+
return [
|
|
36877
|
+
`DROP TEMP TABLE ${stmt.name}`,
|
|
36878
|
+
" \u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u30B9\u30C8\u30A2\u306E\u89E3\u653E\u306E\u307F\uFF08kintone \u30A2\u30AF\u30BB\u30B9\u306A\u3057\uFF09"
|
|
36879
|
+
];
|
|
36880
|
+
}
|
|
36881
|
+
if (stmt.type === "SHOW_APPS") return ["SHOW APPS\uFF08\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\uFF09"];
|
|
36882
|
+
if (stmt.type === "DESCRIBE") return [`DESCRIBE APP${stmt.appId}\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\uFF09`];
|
|
36883
|
+
if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info);
|
|
36884
|
+
return buildPlanForBatchQuery(stmt, info);
|
|
36885
|
+
}
|
|
36886
|
+
function buildPlanForBatchQuery(query, info) {
|
|
36887
|
+
if (info.tempTablesReferenced.length === 0) {
|
|
36888
|
+
return buildExplainPlan(query);
|
|
36889
|
+
}
|
|
36890
|
+
const lines = [];
|
|
36891
|
+
if (query.type === "INSERT_SELECT") {
|
|
36892
|
+
lines.push(
|
|
36893
|
+
`INSERT INTO APP${query.appId} ... SELECT\uFF08\u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u30BD\u30FC\u30B9\u3002\u5B9F\u884C\u6642\u306B\u4EF6\u6570\u78BA\u5B9A \u2192 dmlMaxRows \u9069\u7528\uFF09`
|
|
36894
|
+
);
|
|
36895
|
+
}
|
|
36896
|
+
lines.push(" mode: FULL_SCAN\uFF08\u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u53C2\u7167\uFF09");
|
|
36897
|
+
lines.push(
|
|
36898
|
+
` temp: ${info.tempTablesReferenced.join(", ")}\uFF08\u30A4\u30F3\u30E1\u30E2\u30EA\u8D70\u67FB\u3002\u5B9F\u4F53\u5316\u524D\u306E\u305F\u3081\u884C\u6570\u4E0D\u660E\uFF09`
|
|
36899
|
+
);
|
|
36900
|
+
const apps = info.appIds.filter((a) => query.type !== "INSERT_SELECT" || a !== query.appId);
|
|
36901
|
+
if (apps.length > 0) {
|
|
36902
|
+
lines.push(` app: ${apps.map((a) => `APP${a}`).join(", ")}`);
|
|
36903
|
+
}
|
|
36904
|
+
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");
|
|
36905
|
+
return lines;
|
|
36906
|
+
}
|
|
36332
36907
|
function executeExplain(stmt) {
|
|
36333
36908
|
const lines = buildExplainPlan(stmt.query);
|
|
36334
36909
|
return {
|
|
@@ -36649,6 +37224,10 @@ function parseSqlStatement(sql) {
|
|
|
36649
37224
|
const tokens = new Lexer(sql).tokenize();
|
|
36650
37225
|
return new Parser(tokens).parse();
|
|
36651
37226
|
}
|
|
37227
|
+
function parseSqlStatements(sql) {
|
|
37228
|
+
const tokens = new Lexer(sql).tokenize();
|
|
37229
|
+
return new Parser(tokens).parseStatements();
|
|
37230
|
+
}
|
|
36652
37231
|
|
|
36653
37232
|
// src/node/appProfiles.ts
|
|
36654
37233
|
function parseTokenMap(raw) {
|
|
@@ -36834,35 +37413,6 @@ function buildCacheContext(defaultProfile, appBindingByMappedApp) {
|
|
|
36834
37413
|
return `apps:${pairs.join(",")}`;
|
|
36835
37414
|
}
|
|
36836
37415
|
|
|
36837
|
-
// src/node/dmlGuard.ts
|
|
36838
|
-
function getStatementType(stmt) {
|
|
36839
|
-
if (!stmt || typeof stmt !== "object") return "UNKNOWN";
|
|
36840
|
-
const obj = stmt;
|
|
36841
|
-
return typeof obj.type === "string" ? obj.type : "UNKNOWN";
|
|
36842
|
-
}
|
|
36843
|
-
function isDmlType(type) {
|
|
36844
|
-
return type === "INSERT" || type === "INSERT_SELECT" || type === "UPDATE" || type === "DELETE" || type === "UPSERT" || type === "UPSERT_SELECT" || type === "REORDER";
|
|
36845
|
-
}
|
|
36846
|
-
function isReadOnlyType(type) {
|
|
36847
|
-
return type === "SELECT" || type === "UNION" || type === "WITH" || type === "EXPLAIN" || type === "SHOW_APPS" || type === "DESCRIBE";
|
|
36848
|
-
}
|
|
36849
|
-
function hasWhereClause(stmt) {
|
|
36850
|
-
if (!stmt || typeof stmt !== "object") return false;
|
|
36851
|
-
const obj = stmt;
|
|
36852
|
-
return obj.where !== null && obj.where !== void 0;
|
|
36853
|
-
}
|
|
36854
|
-
function isNoFromSelectStatement(stmt) {
|
|
36855
|
-
if (!stmt || typeof stmt !== "object") return false;
|
|
36856
|
-
const obj = stmt;
|
|
36857
|
-
return obj.type === "SELECT" && obj.from?.appId === 0 && obj.from?.cteName === "__NO_FROM__";
|
|
36858
|
-
}
|
|
36859
|
-
function getInsertValuesCount(stmt) {
|
|
36860
|
-
if (!stmt || typeof stmt !== "object") return null;
|
|
36861
|
-
const obj = stmt;
|
|
36862
|
-
if (obj.type !== "INSERT") return null;
|
|
36863
|
-
return Array.isArray(obj.values) ? obj.values.length : null;
|
|
36864
|
-
}
|
|
36865
|
-
|
|
36866
37416
|
// src/node/config.ts
|
|
36867
37417
|
var import_fs = require("fs");
|
|
36868
37418
|
function loadKsqlConfig(configPath) {
|
|
@@ -36904,6 +37454,107 @@ function resolveTokenValue(raw) {
|
|
|
36904
37454
|
return raw;
|
|
36905
37455
|
}
|
|
36906
37456
|
|
|
37457
|
+
// src/api/requestGate.ts
|
|
37458
|
+
var DEFAULT_MAX_CONCURRENT = 10;
|
|
37459
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
37460
|
+
var DEFAULT_BASE_DELAY_MS = 500;
|
|
37461
|
+
var DEFAULT_MAX_DELAY_MS = 8e3;
|
|
37462
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([408, 429, 502, 503, 504]);
|
|
37463
|
+
function isRetryableError(err) {
|
|
37464
|
+
if (!(err instanceof Error)) return false;
|
|
37465
|
+
const status = err.message.match(/^kintone API error (\d{3}):/);
|
|
37466
|
+
if (status) return RETRYABLE_STATUSES.has(Number(status[1]));
|
|
37467
|
+
if (err.name === "AbortError" || err.name === "TimeoutError") return true;
|
|
37468
|
+
if (/fetch failed/i.test(err.message)) return true;
|
|
37469
|
+
return false;
|
|
37470
|
+
}
|
|
37471
|
+
var RequestGate = class {
|
|
37472
|
+
constructor(options = {}) {
|
|
37473
|
+
this.active = 0;
|
|
37474
|
+
this.waiters = [];
|
|
37475
|
+
this.maxConcurrent = clampInt(options.maxConcurrent ?? DEFAULT_MAX_CONCURRENT, 1, 50);
|
|
37476
|
+
this.maxRetries = clampInt(options.maxRetries ?? DEFAULT_MAX_RETRIES, 0, 10);
|
|
37477
|
+
this.baseDelayMs = options.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
|
|
37478
|
+
this.maxDelayMs = options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
|
|
37479
|
+
this.sleep = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
37480
|
+
this.random = options.random ?? Math.random;
|
|
37481
|
+
}
|
|
37482
|
+
/** 現在の同時実行数(テスト・診断用) */
|
|
37483
|
+
get activeCount() {
|
|
37484
|
+
return this.active;
|
|
37485
|
+
}
|
|
37486
|
+
get limit() {
|
|
37487
|
+
return this.maxConcurrent;
|
|
37488
|
+
}
|
|
37489
|
+
/** GET 系: セマフォ + リトライ付きで実行する */
|
|
37490
|
+
async runReadOnly(fn) {
|
|
37491
|
+
let attempt = 0;
|
|
37492
|
+
while (true) {
|
|
37493
|
+
try {
|
|
37494
|
+
return await this.withSlot(fn);
|
|
37495
|
+
} catch (err) {
|
|
37496
|
+
if (attempt >= this.maxRetries || !isRetryableError(err)) throw err;
|
|
37497
|
+
await this.sleep(this.backoffDelay(attempt));
|
|
37498
|
+
attempt += 1;
|
|
37499
|
+
}
|
|
37500
|
+
}
|
|
37501
|
+
}
|
|
37502
|
+
/** 書き込み系: セマフォのみ(リトライしない — 二重実行防止) */
|
|
37503
|
+
async runMutation(fn) {
|
|
37504
|
+
return this.withSlot(fn);
|
|
37505
|
+
}
|
|
37506
|
+
async withSlot(fn) {
|
|
37507
|
+
await this.acquire();
|
|
37508
|
+
try {
|
|
37509
|
+
return await fn();
|
|
37510
|
+
} finally {
|
|
37511
|
+
this.release();
|
|
37512
|
+
}
|
|
37513
|
+
}
|
|
37514
|
+
async acquire() {
|
|
37515
|
+
if (this.active < this.maxConcurrent) {
|
|
37516
|
+
this.active += 1;
|
|
37517
|
+
return;
|
|
37518
|
+
}
|
|
37519
|
+
await new Promise((resolve2) => this.waiters.push(resolve2));
|
|
37520
|
+
this.active += 1;
|
|
37521
|
+
}
|
|
37522
|
+
release() {
|
|
37523
|
+
this.active -= 1;
|
|
37524
|
+
const next = this.waiters.shift();
|
|
37525
|
+
if (next) next();
|
|
37526
|
+
}
|
|
37527
|
+
/** 指数バックオフ + ジッタ(attempt: 0 始まり) */
|
|
37528
|
+
backoffDelay(attempt) {
|
|
37529
|
+
const base = Math.min(this.baseDelayMs * 2 ** attempt, this.maxDelayMs);
|
|
37530
|
+
const jitter = 1 + (this.random() - 0.5) * 0.5;
|
|
37531
|
+
return Math.round(base * jitter);
|
|
37532
|
+
}
|
|
37533
|
+
};
|
|
37534
|
+
function withRequestGate(client, gate) {
|
|
37535
|
+
return {
|
|
37536
|
+
getRecords: (params) => gate.runReadOnly(() => client.getRecords(params)),
|
|
37537
|
+
getApps: () => gate.runReadOnly(() => client.getApps()),
|
|
37538
|
+
getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
|
|
37539
|
+
postRecords: (params) => gate.runMutation(() => client.postRecords(params)),
|
|
37540
|
+
putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
|
|
37541
|
+
deleteRecords: (params) => gate.runMutation(() => client.deleteRecords(params))
|
|
37542
|
+
};
|
|
37543
|
+
}
|
|
37544
|
+
var globalGate = null;
|
|
37545
|
+
function getGlobalRequestGate(limitHint) {
|
|
37546
|
+
if (globalGate === null) {
|
|
37547
|
+
const envValue = Number(process.env.KSQL_MAX_CONCURRENT);
|
|
37548
|
+
const limit = Number.isInteger(envValue) && envValue > 0 ? envValue : limitHint;
|
|
37549
|
+
globalGate = new RequestGate({ maxConcurrent: limit });
|
|
37550
|
+
}
|
|
37551
|
+
return globalGate;
|
|
37552
|
+
}
|
|
37553
|
+
function clampInt(v, min, max) {
|
|
37554
|
+
if (!Number.isFinite(v)) return min;
|
|
37555
|
+
return Math.max(min, Math.min(max, Math.trunc(v)));
|
|
37556
|
+
}
|
|
37557
|
+
|
|
36907
37558
|
// src/cli/nodeKintoneClient.ts
|
|
36908
37559
|
function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
36909
37560
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
@@ -37246,10 +37897,14 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
37246
37897
|
},
|
|
37247
37898
|
getApps: () => defaultClient.getApps()
|
|
37248
37899
|
};
|
|
37900
|
+
const gatedClient = withRequestGate(
|
|
37901
|
+
routedClient,
|
|
37902
|
+
getGlobalRequestGate(profile2.query?.maxConcurrent)
|
|
37903
|
+
);
|
|
37249
37904
|
return {
|
|
37250
37905
|
sql,
|
|
37251
37906
|
profileName,
|
|
37252
|
-
client:
|
|
37907
|
+
client: gatedClient,
|
|
37253
37908
|
cacheContext: buildCacheContext(profileName, normalized.appBindingByMappedApp),
|
|
37254
37909
|
maxRecords: maxRecords2,
|
|
37255
37910
|
fetchParallel: fetchParallel2,
|
|
@@ -37438,6 +38093,14 @@ function deleteSavedQuery(catalog, name) {
|
|
|
37438
38093
|
}
|
|
37439
38094
|
|
|
37440
38095
|
// src/mcp/tools.ts
|
|
38096
|
+
function requireSingleStatement(validation, toolName) {
|
|
38097
|
+
if (validation.batch) {
|
|
38098
|
+
throw new Error(
|
|
38099
|
+
`ArgumentError: batch SQL (multiple statements) is not supported by ${toolName} yet.`
|
|
38100
|
+
);
|
|
38101
|
+
}
|
|
38102
|
+
return validation;
|
|
38103
|
+
}
|
|
37441
38104
|
var DEFAULT_MAX_RECORDS = 500;
|
|
37442
38105
|
var DEFAULT_ON_LIMIT = "error";
|
|
37443
38106
|
function noOpClient() {
|
|
@@ -37493,6 +38156,59 @@ function toSelectPayload(result) {
|
|
|
37493
38156
|
warnings: result.warnings ?? []
|
|
37494
38157
|
};
|
|
37495
38158
|
}
|
|
38159
|
+
function toMutationSummary(result) {
|
|
38160
|
+
if (result.type === "INSERT") {
|
|
38161
|
+
return { insertedCount: result.insertedCount, createdIds: result.createdIds };
|
|
38162
|
+
}
|
|
38163
|
+
if (result.type === "UPDATE") return { updatedCount: result.updatedCount };
|
|
38164
|
+
if (result.type === "DELETE") return { deletedCount: result.deletedCount };
|
|
38165
|
+
if (result.type === "UPSERT") {
|
|
38166
|
+
return { insertedCount: result.insertedCount, updatedCount: result.updatedCount };
|
|
38167
|
+
}
|
|
38168
|
+
return { reorderedParentCount: result.reorderedParentCount };
|
|
38169
|
+
}
|
|
38170
|
+
function toBatchQueryPayload(batch, maxTotalRecords) {
|
|
38171
|
+
const results = [];
|
|
38172
|
+
let totalRows = 0;
|
|
38173
|
+
const statements = batch.statements.map((s) => {
|
|
38174
|
+
const entry = {
|
|
38175
|
+
index: s.index,
|
|
38176
|
+
type: s.type,
|
|
38177
|
+
status: s.status
|
|
38178
|
+
};
|
|
38179
|
+
if (s.status === "error" && s.error) entry.error = s.error;
|
|
38180
|
+
if (s.status === "skipped" && s.skippedReason) entry.skippedReason = s.skippedReason;
|
|
38181
|
+
if (s.tempTable !== void 0) entry.tempTable = s.tempTable;
|
|
38182
|
+
if (s.rowCount !== void 0) entry.rowCount = s.rowCount;
|
|
38183
|
+
if (s.status === "success" && s.result?.type === "SELECT") {
|
|
38184
|
+
totalRows += s.result.rowCount;
|
|
38185
|
+
if (maxTotalRecords !== void 0 && totalRows > maxTotalRecords) {
|
|
38186
|
+
throw new Error(
|
|
38187
|
+
`ArgumentError: batch total rows (${totalRows}) exceed maxTotalRecords (${maxTotalRecords}).`
|
|
38188
|
+
);
|
|
38189
|
+
}
|
|
38190
|
+
entry.resultIndex = results.length;
|
|
38191
|
+
results.push({
|
|
38192
|
+
columns: s.result.columns,
|
|
38193
|
+
rows: s.result.rows,
|
|
38194
|
+
rowCount: s.result.rowCount,
|
|
38195
|
+
warnings: s.result.warnings ?? []
|
|
38196
|
+
});
|
|
38197
|
+
} else if (s.status === "success" && s.result && s.result.type !== "SELECT") {
|
|
38198
|
+
Object.assign(entry, toMutationSummary(s.result));
|
|
38199
|
+
}
|
|
38200
|
+
return entry;
|
|
38201
|
+
});
|
|
38202
|
+
return {
|
|
38203
|
+
ok: batch.ok,
|
|
38204
|
+
batch: true,
|
|
38205
|
+
statementCount: batch.statementCount,
|
|
38206
|
+
statements,
|
|
38207
|
+
results,
|
|
38208
|
+
// バッチ全体の警告(仕様 §6.2)。文ごとの警告は results[].warnings に入る
|
|
38209
|
+
warnings: []
|
|
38210
|
+
};
|
|
38211
|
+
}
|
|
37496
38212
|
function toMutationPayload(result) {
|
|
37497
38213
|
if (result.type === "INSERT") {
|
|
37498
38214
|
return {
|
|
@@ -37577,35 +38293,71 @@ async function runSafely(fn) {
|
|
|
37577
38293
|
function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
37578
38294
|
const createRuntime = deps.createRuntime ?? createKsqlRuntime;
|
|
37579
38295
|
const executeSql = deps.executeSql ?? execute;
|
|
38296
|
+
const executeBatchSql = deps.executeBatchSql ?? executeBatch;
|
|
37580
38297
|
async function validate(input) {
|
|
37581
38298
|
const normalized = normalizeSqlForTool(serverOptions, input.sql, input.profile);
|
|
37582
|
-
const
|
|
37583
|
-
const
|
|
37584
|
-
const isDml = isDmlType(statementType);
|
|
37585
|
-
const isReadOnly = isReadOnlyType(statementType);
|
|
38299
|
+
const statements = parseSqlStatements(normalized.normalizedSql);
|
|
38300
|
+
const analysis = analyzeBatch(statements);
|
|
37586
38301
|
const appBindings = [...normalized.appBindingByMappedApp.entries()].map(([mappedAppId, binding]) => ({
|
|
37587
38302
|
mappedAppId,
|
|
37588
38303
|
appId: binding.appId,
|
|
37589
38304
|
profile: binding.profile
|
|
37590
38305
|
}));
|
|
37591
|
-
|
|
38306
|
+
const statementValidations = analysis.statements.map((s2) => ({
|
|
38307
|
+
index: s2.index,
|
|
38308
|
+
statementType: s2.statementType,
|
|
38309
|
+
isDml: s2.isDml,
|
|
38310
|
+
isReadOnly: s2.isReadOnly,
|
|
38311
|
+
hasWhere: s2.hasWhere,
|
|
38312
|
+
insertValuesCount: s2.insertValuesCount,
|
|
38313
|
+
appIds: s2.appIds,
|
|
38314
|
+
tempTablesCreated: s2.tempTablesCreated,
|
|
38315
|
+
tempTablesReferenced: s2.tempTablesReferenced,
|
|
38316
|
+
tempTablesDropped: s2.tempTablesDropped,
|
|
38317
|
+
tempOnlySource: s2.tempOnlySource,
|
|
38318
|
+
targetAppId: s2.targetAppId
|
|
38319
|
+
}));
|
|
38320
|
+
const common = {
|
|
37592
38321
|
ok: true,
|
|
37593
|
-
|
|
37594
|
-
|
|
37595
|
-
|
|
37596
|
-
|
|
37597
|
-
|
|
37598
|
-
|
|
37599
|
-
|
|
37600
|
-
requiresMutationTool: isDml,
|
|
38322
|
+
statementCount: analysis.statementCount,
|
|
38323
|
+
isReadOnlyBatch: analysis.isReadOnlyBatch,
|
|
38324
|
+
containsDml: analysis.containsDml,
|
|
38325
|
+
tempTables: analysis.tempTables,
|
|
38326
|
+
canRunWithQueryTool: analysis.isReadOnlyBatch,
|
|
38327
|
+
requiresMutationTool: analysis.containsDml,
|
|
38328
|
+
statements: statementValidations,
|
|
37601
38329
|
normalizedSql: normalized.normalizedSql,
|
|
37602
38330
|
hasProfileSyntax: normalized.hasProfileSyntax,
|
|
37603
38331
|
cacheContext: normalized.cacheContext,
|
|
37604
38332
|
appBindings
|
|
37605
38333
|
};
|
|
38334
|
+
if (analysis.statementCount > 1) {
|
|
38335
|
+
return { ...common, batch: true };
|
|
38336
|
+
}
|
|
38337
|
+
const s = statementValidations[0];
|
|
38338
|
+
return {
|
|
38339
|
+
...common,
|
|
38340
|
+
batch: false,
|
|
38341
|
+
statementType: s.statementType,
|
|
38342
|
+
isDml: s.isDml,
|
|
38343
|
+
isReadOnly: s.isReadOnly,
|
|
38344
|
+
hasWhere: s.hasWhere,
|
|
38345
|
+
insertValuesCount: s.insertValuesCount,
|
|
38346
|
+
appIds: s.appIds
|
|
38347
|
+
};
|
|
37606
38348
|
}
|
|
37607
38349
|
async function explain(input) {
|
|
37608
38350
|
const normalized = normalizeSqlForTool(serverOptions, input.sql, input.profile);
|
|
38351
|
+
const statements = parseSqlStatements(normalized.normalizedSql);
|
|
38352
|
+
if (statements.length > 1) {
|
|
38353
|
+
const plans = buildBatchExplainPlans(normalized.normalizedSql);
|
|
38354
|
+
return {
|
|
38355
|
+
ok: true,
|
|
38356
|
+
batch: true,
|
|
38357
|
+
statementCount: plans.statementCount,
|
|
38358
|
+
statements: plans.statements
|
|
38359
|
+
};
|
|
38360
|
+
}
|
|
37609
38361
|
const result = await executeSql(explainSql(normalized.normalizedSql), noOpClient(), {
|
|
37610
38362
|
cacheContext: normalized.cacheContext
|
|
37611
38363
|
});
|
|
@@ -37616,6 +38368,31 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
37616
38368
|
}
|
|
37617
38369
|
async function query(input) {
|
|
37618
38370
|
const validation = await validate(input);
|
|
38371
|
+
if (validation.batch) {
|
|
38372
|
+
if (validation.containsDml) {
|
|
38373
|
+
throw new Error("ArgumentError: batch contains DML statements. Use ksql_mutate.");
|
|
38374
|
+
}
|
|
38375
|
+
const runtime2 = await createRuntime(serverOptions, {
|
|
38376
|
+
sql: input.sql,
|
|
38377
|
+
profile: input.profile,
|
|
38378
|
+
maxRecords: input.maxRecords,
|
|
38379
|
+
fetchParallel: input.fetchParallel,
|
|
38380
|
+
onLimit: input.onLimit,
|
|
38381
|
+
timeout: input.timeout
|
|
38382
|
+
});
|
|
38383
|
+
const batchResult = await executeBatchSql(runtime2.sql, runtime2.client, {
|
|
38384
|
+
maxRecords: runtime2.maxRecords,
|
|
38385
|
+
fetchParallel: runtime2.fetchParallel,
|
|
38386
|
+
onLimitReached: runtime2.onLimit,
|
|
38387
|
+
cacheContext: runtime2.cacheContext,
|
|
38388
|
+
continueOnError: input.continueOnError,
|
|
38389
|
+
// バッチでは timeout を合計タイムアウトとして扱う(仕様 §5.7)。
|
|
38390
|
+
// runtime.timeout は env / profile / 既定 30000ms を解決済みの値で、
|
|
38391
|
+
// HTTP クライアント側の per-request タイムアウトと同値になる
|
|
38392
|
+
timeoutMs: runtime2.timeout
|
|
38393
|
+
});
|
|
38394
|
+
return toBatchQueryPayload(batchResult, input.maxTotalRecords);
|
|
38395
|
+
}
|
|
37619
38396
|
if (!validation.isReadOnly) {
|
|
37620
38397
|
throw new Error(`ArgumentError: ${validation.statementType} is not allowed by ksql_query. Use ksql_mutate.`);
|
|
37621
38398
|
}
|
|
@@ -37651,9 +38428,75 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
37651
38428
|
}
|
|
37652
38429
|
return toSelectPayload(result);
|
|
37653
38430
|
}
|
|
38431
|
+
async function mutateBatch(input, validation, dmlMaxRows2) {
|
|
38432
|
+
if (!validation.containsDml) {
|
|
38433
|
+
throw new Error("ArgumentError: batch contains no DML statements. Use ksql_query.");
|
|
38434
|
+
}
|
|
38435
|
+
let staticInsertTotal = 0;
|
|
38436
|
+
for (const s of validation.statements) {
|
|
38437
|
+
if (!s.isDml) continue;
|
|
38438
|
+
const at = ` (statement ${s.index})`;
|
|
38439
|
+
if (s.statementType === "INSERT_SELECT" && !s.tempOnlySource) {
|
|
38440
|
+
throw new Error(
|
|
38441
|
+
`ArgumentError: INSERT_SELECT in a batch must select from temp tables only.${at}`
|
|
38442
|
+
);
|
|
38443
|
+
}
|
|
38444
|
+
if (s.statementType === "UPSERT_SELECT") {
|
|
38445
|
+
throw new Error(`ArgumentError: ${s.statementType} is not supported by ksql_mutate yet.${at}`);
|
|
38446
|
+
}
|
|
38447
|
+
if ((s.statementType === "UPDATE" || s.statementType === "DELETE") && !s.hasWhere) {
|
|
38448
|
+
throw new Error(`ArgumentError: ${s.statementType} without WHERE is blocked by ksql_mutate.${at}`);
|
|
38449
|
+
}
|
|
38450
|
+
if (s.insertValuesCount !== null && s.insertValuesCount > dmlMaxRows2) {
|
|
38451
|
+
throw new Error(
|
|
38452
|
+
`ArgumentError: INSERT rows (${s.insertValuesCount}) exceed dmlMaxRows (${dmlMaxRows2}).${at}`
|
|
38453
|
+
);
|
|
38454
|
+
}
|
|
38455
|
+
staticInsertTotal += s.insertValuesCount ?? 0;
|
|
38456
|
+
}
|
|
38457
|
+
const dmlTotalMaxRows = input.dmlTotalMaxRows;
|
|
38458
|
+
if (dmlTotalMaxRows !== void 0 && staticInsertTotal > dmlTotalMaxRows) {
|
|
38459
|
+
throw new Error(
|
|
38460
|
+
`ArgumentError: batch INSERT rows (${staticInsertTotal}) exceed dmlTotalMaxRows (${dmlTotalMaxRows}).`
|
|
38461
|
+
);
|
|
38462
|
+
}
|
|
38463
|
+
const runtime = await createRuntime(serverOptions, {
|
|
38464
|
+
sql: input.sql,
|
|
38465
|
+
profile: input.profile,
|
|
38466
|
+
maxRecords: dmlMaxRows2 + 1,
|
|
38467
|
+
fetchParallel: input.fetchParallel,
|
|
38468
|
+
onLimit: DEFAULT_ON_LIMIT,
|
|
38469
|
+
timeout: input.timeout
|
|
38470
|
+
});
|
|
38471
|
+
let totalAffected = staticInsertTotal;
|
|
38472
|
+
const batchResult = await executeBatchSql(runtime.sql, runtime.client, {
|
|
38473
|
+
maxRecords: runtime.maxRecords,
|
|
38474
|
+
fetchParallel: runtime.fetchParallel,
|
|
38475
|
+
onLimitReached: runtime.onLimit,
|
|
38476
|
+
cacheContext: runtime.cacheContext,
|
|
38477
|
+
// 合計タイムアウト(解決済みの runtime.timeout。per-request と同値)
|
|
38478
|
+
timeoutMs: runtime.timeout,
|
|
38479
|
+
confirm: async (count, operation) => {
|
|
38480
|
+
if (count > dmlMaxRows2) {
|
|
38481
|
+
throw new Error(`ArgumentError: ${operation} affected rows (${count}) exceed dmlMaxRows (${dmlMaxRows2}).`);
|
|
38482
|
+
}
|
|
38483
|
+
totalAffected += count;
|
|
38484
|
+
if (dmlTotalMaxRows !== void 0 && totalAffected > dmlTotalMaxRows) {
|
|
38485
|
+
throw new Error(
|
|
38486
|
+
`ArgumentError: batch affected rows (${totalAffected}) exceed dmlTotalMaxRows (${dmlTotalMaxRows}).`
|
|
38487
|
+
);
|
|
38488
|
+
}
|
|
38489
|
+
return true;
|
|
38490
|
+
}
|
|
38491
|
+
});
|
|
38492
|
+
return toBatchQueryPayload(batchResult);
|
|
38493
|
+
}
|
|
37654
38494
|
async function mutate(input) {
|
|
37655
38495
|
const dmlMaxRows2 = requireDmlApproval(input, "ksql_mutate");
|
|
37656
38496
|
const validation = await validate(input);
|
|
38497
|
+
if (validation.batch) {
|
|
38498
|
+
return mutateBatch(input, validation, dmlMaxRows2);
|
|
38499
|
+
}
|
|
37657
38500
|
if (!validation.isDml) {
|
|
37658
38501
|
throw new Error(`ArgumentError: ${validation.statementType} is not allowed by ksql_mutate. Use ksql_query.`);
|
|
37659
38502
|
}
|
|
@@ -37712,10 +38555,13 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
37712
38555
|
});
|
|
37713
38556
|
}
|
|
37714
38557
|
async function saveQuery(input) {
|
|
37715
|
-
const validation =
|
|
37716
|
-
|
|
37717
|
-
|
|
37718
|
-
|
|
38558
|
+
const validation = requireSingleStatement(
|
|
38559
|
+
await validate({
|
|
38560
|
+
sql: input.sql,
|
|
38561
|
+
profile: input.defaultProfile
|
|
38562
|
+
}),
|
|
38563
|
+
"ksql_save_query"
|
|
38564
|
+
);
|
|
37719
38565
|
assertSavedQuerySafety(input, {
|
|
37720
38566
|
isDml: validation.isDml,
|
|
37721
38567
|
statementType: validation.statementType
|
|
@@ -37759,10 +38605,13 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
37759
38605
|
const saved = getSavedQuery(catalog, input.name);
|
|
37760
38606
|
assertProfileOverrideAllowed(saved, input.profile);
|
|
37761
38607
|
const profile2 = input.profile ?? saved.defaultProfile;
|
|
37762
|
-
const validation =
|
|
37763
|
-
|
|
37764
|
-
|
|
37765
|
-
|
|
38608
|
+
const validation = requireSingleStatement(
|
|
38609
|
+
await validate({
|
|
38610
|
+
sql: saved.sql,
|
|
38611
|
+
profile: profile2
|
|
38612
|
+
}),
|
|
38613
|
+
"ksql_run_saved_query"
|
|
38614
|
+
);
|
|
37766
38615
|
assertSavedQuerySafety(saved, {
|
|
37767
38616
|
isDml: validation.isDml,
|
|
37768
38617
|
statementType: validation.statementType
|
|
@@ -37858,7 +38707,11 @@ var queryInputSchema = external_exports.object({
|
|
|
37858
38707
|
maxRecords,
|
|
37859
38708
|
fetchParallel,
|
|
37860
38709
|
onLimit,
|
|
37861
|
-
timeout
|
|
38710
|
+
timeout,
|
|
38711
|
+
/** バッチ(複文)専用: 実行時エラー後も後続文を実行する(既定 false = fail-fast) */
|
|
38712
|
+
continueOnError: external_exports.boolean().optional(),
|
|
38713
|
+
/** バッチ(複文)専用: 返却する結果セットの合計行数上限(既定なし) */
|
|
38714
|
+
maxTotalRecords: external_exports.number().int().positive().optional()
|
|
37862
38715
|
});
|
|
37863
38716
|
var mutateInputSchema = external_exports.object({
|
|
37864
38717
|
sql: external_exports.string().min(1),
|
|
@@ -37867,7 +38720,10 @@ var mutateInputSchema = external_exports.object({
|
|
|
37867
38720
|
confirmText: external_exports.literal("yes"),
|
|
37868
38721
|
dmlMaxRows,
|
|
37869
38722
|
fetchParallel,
|
|
37870
|
-
timeout
|
|
38723
|
+
timeout,
|
|
38724
|
+
/** バッチ(複文)専用: バッチ合計の影響行数上限(既定なし = 文ごとの dmlMaxRows のみ)。
|
|
38725
|
+
* なお DML バッチに continueOnError は存在しない(常に fail-fast) */
|
|
38726
|
+
dmlTotalMaxRows: dmlMaxRows.optional()
|
|
37871
38727
|
});
|
|
37872
38728
|
var describeAppInputSchema = external_exports.object({
|
|
37873
38729
|
app: external_exports.number().int().positive(),
|