@rex0220/kintone-sql-tools 2.6.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 +634 -303
- package/dist-mcp/ksql-mcp.js +577 -247
- 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"
|
|
@@ -35137,7 +35392,8 @@ var SELECTION_IN_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
35137
35392
|
"DROP_DOWN",
|
|
35138
35393
|
"RADIO_BUTTON",
|
|
35139
35394
|
"CHECK_BOX",
|
|
35140
|
-
"MULTI_SELECT"
|
|
35395
|
+
"MULTI_SELECT",
|
|
35396
|
+
"STATUS"
|
|
35141
35397
|
]);
|
|
35142
35398
|
function isSelectionInComparison(expr, options) {
|
|
35143
35399
|
if (!isSelectionInCandidate(expr, options)) return false;
|
|
@@ -35788,6 +36044,7 @@ function createEmptyMetrics() {
|
|
|
35788
36044
|
deleteCalls: 0,
|
|
35789
36045
|
fieldCalls: 0,
|
|
35790
36046
|
appsCalls: 0,
|
|
36047
|
+
processStatusCalls: 0,
|
|
35791
36048
|
fetchedRows: 0,
|
|
35792
36049
|
elapsedMs: 0
|
|
35793
36050
|
};
|
|
@@ -35819,6 +36076,10 @@ function wrapClientWithMetrics(client, metrics) {
|
|
|
35819
36076
|
getFields: (appId) => {
|
|
35820
36077
|
metrics.fieldCalls += 1;
|
|
35821
36078
|
return client.getFields(appId);
|
|
36079
|
+
},
|
|
36080
|
+
getProcessStatuses: (appId) => {
|
|
36081
|
+
metrics.processStatusCalls += 1;
|
|
36082
|
+
return client.getProcessStatuses(appId);
|
|
35822
36083
|
}
|
|
35823
36084
|
};
|
|
35824
36085
|
}
|
|
@@ -35832,6 +36093,7 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
35832
36093
|
if (unresolved !== null) {
|
|
35833
36094
|
throw new Error(`ParseError: variable @${unresolved} is not defined in a batch.`);
|
|
35834
36095
|
}
|
|
36096
|
+
validateKlikeStatement(stmt);
|
|
35835
36097
|
switch (stmt.type) {
|
|
35836
36098
|
case "SELECT":
|
|
35837
36099
|
return executeSelect(stmt, client, options, cacheContext);
|
|
@@ -35968,6 +36230,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
35968
36230
|
async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables) {
|
|
35969
36231
|
if (stmt.type === "SET_VARIABLE") {
|
|
35970
36232
|
const resolvedStmt2 = resolveVariableRefs(stmt, variables);
|
|
36233
|
+
validateKlikeStatement(resolvedStmt2);
|
|
35971
36234
|
if (resolvedStmt2.expr.type === "SCALAR_SUBQUERY") {
|
|
35972
36235
|
try {
|
|
35973
36236
|
const value = await evaluateScalarSubquery(
|
|
@@ -36000,6 +36263,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
36000
36263
|
return {};
|
|
36001
36264
|
}
|
|
36002
36265
|
const resolvedStmt = resolveVariableRefs(stmt, variables);
|
|
36266
|
+
validateKlikeStatement(resolvedStmt);
|
|
36003
36267
|
if (resolvedStmt.type === "CREATE_TEMP_TABLE") {
|
|
36004
36268
|
const materializeOptions = {
|
|
36005
36269
|
...options,
|
|
@@ -36425,22 +36689,36 @@ function extractMainTypedPushdownCandidate(stmt) {
|
|
|
36425
36689
|
return extractTypedPushdownCandidates(stmt.where, { tableAlias: stmt.from.alias });
|
|
36426
36690
|
}
|
|
36427
36691
|
async function loadTypedPushdownMeta(stmt, client, cacheContext) {
|
|
36428
|
-
const
|
|
36429
|
-
|
|
36692
|
+
const candidatesByApp = /* @__PURE__ */ new Map();
|
|
36693
|
+
const addCandidate = (appId, candidate) => {
|
|
36694
|
+
if (candidate === null) return;
|
|
36695
|
+
const existing = candidatesByApp.get(appId);
|
|
36696
|
+
if (existing) existing.push(candidate);
|
|
36697
|
+
else candidatesByApp.set(appId, [candidate]);
|
|
36698
|
+
};
|
|
36699
|
+
addCandidate(stmt.from.appId, extractMainTypedPushdownCandidate(stmt));
|
|
36430
36700
|
if (stmt.where !== null) {
|
|
36431
36701
|
for (const join of stmt.joins) {
|
|
36432
36702
|
if (!join.table.alias || join.table.subtableCode || join.table.cteName !== null) continue;
|
|
36433
36703
|
const candidate = extractTypedPushdownCandidates(stmt.where, {
|
|
36434
36704
|
tableAlias: join.table.alias
|
|
36435
36705
|
});
|
|
36436
|
-
|
|
36706
|
+
addCandidate(join.table.appId, candidate);
|
|
36437
36707
|
}
|
|
36438
36708
|
}
|
|
36439
|
-
const entries = await Promise.all([...
|
|
36709
|
+
const entries = await Promise.all([...candidatesByApp.entries()].map(async ([appId, candidates]) => {
|
|
36440
36710
|
const [fieldTypes, fieldOptions] = await Promise.all([
|
|
36441
36711
|
getFieldTypeMap(appId, client, cacheContext),
|
|
36442
36712
|
getFieldOptionSetMapByApp(appId, client, cacheContext)
|
|
36443
36713
|
]);
|
|
36714
|
+
const statusFields = collectCandidateFieldCodes(candidates).filter((fieldCode) => fieldTypes.get(fieldCode) === "STATUS");
|
|
36715
|
+
if (statusFields.length > 0) {
|
|
36716
|
+
const process4 = await getProcessStatusesCached(appId, client, cacheContext);
|
|
36717
|
+
if (process4.enable && process4.states.length > 0) {
|
|
36718
|
+
const states = new Set(process4.states);
|
|
36719
|
+
for (const fieldCode of statusFields) fieldOptions.set(fieldCode, states);
|
|
36720
|
+
}
|
|
36721
|
+
}
|
|
36444
36722
|
return [appId, fieldTypes, fieldOptions];
|
|
36445
36723
|
}));
|
|
36446
36724
|
return {
|
|
@@ -36448,6 +36726,23 @@ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
|
|
|
36448
36726
|
fieldOptionsByApp: new Map(entries.map(([appId, , fieldOptions]) => [appId, fieldOptions]))
|
|
36449
36727
|
};
|
|
36450
36728
|
}
|
|
36729
|
+
function collectCandidateFieldCodes(candidates) {
|
|
36730
|
+
const fields = /* @__PURE__ */ new Set();
|
|
36731
|
+
const visit = (expr) => {
|
|
36732
|
+
if (expr.type === "BINARY") {
|
|
36733
|
+
if (expr.left.type === "FIELD") fields.add(expr.left.field);
|
|
36734
|
+
return;
|
|
36735
|
+
}
|
|
36736
|
+
if (expr.type === "LOGICAL") {
|
|
36737
|
+
visit(expr.left);
|
|
36738
|
+
visit(expr.right);
|
|
36739
|
+
return;
|
|
36740
|
+
}
|
|
36741
|
+
if (expr.type === "GROUP" || expr.type === "NOT") visit(expr.expr);
|
|
36742
|
+
};
|
|
36743
|
+
for (const candidate of candidates) visit(candidate);
|
|
36744
|
+
return [...fields];
|
|
36745
|
+
}
|
|
36451
36746
|
function collectTypedInFieldRefs(expr, out) {
|
|
36452
36747
|
if (expr === null) return;
|
|
36453
36748
|
switch (expr.type) {
|
|
@@ -37073,6 +37368,7 @@ var fieldTypeCache = /* @__PURE__ */ new Map();
|
|
|
37073
37368
|
var optionOrderCache = /* @__PURE__ */ new Map();
|
|
37074
37369
|
var sortKindCache = /* @__PURE__ */ new Map();
|
|
37075
37370
|
var fieldInfoCache = /* @__PURE__ */ new Map();
|
|
37371
|
+
var processStatusCache = /* @__PURE__ */ new Map();
|
|
37076
37372
|
function getScopedCacheValue(root, cacheContext, appId) {
|
|
37077
37373
|
return root.get(cacheContext)?.get(appId);
|
|
37078
37374
|
}
|
|
@@ -37094,6 +37390,13 @@ async function getFieldsCached(appId, client, cacheContext) {
|
|
|
37094
37390
|
setScopedCacheValue(fieldInfoCache, cacheContext, appId, loading);
|
|
37095
37391
|
return loading;
|
|
37096
37392
|
}
|
|
37393
|
+
async function getProcessStatusesCached(appId, client, cacheContext) {
|
|
37394
|
+
const cached2 = getScopedCacheValue(processStatusCache, cacheContext, appId);
|
|
37395
|
+
if (cached2) return cached2;
|
|
37396
|
+
const loading = client.getProcessStatuses(appId);
|
|
37397
|
+
setScopedCacheValue(processStatusCache, cacheContext, appId, loading);
|
|
37398
|
+
return loading;
|
|
37399
|
+
}
|
|
37097
37400
|
async function getFieldTypeMap(appId, client, cacheContext) {
|
|
37098
37401
|
const cached2 = getScopedCacheValue(fieldTypeCache, cacheContext, appId);
|
|
37099
37402
|
if (cached2) return cached2;
|
|
@@ -37829,7 +38132,9 @@ async function executeDescribe(stmt, client, cacheContext) {
|
|
|
37829
38132
|
function parseSql(sql) {
|
|
37830
38133
|
try {
|
|
37831
38134
|
const tokens = new Lexer(sql).tokenize();
|
|
37832
|
-
|
|
38135
|
+
const stmt = new Parser(tokens).parse();
|
|
38136
|
+
validateKlikeStatement(stmt);
|
|
38137
|
+
return stmt;
|
|
37833
38138
|
} catch (e) {
|
|
37834
38139
|
if (e instanceof LexError || e instanceof ParseError) {
|
|
37835
38140
|
throw e;
|
|
@@ -37940,6 +38245,7 @@ function buildBatchExplainPlans(sql, injectedVariables) {
|
|
|
37940
38245
|
statementCount: statements.length,
|
|
37941
38246
|
statements: statements.map((stmt, i) => {
|
|
37942
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);
|
|
37943
38249
|
const result = {
|
|
37944
38250
|
index: i,
|
|
37945
38251
|
type: analysis.statements[i].statementType,
|
|
@@ -38373,11 +38679,15 @@ var OperationCancelledError = class extends Error {
|
|
|
38373
38679
|
// src/core/sql.ts
|
|
38374
38680
|
function parseSqlStatement(sql) {
|
|
38375
38681
|
const tokens = new Lexer(sql).tokenize();
|
|
38376
|
-
|
|
38682
|
+
const stmt = new Parser(tokens).parse();
|
|
38683
|
+
validateKlikeStatement(stmt);
|
|
38684
|
+
return stmt;
|
|
38377
38685
|
}
|
|
38378
38686
|
function parseSqlStatements(sql) {
|
|
38379
38687
|
const tokens = new Lexer(sql).tokenize();
|
|
38380
|
-
|
|
38688
|
+
const statements = new Parser(tokens).parseStatements();
|
|
38689
|
+
statements.forEach(validateKlikeStatement);
|
|
38690
|
+
return statements;
|
|
38381
38691
|
}
|
|
38382
38692
|
|
|
38383
38693
|
// src/output/batchEnvelope.ts
|
|
@@ -38755,6 +39065,7 @@ function withRequestGate(client, gate) {
|
|
|
38755
39065
|
getRecords: (params) => gate.runReadOnly(() => client.getRecords(params)),
|
|
38756
39066
|
getApps: () => gate.runReadOnly(() => client.getApps()),
|
|
38757
39067
|
getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
|
|
39068
|
+
getProcessStatuses: (appId) => gate.runReadOnly(() => client.getProcessStatuses(appId)),
|
|
38758
39069
|
postRecords: (params) => gate.runMutation(() => client.postRecords(params)),
|
|
38759
39070
|
putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
|
|
38760
39071
|
deleteRecords: (params) => gate.runMutation(() => client.deleteRecords(params))
|
|
@@ -38989,6 +39300,16 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
38989
39300
|
appId
|
|
38990
39301
|
);
|
|
38991
39302
|
return flattenFormFieldProperties(res.properties);
|
|
39303
|
+
},
|
|
39304
|
+
async getProcessStatuses(appId) {
|
|
39305
|
+
const qs = new URLSearchParams();
|
|
39306
|
+
qs.set("app", String(appId));
|
|
39307
|
+
qs.set("lang", "user");
|
|
39308
|
+
const res = await requestJson(`${apiBasePath}/app/status.json?${qs.toString()}`, { method: "GET" }, appId);
|
|
39309
|
+
return {
|
|
39310
|
+
enable: res.enable,
|
|
39311
|
+
states: Object.values(res.states ?? {}).map((state) => state.name)
|
|
39312
|
+
};
|
|
38992
39313
|
}
|
|
38993
39314
|
};
|
|
38994
39315
|
}
|
|
@@ -39496,6 +39817,12 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
39496
39817
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
|
|
39497
39818
|
return routed.getFields(binding.appId);
|
|
39498
39819
|
},
|
|
39820
|
+
getProcessStatuses: (appId) => {
|
|
39821
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, appId);
|
|
39822
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
39823
|
+
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
|
|
39824
|
+
return routed.getProcessStatuses(binding.appId);
|
|
39825
|
+
},
|
|
39499
39826
|
getApps: () => defaultClient.getApps()
|
|
39500
39827
|
};
|
|
39501
39828
|
const gatedClient = withRequestGate(
|
|
@@ -39720,7 +40047,10 @@ function noOpClient() {
|
|
|
39720
40047
|
putRecords: fail,
|
|
39721
40048
|
deleteRecords: fail,
|
|
39722
40049
|
getApps: fail,
|
|
39723
|
-
getFields: fail
|
|
40050
|
+
getFields: fail,
|
|
40051
|
+
async getProcessStatuses() {
|
|
40052
|
+
return { enable: false, states: [] };
|
|
40053
|
+
}
|
|
39724
40054
|
};
|
|
39725
40055
|
}
|
|
39726
40056
|
function getServerConfigPath(serverOptions) {
|
|
@@ -40451,7 +40781,7 @@ Options:
|
|
|
40451
40781
|
-h, --help Show help
|
|
40452
40782
|
`);
|
|
40453
40783
|
}
|
|
40454
|
-
var SERVER_VERSION = true ? "2.
|
|
40784
|
+
var SERVER_VERSION = true ? "2.8.0" : "0.0.0-dev";
|
|
40455
40785
|
function createServer(args) {
|
|
40456
40786
|
const server = new McpServer({
|
|
40457
40787
|
name: "ksql-mcp",
|