@rex0220/kintone-sql-tools 1.13.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cli/ksql.js +329 -44
- package/dist-mcp/ksql-mcp.js +330 -45
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -31096,6 +31096,7 @@ var Lexer = class {
|
|
|
31096
31096
|
if (opTok) return opTok;
|
|
31097
31097
|
if (isIdentStart(ch)) return this.readIdentOrKeyword(start);
|
|
31098
31098
|
if (ch === "#") return this.readHashIdent(start);
|
|
31099
|
+
if (ch === "@") return this.readVariable(start);
|
|
31099
31100
|
throw new LexError(
|
|
31100
31101
|
`\u4E88\u671F\u3057\u306A\u3044\u6587\u5B57 \u300C${ch}\u300D \u3067\u3059`,
|
|
31101
31102
|
this.pos,
|
|
@@ -31275,6 +31276,23 @@ var Lexer = class {
|
|
|
31275
31276
|
}
|
|
31276
31277
|
return this.makeToken("IDENT" /* IDENT */, value, start);
|
|
31277
31278
|
}
|
|
31279
|
+
/** バッチ変数: @[A-Za-z_][A-Za-z0-9_]{0,63} */
|
|
31280
|
+
readVariable(start) {
|
|
31281
|
+
this.pos++;
|
|
31282
|
+
const first = this.input[this.pos] ?? "";
|
|
31283
|
+
if (!/[A-Za-z_]/.test(first)) {
|
|
31284
|
+
throw new LexError("\u300C@\u300D \u306E\u76F4\u5F8C\u306B\u306F\u82F1\u5B57\u307E\u305F\u306F _ \u3067\u59CB\u307E\u308B\u5909\u6570\u540D\u304C\u5FC5\u8981\u3067\u3059", start, this.input);
|
|
31285
|
+
}
|
|
31286
|
+
this.pos++;
|
|
31287
|
+
while (this.pos < this.input.length && /[A-Za-z0-9_]/.test(this.input[this.pos])) {
|
|
31288
|
+
this.pos++;
|
|
31289
|
+
}
|
|
31290
|
+
const nameLength = this.pos - start - 1;
|
|
31291
|
+
if (nameLength > 64) {
|
|
31292
|
+
throw new LexError("\u5909\u6570\u540D\u306F 64 \u6587\u5B57\u4EE5\u5185\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044", start, this.input);
|
|
31293
|
+
}
|
|
31294
|
+
return this.makeToken("VARIABLE" /* VARIABLE */, this.input.slice(start, this.pos), start);
|
|
31295
|
+
}
|
|
31278
31296
|
// ----------------------------------------------------------
|
|
31279
31297
|
// 空白・コメントをスキップ
|
|
31280
31298
|
// ----------------------------------------------------------
|
|
@@ -31486,6 +31504,8 @@ var Parser = class {
|
|
|
31486
31504
|
return this.parseDescribe();
|
|
31487
31505
|
case "EXPLAIN" /* EXPLAIN */:
|
|
31488
31506
|
return this.parseExplain();
|
|
31507
|
+
case "SET" /* SET */:
|
|
31508
|
+
return this.parseSetVariable();
|
|
31489
31509
|
case "ASSERT" /* ASSERT */:
|
|
31490
31510
|
return this.parseAssert();
|
|
31491
31511
|
case "IDENT" /* IDENT */: {
|
|
@@ -31498,11 +31518,65 @@ var Parser = class {
|
|
|
31498
31518
|
break;
|
|
31499
31519
|
}
|
|
31500
31520
|
throw new ParseError(
|
|
31501
|
-
"SELECT / INSERT / UPDATE / DELETE / REORDER / WITH / SHOW / DESCRIBE / EXPLAIN / CREATE TEMP TABLE / DROP TEMP TABLE / ASSERT \u306E\u3044\u305A\u308C\u304B\u3067\u59CB\u307E\u308B SQL \u6587\u304C\u5FC5\u8981\u3067\u3059",
|
|
31521
|
+
"SELECT / INSERT / UPDATE / DELETE / REORDER / WITH / SHOW / DESCRIBE / EXPLAIN / CREATE TEMP TABLE / DROP TEMP TABLE / SET / ASSERT \u306E\u3044\u305A\u308C\u304B\u3067\u59CB\u307E\u308B SQL \u6587\u304C\u5FC5\u8981\u3067\u3059",
|
|
31502
31522
|
tok
|
|
31503
31523
|
);
|
|
31504
31524
|
}
|
|
31505
31525
|
// ----------------------------------------------------------
|
|
31526
|
+
// SET @name = <ScalarExpr>
|
|
31527
|
+
// ----------------------------------------------------------
|
|
31528
|
+
parseSetVariable() {
|
|
31529
|
+
this.expect("SET" /* SET */);
|
|
31530
|
+
const variable = this.expect("VARIABLE" /* VARIABLE */, "SET \u306E\u5F8C\u306B\u306F\u5909\u6570\u540D\uFF08\u4F8B: @name\uFF09\u304C\u5FC5\u8981\u3067\u3059");
|
|
31531
|
+
this.expect("=" /* EQ */);
|
|
31532
|
+
const expr = this.parseScalarExpr();
|
|
31533
|
+
return { type: "SET_VARIABLE", name: variable.value.slice(1).toLowerCase(), expr };
|
|
31534
|
+
}
|
|
31535
|
+
/** SET RHS 専用。既存式パーサーで構文を読み、フィールド参照を明示的に拒否する。 */
|
|
31536
|
+
parseScalarExpr() {
|
|
31537
|
+
const tok = this.peek();
|
|
31538
|
+
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
31539
|
+
throw new ParseError("SET \u306E\u53F3\u8FBA\u3067\u306F\u4ED6\u306E\u5909\u6570\u3092\u53C2\u7167\u3067\u304D\u307E\u305B\u3093\uFF08Phase 1a\uFF09", tok);
|
|
31540
|
+
}
|
|
31541
|
+
if (tok.kind === "NULL" /* NULL */) {
|
|
31542
|
+
throw new ParseError("SET \u306E\u53F3\u8FBA\u3067 NULL \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\uFF08Phase 1a\uFF09", tok);
|
|
31543
|
+
}
|
|
31544
|
+
if (tok.kind === "(" /* LPAREN */ && this.peekAt(1).kind === "SELECT" /* SELECT */) {
|
|
31545
|
+
throw new ParseError("SET \u306E\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u4EE3\u5165\u306F Phase 1b \u3067\u5BFE\u5FDC\u4E88\u5B9A\u3067\u3059", tok);
|
|
31546
|
+
}
|
|
31547
|
+
if (tok.kind === "STRING" /* STRING */) {
|
|
31548
|
+
this.advance();
|
|
31549
|
+
return { type: "STRING", value: tok.value };
|
|
31550
|
+
}
|
|
31551
|
+
if (tok.kind === "LOGINUSER" /* LOGINUSER */) {
|
|
31552
|
+
throw new ParseError(
|
|
31553
|
+
"SET \u306E\u53F3\u8FBA\u3067 LOGINUSER() \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\uFF08\u5B9F\u884C\u74B0\u5883\u5171\u901A\u306E\u30ED\u30B0\u30A4\u30F3\u30E6\u30FC\u30B6\u30FC\u89E3\u6C7A\u306F\u672A\u5BFE\u5FDC\u3067\u3059\uFF09",
|
|
31554
|
+
tok
|
|
31555
|
+
);
|
|
31556
|
+
}
|
|
31557
|
+
if (tok.kind === "TODAY" /* TODAY */ || tok.kind === "NOW" /* NOW */) {
|
|
31558
|
+
return this.parseSqlValue();
|
|
31559
|
+
}
|
|
31560
|
+
const expr = this.parseArithAddSub();
|
|
31561
|
+
this.rejectNonScalarExpr(expr, tok);
|
|
31562
|
+
if (expr.type === "NUMBER" || expr.type === "STRING_FUNC" || expr.type === "ARITH") return expr;
|
|
31563
|
+
throw new ParseError("SET \u306E\u53F3\u8FBA\u306B\u306F\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u3092\u542B\u307E\u306A\u3044\u30B9\u30AB\u30E9\u30FC\u5F0F\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044", tok);
|
|
31564
|
+
}
|
|
31565
|
+
rejectNonScalarExpr(node, tok) {
|
|
31566
|
+
if (node.type === "STRING" || node.type === "NUMBER") return;
|
|
31567
|
+
if (node.type === "FIELD_REF" || node.type === "AGG_REF") {
|
|
31568
|
+
throw new ParseError("SET \u306E\u53F3\u8FBA\u3067\u306F\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u30FB\u96C6\u8A08\u95A2\u6570\u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
|
|
31569
|
+
}
|
|
31570
|
+
if (node.type === "ARITH" || node.type === "AGG_ARITH") {
|
|
31571
|
+
this.rejectNonScalarExpr(node.left, tok);
|
|
31572
|
+
this.rejectNonScalarExpr(node.right, tok);
|
|
31573
|
+
return;
|
|
31574
|
+
}
|
|
31575
|
+
if (node.type === "STRING_FUNC") {
|
|
31576
|
+
for (const arg of node.args) this.rejectNonScalarExpr(arg, tok);
|
|
31577
|
+
}
|
|
31578
|
+
}
|
|
31579
|
+
// ----------------------------------------------------------
|
|
31506
31580
|
// CREATE TEMP TABLE / DROP TEMP TABLE(バッチ内一時テーブル)
|
|
31507
31581
|
// CREATE / DROP / TEMP / TABLE は予約語にしない(ソフトキーワード)
|
|
31508
31582
|
// ----------------------------------------------------------
|
|
@@ -31646,6 +31720,10 @@ var Parser = class {
|
|
|
31646
31720
|
/** ASSERT のオペランド: 文字列 / スカラーサブクエリ / 数値算術式 */
|
|
31647
31721
|
parseAssertOperand() {
|
|
31648
31722
|
const tok = this.peek();
|
|
31723
|
+
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
31724
|
+
this.advance();
|
|
31725
|
+
return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
|
|
31726
|
+
}
|
|
31649
31727
|
if (tok.kind === "STRING" /* STRING */) {
|
|
31650
31728
|
this.advance();
|
|
31651
31729
|
return { type: "STRING", value: tok.value };
|
|
@@ -32553,6 +32631,10 @@ var Parser = class {
|
|
|
32553
32631
|
// 右辺の値
|
|
32554
32632
|
parseSqlValue() {
|
|
32555
32633
|
const tok = this.peek();
|
|
32634
|
+
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
32635
|
+
this.advance();
|
|
32636
|
+
return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
|
|
32637
|
+
}
|
|
32556
32638
|
if (tok.kind === "STRING" /* STRING */) {
|
|
32557
32639
|
this.advance();
|
|
32558
32640
|
return { type: "STRING", value: tok.value };
|
|
@@ -32615,8 +32697,10 @@ var Parser = class {
|
|
|
32615
32697
|
values.push({ type: "STRING", value: tok.value });
|
|
32616
32698
|
} else if (tok.kind === "NUMBER" /* NUMBER */) {
|
|
32617
32699
|
values.push({ type: "NUMBER", value: Number(tok.value) });
|
|
32700
|
+
} else if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
32701
|
+
values.push({ type: "VARIABLE", name: tok.value.slice(1).toLowerCase() });
|
|
32618
32702
|
} else {
|
|
32619
|
-
throw new ParseError("IN \u30EA\u30B9\u30C8\u306B\u306F\u6587\u5B57\u5217\u307E\u305F\u306F\u6570\
|
|
32703
|
+
throw new ParseError("IN \u30EA\u30B9\u30C8\u306B\u306F\u6587\u5B57\u5217\u3001\u6570\u5024\u3001\u307E\u305F\u306F\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059", tok);
|
|
32620
32704
|
}
|
|
32621
32705
|
} while (this.consume("," /* COMMA */));
|
|
32622
32706
|
return values;
|
|
@@ -32848,6 +32932,7 @@ var Parser = class {
|
|
|
32848
32932
|
*/
|
|
32849
32933
|
parseAssignmentValue() {
|
|
32850
32934
|
const tok = this.peek();
|
|
32935
|
+
if (tok.kind === "VARIABLE" /* VARIABLE */) return this.parseSqlValue();
|
|
32851
32936
|
if (tok.kind === "STRING" /* STRING */) return this.parseSqlValue();
|
|
32852
32937
|
if (tok.kind === "TODAY" /* TODAY */ || tok.kind === "NOW" /* NOW */ || tok.kind === "LOGINUSER" /* LOGINUSER */) return this.parseSqlValue();
|
|
32853
32938
|
if (tok.kind === "IN" /* IN */) return this.parseSqlValue();
|
|
@@ -33109,7 +33194,7 @@ function isDmlType(type) {
|
|
|
33109
33194
|
return type === "INSERT" || type === "INSERT_SELECT" || type === "UPDATE" || type === "DELETE" || type === "UPSERT" || type === "UPSERT_SELECT" || type === "REORDER";
|
|
33110
33195
|
}
|
|
33111
33196
|
function isReadOnlyType(type) {
|
|
33112
|
-
return type === "SELECT" || type === "UNION" || type === "WITH" || type === "EXPLAIN" || type === "SHOW_APPS" || type === "DESCRIBE" || type === "CREATE_TEMP_TABLE" || type === "DROP_TEMP_TABLE" || type === "ASSERT";
|
|
33197
|
+
return type === "SELECT" || type === "UNION" || type === "WITH" || type === "EXPLAIN" || type === "SHOW_APPS" || type === "DESCRIBE" || type === "CREATE_TEMP_TABLE" || type === "DROP_TEMP_TABLE" || type === "SET_VARIABLE" || type === "ASSERT";
|
|
33113
33198
|
}
|
|
33114
33199
|
function hasWhereClause(stmt) {
|
|
33115
33200
|
if (!stmt || typeof stmt !== "object") return false;
|
|
@@ -33130,6 +33215,7 @@ function getInsertValuesCount(stmt) {
|
|
|
33130
33215
|
|
|
33131
33216
|
// src/core/batch.ts
|
|
33132
33217
|
var MAX_TEMP_TABLES = 16;
|
|
33218
|
+
var MAX_BATCH_VARIABLES = 64;
|
|
33133
33219
|
var BatchAnalysisError = class extends Error {
|
|
33134
33220
|
constructor(message, statementIndex) {
|
|
33135
33221
|
super(message);
|
|
@@ -33150,12 +33236,29 @@ function collectRefs(node, tempRefs, appIds) {
|
|
|
33150
33236
|
for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
|
|
33151
33237
|
}
|
|
33152
33238
|
}
|
|
33239
|
+
function collectVariableRefs(node, refs) {
|
|
33240
|
+
if (Array.isArray(node)) {
|
|
33241
|
+
for (const v of node) collectVariableRefs(v, refs);
|
|
33242
|
+
return;
|
|
33243
|
+
}
|
|
33244
|
+
if (node !== null && typeof node === "object") {
|
|
33245
|
+
const obj = node;
|
|
33246
|
+
if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
|
|
33247
|
+
refs.add(obj["name"]);
|
|
33248
|
+
return;
|
|
33249
|
+
}
|
|
33250
|
+
for (const v of Object.values(obj)) collectVariableRefs(v, refs);
|
|
33251
|
+
}
|
|
33252
|
+
}
|
|
33153
33253
|
function analyzeBatch(statements) {
|
|
33154
33254
|
if (statements.length === 0) {
|
|
33155
33255
|
throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
|
|
33156
33256
|
}
|
|
33157
33257
|
if (statements.length === 1) {
|
|
33158
33258
|
const t = statements[0].type;
|
|
33259
|
+
if (t === "SET_VARIABLE") {
|
|
33260
|
+
throw new BatchAnalysisError("ArgumentError: SET variable requires a batch.", 0);
|
|
33261
|
+
}
|
|
33159
33262
|
if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
|
|
33160
33263
|
const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
|
|
33161
33264
|
throw new BatchAnalysisError(
|
|
@@ -33167,6 +33270,8 @@ function analyzeBatch(statements) {
|
|
|
33167
33270
|
const defined = /* @__PURE__ */ new Map();
|
|
33168
33271
|
const createdOrder = [];
|
|
33169
33272
|
const results = [];
|
|
33273
|
+
const variableDefs = /* @__PURE__ */ new Map();
|
|
33274
|
+
const variableOrder = [];
|
|
33170
33275
|
statements.forEach((stmt, index) => {
|
|
33171
33276
|
const statementType = getStatementType(stmt);
|
|
33172
33277
|
const created = [];
|
|
@@ -33174,6 +33279,31 @@ function analyzeBatch(statements) {
|
|
|
33174
33279
|
const refs = /* @__PURE__ */ new Set();
|
|
33175
33280
|
const stmtAppIds = /* @__PURE__ */ new Set();
|
|
33176
33281
|
const dependsOn = /* @__PURE__ */ new Set();
|
|
33282
|
+
const variableRefs = /* @__PURE__ */ new Set();
|
|
33283
|
+
collectVariableRefs(stmt, variableRefs);
|
|
33284
|
+
for (const name of variableRefs) {
|
|
33285
|
+
const def = variableDefs.get(name);
|
|
33286
|
+
if (def === void 0) {
|
|
33287
|
+
throw new BatchAnalysisError(
|
|
33288
|
+
`ParseError: variable @${name} is not defined before statement ${index + 1}.`,
|
|
33289
|
+
index
|
|
33290
|
+
);
|
|
33291
|
+
}
|
|
33292
|
+
def.referencedBy.push(index);
|
|
33293
|
+
}
|
|
33294
|
+
if (stmt.type === "SET_VARIABLE") {
|
|
33295
|
+
if (variableDefs.has(stmt.name)) {
|
|
33296
|
+
throw new BatchAnalysisError(`ParseError: variable @${stmt.name} is already defined.`, index);
|
|
33297
|
+
}
|
|
33298
|
+
variableDefs.set(stmt.name, { index, referencedBy: [] });
|
|
33299
|
+
variableOrder.push(stmt.name);
|
|
33300
|
+
if (variableOrder.length > MAX_BATCH_VARIABLES) {
|
|
33301
|
+
throw new BatchAnalysisError(
|
|
33302
|
+
`ParseError: batch exceeds ${MAX_BATCH_VARIABLES} variables.`,
|
|
33303
|
+
index
|
|
33304
|
+
);
|
|
33305
|
+
}
|
|
33306
|
+
}
|
|
33177
33307
|
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
33178
33308
|
collectRefs(stmt.query, refs, stmtAppIds);
|
|
33179
33309
|
} else if (stmt.type === "DROP_TEMP_TABLE") {
|
|
@@ -33243,11 +33373,17 @@ function analyzeBatch(statements) {
|
|
|
33243
33373
|
});
|
|
33244
33374
|
});
|
|
33245
33375
|
const containsDml = results.some((r) => r.isDml);
|
|
33376
|
+
const variables = variableOrder.map((name) => ({
|
|
33377
|
+
name,
|
|
33378
|
+
referencedBy: [...variableDefs.get(name).referencedBy]
|
|
33379
|
+
}));
|
|
33246
33380
|
return {
|
|
33247
33381
|
statementCount: statements.length,
|
|
33248
33382
|
isReadOnlyBatch: !containsDml && results.every((r) => r.isReadOnly),
|
|
33249
33383
|
containsDml,
|
|
33250
33384
|
tempTables: createdOrder,
|
|
33385
|
+
variables,
|
|
33386
|
+
warnings: variables.filter((v) => v.referencedBy.length === 0).map((v) => `variable @${v.name} is never used.`),
|
|
33251
33387
|
statements: results
|
|
33252
33388
|
};
|
|
33253
33389
|
}
|
|
@@ -33308,6 +33444,29 @@ function negateOp(op) {
|
|
|
33308
33444
|
}
|
|
33309
33445
|
}
|
|
33310
33446
|
|
|
33447
|
+
// src/core/like.ts
|
|
33448
|
+
function likePatternHasWildcard(pattern) {
|
|
33449
|
+
return pattern.includes("%") || pattern.includes("_");
|
|
33450
|
+
}
|
|
33451
|
+
function isLike(where) {
|
|
33452
|
+
return where.type === "BINARY" && (where.op === "LIKE" || where.op === "NOT_LIKE");
|
|
33453
|
+
}
|
|
33454
|
+
function whereHasLike(where) {
|
|
33455
|
+
if (where === null) return false;
|
|
33456
|
+
if (isLike(where)) return true;
|
|
33457
|
+
switch (where.type) {
|
|
33458
|
+
case "LOGICAL":
|
|
33459
|
+
return whereHasLike(where.left) || whereHasLike(where.right);
|
|
33460
|
+
case "NOT":
|
|
33461
|
+
case "GROUP":
|
|
33462
|
+
return whereHasLike(where.expr);
|
|
33463
|
+
case "BINARY":
|
|
33464
|
+
case "NULL_CHECK":
|
|
33465
|
+
case "EXISTS":
|
|
33466
|
+
return false;
|
|
33467
|
+
}
|
|
33468
|
+
}
|
|
33469
|
+
|
|
33311
33470
|
// src/converter/whereToKintone.ts
|
|
33312
33471
|
function whereToKintone(expr) {
|
|
33313
33472
|
switch (expr.type) {
|
|
@@ -33326,6 +33485,11 @@ function whereToKintone(expr) {
|
|
|
33326
33485
|
}
|
|
33327
33486
|
}
|
|
33328
33487
|
function convertBinary(expr) {
|
|
33488
|
+
if (isLike(expr)) {
|
|
33489
|
+
throw new KintoneQueryError(
|
|
33490
|
+
"LIKE / NOT LIKE \u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093\uFF08\u5E38\u306B JS \u8A55\u4FA1\u304C\u5FC5\u8981\u3067\u3059\uFF09"
|
|
33491
|
+
);
|
|
33492
|
+
}
|
|
33329
33493
|
const left = convertField(expr.left);
|
|
33330
33494
|
const op = convertOp(expr.op);
|
|
33331
33495
|
const right = convertValue(expr.right, expr.op);
|
|
@@ -33390,6 +33554,8 @@ function convertField(field) {
|
|
|
33390
33554
|
}
|
|
33391
33555
|
function convertValue(value, op) {
|
|
33392
33556
|
switch (value.type) {
|
|
33557
|
+
case "VARIABLE":
|
|
33558
|
+
throw new KintoneQueryError(`\u672A\u89E3\u6C7A\u306E\u30D0\u30C3\u30C1\u5909\u6570 @${value.name} \u304C\u3042\u308A\u307E\u3059`);
|
|
33393
33559
|
case "STRING":
|
|
33394
33560
|
return convertString(value);
|
|
33395
33561
|
case "NUMBER":
|
|
@@ -33420,11 +33586,18 @@ function convertInList(v, op) {
|
|
|
33420
33586
|
if (op !== "IN" && op !== "NOT_IN") {
|
|
33421
33587
|
throw new KintoneQueryError("IN_LIST \u306F IN / NOT IN \u6F14\u7B97\u5B50\u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059");
|
|
33422
33588
|
}
|
|
33589
|
+
assertResolvedInListValues(v.values);
|
|
33423
33590
|
const values = v.values.map(
|
|
33424
33591
|
(item) => item.type === "STRING" ? convertString(item) : String(item.value)
|
|
33425
33592
|
).join(",");
|
|
33426
33593
|
return `(${values})`;
|
|
33427
33594
|
}
|
|
33595
|
+
function assertResolvedInListValues(values) {
|
|
33596
|
+
const unresolved = values.find((item) => item.type === "VARIABLE");
|
|
33597
|
+
if (unresolved?.type === "VARIABLE") {
|
|
33598
|
+
throw new KintoneQueryError(`\u672A\u89E3\u6C7A\u306E\u30D0\u30C3\u30C1\u5909\u6570 @${unresolved.name} \u304C\u3042\u308A\u307E\u3059`);
|
|
33599
|
+
}
|
|
33600
|
+
}
|
|
33428
33601
|
function quoteIdentifier(name) {
|
|
33429
33602
|
if (/^[\w$\u3000-\u9FFF]+$/u.test(name)) {
|
|
33430
33603
|
return name;
|
|
@@ -33451,22 +33624,22 @@ function resolveSelectMode(stmt) {
|
|
|
33451
33624
|
if (stmt.columns.some(
|
|
33452
33625
|
(c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
|
|
33453
33626
|
)) return "FULL_SCAN";
|
|
33454
|
-
if (
|
|
33627
|
+
if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
|
|
33455
33628
|
if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
|
|
33456
33629
|
return "SIMPLE";
|
|
33457
33630
|
}
|
|
33458
|
-
function
|
|
33631
|
+
function whereRequiresJsEval(where) {
|
|
33459
33632
|
if (where === null) return false;
|
|
33460
33633
|
switch (where.type) {
|
|
33461
33634
|
case "BINARY":
|
|
33462
|
-
return isFunc(where.left) || where.right.type === "ARITH_VALUE" || where.right.type === "CASE_VALUE" || where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY";
|
|
33635
|
+
return isFunc(where.left) || where.right.type === "ARITH_VALUE" || where.right.type === "CASE_VALUE" || where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY" || isLike(where);
|
|
33463
33636
|
case "NULL_CHECK":
|
|
33464
33637
|
return isFunc(where.field);
|
|
33465
33638
|
case "LOGICAL":
|
|
33466
|
-
return
|
|
33639
|
+
return whereRequiresJsEval(where.left) || whereRequiresJsEval(where.right);
|
|
33467
33640
|
case "NOT":
|
|
33468
33641
|
case "GROUP":
|
|
33469
|
-
return
|
|
33642
|
+
return whereRequiresJsEval(where.expr);
|
|
33470
33643
|
case "EXISTS":
|
|
33471
33644
|
return true;
|
|
33472
33645
|
}
|
|
@@ -33502,7 +33675,7 @@ function selectToKintoneParams(stmt) {
|
|
|
33502
33675
|
}
|
|
33503
33676
|
function selectToFetchAllParams(stmt, appId) {
|
|
33504
33677
|
const queryParts = [];
|
|
33505
|
-
if (stmt.where !== null && stmt.joins.length === 0 && !
|
|
33678
|
+
if (stmt.where !== null && stmt.joins.length === 0 && !whereRequiresJsEval(stmt.where)) {
|
|
33506
33679
|
queryParts.push(whereToKintone(stmt.where));
|
|
33507
33680
|
}
|
|
33508
33681
|
return {
|
|
@@ -34168,15 +34341,17 @@ function evalBinary(expr, row) {
|
|
|
34168
34341
|
return evalOp(expr.op, left, expr.right, row);
|
|
34169
34342
|
}
|
|
34170
34343
|
function evalOp(op, leftStr, right, row) {
|
|
34171
|
-
if (op === "IN") {
|
|
34172
|
-
if (right.type === "IN_LIST")
|
|
34173
|
-
|
|
34174
|
-
|
|
34175
|
-
|
|
34176
|
-
|
|
34177
|
-
if (right.type === "
|
|
34178
|
-
|
|
34179
|
-
|
|
34344
|
+
if (op === "IN" || op === "NOT_IN") {
|
|
34345
|
+
if (right.type === "IN_LIST") {
|
|
34346
|
+
assertResolvedInListValues2(right.values);
|
|
34347
|
+
const contains = right.values.some((v) => leftStr === String(v.value));
|
|
34348
|
+
return op === "IN" ? contains : !contains;
|
|
34349
|
+
}
|
|
34350
|
+
if (right.type === "SUBQUERY_IN_LIST") {
|
|
34351
|
+
const contains = right.resolved.has(leftStr);
|
|
34352
|
+
return op === "IN" ? contains : !contains;
|
|
34353
|
+
}
|
|
34354
|
+
return op === "NOT_IN";
|
|
34180
34355
|
}
|
|
34181
34356
|
if (op === "LIKE") {
|
|
34182
34357
|
const pattern = resolveValue(right, row);
|
|
@@ -34206,6 +34381,12 @@ function evalOp(op, leftStr, right, row) {
|
|
|
34206
34381
|
return numeric ? leftNum <= rightNum : leftStr <= rightStr;
|
|
34207
34382
|
}
|
|
34208
34383
|
}
|
|
34384
|
+
function assertResolvedInListValues2(values) {
|
|
34385
|
+
const unresolved = values.find((item) => item.type === "VARIABLE");
|
|
34386
|
+
if (unresolved?.type === "VARIABLE") {
|
|
34387
|
+
throw new Error(`ParseError: unresolved batch variable @${unresolved.name}.`);
|
|
34388
|
+
}
|
|
34389
|
+
}
|
|
34209
34390
|
function evalNullCheck(expr, row) {
|
|
34210
34391
|
const val = resolveField(expr.field, row);
|
|
34211
34392
|
return expr.not ? val !== "" : val === "";
|
|
@@ -34225,6 +34406,8 @@ function resolveField(field, row) {
|
|
|
34225
34406
|
}
|
|
34226
34407
|
function resolveValue(value, row) {
|
|
34227
34408
|
switch (value.type) {
|
|
34409
|
+
case "VARIABLE":
|
|
34410
|
+
throw new Error(`ParseError: unresolved batch variable @${value.name}.`);
|
|
34228
34411
|
case "STRING":
|
|
34229
34412
|
return value.value;
|
|
34230
34413
|
case "NUMBER":
|
|
@@ -34240,6 +34423,8 @@ function resolveValue(value, row) {
|
|
|
34240
34423
|
case "SCALAR_SUBQUERY":
|
|
34241
34424
|
return value.resolved;
|
|
34242
34425
|
case "ARITH_VALUE":
|
|
34426
|
+
if (value.expr.type === "FIELD_REF") return resolveFieldRef(row, value.expr.field);
|
|
34427
|
+
if (value.expr.type === "STRING_FUNC") return evalStringFunc(value.expr, row);
|
|
34243
34428
|
return String(evalArithExpr(value.expr, row));
|
|
34244
34429
|
case "CASE_VALUE":
|
|
34245
34430
|
return evalCaseWhen(value.expr, row);
|
|
@@ -34283,7 +34468,7 @@ function resolveKintoneFunc(name) {
|
|
|
34283
34468
|
var likeRegexCache = /* @__PURE__ */ new Map();
|
|
34284
34469
|
var LIKE_REGEX_CACHE_MAX = 200;
|
|
34285
34470
|
function matchLike(value, pattern) {
|
|
34286
|
-
if (!
|
|
34471
|
+
if (!likePatternHasWildcard(pattern)) {
|
|
34287
34472
|
return value.includes(pattern);
|
|
34288
34473
|
}
|
|
34289
34474
|
let regex = likeRegexCache.get(pattern);
|
|
@@ -34308,6 +34493,12 @@ function matchLike(value, pattern) {
|
|
|
34308
34493
|
}
|
|
34309
34494
|
|
|
34310
34495
|
// src/converter/dmlToKintone.ts
|
|
34496
|
+
function assertDmlWhereIsSafe(where) {
|
|
34497
|
+
if (!whereHasLike(where)) return;
|
|
34498
|
+
throw new DmlConvertError(
|
|
34499
|
+
"UPDATE / DELETE \u306E WHERE \u306B LIKE / NOT LIKE \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002LIKE \u306F kSQL \u306E\u610F\u5473\u8AD6\u306B\u5F93\u3063\u3066 JS \u3067\u8A55\u4FA1\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u304C\u3001\u89AA\u30EC\u30B3\u30FC\u30C9 DML \u306B\u306F JS \u8A55\u4FA1\u7D4C\u8DEF\u304C\u306A\u3044\u305F\u3081\u3001\u5B89\u5168\u4E0A\u62D2\u5426\u3057\u307E\u3057\u305F\u3002SELECT \u3067\u5BFE\u8C61\u30EC\u30B3\u30FC\u30C9\u756A\u53F7\u3092\u78BA\u8A8D\u3057\u3001IN \u307E\u305F\u306F\u5B8C\u5168\u4E00\u81F4\u3067\u5BFE\u8C61\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
34500
|
+
);
|
|
34501
|
+
}
|
|
34311
34502
|
var USER_TYPES = /* @__PURE__ */ new Set(["USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT"]);
|
|
34312
34503
|
var ARRAY_TYPES = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
|
|
34313
34504
|
function insertToPostBatches(stmt, fieldTypes = /* @__PURE__ */ new Map()) {
|
|
@@ -34332,6 +34523,7 @@ function buildInsertRecord(fields, row, fieldTypes) {
|
|
|
34332
34523
|
return record2;
|
|
34333
34524
|
}
|
|
34334
34525
|
function updateToGetQuery(stmt) {
|
|
34526
|
+
assertDmlWhereIsSafe(stmt.where);
|
|
34335
34527
|
return {
|
|
34336
34528
|
app: stmt.appId,
|
|
34337
34529
|
query: whereToKintone(stmt.where),
|
|
@@ -34360,6 +34552,7 @@ function hasArithAssignment(stmt) {
|
|
|
34360
34552
|
);
|
|
34361
34553
|
}
|
|
34362
34554
|
function updateToGetQueryForArith(stmt) {
|
|
34555
|
+
assertDmlWhereIsSafe(stmt.where);
|
|
34363
34556
|
const refFields = /* @__PURE__ */ new Set();
|
|
34364
34557
|
for (const { value } of stmt.assignments) {
|
|
34365
34558
|
if (value.type === "ARITH") {
|
|
@@ -34505,6 +34698,7 @@ function resolveArithOperand(operand, raw) {
|
|
|
34505
34698
|
return n;
|
|
34506
34699
|
}
|
|
34507
34700
|
function deleteToGetQuery(stmt) {
|
|
34701
|
+
assertDmlWhereIsSafe(stmt.where);
|
|
34508
34702
|
return {
|
|
34509
34703
|
app: stmt.appId,
|
|
34510
34704
|
query: whereToKintone(stmt.where),
|
|
@@ -34577,6 +34771,8 @@ function evalCaseWhenValue(expr, row, fieldType) {
|
|
|
34577
34771
|
}
|
|
34578
34772
|
function toKintoneValue(value, fieldType) {
|
|
34579
34773
|
switch (value.type) {
|
|
34774
|
+
case "VARIABLE":
|
|
34775
|
+
throw new DmlConvertError(`\u672A\u89E3\u6C7A\u306E\u30D0\u30C3\u30C1\u5909\u6570 @${value.name} \u304C\u3042\u308A\u307E\u3059`);
|
|
34580
34776
|
case "STRING":
|
|
34581
34777
|
return convertString2(value.value, fieldType);
|
|
34582
34778
|
case "NUMBER":
|
|
@@ -34789,6 +34985,7 @@ async function resolveDmlTargetIds(getRecords, app, query, options) {
|
|
|
34789
34985
|
function extractTableCondition(where, tableAlias) {
|
|
34790
34986
|
switch (where.type) {
|
|
34791
34987
|
case "BINARY":
|
|
34988
|
+
if (isLike(where)) return null;
|
|
34792
34989
|
if (!isSingleTableField(where.left, tableAlias)) return null;
|
|
34793
34990
|
if (!isPushDownableRight(where.right)) return null;
|
|
34794
34991
|
return where;
|
|
@@ -34828,7 +35025,7 @@ function isPushDownableRight(value) {
|
|
|
34828
35025
|
function referencesOnlyTable(expr, tableAlias) {
|
|
34829
35026
|
switch (expr.type) {
|
|
34830
35027
|
case "BINARY":
|
|
34831
|
-
return isSingleTableField(expr.left, tableAlias) && isPushDownableRight(expr.right);
|
|
35028
|
+
return !isLike(expr) && isSingleTableField(expr.left, tableAlias) && isPushDownableRight(expr.right);
|
|
34832
35029
|
case "NULL_CHECK":
|
|
34833
35030
|
return isSingleTableField(expr.field, tableAlias);
|
|
34834
35031
|
case "LOGICAL":
|
|
@@ -35451,6 +35648,10 @@ async function executeStatement(sql, client, options) {
|
|
|
35451
35648
|
return executeParsedStatement(stmt, client, options, cacheContext);
|
|
35452
35649
|
}
|
|
35453
35650
|
async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
35651
|
+
const unresolved = findVariableRef(stmt);
|
|
35652
|
+
if (unresolved !== null) {
|
|
35653
|
+
throw new Error(`ParseError: variable @${unresolved} is not defined in a batch.`);
|
|
35654
|
+
}
|
|
35454
35655
|
switch (stmt.type) {
|
|
35455
35656
|
case "SELECT":
|
|
35456
35657
|
return executeSelect(stmt, client, options, cacheContext);
|
|
@@ -35483,6 +35684,8 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
35483
35684
|
throw new Error("ArgumentError: CREATE TEMP TABLE requires a batch (temp tables are batch-scoped).");
|
|
35484
35685
|
case "DROP_TEMP_TABLE":
|
|
35485
35686
|
throw new Error("ArgumentError: DROP TEMP TABLE requires a batch (temp tables are batch-scoped).");
|
|
35687
|
+
case "SET_VARIABLE":
|
|
35688
|
+
throw new Error("ArgumentError: SET variable requires a batch.");
|
|
35486
35689
|
case "ASSERT":
|
|
35487
35690
|
return executeAssert(stmt, client, options, cacheContext);
|
|
35488
35691
|
}
|
|
@@ -35513,6 +35716,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
35513
35716
|
const deadline = options.timeoutMs != null ? startedAt + options.timeoutMs : null;
|
|
35514
35717
|
const cacheContext = options.cacheContext ?? "default";
|
|
35515
35718
|
const tempTables = /* @__PURE__ */ new Map();
|
|
35719
|
+
const variables = /* @__PURE__ */ new Map();
|
|
35516
35720
|
const results = [];
|
|
35517
35721
|
const failed = /* @__PURE__ */ new Set();
|
|
35518
35722
|
let aborted2 = null;
|
|
@@ -35550,7 +35754,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
35550
35754
|
})
|
|
35551
35755
|
} : options;
|
|
35552
35756
|
const outcome = await runWithDeadline(
|
|
35553
|
-
executeBatchStatement(statements[i], info, countedClient, stmtOptions, cacheContext, tempTables),
|
|
35757
|
+
executeBatchStatement(statements[i], info, countedClient, stmtOptions, cacheContext, tempTables, variables),
|
|
35554
35758
|
remaining
|
|
35555
35759
|
);
|
|
35556
35760
|
results.push({ ...base, status: "success", ...outcome });
|
|
@@ -35561,6 +35765,8 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
35561
35765
|
aborted2 = "timeout";
|
|
35562
35766
|
} else if (e instanceof AssertError) {
|
|
35563
35767
|
aborted2 = "assertion";
|
|
35768
|
+
} else if (info.statementType === "SET_VARIABLE") {
|
|
35769
|
+
aborted2 = "fail-fast";
|
|
35564
35770
|
} else if (!options.continueOnError) {
|
|
35565
35771
|
aborted2 = "fail-fast";
|
|
35566
35772
|
}
|
|
@@ -35575,44 +35781,49 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
35575
35781
|
metrics
|
|
35576
35782
|
};
|
|
35577
35783
|
}
|
|
35578
|
-
async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables) {
|
|
35579
|
-
if (stmt.type === "
|
|
35784
|
+
async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables) {
|
|
35785
|
+
if (stmt.type === "SET_VARIABLE") {
|
|
35786
|
+
variables.set(stmt.name, evaluateScalarExpr(stmt.expr));
|
|
35787
|
+
return {};
|
|
35788
|
+
}
|
|
35789
|
+
const resolvedStmt = resolveVariableRefs(stmt, variables);
|
|
35790
|
+
if (resolvedStmt.type === "CREATE_TEMP_TABLE") {
|
|
35580
35791
|
const materializeOptions = {
|
|
35581
35792
|
...options,
|
|
35582
35793
|
maxRecords: options.tempTableMaxRows ?? TEMP_TABLE_MAX_ROWS,
|
|
35583
35794
|
onLimitReached: "error"
|
|
35584
35795
|
};
|
|
35585
|
-
const result = await runSelectLike(
|
|
35586
|
-
tempTables.set(
|
|
35587
|
-
return { tempTable:
|
|
35796
|
+
const result = await runSelectLike(resolvedStmt.query, client, materializeOptions, cacheContext, tempTables);
|
|
35797
|
+
tempTables.set(resolvedStmt.name, result.rows);
|
|
35798
|
+
return { tempTable: resolvedStmt.name, rowCount: result.rows.length };
|
|
35588
35799
|
}
|
|
35589
35800
|
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
35590
35801
|
tempTables.delete(stmt.name);
|
|
35591
35802
|
return { tempTable: stmt.name };
|
|
35592
35803
|
}
|
|
35593
35804
|
if (stmt.type === "EXPLAIN") {
|
|
35594
|
-
return { result: await executeParsedStatement(
|
|
35805
|
+
return { result: await executeParsedStatement(resolvedStmt, client, options, cacheContext) };
|
|
35595
35806
|
}
|
|
35596
|
-
if (
|
|
35597
|
-
await executeAssert(
|
|
35807
|
+
if (resolvedStmt.type === "ASSERT") {
|
|
35808
|
+
await executeAssert(resolvedStmt, client, options, cacheContext, tempTables);
|
|
35598
35809
|
return {};
|
|
35599
35810
|
}
|
|
35600
35811
|
if (info.tempTablesReferenced.length > 0) {
|
|
35601
|
-
if (
|
|
35602
|
-
return { result: await executeQueryWithCte(
|
|
35812
|
+
if (resolvedStmt.type === "SELECT" || resolvedStmt.type === "UNION") {
|
|
35813
|
+
return { result: await executeQueryWithCte(resolvedStmt, client, options, tempTables, cacheContext) };
|
|
35603
35814
|
}
|
|
35604
|
-
if (
|
|
35605
|
-
return { result: await executeWith(
|
|
35815
|
+
if (resolvedStmt.type === "WITH") {
|
|
35816
|
+
return { result: await executeWith(resolvedStmt, client, options, cacheContext, tempTables) };
|
|
35606
35817
|
}
|
|
35607
|
-
if (
|
|
35608
|
-
return { result: await executeInsertSelect(
|
|
35818
|
+
if (resolvedStmt.type === "INSERT_SELECT") {
|
|
35819
|
+
return { result: await executeInsertSelect(resolvedStmt, client, options, cacheContext, tempTables) };
|
|
35609
35820
|
}
|
|
35610
|
-
if (
|
|
35611
|
-
return { result: await executeUpsertSelect(
|
|
35821
|
+
if (resolvedStmt.type === "UPSERT_SELECT") {
|
|
35822
|
+
return { result: await executeUpsertSelect(resolvedStmt, client, options, cacheContext, tempTables) };
|
|
35612
35823
|
}
|
|
35613
35824
|
throw new Error(`ArgumentError: temp table references in ${stmt.type} are not supported yet.`);
|
|
35614
35825
|
}
|
|
35615
|
-
return { result: await executeParsedStatement(
|
|
35826
|
+
return { result: await executeParsedStatement(resolvedStmt, client, options, cacheContext) };
|
|
35616
35827
|
}
|
|
35617
35828
|
async function runSelectLike(query, client, options, cacheContext, tempTables) {
|
|
35618
35829
|
if (query.type === "WITH") {
|
|
@@ -35673,6 +35884,62 @@ function parseSqlBatch(sql) {
|
|
|
35673
35884
|
const tokens = new Lexer(sql).tokenize();
|
|
35674
35885
|
return new Parser(tokens).parseStatements();
|
|
35675
35886
|
}
|
|
35887
|
+
function evaluateScalarExpr(expr) {
|
|
35888
|
+
switch (expr.type) {
|
|
35889
|
+
case "STRING":
|
|
35890
|
+
return { type: "string", value: expr.value };
|
|
35891
|
+
case "NUMBER":
|
|
35892
|
+
return { type: "number", value: expr.value };
|
|
35893
|
+
case "KINTONE_FUNC":
|
|
35894
|
+
return { type: "string", value: resolveKintoneFunc(expr.name) };
|
|
35895
|
+
case "STRING_FUNC":
|
|
35896
|
+
return { type: "string", value: evalStringFunc(expr, {}) };
|
|
35897
|
+
case "ARITH": {
|
|
35898
|
+
const value = evalArithExpr(expr, {});
|
|
35899
|
+
if (!Number.isFinite(value)) {
|
|
35900
|
+
throw new Error("ArgumentError: SET scalar arithmetic produced a non-finite number.");
|
|
35901
|
+
}
|
|
35902
|
+
return { type: "number", value };
|
|
35903
|
+
}
|
|
35904
|
+
}
|
|
35905
|
+
}
|
|
35906
|
+
function resolveVariableRefs(node, variables) {
|
|
35907
|
+
if (Array.isArray(node)) {
|
|
35908
|
+
return node.map((v) => resolveVariableRefs(v, variables));
|
|
35909
|
+
}
|
|
35910
|
+
if (node !== null && typeof node === "object") {
|
|
35911
|
+
const obj = node;
|
|
35912
|
+
if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
|
|
35913
|
+
const value = variables.get(obj["name"]);
|
|
35914
|
+
if (value === void 0) {
|
|
35915
|
+
throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
|
|
35916
|
+
}
|
|
35917
|
+
return value.type === "number" ? { type: "NUMBER", value: value.value } : { type: "STRING", value: value.value };
|
|
35918
|
+
}
|
|
35919
|
+
return Object.fromEntries(
|
|
35920
|
+
Object.entries(obj).map(([key, value]) => [key, resolveVariableRefs(value, variables)])
|
|
35921
|
+
);
|
|
35922
|
+
}
|
|
35923
|
+
return node;
|
|
35924
|
+
}
|
|
35925
|
+
function findVariableRef(node) {
|
|
35926
|
+
if (Array.isArray(node)) {
|
|
35927
|
+
for (const value of node) {
|
|
35928
|
+
const found = findVariableRef(value);
|
|
35929
|
+
if (found !== null) return found;
|
|
35930
|
+
}
|
|
35931
|
+
return null;
|
|
35932
|
+
}
|
|
35933
|
+
if (node !== null && typeof node === "object") {
|
|
35934
|
+
const obj = node;
|
|
35935
|
+
if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") return obj["name"];
|
|
35936
|
+
for (const value of Object.values(obj)) {
|
|
35937
|
+
const found = findVariableRef(value);
|
|
35938
|
+
if (found !== null) return found;
|
|
35939
|
+
}
|
|
35940
|
+
}
|
|
35941
|
+
return null;
|
|
35942
|
+
}
|
|
35676
35943
|
var AssertError = class extends Error {
|
|
35677
35944
|
constructor(message) {
|
|
35678
35945
|
super(`AssertError: ${message}`);
|
|
@@ -35703,6 +35970,8 @@ async function executeAssert(stmt, client, options, cacheContext, tempTables) {
|
|
|
35703
35970
|
}
|
|
35704
35971
|
async function evalAssertOperand(operand, client, options, cacheContext, tempTables) {
|
|
35705
35972
|
switch (operand.type) {
|
|
35973
|
+
case "VARIABLE":
|
|
35974
|
+
throw new Error(`ParseError: unresolved batch variable @${operand.name}.`);
|
|
35706
35975
|
case "NUMBER":
|
|
35707
35976
|
return String(operand.value);
|
|
35708
35977
|
case "STRING":
|
|
@@ -37204,13 +37473,21 @@ async function resolveScalarColumns(columns, client, options, cacheContext, cteC
|
|
|
37204
37473
|
function buildBatchExplainPlans(sql) {
|
|
37205
37474
|
const statements = parseSqlBatch(sql);
|
|
37206
37475
|
const analysis = analyzeBatch(statements);
|
|
37476
|
+
const variables = /* @__PURE__ */ new Map();
|
|
37207
37477
|
return {
|
|
37208
37478
|
statementCount: statements.length,
|
|
37209
|
-
statements: statements.map((stmt, i) =>
|
|
37210
|
-
|
|
37211
|
-
|
|
37212
|
-
|
|
37213
|
-
|
|
37479
|
+
statements: statements.map((stmt, i) => {
|
|
37480
|
+
const planStmt = stmt.type === "SET_VARIABLE" ? stmt : resolveVariableRefs(stmt, variables);
|
|
37481
|
+
const result = {
|
|
37482
|
+
index: i,
|
|
37483
|
+
type: analysis.statements[i].statementType,
|
|
37484
|
+
plan: buildBatchStatementPlan(planStmt, analysis.statements[i])
|
|
37485
|
+
};
|
|
37486
|
+
if (stmt.type === "SET_VARIABLE") {
|
|
37487
|
+
variables.set(stmt.name, { type: "string", value: `@${stmt.name}` });
|
|
37488
|
+
}
|
|
37489
|
+
return result;
|
|
37490
|
+
})
|
|
37214
37491
|
};
|
|
37215
37492
|
}
|
|
37216
37493
|
function buildBatchStatementPlan(stmt, info) {
|
|
@@ -37228,6 +37505,12 @@ function buildBatchStatementPlan(stmt, info) {
|
|
|
37228
37505
|
" \u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u30B9\u30C8\u30A2\u306E\u89E3\u653E\u306E\u307F\uFF08kintone \u30A2\u30AF\u30BB\u30B9\u306A\u3057\uFF09"
|
|
37229
37506
|
];
|
|
37230
37507
|
}
|
|
37508
|
+
if (stmt.type === "SET_VARIABLE") {
|
|
37509
|
+
return [
|
|
37510
|
+
`SET @${stmt.name} = <scalar expression>`,
|
|
37511
|
+
" value: \u5B9F\u884C\u6642\u306B1\u56DE\u8A55\u4FA1\uFF08\u30D0\u30C3\u30C1\u5185\u5B9A\u6570\u30FB\u7D50\u679C\u30E1\u30BF\u30C7\u30FC\u30BF\u306B\u306F\u975E\u516C\u958B\uFF09"
|
|
37512
|
+
];
|
|
37513
|
+
}
|
|
37231
37514
|
if (stmt.type === "SHOW_APPS") return ["SHOW APPS\uFF08\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\uFF09"];
|
|
37232
37515
|
if (stmt.type === "DESCRIBE") return [`DESCRIBE APP${stmt.appId}\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\uFF09`];
|
|
37233
37516
|
if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info);
|
|
@@ -37387,8 +37670,10 @@ function collectFullScanReasons(stmt) {
|
|
|
37387
37670
|
r.push("\u96C6\u8A08\u95A2\u6570\uFF08COUNT / SUM \u7B49\uFF09\u3042\u308A");
|
|
37388
37671
|
if (stmt.columns.some((c) => c.type === "SCALAR_SUBQUERY_COL"))
|
|
37389
37672
|
r.push("SELECT \u5217\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA");
|
|
37390
|
-
if (
|
|
37673
|
+
if (whereRequiresJsEval(stmt.where))
|
|
37391
37674
|
r.push("WHERE \u53E5\u306B JS \u8A55\u4FA1\u304C\u5FC5\u8981\u306A\u5F0F");
|
|
37675
|
+
if (whereHasLike(stmt.where))
|
|
37676
|
+
r.push("LIKE \u306F\u5E38\u306B JS \u8A55\u4FA1\u306E\u305F\u3081\u5168\u4EF6\u53D6\u5F97");
|
|
37392
37677
|
if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME"))
|
|
37393
37678
|
r.push("ORDER BY \u306B\u5F0F");
|
|
37394
37679
|
return r;
|
|
@@ -39661,7 +39946,7 @@ Options:
|
|
|
39661
39946
|
-h, --help Show help
|
|
39662
39947
|
`);
|
|
39663
39948
|
}
|
|
39664
|
-
var SERVER_VERSION = true ? "1.
|
|
39949
|
+
var SERVER_VERSION = true ? "2.1.0" : "0.0.0-dev";
|
|
39665
39950
|
function createServer(args) {
|
|
39666
39951
|
const server = new McpServer({
|
|
39667
39952
|
name: "ksql-mcp",
|