@rex0220/kintone-sql-tools 2.7.0 → 2.8.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 +559 -294
- package/dist-mcp/ksql-mcp.js +506 -241
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -1811,7 +1811,7 @@ var require_code2 = __commonJS({
|
|
|
1811
1811
|
}
|
|
1812
1812
|
}
|
|
1813
1813
|
exports2.validateArray = validateArray;
|
|
1814
|
-
function
|
|
1814
|
+
function validateUnion2(cxt) {
|
|
1815
1815
|
const { gen, schema, keyword, it } = cxt;
|
|
1816
1816
|
if (!Array.isArray(schema))
|
|
1817
1817
|
throw new Error("ajv implementation error");
|
|
@@ -1833,7 +1833,7 @@ var require_code2 = __commonJS({
|
|
|
1833
1833
|
}));
|
|
1834
1834
|
cxt.result(valid, () => cxt.reset(), () => cxt.error(true));
|
|
1835
1835
|
}
|
|
1836
|
-
exports2.validateUnion =
|
|
1836
|
+
exports2.validateUnion = validateUnion2;
|
|
1837
1837
|
}
|
|
1838
1838
|
});
|
|
1839
1839
|
|
|
@@ -31007,6 +31007,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31007
31007
|
["IS", "IS" /* IS */],
|
|
31008
31008
|
["NULL", "NULL" /* NULL */],
|
|
31009
31009
|
["LIKE", "LIKE" /* LIKE */],
|
|
31010
|
+
["KLIKE", "KLIKE" /* KLIKE */],
|
|
31010
31011
|
["IN", "IN" /* IN */],
|
|
31011
31012
|
["BETWEEN", "BETWEEN" /* BETWEEN */],
|
|
31012
31013
|
["TODAY", "TODAY" /* TODAY */],
|
|
@@ -32532,7 +32533,7 @@ var Parser = class {
|
|
|
32532
32533
|
}
|
|
32533
32534
|
return false;
|
|
32534
32535
|
}
|
|
32535
|
-
// 比較演算子: =, !=, <>, >, <, >=, <=, LIKE, IN, IS NULL
|
|
32536
|
+
// 比較演算子: =, !=, <>, >, <, >=, <=, LIKE, KLIKE, IN, IS NULL
|
|
32536
32537
|
parseCompareExpr() {
|
|
32537
32538
|
if (this.peek().kind === "(" /* LPAREN */ && !this.isArithParen()) {
|
|
32538
32539
|
this.advance();
|
|
@@ -32568,8 +32569,12 @@ var Parser = class {
|
|
|
32568
32569
|
const pattern = this.parseSqlValue();
|
|
32569
32570
|
return { type: "BINARY", op: "NOT_LIKE", left: field, right: pattern };
|
|
32570
32571
|
}
|
|
32572
|
+
if (this.consume("KLIKE" /* KLIKE */)) {
|
|
32573
|
+
const pattern = this.parseKlikePattern();
|
|
32574
|
+
return { type: "BINARY", op: "NOT_KLIKE", left: field, right: pattern };
|
|
32575
|
+
}
|
|
32571
32576
|
throw new ParseError(
|
|
32572
|
-
"NOT \u306E\u5F8C\u306B\u306F IN \
|
|
32577
|
+
"NOT \u306E\u5F8C\u306B\u306F IN\u3001LIKE\u3001KLIKE \u306E\u3044\u305A\u308C\u304B\u304C\u5FC5\u8981\u3067\u3059",
|
|
32573
32578
|
this.peek()
|
|
32574
32579
|
);
|
|
32575
32580
|
}
|
|
@@ -32579,6 +32584,10 @@ var Parser = class {
|
|
|
32579
32584
|
this.expect(")" /* RPAREN */);
|
|
32580
32585
|
return { type: "BINARY", op: "IN", left: field, right: right2 };
|
|
32581
32586
|
}
|
|
32587
|
+
if (this.consume("KLIKE" /* KLIKE */)) {
|
|
32588
|
+
const pattern = this.parseKlikePattern();
|
|
32589
|
+
return { type: "BINARY", op: "KLIKE", left: field, right: pattern };
|
|
32590
|
+
}
|
|
32582
32591
|
const op = this.parseCompareOp();
|
|
32583
32592
|
const right = this.parseSqlValue();
|
|
32584
32593
|
return { type: "BINARY", op, left: field, right };
|
|
@@ -32604,11 +32613,27 @@ var Parser = class {
|
|
|
32604
32613
|
return "LIKE";
|
|
32605
32614
|
default:
|
|
32606
32615
|
throw new ParseError(
|
|
32607
|
-
"\u6BD4\u8F03\u6F14\u7B97\u5B50\uFF08=, !=, >, <, >=, <=, LIKE, IN, IS\uFF09\u304C\u5FC5\u8981\u3067\u3059",
|
|
32616
|
+
"\u6BD4\u8F03\u6F14\u7B97\u5B50\uFF08=, !=, >, <, >=, <=, LIKE, KLIKE, IN, IS\uFF09\u304C\u5FC5\u8981\u3067\u3059",
|
|
32608
32617
|
tok
|
|
32609
32618
|
);
|
|
32610
32619
|
}
|
|
32611
32620
|
}
|
|
32621
|
+
/** KLIKE / NOT KLIKE の右辺。kintone キーワードは文字列値だけを受け付ける。 */
|
|
32622
|
+
parseKlikePattern() {
|
|
32623
|
+
const tok = this.peek();
|
|
32624
|
+
if (tok.kind === "STRING" /* STRING */) {
|
|
32625
|
+
this.advance();
|
|
32626
|
+
return { type: "STRING", value: tok.value };
|
|
32627
|
+
}
|
|
32628
|
+
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
32629
|
+
this.advance();
|
|
32630
|
+
return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
|
|
32631
|
+
}
|
|
32632
|
+
throw new ParseError(
|
|
32633
|
+
"KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059",
|
|
32634
|
+
tok
|
|
32635
|
+
);
|
|
32636
|
+
}
|
|
32612
32637
|
// WHERE / HAVING の左辺
|
|
32613
32638
|
// - 文字列・数値関数: UPPER(f) / LENGTH(f) / ROUND(f, 2) ...
|
|
32614
32639
|
// - 集計関数(HAVING のみ): COUNT(*) / SUM(f) ...
|
|
@@ -33247,238 +33272,6 @@ function getInsertValuesCount(stmt) {
|
|
|
33247
33272
|
return Array.isArray(obj.values) ? obj.values.length : null;
|
|
33248
33273
|
}
|
|
33249
33274
|
|
|
33250
|
-
// src/core/batch.ts
|
|
33251
|
-
var MAX_TEMP_TABLES = 16;
|
|
33252
|
-
var MAX_BATCH_VARIABLES = 64;
|
|
33253
|
-
var BatchAnalysisError = class extends Error {
|
|
33254
|
-
constructor(message, statementIndex) {
|
|
33255
|
-
super(message);
|
|
33256
|
-
this.statementIndex = statementIndex;
|
|
33257
|
-
}
|
|
33258
|
-
};
|
|
33259
|
-
function collectRefs(node, tempRefs, appIds) {
|
|
33260
|
-
if (Array.isArray(node)) {
|
|
33261
|
-
for (const v of node) collectRefs(v, tempRefs, appIds);
|
|
33262
|
-
return;
|
|
33263
|
-
}
|
|
33264
|
-
if (node !== null && typeof node === "object") {
|
|
33265
|
-
const obj = node;
|
|
33266
|
-
const cte = obj["cteName"];
|
|
33267
|
-
if (typeof cte === "string" && cte.startsWith("#")) tempRefs.add(cte);
|
|
33268
|
-
const appId = obj["appId"];
|
|
33269
|
-
if (typeof appId === "number" && appId > 0) appIds.add(appId);
|
|
33270
|
-
for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
|
|
33271
|
-
}
|
|
33272
|
-
}
|
|
33273
|
-
function collectVariableRefs(node, refs) {
|
|
33274
|
-
if (Array.isArray(node)) {
|
|
33275
|
-
for (const v of node) collectVariableRefs(v, refs);
|
|
33276
|
-
return;
|
|
33277
|
-
}
|
|
33278
|
-
if (node !== null && typeof node === "object") {
|
|
33279
|
-
const obj = node;
|
|
33280
|
-
if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
|
|
33281
|
-
refs.add(obj["name"]);
|
|
33282
|
-
return;
|
|
33283
|
-
}
|
|
33284
|
-
for (const v of Object.values(obj)) collectVariableRefs(v, refs);
|
|
33285
|
-
}
|
|
33286
|
-
}
|
|
33287
|
-
function analyzeBatch(statements) {
|
|
33288
|
-
if (statements.length === 0) {
|
|
33289
|
-
throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
|
|
33290
|
-
}
|
|
33291
|
-
if (statements.length === 1) {
|
|
33292
|
-
const t = statements[0].type;
|
|
33293
|
-
if (t === "SET_VARIABLE" || t === "DECLARE_VARIABLE") {
|
|
33294
|
-
const verb = t === "SET_VARIABLE" ? "SET" : "DECLARE";
|
|
33295
|
-
throw new BatchAnalysisError(`ArgumentError: ${verb} variable requires a batch.`, 0);
|
|
33296
|
-
}
|
|
33297
|
-
if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
|
|
33298
|
-
const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
|
|
33299
|
-
throw new BatchAnalysisError(
|
|
33300
|
-
`ArgumentError: ${verb} requires a batch (temp tables are batch-scoped).`,
|
|
33301
|
-
0
|
|
33302
|
-
);
|
|
33303
|
-
}
|
|
33304
|
-
}
|
|
33305
|
-
const defined = /* @__PURE__ */ new Map();
|
|
33306
|
-
const createdOrder = [];
|
|
33307
|
-
const results = [];
|
|
33308
|
-
const variableDefs = /* @__PURE__ */ new Map();
|
|
33309
|
-
const variableOrder = [];
|
|
33310
|
-
statements.forEach((stmt, index) => {
|
|
33311
|
-
const statementType = getStatementType(stmt);
|
|
33312
|
-
const created = [];
|
|
33313
|
-
const dropped = [];
|
|
33314
|
-
const refs = /* @__PURE__ */ new Set();
|
|
33315
|
-
const stmtAppIds = /* @__PURE__ */ new Set();
|
|
33316
|
-
const dependsOn = /* @__PURE__ */ new Set();
|
|
33317
|
-
const variableRefs = /* @__PURE__ */ new Set();
|
|
33318
|
-
collectVariableRefs(stmt, variableRefs);
|
|
33319
|
-
for (const name of variableRefs) {
|
|
33320
|
-
const def = variableDefs.get(name);
|
|
33321
|
-
if (def === void 0) {
|
|
33322
|
-
throw new BatchAnalysisError(
|
|
33323
|
-
`ParseError: variable @${name} is not defined before statement ${index + 1}.`,
|
|
33324
|
-
index
|
|
33325
|
-
);
|
|
33326
|
-
}
|
|
33327
|
-
def.referencedBy.push(index);
|
|
33328
|
-
}
|
|
33329
|
-
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
33330
|
-
if (variableDefs.has(stmt.name)) {
|
|
33331
|
-
throw new BatchAnalysisError(`ParseError: variable @${stmt.name} is already defined.`, index);
|
|
33332
|
-
}
|
|
33333
|
-
variableDefs.set(stmt.name, { index, referencedBy: [] });
|
|
33334
|
-
variableOrder.push(stmt.name);
|
|
33335
|
-
if (variableOrder.length > MAX_BATCH_VARIABLES) {
|
|
33336
|
-
throw new BatchAnalysisError(
|
|
33337
|
-
`ParseError: batch exceeds ${MAX_BATCH_VARIABLES} variables.`,
|
|
33338
|
-
index
|
|
33339
|
-
);
|
|
33340
|
-
}
|
|
33341
|
-
}
|
|
33342
|
-
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
33343
|
-
collectRefs(stmt.query, refs, stmtAppIds);
|
|
33344
|
-
} else if (stmt.type === "DROP_TEMP_TABLE") {
|
|
33345
|
-
} else {
|
|
33346
|
-
collectRefs(stmt, refs, stmtAppIds);
|
|
33347
|
-
}
|
|
33348
|
-
let tempOnlySource = false;
|
|
33349
|
-
if (stmt.type === "INSERT_SELECT" || stmt.type === "UPSERT_SELECT") {
|
|
33350
|
-
const srcTemp = /* @__PURE__ */ new Set();
|
|
33351
|
-
const srcApps = /* @__PURE__ */ new Set();
|
|
33352
|
-
collectRefs(stmt.select, srcTemp, srcApps);
|
|
33353
|
-
tempOnlySource = srcTemp.size > 0 && srcApps.size === 0;
|
|
33354
|
-
}
|
|
33355
|
-
for (const name of refs) {
|
|
33356
|
-
const at = defined.get(name);
|
|
33357
|
-
if (at === void 0) {
|
|
33358
|
-
throw new BatchAnalysisError(
|
|
33359
|
-
`ParseError: temp table ${name} is not defined in this batch.`,
|
|
33360
|
-
index
|
|
33361
|
-
);
|
|
33362
|
-
}
|
|
33363
|
-
dependsOn.add(at);
|
|
33364
|
-
}
|
|
33365
|
-
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
33366
|
-
if (defined.has(stmt.name)) {
|
|
33367
|
-
throw new BatchAnalysisError(
|
|
33368
|
-
`ParseError: temp table ${stmt.name} is already defined.`,
|
|
33369
|
-
index
|
|
33370
|
-
);
|
|
33371
|
-
}
|
|
33372
|
-
defined.set(stmt.name, index);
|
|
33373
|
-
createdOrder.push(stmt.name);
|
|
33374
|
-
created.push(stmt.name);
|
|
33375
|
-
if (defined.size > MAX_TEMP_TABLES) {
|
|
33376
|
-
throw new BatchAnalysisError(
|
|
33377
|
-
`ParseError: batch exceeds ${MAX_TEMP_TABLES} temp tables.`,
|
|
33378
|
-
index
|
|
33379
|
-
);
|
|
33380
|
-
}
|
|
33381
|
-
}
|
|
33382
|
-
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
33383
|
-
const at = defined.get(stmt.name);
|
|
33384
|
-
if (at === void 0) {
|
|
33385
|
-
throw new BatchAnalysisError(
|
|
33386
|
-
`ParseError: temp table ${stmt.name} is not defined in this batch.`,
|
|
33387
|
-
index
|
|
33388
|
-
);
|
|
33389
|
-
}
|
|
33390
|
-
dependsOn.add(at);
|
|
33391
|
-
dropped.push(stmt.name);
|
|
33392
|
-
defined.delete(stmt.name);
|
|
33393
|
-
}
|
|
33394
|
-
results.push({
|
|
33395
|
-
index,
|
|
33396
|
-
statementType,
|
|
33397
|
-
isDml: isDmlType(statementType),
|
|
33398
|
-
isReadOnly: isReadOnlyType(statementType),
|
|
33399
|
-
hasWhere: hasWhereClause(stmt),
|
|
33400
|
-
insertValuesCount: getInsertValuesCount(stmt),
|
|
33401
|
-
appIds: [...stmtAppIds].sort((a, b) => a - b),
|
|
33402
|
-
tempTablesCreated: created,
|
|
33403
|
-
tempTablesReferenced: [...refs],
|
|
33404
|
-
tempTablesDropped: dropped,
|
|
33405
|
-
dependsOn: [...dependsOn].sort((a, b) => a - b),
|
|
33406
|
-
tempOnlySource,
|
|
33407
|
-
targetAppId: isDmlType(statementType) && typeof stmt.appId === "number" ? stmt.appId : null
|
|
33408
|
-
});
|
|
33409
|
-
});
|
|
33410
|
-
const containsDml = results.some((r) => r.isDml);
|
|
33411
|
-
const variables = variableOrder.map((name) => ({
|
|
33412
|
-
name,
|
|
33413
|
-
referencedBy: [...variableDefs.get(name).referencedBy]
|
|
33414
|
-
}));
|
|
33415
|
-
return {
|
|
33416
|
-
statementCount: statements.length,
|
|
33417
|
-
isReadOnlyBatch: !containsDml && results.every((r) => r.isReadOnly),
|
|
33418
|
-
containsDml,
|
|
33419
|
-
tempTables: createdOrder,
|
|
33420
|
-
variables,
|
|
33421
|
-
warnings: variables.filter((v) => v.referencedBy.length === 0).map((v) => `variable @${v.name} is never used.`),
|
|
33422
|
-
statements: results
|
|
33423
|
-
};
|
|
33424
|
-
}
|
|
33425
|
-
|
|
33426
|
-
// src/core/batchVariables.ts
|
|
33427
|
-
var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
33428
|
-
function normalizeBatchVariableName(name) {
|
|
33429
|
-
if (!VARIABLE_NAME_RE.test(name)) {
|
|
33430
|
-
throw new Error(
|
|
33431
|
-
`ArgumentError: invalid variable name "${name}". Use a name without @ matching [A-Za-z_][A-Za-z0-9_]{0,63}.`
|
|
33432
|
-
);
|
|
33433
|
-
}
|
|
33434
|
-
return name.toLowerCase();
|
|
33435
|
-
}
|
|
33436
|
-
function normalizeBatchVariables(input) {
|
|
33437
|
-
const normalized = /* @__PURE__ */ Object.create(null);
|
|
33438
|
-
for (const [rawName, value] of Object.entries(input ?? {})) {
|
|
33439
|
-
const name = normalizeBatchVariableName(rawName);
|
|
33440
|
-
if (Object.prototype.hasOwnProperty.call(normalized, name)) {
|
|
33441
|
-
throw new Error(`ArgumentError: variable "${rawName}" is specified more than once.`);
|
|
33442
|
-
}
|
|
33443
|
-
normalized[name] = value;
|
|
33444
|
-
}
|
|
33445
|
-
return normalized;
|
|
33446
|
-
}
|
|
33447
|
-
function validateDeclaredBatchVariables(statements, input) {
|
|
33448
|
-
const normalized = normalizeBatchVariables(input);
|
|
33449
|
-
const declared = new Set(
|
|
33450
|
-
statements.filter((stmt) => stmt.type === "DECLARE_VARIABLE").map((stmt) => stmt.name)
|
|
33451
|
-
);
|
|
33452
|
-
for (const name of Object.keys(normalized)) {
|
|
33453
|
-
if (!declared.has(name)) {
|
|
33454
|
-
throw new Error(`ArgumentError: injected variable @${name} is not declared.`);
|
|
33455
|
-
}
|
|
33456
|
-
}
|
|
33457
|
-
return normalized;
|
|
33458
|
-
}
|
|
33459
|
-
|
|
33460
|
-
// src/core/scalarCompare.ts
|
|
33461
|
-
function compareScalarValues(op, leftStr, rightStr) {
|
|
33462
|
-
if (op === "=") return leftStr === rightStr;
|
|
33463
|
-
if (op === "!=" || op === "<>") return leftStr !== rightStr;
|
|
33464
|
-
const rightNum = Number(rightStr);
|
|
33465
|
-
if (leftStr === "" && rightStr !== "" && Number.isFinite(rightNum)) {
|
|
33466
|
-
return op === "<" || op === "<=";
|
|
33467
|
-
}
|
|
33468
|
-
const leftNum = Number(leftStr);
|
|
33469
|
-
const numeric = !Number.isNaN(leftNum) && !Number.isNaN(rightNum);
|
|
33470
|
-
switch (op) {
|
|
33471
|
-
case ">":
|
|
33472
|
-
return numeric ? leftNum > rightNum : leftStr > rightStr;
|
|
33473
|
-
case "<":
|
|
33474
|
-
return numeric ? leftNum < rightNum : leftStr < rightStr;
|
|
33475
|
-
case ">=":
|
|
33476
|
-
return numeric ? leftNum >= rightNum : leftStr >= rightStr;
|
|
33477
|
-
case "<=":
|
|
33478
|
-
return numeric ? leftNum <= rightNum : leftStr <= rightStr;
|
|
33479
|
-
}
|
|
33480
|
-
}
|
|
33481
|
-
|
|
33482
33275
|
// src/engine/pushDownNot.ts
|
|
33483
33276
|
function pushDownNot(expr) {
|
|
33484
33277
|
switch (expr.type) {
|
|
@@ -33528,6 +33321,10 @@ function negateOp(op) {
|
|
|
33528
33321
|
return "NOT_LIKE";
|
|
33529
33322
|
case "NOT_LIKE":
|
|
33530
33323
|
return "LIKE";
|
|
33324
|
+
case "KLIKE":
|
|
33325
|
+
return "NOT_KLIKE";
|
|
33326
|
+
case "NOT_KLIKE":
|
|
33327
|
+
return "KLIKE";
|
|
33531
33328
|
case "IN":
|
|
33532
33329
|
return "NOT_IN";
|
|
33533
33330
|
case "NOT_IN":
|
|
@@ -33542,6 +33339,9 @@ function likePatternHasWildcard(pattern) {
|
|
|
33542
33339
|
function isLike(where) {
|
|
33543
33340
|
return where.type === "BINARY" && (where.op === "LIKE" || where.op === "NOT_LIKE");
|
|
33544
33341
|
}
|
|
33342
|
+
function isKlike(where) {
|
|
33343
|
+
return where.type === "BINARY" && (where.op === "KLIKE" || where.op === "NOT_KLIKE");
|
|
33344
|
+
}
|
|
33545
33345
|
function whereHasLike(where) {
|
|
33546
33346
|
if (where === null) return false;
|
|
33547
33347
|
if (isLike(where)) return true;
|
|
@@ -33557,6 +33357,21 @@ function whereHasLike(where) {
|
|
|
33557
33357
|
return false;
|
|
33558
33358
|
}
|
|
33559
33359
|
}
|
|
33360
|
+
function whereHasKlike(where) {
|
|
33361
|
+
if (where === null) return false;
|
|
33362
|
+
if (isKlike(where)) return true;
|
|
33363
|
+
switch (where.type) {
|
|
33364
|
+
case "LOGICAL":
|
|
33365
|
+
return whereHasKlike(where.left) || whereHasKlike(where.right);
|
|
33366
|
+
case "NOT":
|
|
33367
|
+
case "GROUP":
|
|
33368
|
+
return whereHasKlike(where.expr);
|
|
33369
|
+
case "BINARY":
|
|
33370
|
+
case "NULL_CHECK":
|
|
33371
|
+
case "EXISTS":
|
|
33372
|
+
return false;
|
|
33373
|
+
}
|
|
33374
|
+
}
|
|
33560
33375
|
|
|
33561
33376
|
// src/converter/whereToKintone.ts
|
|
33562
33377
|
function whereToKintone(expr) {
|
|
@@ -33605,6 +33420,10 @@ function convertOp(op) {
|
|
|
33605
33420
|
return "like";
|
|
33606
33421
|
case "NOT_LIKE":
|
|
33607
33422
|
return "not like";
|
|
33423
|
+
case "KLIKE":
|
|
33424
|
+
return "like";
|
|
33425
|
+
case "NOT_KLIKE":
|
|
33426
|
+
return "not like";
|
|
33608
33427
|
case "IN":
|
|
33609
33428
|
return "in";
|
|
33610
33429
|
case "NOT_IN":
|
|
@@ -34198,6 +34017,434 @@ function isAggregateSyntheticName(name) {
|
|
|
34198
34017
|
return /^(COUNT|SUM|AVG|MAX|MIN)\(/i.test(name);
|
|
34199
34018
|
}
|
|
34200
34019
|
|
|
34020
|
+
// src/core/klikeValidation.ts
|
|
34021
|
+
var KlikeValidationError = class extends Error {
|
|
34022
|
+
constructor(message) {
|
|
34023
|
+
super(`ArgumentError: ${message}`);
|
|
34024
|
+
this.name = "ArgumentError";
|
|
34025
|
+
}
|
|
34026
|
+
};
|
|
34027
|
+
function validateKlikeStatement(stmt) {
|
|
34028
|
+
validateStatement(stmt);
|
|
34029
|
+
}
|
|
34030
|
+
function validateStatement(stmt) {
|
|
34031
|
+
switch (stmt.type) {
|
|
34032
|
+
case "SELECT":
|
|
34033
|
+
validateSelect(stmt);
|
|
34034
|
+
return;
|
|
34035
|
+
case "UNION":
|
|
34036
|
+
validateUnion(stmt);
|
|
34037
|
+
return;
|
|
34038
|
+
case "WITH":
|
|
34039
|
+
validateWith(stmt);
|
|
34040
|
+
return;
|
|
34041
|
+
case "EXPLAIN":
|
|
34042
|
+
validateStatement(stmt.query);
|
|
34043
|
+
return;
|
|
34044
|
+
case "CREATE_TEMP_TABLE":
|
|
34045
|
+
validateSelectLike(stmt.query);
|
|
34046
|
+
return;
|
|
34047
|
+
case "SET_VARIABLE":
|
|
34048
|
+
case "DECLARE_VARIABLE":
|
|
34049
|
+
case "ASSERT":
|
|
34050
|
+
validateNestedSelects(stmt);
|
|
34051
|
+
return;
|
|
34052
|
+
case "INSERT":
|
|
34053
|
+
case "INSERT_SELECT":
|
|
34054
|
+
case "UPSERT":
|
|
34055
|
+
case "UPSERT_SELECT":
|
|
34056
|
+
case "UPDATE":
|
|
34057
|
+
case "DELETE":
|
|
34058
|
+
case "REORDER":
|
|
34059
|
+
if (containsKlike(stmt)) {
|
|
34060
|
+
throw new KlikeValidationError(
|
|
34061
|
+
"KLIKE / NOT KLIKE \u306F v1 \u3067\u306F\u5168 DML\uFF08UPDATE / DELETE / INSERT / UPSERT / REORDER\uFF09\u3067\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
|
|
34062
|
+
);
|
|
34063
|
+
}
|
|
34064
|
+
return;
|
|
34065
|
+
case "SHOW_APPS":
|
|
34066
|
+
case "DESCRIBE":
|
|
34067
|
+
case "DROP_TEMP_TABLE":
|
|
34068
|
+
return;
|
|
34069
|
+
}
|
|
34070
|
+
}
|
|
34071
|
+
function validateSelectLike(query) {
|
|
34072
|
+
if (query.type === "SELECT") validateSelect(query);
|
|
34073
|
+
else if (query.type === "UNION") validateUnion(query);
|
|
34074
|
+
else validateWith(query);
|
|
34075
|
+
}
|
|
34076
|
+
function validateUnion(stmt) {
|
|
34077
|
+
validateSelectLike(stmt.left);
|
|
34078
|
+
validateSelect(stmt.right);
|
|
34079
|
+
}
|
|
34080
|
+
function validateWith(stmt) {
|
|
34081
|
+
const inlined = buildEffectiveInlineSelect(stmt);
|
|
34082
|
+
if (inlined !== null) {
|
|
34083
|
+
validateSelect(inlined);
|
|
34084
|
+
return;
|
|
34085
|
+
}
|
|
34086
|
+
for (const cte of stmt.ctes) {
|
|
34087
|
+
if (cte.query.type === "SELECT") validateSelect(cte.query);
|
|
34088
|
+
else if (cte.query.type === "UNION") validateUnion(cte.query);
|
|
34089
|
+
}
|
|
34090
|
+
validateSelectLike(stmt.query);
|
|
34091
|
+
}
|
|
34092
|
+
function validateSelect(stmt) {
|
|
34093
|
+
validateOwnKlikeExpressions(stmt);
|
|
34094
|
+
if (whereHasKlike(stmt.where)) {
|
|
34095
|
+
const inMemorySource = stmt.from.cteName !== null || stmt.joins.some((join) => join.table.cteName !== null);
|
|
34096
|
+
if (inMemorySource || resolveSelectMode(stmt) === "FULL_SCAN") {
|
|
34097
|
+
throw new KlikeValidationError(
|
|
34098
|
+
"KLIKE / NOT KLIKE \u306F kintone \u3078\u62BC\u3057\u4E0B\u3052\u308B SIMPLE SELECT \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002\u3053\u306E SELECT \u306F FULL_SCAN \u306B\u306A\u308A\u307E\u3059"
|
|
34099
|
+
);
|
|
34100
|
+
}
|
|
34101
|
+
}
|
|
34102
|
+
validateNestedSelects(stmt);
|
|
34103
|
+
}
|
|
34104
|
+
function validateOwnKlikeExpressions(stmt) {
|
|
34105
|
+
walkWithoutNestedSelects(stmt, (where) => {
|
|
34106
|
+
if (!isKlike(where)) return;
|
|
34107
|
+
if (!isDescendantOf(stmt.where, where)) {
|
|
34108
|
+
throw new KlikeValidationError("KLIKE / NOT KLIKE \u306F SELECT \u306E WHERE \u53E5\u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059");
|
|
34109
|
+
}
|
|
34110
|
+
const right = where.right;
|
|
34111
|
+
if (right.type !== "STRING" && right.type !== "VARIABLE") {
|
|
34112
|
+
throw new KlikeValidationError(
|
|
34113
|
+
"KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u6587\u5B57\u5217\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059"
|
|
34114
|
+
);
|
|
34115
|
+
}
|
|
34116
|
+
if (right.type === "STRING" && right.value.includes("%")) {
|
|
34117
|
+
throw new KlikeValidationError(
|
|
34118
|
+
"KLIKE / NOT KLIKE \u306E\u691C\u7D22\u8A9E\u306B % \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002SQL \u30EF\u30A4\u30EB\u30C9\u30AB\u30FC\u30C9\u691C\u7D22\u306B\u306F LIKE \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
34119
|
+
);
|
|
34120
|
+
}
|
|
34121
|
+
});
|
|
34122
|
+
}
|
|
34123
|
+
function validateNestedSelects(node) {
|
|
34124
|
+
walkObjects(node, (obj) => {
|
|
34125
|
+
if (obj.type === "SELECT") validateSelect(obj);
|
|
34126
|
+
}, true);
|
|
34127
|
+
}
|
|
34128
|
+
function buildEffectiveInlineSelect(stmt) {
|
|
34129
|
+
if (stmt.ctes.length !== 1) return null;
|
|
34130
|
+
const cte = stmt.ctes[0];
|
|
34131
|
+
if (cte.query.type !== "SELECT" || resolveSelectMode(cte.query) !== "SIMPLE") return null;
|
|
34132
|
+
if (stmt.query.type !== "SELECT") return null;
|
|
34133
|
+
const final = stmt.query;
|
|
34134
|
+
if (final.from.cteName !== cte.name || final.joins.length > 0) return null;
|
|
34135
|
+
if (final.groupBy.length > 0 || final.distinct) return null;
|
|
34136
|
+
if (final.columns.some(
|
|
34137
|
+
(column) => column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL"
|
|
34138
|
+
)) return null;
|
|
34139
|
+
const where = cte.query.where === null ? final.where : final.where === null ? cte.query.where : { type: "LOGICAL", op: "AND", left: cte.query.where, right: final.where };
|
|
34140
|
+
const columns = final.columns.every((column) => column.type === "WILDCARD") ? cte.query.columns : final.columns;
|
|
34141
|
+
return {
|
|
34142
|
+
type: "SELECT",
|
|
34143
|
+
from: cte.query.from,
|
|
34144
|
+
joins: [],
|
|
34145
|
+
columns,
|
|
34146
|
+
where,
|
|
34147
|
+
groupBy: [],
|
|
34148
|
+
having: null,
|
|
34149
|
+
orderBy: final.orderBy.length > 0 ? final.orderBy : cte.query.orderBy,
|
|
34150
|
+
limit: final.limit ?? cte.query.limit,
|
|
34151
|
+
offset: final.offset ?? cte.query.offset,
|
|
34152
|
+
distinct: false
|
|
34153
|
+
};
|
|
34154
|
+
}
|
|
34155
|
+
function containsKlike(node) {
|
|
34156
|
+
let found = false;
|
|
34157
|
+
walkObjects(node, (obj) => {
|
|
34158
|
+
if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) found = true;
|
|
34159
|
+
});
|
|
34160
|
+
return found;
|
|
34161
|
+
}
|
|
34162
|
+
function isDescendantOf(root, target) {
|
|
34163
|
+
if (root === null) return false;
|
|
34164
|
+
if (root === target) return true;
|
|
34165
|
+
switch (root.type) {
|
|
34166
|
+
case "LOGICAL":
|
|
34167
|
+
return isDescendantOf(root.left, target) || isDescendantOf(root.right, target);
|
|
34168
|
+
case "NOT":
|
|
34169
|
+
case "GROUP":
|
|
34170
|
+
return isDescendantOf(root.expr, target);
|
|
34171
|
+
case "BINARY":
|
|
34172
|
+
case "NULL_CHECK":
|
|
34173
|
+
case "EXISTS":
|
|
34174
|
+
return false;
|
|
34175
|
+
}
|
|
34176
|
+
}
|
|
34177
|
+
function walkWithoutNestedSelects(node, visitWhere) {
|
|
34178
|
+
if (Array.isArray(node)) {
|
|
34179
|
+
for (const value of node) walkWithoutNestedSelects(value, visitWhere);
|
|
34180
|
+
return;
|
|
34181
|
+
}
|
|
34182
|
+
if (node === null || typeof node !== "object") return;
|
|
34183
|
+
const obj = node;
|
|
34184
|
+
if (obj.type === "BINARY" || obj.type === "NULL_CHECK" || obj.type === "LOGICAL" || obj.type === "NOT" || obj.type === "GROUP" || obj.type === "EXISTS") {
|
|
34185
|
+
visitWhere(obj);
|
|
34186
|
+
}
|
|
34187
|
+
for (const value of Object.values(obj)) {
|
|
34188
|
+
if (value !== node && isSelectObject(value)) continue;
|
|
34189
|
+
walkWithoutNestedSelects(value, visitWhere);
|
|
34190
|
+
}
|
|
34191
|
+
}
|
|
34192
|
+
function walkObjects(node, visit, skipRoot = false) {
|
|
34193
|
+
if (Array.isArray(node)) {
|
|
34194
|
+
for (const value of node) walkObjects(value, visit);
|
|
34195
|
+
return;
|
|
34196
|
+
}
|
|
34197
|
+
if (node === null || typeof node !== "object") return;
|
|
34198
|
+
const obj = node;
|
|
34199
|
+
if (!skipRoot) visit(obj);
|
|
34200
|
+
for (const value of Object.values(obj)) walkObjects(value, visit);
|
|
34201
|
+
}
|
|
34202
|
+
function isSelectObject(value) {
|
|
34203
|
+
return value !== null && typeof value === "object" && value.type === "SELECT";
|
|
34204
|
+
}
|
|
34205
|
+
|
|
34206
|
+
// src/core/batch.ts
|
|
34207
|
+
var MAX_TEMP_TABLES = 16;
|
|
34208
|
+
var MAX_BATCH_VARIABLES = 64;
|
|
34209
|
+
var BatchAnalysisError = class extends Error {
|
|
34210
|
+
constructor(message, statementIndex) {
|
|
34211
|
+
super(message);
|
|
34212
|
+
this.statementIndex = statementIndex;
|
|
34213
|
+
}
|
|
34214
|
+
};
|
|
34215
|
+
function collectRefs(node, tempRefs, appIds) {
|
|
34216
|
+
if (Array.isArray(node)) {
|
|
34217
|
+
for (const v of node) collectRefs(v, tempRefs, appIds);
|
|
34218
|
+
return;
|
|
34219
|
+
}
|
|
34220
|
+
if (node !== null && typeof node === "object") {
|
|
34221
|
+
const obj = node;
|
|
34222
|
+
const cte = obj["cteName"];
|
|
34223
|
+
if (typeof cte === "string" && cte.startsWith("#")) tempRefs.add(cte);
|
|
34224
|
+
const appId = obj["appId"];
|
|
34225
|
+
if (typeof appId === "number" && appId > 0) appIds.add(appId);
|
|
34226
|
+
for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
|
|
34227
|
+
}
|
|
34228
|
+
}
|
|
34229
|
+
function collectVariableRefs(node, refs) {
|
|
34230
|
+
if (Array.isArray(node)) {
|
|
34231
|
+
for (const v of node) collectVariableRefs(v, refs);
|
|
34232
|
+
return;
|
|
34233
|
+
}
|
|
34234
|
+
if (node !== null && typeof node === "object") {
|
|
34235
|
+
const obj = node;
|
|
34236
|
+
if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
|
|
34237
|
+
refs.add(obj["name"]);
|
|
34238
|
+
return;
|
|
34239
|
+
}
|
|
34240
|
+
for (const v of Object.values(obj)) collectVariableRefs(v, refs);
|
|
34241
|
+
}
|
|
34242
|
+
}
|
|
34243
|
+
function analyzeBatch(statements) {
|
|
34244
|
+
if (statements.length === 0) {
|
|
34245
|
+
throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
|
|
34246
|
+
}
|
|
34247
|
+
statements.forEach((stmt, index) => {
|
|
34248
|
+
try {
|
|
34249
|
+
validateKlikeStatement(stmt);
|
|
34250
|
+
} catch (error51) {
|
|
34251
|
+
if (error51 instanceof KlikeValidationError) {
|
|
34252
|
+
throw new BatchAnalysisError(error51.message, index);
|
|
34253
|
+
}
|
|
34254
|
+
throw error51;
|
|
34255
|
+
}
|
|
34256
|
+
});
|
|
34257
|
+
if (statements.length === 1) {
|
|
34258
|
+
const t = statements[0].type;
|
|
34259
|
+
if (t === "SET_VARIABLE" || t === "DECLARE_VARIABLE") {
|
|
34260
|
+
const verb = t === "SET_VARIABLE" ? "SET" : "DECLARE";
|
|
34261
|
+
throw new BatchAnalysisError(`ArgumentError: ${verb} variable requires a batch.`, 0);
|
|
34262
|
+
}
|
|
34263
|
+
if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
|
|
34264
|
+
const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
|
|
34265
|
+
throw new BatchAnalysisError(
|
|
34266
|
+
`ArgumentError: ${verb} requires a batch (temp tables are batch-scoped).`,
|
|
34267
|
+
0
|
|
34268
|
+
);
|
|
34269
|
+
}
|
|
34270
|
+
}
|
|
34271
|
+
const defined = /* @__PURE__ */ new Map();
|
|
34272
|
+
const createdOrder = [];
|
|
34273
|
+
const results = [];
|
|
34274
|
+
const variableDefs = /* @__PURE__ */ new Map();
|
|
34275
|
+
const variableOrder = [];
|
|
34276
|
+
statements.forEach((stmt, index) => {
|
|
34277
|
+
const statementType = getStatementType(stmt);
|
|
34278
|
+
const created = [];
|
|
34279
|
+
const dropped = [];
|
|
34280
|
+
const refs = /* @__PURE__ */ new Set();
|
|
34281
|
+
const stmtAppIds = /* @__PURE__ */ new Set();
|
|
34282
|
+
const dependsOn = /* @__PURE__ */ new Set();
|
|
34283
|
+
const variableRefs = /* @__PURE__ */ new Set();
|
|
34284
|
+
collectVariableRefs(stmt, variableRefs);
|
|
34285
|
+
for (const name of variableRefs) {
|
|
34286
|
+
const def = variableDefs.get(name);
|
|
34287
|
+
if (def === void 0) {
|
|
34288
|
+
throw new BatchAnalysisError(
|
|
34289
|
+
`ParseError: variable @${name} is not defined before statement ${index + 1}.`,
|
|
34290
|
+
index
|
|
34291
|
+
);
|
|
34292
|
+
}
|
|
34293
|
+
def.referencedBy.push(index);
|
|
34294
|
+
}
|
|
34295
|
+
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
34296
|
+
if (variableDefs.has(stmt.name)) {
|
|
34297
|
+
throw new BatchAnalysisError(`ParseError: variable @${stmt.name} is already defined.`, index);
|
|
34298
|
+
}
|
|
34299
|
+
variableDefs.set(stmt.name, { index, referencedBy: [] });
|
|
34300
|
+
variableOrder.push(stmt.name);
|
|
34301
|
+
if (variableOrder.length > MAX_BATCH_VARIABLES) {
|
|
34302
|
+
throw new BatchAnalysisError(
|
|
34303
|
+
`ParseError: batch exceeds ${MAX_BATCH_VARIABLES} variables.`,
|
|
34304
|
+
index
|
|
34305
|
+
);
|
|
34306
|
+
}
|
|
34307
|
+
}
|
|
34308
|
+
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
34309
|
+
collectRefs(stmt.query, refs, stmtAppIds);
|
|
34310
|
+
} else if (stmt.type === "DROP_TEMP_TABLE") {
|
|
34311
|
+
} else {
|
|
34312
|
+
collectRefs(stmt, refs, stmtAppIds);
|
|
34313
|
+
}
|
|
34314
|
+
let tempOnlySource = false;
|
|
34315
|
+
if (stmt.type === "INSERT_SELECT" || stmt.type === "UPSERT_SELECT") {
|
|
34316
|
+
const srcTemp = /* @__PURE__ */ new Set();
|
|
34317
|
+
const srcApps = /* @__PURE__ */ new Set();
|
|
34318
|
+
collectRefs(stmt.select, srcTemp, srcApps);
|
|
34319
|
+
tempOnlySource = srcTemp.size > 0 && srcApps.size === 0;
|
|
34320
|
+
}
|
|
34321
|
+
for (const name of refs) {
|
|
34322
|
+
const at = defined.get(name);
|
|
34323
|
+
if (at === void 0) {
|
|
34324
|
+
throw new BatchAnalysisError(
|
|
34325
|
+
`ParseError: temp table ${name} is not defined in this batch.`,
|
|
34326
|
+
index
|
|
34327
|
+
);
|
|
34328
|
+
}
|
|
34329
|
+
dependsOn.add(at);
|
|
34330
|
+
}
|
|
34331
|
+
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
34332
|
+
if (defined.has(stmt.name)) {
|
|
34333
|
+
throw new BatchAnalysisError(
|
|
34334
|
+
`ParseError: temp table ${stmt.name} is already defined.`,
|
|
34335
|
+
index
|
|
34336
|
+
);
|
|
34337
|
+
}
|
|
34338
|
+
defined.set(stmt.name, index);
|
|
34339
|
+
createdOrder.push(stmt.name);
|
|
34340
|
+
created.push(stmt.name);
|
|
34341
|
+
if (defined.size > MAX_TEMP_TABLES) {
|
|
34342
|
+
throw new BatchAnalysisError(
|
|
34343
|
+
`ParseError: batch exceeds ${MAX_TEMP_TABLES} temp tables.`,
|
|
34344
|
+
index
|
|
34345
|
+
);
|
|
34346
|
+
}
|
|
34347
|
+
}
|
|
34348
|
+
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
34349
|
+
const at = defined.get(stmt.name);
|
|
34350
|
+
if (at === void 0) {
|
|
34351
|
+
throw new BatchAnalysisError(
|
|
34352
|
+
`ParseError: temp table ${stmt.name} is not defined in this batch.`,
|
|
34353
|
+
index
|
|
34354
|
+
);
|
|
34355
|
+
}
|
|
34356
|
+
dependsOn.add(at);
|
|
34357
|
+
dropped.push(stmt.name);
|
|
34358
|
+
defined.delete(stmt.name);
|
|
34359
|
+
}
|
|
34360
|
+
results.push({
|
|
34361
|
+
index,
|
|
34362
|
+
statementType,
|
|
34363
|
+
isDml: isDmlType(statementType),
|
|
34364
|
+
isReadOnly: isReadOnlyType(statementType),
|
|
34365
|
+
hasWhere: hasWhereClause(stmt),
|
|
34366
|
+
insertValuesCount: getInsertValuesCount(stmt),
|
|
34367
|
+
appIds: [...stmtAppIds].sort((a, b) => a - b),
|
|
34368
|
+
tempTablesCreated: created,
|
|
34369
|
+
tempTablesReferenced: [...refs],
|
|
34370
|
+
tempTablesDropped: dropped,
|
|
34371
|
+
dependsOn: [...dependsOn].sort((a, b) => a - b),
|
|
34372
|
+
tempOnlySource,
|
|
34373
|
+
targetAppId: isDmlType(statementType) && typeof stmt.appId === "number" ? stmt.appId : null
|
|
34374
|
+
});
|
|
34375
|
+
});
|
|
34376
|
+
const containsDml = results.some((r) => r.isDml);
|
|
34377
|
+
const variables = variableOrder.map((name) => ({
|
|
34378
|
+
name,
|
|
34379
|
+
referencedBy: [...variableDefs.get(name).referencedBy]
|
|
34380
|
+
}));
|
|
34381
|
+
return {
|
|
34382
|
+
statementCount: statements.length,
|
|
34383
|
+
isReadOnlyBatch: !containsDml && results.every((r) => r.isReadOnly),
|
|
34384
|
+
containsDml,
|
|
34385
|
+
tempTables: createdOrder,
|
|
34386
|
+
variables,
|
|
34387
|
+
warnings: variables.filter((v) => v.referencedBy.length === 0).map((v) => `variable @${v.name} is never used.`),
|
|
34388
|
+
statements: results
|
|
34389
|
+
};
|
|
34390
|
+
}
|
|
34391
|
+
|
|
34392
|
+
// src/core/batchVariables.ts
|
|
34393
|
+
var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
34394
|
+
function normalizeBatchVariableName(name) {
|
|
34395
|
+
if (!VARIABLE_NAME_RE.test(name)) {
|
|
34396
|
+
throw new Error(
|
|
34397
|
+
`ArgumentError: invalid variable name "${name}". Use a name without @ matching [A-Za-z_][A-Za-z0-9_]{0,63}.`
|
|
34398
|
+
);
|
|
34399
|
+
}
|
|
34400
|
+
return name.toLowerCase();
|
|
34401
|
+
}
|
|
34402
|
+
function normalizeBatchVariables(input) {
|
|
34403
|
+
const normalized = /* @__PURE__ */ Object.create(null);
|
|
34404
|
+
for (const [rawName, value] of Object.entries(input ?? {})) {
|
|
34405
|
+
const name = normalizeBatchVariableName(rawName);
|
|
34406
|
+
if (Object.prototype.hasOwnProperty.call(normalized, name)) {
|
|
34407
|
+
throw new Error(`ArgumentError: variable "${rawName}" is specified more than once.`);
|
|
34408
|
+
}
|
|
34409
|
+
normalized[name] = value;
|
|
34410
|
+
}
|
|
34411
|
+
return normalized;
|
|
34412
|
+
}
|
|
34413
|
+
function validateDeclaredBatchVariables(statements, input) {
|
|
34414
|
+
const normalized = normalizeBatchVariables(input);
|
|
34415
|
+
const declared = new Set(
|
|
34416
|
+
statements.filter((stmt) => stmt.type === "DECLARE_VARIABLE").map((stmt) => stmt.name)
|
|
34417
|
+
);
|
|
34418
|
+
for (const name of Object.keys(normalized)) {
|
|
34419
|
+
if (!declared.has(name)) {
|
|
34420
|
+
throw new Error(`ArgumentError: injected variable @${name} is not declared.`);
|
|
34421
|
+
}
|
|
34422
|
+
}
|
|
34423
|
+
return normalized;
|
|
34424
|
+
}
|
|
34425
|
+
|
|
34426
|
+
// src/core/scalarCompare.ts
|
|
34427
|
+
function compareScalarValues(op, leftStr, rightStr) {
|
|
34428
|
+
if (op === "=") return leftStr === rightStr;
|
|
34429
|
+
if (op === "!=" || op === "<>") return leftStr !== rightStr;
|
|
34430
|
+
const rightNum = Number(rightStr);
|
|
34431
|
+
if (leftStr === "" && rightStr !== "" && Number.isFinite(rightNum)) {
|
|
34432
|
+
return op === "<" || op === "<=";
|
|
34433
|
+
}
|
|
34434
|
+
const leftNum = Number(leftStr);
|
|
34435
|
+
const numeric = !Number.isNaN(leftNum) && !Number.isNaN(rightNum);
|
|
34436
|
+
switch (op) {
|
|
34437
|
+
case ">":
|
|
34438
|
+
return numeric ? leftNum > rightNum : leftStr > rightStr;
|
|
34439
|
+
case "<":
|
|
34440
|
+
return numeric ? leftNum < rightNum : leftStr < rightStr;
|
|
34441
|
+
case ">=":
|
|
34442
|
+
return numeric ? leftNum >= rightNum : leftStr >= rightStr;
|
|
34443
|
+
case "<=":
|
|
34444
|
+
return numeric ? leftNum <= rightNum : leftStr <= rightStr;
|
|
34445
|
+
}
|
|
34446
|
+
}
|
|
34447
|
+
|
|
34201
34448
|
// src/engine/evalFunc.ts
|
|
34202
34449
|
function evalArithExpr(expr, row) {
|
|
34203
34450
|
if (expr.type === "NUMBER") return expr.value;
|
|
@@ -34454,6 +34701,9 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
|
|
|
34454
34701
|
const pattern = resolveValue(right, row, resolveFieldType);
|
|
34455
34702
|
return !matchLike(leftStr, pattern);
|
|
34456
34703
|
}
|
|
34704
|
+
if (op === "KLIKE" || op === "NOT_KLIKE") {
|
|
34705
|
+
throw new Error("KLIKE / NOT KLIKE \u306F JavaScript \u5074\u3067\u306F\u8A55\u4FA1\u3067\u304D\u307E\u305B\u3093\uFF08SIMPLE SELECT \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059\uFF09");
|
|
34706
|
+
}
|
|
34457
34707
|
const rightStr = resolveValue(right, row, resolveFieldType);
|
|
34458
34708
|
return compareScalarValues(op, leftStr, rightStr);
|
|
34459
34709
|
}
|
|
@@ -34609,6 +34859,11 @@ function matchLike(value, pattern) {
|
|
|
34609
34859
|
|
|
34610
34860
|
// src/converter/dmlToKintone.ts
|
|
34611
34861
|
function assertDmlWhereIsSafe(where) {
|
|
34862
|
+
if (whereHasKlike(where)) {
|
|
34863
|
+
throw new DmlConvertError(
|
|
34864
|
+
"UPDATE / DELETE \u306E WHERE \u306B KLIKE / NOT KLIKE \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002kintone \u30AD\u30FC\u30EF\u30FC\u30C9\u691C\u7D22\u306E\u6253\u3061\u5207\u308A\u3092\u691C\u51FA\u3067\u304D\u306A\u3044\u305F\u3081\u3001v1 \u3067\u306F\u5168 DML \u3067\u5B89\u5168\u4E0A\u62D2\u5426\u3057\u307E\u3057\u305F\u3002"
|
|
34865
|
+
);
|
|
34866
|
+
}
|
|
34612
34867
|
if (!whereHasLike(where)) return;
|
|
34613
34868
|
throw new DmlConvertError(
|
|
34614
34869
|
"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"
|
|
@@ -35838,6 +36093,7 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
35838
36093
|
if (unresolved !== null) {
|
|
35839
36094
|
throw new Error(`ParseError: variable @${unresolved} is not defined in a batch.`);
|
|
35840
36095
|
}
|
|
36096
|
+
validateKlikeStatement(stmt);
|
|
35841
36097
|
switch (stmt.type) {
|
|
35842
36098
|
case "SELECT":
|
|
35843
36099
|
return executeSelect(stmt, client, options, cacheContext);
|
|
@@ -35974,6 +36230,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
35974
36230
|
async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables) {
|
|
35975
36231
|
if (stmt.type === "SET_VARIABLE") {
|
|
35976
36232
|
const resolvedStmt2 = resolveVariableRefs(stmt, variables);
|
|
36233
|
+
validateKlikeStatement(resolvedStmt2);
|
|
35977
36234
|
if (resolvedStmt2.expr.type === "SCALAR_SUBQUERY") {
|
|
35978
36235
|
try {
|
|
35979
36236
|
const value = await evaluateScalarSubquery(
|
|
@@ -36006,6 +36263,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
36006
36263
|
return {};
|
|
36007
36264
|
}
|
|
36008
36265
|
const resolvedStmt = resolveVariableRefs(stmt, variables);
|
|
36266
|
+
validateKlikeStatement(resolvedStmt);
|
|
36009
36267
|
if (resolvedStmt.type === "CREATE_TEMP_TABLE") {
|
|
36010
36268
|
const materializeOptions = {
|
|
36011
36269
|
...options,
|
|
@@ -37874,7 +38132,9 @@ async function executeDescribe(stmt, client, cacheContext) {
|
|
|
37874
38132
|
function parseSql(sql) {
|
|
37875
38133
|
try {
|
|
37876
38134
|
const tokens = new Lexer(sql).tokenize();
|
|
37877
|
-
|
|
38135
|
+
const stmt = new Parser(tokens).parse();
|
|
38136
|
+
validateKlikeStatement(stmt);
|
|
38137
|
+
return stmt;
|
|
37878
38138
|
} catch (e) {
|
|
37879
38139
|
if (e instanceof LexError || e instanceof ParseError) {
|
|
37880
38140
|
throw e;
|
|
@@ -37985,6 +38245,7 @@ function buildBatchExplainPlans(sql, injectedVariables) {
|
|
|
37985
38245
|
statementCount: statements.length,
|
|
37986
38246
|
statements: statements.map((stmt, i) => {
|
|
37987
38247
|
const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveVariableRefs(stmt.expr, variables) } : stmt : resolveVariableRefs(stmt, variables);
|
|
38248
|
+
validateKlikeStatement(planStmt);
|
|
37988
38249
|
const result = {
|
|
37989
38250
|
index: i,
|
|
37990
38251
|
type: analysis.statements[i].statementType,
|
|
@@ -38418,11 +38679,15 @@ var OperationCancelledError = class extends Error {
|
|
|
38418
38679
|
// src/core/sql.ts
|
|
38419
38680
|
function parseSqlStatement(sql) {
|
|
38420
38681
|
const tokens = new Lexer(sql).tokenize();
|
|
38421
|
-
|
|
38682
|
+
const stmt = new Parser(tokens).parse();
|
|
38683
|
+
validateKlikeStatement(stmt);
|
|
38684
|
+
return stmt;
|
|
38422
38685
|
}
|
|
38423
38686
|
function parseSqlStatements(sql) {
|
|
38424
38687
|
const tokens = new Lexer(sql).tokenize();
|
|
38425
|
-
|
|
38688
|
+
const statements = new Parser(tokens).parseStatements();
|
|
38689
|
+
statements.forEach(validateKlikeStatement);
|
|
38690
|
+
return statements;
|
|
38426
38691
|
}
|
|
38427
38692
|
|
|
38428
38693
|
// src/output/batchEnvelope.ts
|
|
@@ -40516,7 +40781,7 @@ Options:
|
|
|
40516
40781
|
-h, --help Show help
|
|
40517
40782
|
`);
|
|
40518
40783
|
}
|
|
40519
|
-
var SERVER_VERSION = true ? "2.
|
|
40784
|
+
var SERVER_VERSION = true ? "2.8.0" : "0.0.0-dev";
|
|
40520
40785
|
function createServer(args) {
|
|
40521
40786
|
const server = new McpServer({
|
|
40522
40787
|
name: "ksql-mcp",
|