@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.
@@ -1811,7 +1811,7 @@ var require_code2 = __commonJS({
1811
1811
  }
1812
1812
  }
1813
1813
  exports2.validateArray = validateArray;
1814
- function validateUnion(cxt) {
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 = 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 \u307E\u305F\u306F LIKE \u304C\u5FC5\u8981\u3067\u3059",
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
- return new Parser(tokens).parse();
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
- return new Parser(tokens).parse();
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
- return new Parser(tokens).parseStatements();
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.7.0" : "0.0.0-dev";
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",