@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 CHANGED
@@ -94,6 +94,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
94
94
  ["IS", "IS" /* IS */],
95
95
  ["NULL", "NULL" /* NULL */],
96
96
  ["LIKE", "LIKE" /* LIKE */],
97
+ ["KLIKE", "KLIKE" /* KLIKE */],
97
98
  ["IN", "IN" /* IN */],
98
99
  ["BETWEEN", "BETWEEN" /* BETWEEN */],
99
100
  ["TODAY", "TODAY" /* TODAY */],
@@ -1619,7 +1620,7 @@ var Parser = class {
1619
1620
  }
1620
1621
  return false;
1621
1622
  }
1622
- // 比較演算子: =, !=, <>, >, <, >=, <=, LIKE, IN, IS NULL
1623
+ // 比較演算子: =, !=, <>, >, <, >=, <=, LIKE, KLIKE, IN, IS NULL
1623
1624
  parseCompareExpr() {
1624
1625
  if (this.peek().kind === "(" /* LPAREN */ && !this.isArithParen()) {
1625
1626
  this.advance();
@@ -1655,8 +1656,12 @@ var Parser = class {
1655
1656
  const pattern = this.parseSqlValue();
1656
1657
  return { type: "BINARY", op: "NOT_LIKE", left: field, right: pattern };
1657
1658
  }
1659
+ if (this.consume("KLIKE" /* KLIKE */)) {
1660
+ const pattern = this.parseKlikePattern();
1661
+ return { type: "BINARY", op: "NOT_KLIKE", left: field, right: pattern };
1662
+ }
1658
1663
  throw new ParseError(
1659
- "NOT \u306E\u5F8C\u306B\u306F IN \u307E\u305F\u306F LIKE \u304C\u5FC5\u8981\u3067\u3059",
1664
+ "NOT \u306E\u5F8C\u306B\u306F IN\u3001LIKE\u3001KLIKE \u306E\u3044\u305A\u308C\u304B\u304C\u5FC5\u8981\u3067\u3059",
1660
1665
  this.peek()
1661
1666
  );
1662
1667
  }
@@ -1666,6 +1671,10 @@ var Parser = class {
1666
1671
  this.expect(")" /* RPAREN */);
1667
1672
  return { type: "BINARY", op: "IN", left: field, right: right2 };
1668
1673
  }
1674
+ if (this.consume("KLIKE" /* KLIKE */)) {
1675
+ const pattern = this.parseKlikePattern();
1676
+ return { type: "BINARY", op: "KLIKE", left: field, right: pattern };
1677
+ }
1669
1678
  const op = this.parseCompareOp();
1670
1679
  const right = this.parseSqlValue();
1671
1680
  return { type: "BINARY", op, left: field, right };
@@ -1691,11 +1700,27 @@ var Parser = class {
1691
1700
  return "LIKE";
1692
1701
  default:
1693
1702
  throw new ParseError(
1694
- "\u6BD4\u8F03\u6F14\u7B97\u5B50\uFF08=, !=, >, <, >=, <=, LIKE, IN, IS\uFF09\u304C\u5FC5\u8981\u3067\u3059",
1703
+ "\u6BD4\u8F03\u6F14\u7B97\u5B50\uFF08=, !=, >, <, >=, <=, LIKE, KLIKE, IN, IS\uFF09\u304C\u5FC5\u8981\u3067\u3059",
1695
1704
  tok
1696
1705
  );
1697
1706
  }
1698
1707
  }
1708
+ /** KLIKE / NOT KLIKE の右辺。kintone キーワードは文字列値だけを受け付ける。 */
1709
+ parseKlikePattern() {
1710
+ const tok = this.peek();
1711
+ if (tok.kind === "STRING" /* STRING */) {
1712
+ this.advance();
1713
+ return { type: "STRING", value: tok.value };
1714
+ }
1715
+ if (tok.kind === "VARIABLE" /* VARIABLE */) {
1716
+ this.advance();
1717
+ return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
1718
+ }
1719
+ throw new ParseError(
1720
+ "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",
1721
+ tok
1722
+ );
1723
+ }
1699
1724
  // WHERE / HAVING の左辺
1700
1725
  // - 文字列・数値関数: UPPER(f) / LENGTH(f) / ROUND(f, 2) ...
1701
1726
  // - 集計関数(HAVING のみ): COUNT(*) / SUM(f) ...
@@ -2346,238 +2371,6 @@ function collectDmlTargetFields(stmt) {
2346
2371
  return [];
2347
2372
  }
2348
2373
 
2349
- // src/core/batch.ts
2350
- var MAX_TEMP_TABLES = 16;
2351
- var MAX_BATCH_VARIABLES = 64;
2352
- var BatchAnalysisError = class extends Error {
2353
- constructor(message, statementIndex) {
2354
- super(message);
2355
- this.statementIndex = statementIndex;
2356
- }
2357
- };
2358
- function collectRefs(node, tempRefs, appIds) {
2359
- if (Array.isArray(node)) {
2360
- for (const v of node) collectRefs(v, tempRefs, appIds);
2361
- return;
2362
- }
2363
- if (node !== null && typeof node === "object") {
2364
- const obj = node;
2365
- const cte = obj["cteName"];
2366
- if (typeof cte === "string" && cte.startsWith("#")) tempRefs.add(cte);
2367
- const appId = obj["appId"];
2368
- if (typeof appId === "number" && appId > 0) appIds.add(appId);
2369
- for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
2370
- }
2371
- }
2372
- function collectVariableRefs(node, refs) {
2373
- if (Array.isArray(node)) {
2374
- for (const v of node) collectVariableRefs(v, refs);
2375
- return;
2376
- }
2377
- if (node !== null && typeof node === "object") {
2378
- const obj = node;
2379
- if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
2380
- refs.add(obj["name"]);
2381
- return;
2382
- }
2383
- for (const v of Object.values(obj)) collectVariableRefs(v, refs);
2384
- }
2385
- }
2386
- function analyzeBatch(statements) {
2387
- if (statements.length === 0) {
2388
- throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
2389
- }
2390
- if (statements.length === 1) {
2391
- const t = statements[0].type;
2392
- if (t === "SET_VARIABLE" || t === "DECLARE_VARIABLE") {
2393
- const verb = t === "SET_VARIABLE" ? "SET" : "DECLARE";
2394
- throw new BatchAnalysisError(`ArgumentError: ${verb} variable requires a batch.`, 0);
2395
- }
2396
- if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
2397
- const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
2398
- throw new BatchAnalysisError(
2399
- `ArgumentError: ${verb} requires a batch (temp tables are batch-scoped).`,
2400
- 0
2401
- );
2402
- }
2403
- }
2404
- const defined = /* @__PURE__ */ new Map();
2405
- const createdOrder = [];
2406
- const results = [];
2407
- const variableDefs = /* @__PURE__ */ new Map();
2408
- const variableOrder = [];
2409
- statements.forEach((stmt, index) => {
2410
- const statementType = getStatementType(stmt);
2411
- const created = [];
2412
- const dropped = [];
2413
- const refs = /* @__PURE__ */ new Set();
2414
- const stmtAppIds = /* @__PURE__ */ new Set();
2415
- const dependsOn = /* @__PURE__ */ new Set();
2416
- const variableRefs = /* @__PURE__ */ new Set();
2417
- collectVariableRefs(stmt, variableRefs);
2418
- for (const name of variableRefs) {
2419
- const def = variableDefs.get(name);
2420
- if (def === void 0) {
2421
- throw new BatchAnalysisError(
2422
- `ParseError: variable @${name} is not defined before statement ${index + 1}.`,
2423
- index
2424
- );
2425
- }
2426
- def.referencedBy.push(index);
2427
- }
2428
- if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
2429
- if (variableDefs.has(stmt.name)) {
2430
- throw new BatchAnalysisError(`ParseError: variable @${stmt.name} is already defined.`, index);
2431
- }
2432
- variableDefs.set(stmt.name, { index, referencedBy: [] });
2433
- variableOrder.push(stmt.name);
2434
- if (variableOrder.length > MAX_BATCH_VARIABLES) {
2435
- throw new BatchAnalysisError(
2436
- `ParseError: batch exceeds ${MAX_BATCH_VARIABLES} variables.`,
2437
- index
2438
- );
2439
- }
2440
- }
2441
- if (stmt.type === "CREATE_TEMP_TABLE") {
2442
- collectRefs(stmt.query, refs, stmtAppIds);
2443
- } else if (stmt.type === "DROP_TEMP_TABLE") {
2444
- } else {
2445
- collectRefs(stmt, refs, stmtAppIds);
2446
- }
2447
- let tempOnlySource = false;
2448
- if (stmt.type === "INSERT_SELECT" || stmt.type === "UPSERT_SELECT") {
2449
- const srcTemp = /* @__PURE__ */ new Set();
2450
- const srcApps = /* @__PURE__ */ new Set();
2451
- collectRefs(stmt.select, srcTemp, srcApps);
2452
- tempOnlySource = srcTemp.size > 0 && srcApps.size === 0;
2453
- }
2454
- for (const name of refs) {
2455
- const at = defined.get(name);
2456
- if (at === void 0) {
2457
- throw new BatchAnalysisError(
2458
- `ParseError: temp table ${name} is not defined in this batch.`,
2459
- index
2460
- );
2461
- }
2462
- dependsOn.add(at);
2463
- }
2464
- if (stmt.type === "CREATE_TEMP_TABLE") {
2465
- if (defined.has(stmt.name)) {
2466
- throw new BatchAnalysisError(
2467
- `ParseError: temp table ${stmt.name} is already defined.`,
2468
- index
2469
- );
2470
- }
2471
- defined.set(stmt.name, index);
2472
- createdOrder.push(stmt.name);
2473
- created.push(stmt.name);
2474
- if (defined.size > MAX_TEMP_TABLES) {
2475
- throw new BatchAnalysisError(
2476
- `ParseError: batch exceeds ${MAX_TEMP_TABLES} temp tables.`,
2477
- index
2478
- );
2479
- }
2480
- }
2481
- if (stmt.type === "DROP_TEMP_TABLE") {
2482
- const at = defined.get(stmt.name);
2483
- if (at === void 0) {
2484
- throw new BatchAnalysisError(
2485
- `ParseError: temp table ${stmt.name} is not defined in this batch.`,
2486
- index
2487
- );
2488
- }
2489
- dependsOn.add(at);
2490
- dropped.push(stmt.name);
2491
- defined.delete(stmt.name);
2492
- }
2493
- results.push({
2494
- index,
2495
- statementType,
2496
- isDml: isDmlType(statementType),
2497
- isReadOnly: isReadOnlyType(statementType),
2498
- hasWhere: hasWhereClause(stmt),
2499
- insertValuesCount: getInsertValuesCount(stmt),
2500
- appIds: [...stmtAppIds].sort((a, b) => a - b),
2501
- tempTablesCreated: created,
2502
- tempTablesReferenced: [...refs],
2503
- tempTablesDropped: dropped,
2504
- dependsOn: [...dependsOn].sort((a, b) => a - b),
2505
- tempOnlySource,
2506
- targetAppId: isDmlType(statementType) && typeof stmt.appId === "number" ? stmt.appId : null
2507
- });
2508
- });
2509
- const containsDml = results.some((r) => r.isDml);
2510
- const variables = variableOrder.map((name) => ({
2511
- name,
2512
- referencedBy: [...variableDefs.get(name).referencedBy]
2513
- }));
2514
- return {
2515
- statementCount: statements.length,
2516
- isReadOnlyBatch: !containsDml && results.every((r) => r.isReadOnly),
2517
- containsDml,
2518
- tempTables: createdOrder,
2519
- variables,
2520
- warnings: variables.filter((v) => v.referencedBy.length === 0).map((v) => `variable @${v.name} is never used.`),
2521
- statements: results
2522
- };
2523
- }
2524
-
2525
- // src/core/batchVariables.ts
2526
- var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
2527
- function normalizeBatchVariableName(name) {
2528
- if (!VARIABLE_NAME_RE.test(name)) {
2529
- throw new Error(
2530
- `ArgumentError: invalid variable name "${name}". Use a name without @ matching [A-Za-z_][A-Za-z0-9_]{0,63}.`
2531
- );
2532
- }
2533
- return name.toLowerCase();
2534
- }
2535
- function normalizeBatchVariables(input) {
2536
- const normalized = /* @__PURE__ */ Object.create(null);
2537
- for (const [rawName, value] of Object.entries(input ?? {})) {
2538
- const name = normalizeBatchVariableName(rawName);
2539
- if (Object.prototype.hasOwnProperty.call(normalized, name)) {
2540
- throw new Error(`ArgumentError: variable "${rawName}" is specified more than once.`);
2541
- }
2542
- normalized[name] = value;
2543
- }
2544
- return normalized;
2545
- }
2546
- function validateDeclaredBatchVariables(statements, input) {
2547
- const normalized = normalizeBatchVariables(input);
2548
- const declared = new Set(
2549
- statements.filter((stmt) => stmt.type === "DECLARE_VARIABLE").map((stmt) => stmt.name)
2550
- );
2551
- for (const name of Object.keys(normalized)) {
2552
- if (!declared.has(name)) {
2553
- throw new Error(`ArgumentError: injected variable @${name} is not declared.`);
2554
- }
2555
- }
2556
- return normalized;
2557
- }
2558
-
2559
- // src/core/scalarCompare.ts
2560
- function compareScalarValues(op, leftStr, rightStr) {
2561
- if (op === "=") return leftStr === rightStr;
2562
- if (op === "!=" || op === "<>") return leftStr !== rightStr;
2563
- const rightNum = Number(rightStr);
2564
- if (leftStr === "" && rightStr !== "" && Number.isFinite(rightNum)) {
2565
- return op === "<" || op === "<=";
2566
- }
2567
- const leftNum = Number(leftStr);
2568
- const numeric = !Number.isNaN(leftNum) && !Number.isNaN(rightNum);
2569
- switch (op) {
2570
- case ">":
2571
- return numeric ? leftNum > rightNum : leftStr > rightStr;
2572
- case "<":
2573
- return numeric ? leftNum < rightNum : leftStr < rightStr;
2574
- case ">=":
2575
- return numeric ? leftNum >= rightNum : leftStr >= rightStr;
2576
- case "<=":
2577
- return numeric ? leftNum <= rightNum : leftStr <= rightStr;
2578
- }
2579
- }
2580
-
2581
2374
  // src/engine/pushDownNot.ts
2582
2375
  function pushDownNot(expr) {
2583
2376
  switch (expr.type) {
@@ -2627,6 +2420,10 @@ function negateOp(op) {
2627
2420
  return "NOT_LIKE";
2628
2421
  case "NOT_LIKE":
2629
2422
  return "LIKE";
2423
+ case "KLIKE":
2424
+ return "NOT_KLIKE";
2425
+ case "NOT_KLIKE":
2426
+ return "KLIKE";
2630
2427
  case "IN":
2631
2428
  return "NOT_IN";
2632
2429
  case "NOT_IN":
@@ -2641,6 +2438,9 @@ function likePatternHasWildcard(pattern) {
2641
2438
  function isLike(where) {
2642
2439
  return where.type === "BINARY" && (where.op === "LIKE" || where.op === "NOT_LIKE");
2643
2440
  }
2441
+ function isKlike(where) {
2442
+ return where.type === "BINARY" && (where.op === "KLIKE" || where.op === "NOT_KLIKE");
2443
+ }
2644
2444
  function whereHasLike(where) {
2645
2445
  if (where === null) return false;
2646
2446
  if (isLike(where)) return true;
@@ -2656,6 +2456,21 @@ function whereHasLike(where) {
2656
2456
  return false;
2657
2457
  }
2658
2458
  }
2459
+ function whereHasKlike(where) {
2460
+ if (where === null) return false;
2461
+ if (isKlike(where)) return true;
2462
+ switch (where.type) {
2463
+ case "LOGICAL":
2464
+ return whereHasKlike(where.left) || whereHasKlike(where.right);
2465
+ case "NOT":
2466
+ case "GROUP":
2467
+ return whereHasKlike(where.expr);
2468
+ case "BINARY":
2469
+ case "NULL_CHECK":
2470
+ case "EXISTS":
2471
+ return false;
2472
+ }
2473
+ }
2659
2474
 
2660
2475
  // src/converter/whereToKintone.ts
2661
2476
  function whereToKintone(expr) {
@@ -2704,6 +2519,10 @@ function convertOp(op) {
2704
2519
  return "like";
2705
2520
  case "NOT_LIKE":
2706
2521
  return "not like";
2522
+ case "KLIKE":
2523
+ return "like";
2524
+ case "NOT_KLIKE":
2525
+ return "not like";
2707
2526
  case "IN":
2708
2527
  return "in";
2709
2528
  case "NOT_IN":
@@ -3225,76 +3044,504 @@ function collectRequiredFieldsByTable(stmt) {
3225
3044
  break;
3226
3045
  }
3227
3046
  }
3228
- for (const join2 of stmt.joins) {
3229
- addFieldRef(join2.on.left.field, join2.on.left.tableAlias, "where");
3230
- addFieldRef(join2.on.right.field, join2.on.right.tableAlias, "where");
3047
+ for (const join2 of stmt.joins) {
3048
+ addFieldRef(join2.on.left.field, join2.on.left.tableAlias, "where");
3049
+ addFieldRef(join2.on.right.field, join2.on.right.tableAlias, "where");
3050
+ }
3051
+ walkWhere(stmt.where, "where");
3052
+ for (const gk of stmt.groupBy) walkGroupByKey(gk);
3053
+ walkWhere(stmt.having, "having");
3054
+ for (const ob of stmt.orderBy) walkOrderByKey(ob.key);
3055
+ return states;
3056
+ }
3057
+ function collectSelectOutputNames(columns) {
3058
+ const names = /* @__PURE__ */ new Set();
3059
+ for (const col of columns) {
3060
+ if (col.type === "FIELD" && col.alias) {
3061
+ names.add(col.alias);
3062
+ continue;
3063
+ }
3064
+ if (col.type === "LITERAL_COL") {
3065
+ names.add(col.alias ?? `'${col.value}'`);
3066
+ continue;
3067
+ }
3068
+ if (col.type === "AGGREGATE") {
3069
+ if (col.alias) names.add(col.alias);
3070
+ else names.add(aggregateSyntheticName(col.func, col.distinct, col.arg));
3071
+ continue;
3072
+ }
3073
+ if (col.type === "ARITH_AGG_COL") {
3074
+ if (col.alias) names.add(col.alias);
3075
+ continue;
3076
+ }
3077
+ if (col.type === "ARITH_COL") {
3078
+ if (col.alias) names.add(col.alias);
3079
+ continue;
3080
+ }
3081
+ if (col.type === "CASE_COL") {
3082
+ names.add(col.alias ?? "case");
3083
+ continue;
3084
+ }
3085
+ if (col.type === "STRFUNC_COL") {
3086
+ if (col.alias) names.add(col.alias);
3087
+ continue;
3088
+ }
3089
+ if (col.type === "SCALAR_SUBQUERY_COL") {
3090
+ names.add(col.alias ?? "(subquery)");
3091
+ }
3092
+ }
3093
+ return names;
3094
+ }
3095
+ function aggregateSyntheticName(func, distinct, arg) {
3096
+ const argStr = arg.type === "WILDCARD" ? "*" : arithNodeLabel(arg);
3097
+ return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
3098
+ }
3099
+ function arithNodeLabel(node) {
3100
+ if (node.type === "FIELD_REF") return node.field;
3101
+ if (node.type === "NUMBER") return String(node.value);
3102
+ if (node.type === "STRING_FUNC") return stringFuncLabel(node);
3103
+ return `(${arithNodeLabel(node.left)}${node.op}${arithNodeLabel(node.right)})`;
3104
+ }
3105
+ function stringFuncLabel(expr) {
3106
+ const args = expr.args.map((a) => {
3107
+ if (a.type === "STRING") return `'${a.value}'`;
3108
+ if (a.type === "STRING_FUNC") return stringFuncLabel(a);
3109
+ if (a.type === "AGG_REF") return aggregateSyntheticName(a.func, a.distinct, a.arg);
3110
+ if (a.type === "AGG_ARITH") return "agg_arith";
3111
+ return arithNodeLabel(a);
3112
+ });
3113
+ return `${expr.func}(${args.join(",")})`;
3114
+ }
3115
+ function isAggregateSyntheticName(name) {
3116
+ return /^(COUNT|SUM|AVG|MAX|MIN)\(/i.test(name);
3117
+ }
3118
+
3119
+ // src/core/klikeValidation.ts
3120
+ var KlikeValidationError = class extends Error {
3121
+ constructor(message) {
3122
+ super(`ArgumentError: ${message}`);
3123
+ this.name = "ArgumentError";
3124
+ }
3125
+ };
3126
+ function validateKlikeStatement(stmt) {
3127
+ validateStatement(stmt);
3128
+ }
3129
+ function validateStatement(stmt) {
3130
+ switch (stmt.type) {
3131
+ case "SELECT":
3132
+ validateSelect(stmt);
3133
+ return;
3134
+ case "UNION":
3135
+ validateUnion(stmt);
3136
+ return;
3137
+ case "WITH":
3138
+ validateWith(stmt);
3139
+ return;
3140
+ case "EXPLAIN":
3141
+ validateStatement(stmt.query);
3142
+ return;
3143
+ case "CREATE_TEMP_TABLE":
3144
+ validateSelectLike(stmt.query);
3145
+ return;
3146
+ case "SET_VARIABLE":
3147
+ case "DECLARE_VARIABLE":
3148
+ case "ASSERT":
3149
+ validateNestedSelects(stmt);
3150
+ return;
3151
+ case "INSERT":
3152
+ case "INSERT_SELECT":
3153
+ case "UPSERT":
3154
+ case "UPSERT_SELECT":
3155
+ case "UPDATE":
3156
+ case "DELETE":
3157
+ case "REORDER":
3158
+ if (containsKlike(stmt)) {
3159
+ throw new KlikeValidationError(
3160
+ "KLIKE / NOT KLIKE \u306F v1 \u3067\u306F\u5168 DML\uFF08UPDATE / DELETE / INSERT / UPSERT / REORDER\uFF09\u3067\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
3161
+ );
3162
+ }
3163
+ return;
3164
+ case "SHOW_APPS":
3165
+ case "DESCRIBE":
3166
+ case "DROP_TEMP_TABLE":
3167
+ return;
3168
+ }
3169
+ }
3170
+ function validateSelectLike(query) {
3171
+ if (query.type === "SELECT") validateSelect(query);
3172
+ else if (query.type === "UNION") validateUnion(query);
3173
+ else validateWith(query);
3174
+ }
3175
+ function validateUnion(stmt) {
3176
+ validateSelectLike(stmt.left);
3177
+ validateSelect(stmt.right);
3178
+ }
3179
+ function validateWith(stmt) {
3180
+ const inlined = buildEffectiveInlineSelect(stmt);
3181
+ if (inlined !== null) {
3182
+ validateSelect(inlined);
3183
+ return;
3184
+ }
3185
+ for (const cte of stmt.ctes) {
3186
+ if (cte.query.type === "SELECT") validateSelect(cte.query);
3187
+ else if (cte.query.type === "UNION") validateUnion(cte.query);
3188
+ }
3189
+ validateSelectLike(stmt.query);
3190
+ }
3191
+ function validateSelect(stmt) {
3192
+ validateOwnKlikeExpressions(stmt);
3193
+ if (whereHasKlike(stmt.where)) {
3194
+ const inMemorySource = stmt.from.cteName !== null || stmt.joins.some((join2) => join2.table.cteName !== null);
3195
+ if (inMemorySource || resolveSelectMode(stmt) === "FULL_SCAN") {
3196
+ throw new KlikeValidationError(
3197
+ "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"
3198
+ );
3199
+ }
3200
+ }
3201
+ validateNestedSelects(stmt);
3202
+ }
3203
+ function validateOwnKlikeExpressions(stmt) {
3204
+ walkWithoutNestedSelects(stmt, (where) => {
3205
+ if (!isKlike(where)) return;
3206
+ if (!isDescendantOf(stmt.where, where)) {
3207
+ throw new KlikeValidationError("KLIKE / NOT KLIKE \u306F SELECT \u306E WHERE \u53E5\u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059");
3208
+ }
3209
+ const right = where.right;
3210
+ if (right.type !== "STRING" && right.type !== "VARIABLE") {
3211
+ throw new KlikeValidationError(
3212
+ "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"
3213
+ );
3214
+ }
3215
+ if (right.type === "STRING" && right.value.includes("%")) {
3216
+ throw new KlikeValidationError(
3217
+ "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"
3218
+ );
3219
+ }
3220
+ });
3221
+ }
3222
+ function validateNestedSelects(node) {
3223
+ walkObjects(node, (obj) => {
3224
+ if (obj.type === "SELECT") validateSelect(obj);
3225
+ }, true);
3226
+ }
3227
+ function buildEffectiveInlineSelect(stmt) {
3228
+ if (stmt.ctes.length !== 1) return null;
3229
+ const cte = stmt.ctes[0];
3230
+ if (cte.query.type !== "SELECT" || resolveSelectMode(cte.query) !== "SIMPLE") return null;
3231
+ if (stmt.query.type !== "SELECT") return null;
3232
+ const final = stmt.query;
3233
+ if (final.from.cteName !== cte.name || final.joins.length > 0) return null;
3234
+ if (final.groupBy.length > 0 || final.distinct) return null;
3235
+ if (final.columns.some(
3236
+ (column) => column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL"
3237
+ )) return null;
3238
+ 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 };
3239
+ const columns = final.columns.every((column) => column.type === "WILDCARD") ? cte.query.columns : final.columns;
3240
+ return {
3241
+ type: "SELECT",
3242
+ from: cte.query.from,
3243
+ joins: [],
3244
+ columns,
3245
+ where,
3246
+ groupBy: [],
3247
+ having: null,
3248
+ orderBy: final.orderBy.length > 0 ? final.orderBy : cte.query.orderBy,
3249
+ limit: final.limit ?? cte.query.limit,
3250
+ offset: final.offset ?? cte.query.offset,
3251
+ distinct: false
3252
+ };
3253
+ }
3254
+ function containsKlike(node) {
3255
+ let found = false;
3256
+ walkObjects(node, (obj) => {
3257
+ if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) found = true;
3258
+ });
3259
+ return found;
3260
+ }
3261
+ function isDescendantOf(root, target) {
3262
+ if (root === null) return false;
3263
+ if (root === target) return true;
3264
+ switch (root.type) {
3265
+ case "LOGICAL":
3266
+ return isDescendantOf(root.left, target) || isDescendantOf(root.right, target);
3267
+ case "NOT":
3268
+ case "GROUP":
3269
+ return isDescendantOf(root.expr, target);
3270
+ case "BINARY":
3271
+ case "NULL_CHECK":
3272
+ case "EXISTS":
3273
+ return false;
3274
+ }
3275
+ }
3276
+ function walkWithoutNestedSelects(node, visitWhere) {
3277
+ if (Array.isArray(node)) {
3278
+ for (const value of node) walkWithoutNestedSelects(value, visitWhere);
3279
+ return;
3280
+ }
3281
+ if (node === null || typeof node !== "object") return;
3282
+ const obj = node;
3283
+ if (obj.type === "BINARY" || obj.type === "NULL_CHECK" || obj.type === "LOGICAL" || obj.type === "NOT" || obj.type === "GROUP" || obj.type === "EXISTS") {
3284
+ visitWhere(obj);
3285
+ }
3286
+ for (const value of Object.values(obj)) {
3287
+ if (value !== node && isSelectObject(value)) continue;
3288
+ walkWithoutNestedSelects(value, visitWhere);
3289
+ }
3290
+ }
3291
+ function walkObjects(node, visit, skipRoot = false) {
3292
+ if (Array.isArray(node)) {
3293
+ for (const value of node) walkObjects(value, visit);
3294
+ return;
3295
+ }
3296
+ if (node === null || typeof node !== "object") return;
3297
+ const obj = node;
3298
+ if (!skipRoot) visit(obj);
3299
+ for (const value of Object.values(obj)) walkObjects(value, visit);
3300
+ }
3301
+ function isSelectObject(value) {
3302
+ return value !== null && typeof value === "object" && value.type === "SELECT";
3303
+ }
3304
+
3305
+ // src/core/batch.ts
3306
+ var MAX_TEMP_TABLES = 16;
3307
+ var MAX_BATCH_VARIABLES = 64;
3308
+ var BatchAnalysisError = class extends Error {
3309
+ constructor(message, statementIndex) {
3310
+ super(message);
3311
+ this.statementIndex = statementIndex;
3312
+ }
3313
+ };
3314
+ function collectRefs(node, tempRefs, appIds) {
3315
+ if (Array.isArray(node)) {
3316
+ for (const v of node) collectRefs(v, tempRefs, appIds);
3317
+ return;
3318
+ }
3319
+ if (node !== null && typeof node === "object") {
3320
+ const obj = node;
3321
+ const cte = obj["cteName"];
3322
+ if (typeof cte === "string" && cte.startsWith("#")) tempRefs.add(cte);
3323
+ const appId = obj["appId"];
3324
+ if (typeof appId === "number" && appId > 0) appIds.add(appId);
3325
+ for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
3326
+ }
3327
+ }
3328
+ function collectVariableRefs(node, refs) {
3329
+ if (Array.isArray(node)) {
3330
+ for (const v of node) collectVariableRefs(v, refs);
3331
+ return;
3332
+ }
3333
+ if (node !== null && typeof node === "object") {
3334
+ const obj = node;
3335
+ if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
3336
+ refs.add(obj["name"]);
3337
+ return;
3338
+ }
3339
+ for (const v of Object.values(obj)) collectVariableRefs(v, refs);
3231
3340
  }
3232
- walkWhere(stmt.where, "where");
3233
- for (const gk of stmt.groupBy) walkGroupByKey(gk);
3234
- walkWhere(stmt.having, "having");
3235
- for (const ob of stmt.orderBy) walkOrderByKey(ob.key);
3236
- return states;
3237
3341
  }
3238
- function collectSelectOutputNames(columns) {
3239
- const names = /* @__PURE__ */ new Set();
3240
- for (const col of columns) {
3241
- if (col.type === "FIELD" && col.alias) {
3242
- names.add(col.alias);
3243
- continue;
3342
+ function analyzeBatch(statements) {
3343
+ if (statements.length === 0) {
3344
+ throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
3345
+ }
3346
+ statements.forEach((stmt, index) => {
3347
+ try {
3348
+ validateKlikeStatement(stmt);
3349
+ } catch (error) {
3350
+ if (error instanceof KlikeValidationError) {
3351
+ throw new BatchAnalysisError(error.message, index);
3352
+ }
3353
+ throw error;
3244
3354
  }
3245
- if (col.type === "LITERAL_COL") {
3246
- names.add(col.alias ?? `'${col.value}'`);
3247
- continue;
3355
+ });
3356
+ if (statements.length === 1) {
3357
+ const t = statements[0].type;
3358
+ if (t === "SET_VARIABLE" || t === "DECLARE_VARIABLE") {
3359
+ const verb = t === "SET_VARIABLE" ? "SET" : "DECLARE";
3360
+ throw new BatchAnalysisError(`ArgumentError: ${verb} variable requires a batch.`, 0);
3248
3361
  }
3249
- if (col.type === "AGGREGATE") {
3250
- if (col.alias) names.add(col.alias);
3251
- else names.add(aggregateSyntheticName(col.func, col.distinct, col.arg));
3252
- continue;
3362
+ if (t === "CREATE_TEMP_TABLE" || t === "DROP_TEMP_TABLE") {
3363
+ const verb = t === "CREATE_TEMP_TABLE" ? "CREATE TEMP TABLE" : "DROP TEMP TABLE";
3364
+ throw new BatchAnalysisError(
3365
+ `ArgumentError: ${verb} requires a batch (temp tables are batch-scoped).`,
3366
+ 0
3367
+ );
3253
3368
  }
3254
- if (col.type === "ARITH_AGG_COL") {
3255
- if (col.alias) names.add(col.alias);
3256
- continue;
3369
+ }
3370
+ const defined = /* @__PURE__ */ new Map();
3371
+ const createdOrder = [];
3372
+ const results = [];
3373
+ const variableDefs = /* @__PURE__ */ new Map();
3374
+ const variableOrder = [];
3375
+ statements.forEach((stmt, index) => {
3376
+ const statementType = getStatementType(stmt);
3377
+ const created = [];
3378
+ const dropped = [];
3379
+ const refs = /* @__PURE__ */ new Set();
3380
+ const stmtAppIds = /* @__PURE__ */ new Set();
3381
+ const dependsOn = /* @__PURE__ */ new Set();
3382
+ const variableRefs = /* @__PURE__ */ new Set();
3383
+ collectVariableRefs(stmt, variableRefs);
3384
+ for (const name of variableRefs) {
3385
+ const def = variableDefs.get(name);
3386
+ if (def === void 0) {
3387
+ throw new BatchAnalysisError(
3388
+ `ParseError: variable @${name} is not defined before statement ${index + 1}.`,
3389
+ index
3390
+ );
3391
+ }
3392
+ def.referencedBy.push(index);
3257
3393
  }
3258
- if (col.type === "ARITH_COL") {
3259
- if (col.alias) names.add(col.alias);
3260
- continue;
3394
+ if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
3395
+ if (variableDefs.has(stmt.name)) {
3396
+ throw new BatchAnalysisError(`ParseError: variable @${stmt.name} is already defined.`, index);
3397
+ }
3398
+ variableDefs.set(stmt.name, { index, referencedBy: [] });
3399
+ variableOrder.push(stmt.name);
3400
+ if (variableOrder.length > MAX_BATCH_VARIABLES) {
3401
+ throw new BatchAnalysisError(
3402
+ `ParseError: batch exceeds ${MAX_BATCH_VARIABLES} variables.`,
3403
+ index
3404
+ );
3405
+ }
3261
3406
  }
3262
- if (col.type === "CASE_COL") {
3263
- names.add(col.alias ?? "case");
3264
- continue;
3407
+ if (stmt.type === "CREATE_TEMP_TABLE") {
3408
+ collectRefs(stmt.query, refs, stmtAppIds);
3409
+ } else if (stmt.type === "DROP_TEMP_TABLE") {
3410
+ } else {
3411
+ collectRefs(stmt, refs, stmtAppIds);
3265
3412
  }
3266
- if (col.type === "STRFUNC_COL") {
3267
- if (col.alias) names.add(col.alias);
3268
- continue;
3413
+ let tempOnlySource = false;
3414
+ if (stmt.type === "INSERT_SELECT" || stmt.type === "UPSERT_SELECT") {
3415
+ const srcTemp = /* @__PURE__ */ new Set();
3416
+ const srcApps = /* @__PURE__ */ new Set();
3417
+ collectRefs(stmt.select, srcTemp, srcApps);
3418
+ tempOnlySource = srcTemp.size > 0 && srcApps.size === 0;
3269
3419
  }
3270
- if (col.type === "SCALAR_SUBQUERY_COL") {
3271
- names.add(col.alias ?? "(subquery)");
3420
+ for (const name of refs) {
3421
+ const at = defined.get(name);
3422
+ if (at === void 0) {
3423
+ throw new BatchAnalysisError(
3424
+ `ParseError: temp table ${name} is not defined in this batch.`,
3425
+ index
3426
+ );
3427
+ }
3428
+ dependsOn.add(at);
3272
3429
  }
3273
- }
3274
- return names;
3430
+ if (stmt.type === "CREATE_TEMP_TABLE") {
3431
+ if (defined.has(stmt.name)) {
3432
+ throw new BatchAnalysisError(
3433
+ `ParseError: temp table ${stmt.name} is already defined.`,
3434
+ index
3435
+ );
3436
+ }
3437
+ defined.set(stmt.name, index);
3438
+ createdOrder.push(stmt.name);
3439
+ created.push(stmt.name);
3440
+ if (defined.size > MAX_TEMP_TABLES) {
3441
+ throw new BatchAnalysisError(
3442
+ `ParseError: batch exceeds ${MAX_TEMP_TABLES} temp tables.`,
3443
+ index
3444
+ );
3445
+ }
3446
+ }
3447
+ if (stmt.type === "DROP_TEMP_TABLE") {
3448
+ const at = defined.get(stmt.name);
3449
+ if (at === void 0) {
3450
+ throw new BatchAnalysisError(
3451
+ `ParseError: temp table ${stmt.name} is not defined in this batch.`,
3452
+ index
3453
+ );
3454
+ }
3455
+ dependsOn.add(at);
3456
+ dropped.push(stmt.name);
3457
+ defined.delete(stmt.name);
3458
+ }
3459
+ results.push({
3460
+ index,
3461
+ statementType,
3462
+ isDml: isDmlType(statementType),
3463
+ isReadOnly: isReadOnlyType(statementType),
3464
+ hasWhere: hasWhereClause(stmt),
3465
+ insertValuesCount: getInsertValuesCount(stmt),
3466
+ appIds: [...stmtAppIds].sort((a, b) => a - b),
3467
+ tempTablesCreated: created,
3468
+ tempTablesReferenced: [...refs],
3469
+ tempTablesDropped: dropped,
3470
+ dependsOn: [...dependsOn].sort((a, b) => a - b),
3471
+ tempOnlySource,
3472
+ targetAppId: isDmlType(statementType) && typeof stmt.appId === "number" ? stmt.appId : null
3473
+ });
3474
+ });
3475
+ const containsDml = results.some((r) => r.isDml);
3476
+ const variables = variableOrder.map((name) => ({
3477
+ name,
3478
+ referencedBy: [...variableDefs.get(name).referencedBy]
3479
+ }));
3480
+ return {
3481
+ statementCount: statements.length,
3482
+ isReadOnlyBatch: !containsDml && results.every((r) => r.isReadOnly),
3483
+ containsDml,
3484
+ tempTables: createdOrder,
3485
+ variables,
3486
+ warnings: variables.filter((v) => v.referencedBy.length === 0).map((v) => `variable @${v.name} is never used.`),
3487
+ statements: results
3488
+ };
3275
3489
  }
3276
- function aggregateSyntheticName(func, distinct, arg) {
3277
- const argStr = arg.type === "WILDCARD" ? "*" : arithNodeLabel(arg);
3278
- return distinct ? `${func}(DISTINCT ${argStr})` : `${func}(${argStr})`;
3490
+
3491
+ // src/core/batchVariables.ts
3492
+ var VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
3493
+ function normalizeBatchVariableName(name) {
3494
+ if (!VARIABLE_NAME_RE.test(name)) {
3495
+ throw new Error(
3496
+ `ArgumentError: invalid variable name "${name}". Use a name without @ matching [A-Za-z_][A-Za-z0-9_]{0,63}.`
3497
+ );
3498
+ }
3499
+ return name.toLowerCase();
3279
3500
  }
3280
- function arithNodeLabel(node) {
3281
- if (node.type === "FIELD_REF") return node.field;
3282
- if (node.type === "NUMBER") return String(node.value);
3283
- if (node.type === "STRING_FUNC") return stringFuncLabel(node);
3284
- return `(${arithNodeLabel(node.left)}${node.op}${arithNodeLabel(node.right)})`;
3501
+ function normalizeBatchVariables(input) {
3502
+ const normalized = /* @__PURE__ */ Object.create(null);
3503
+ for (const [rawName, value] of Object.entries(input ?? {})) {
3504
+ const name = normalizeBatchVariableName(rawName);
3505
+ if (Object.prototype.hasOwnProperty.call(normalized, name)) {
3506
+ throw new Error(`ArgumentError: variable "${rawName}" is specified more than once.`);
3507
+ }
3508
+ normalized[name] = value;
3509
+ }
3510
+ return normalized;
3285
3511
  }
3286
- function stringFuncLabel(expr) {
3287
- const args = expr.args.map((a) => {
3288
- if (a.type === "STRING") return `'${a.value}'`;
3289
- if (a.type === "STRING_FUNC") return stringFuncLabel(a);
3290
- if (a.type === "AGG_REF") return aggregateSyntheticName(a.func, a.distinct, a.arg);
3291
- if (a.type === "AGG_ARITH") return "agg_arith";
3292
- return arithNodeLabel(a);
3293
- });
3294
- return `${expr.func}(${args.join(",")})`;
3512
+ function validateDeclaredBatchVariables(statements, input) {
3513
+ const normalized = normalizeBatchVariables(input);
3514
+ const declared = new Set(
3515
+ statements.filter((stmt) => stmt.type === "DECLARE_VARIABLE").map((stmt) => stmt.name)
3516
+ );
3517
+ for (const name of Object.keys(normalized)) {
3518
+ if (!declared.has(name)) {
3519
+ throw new Error(`ArgumentError: injected variable @${name} is not declared.`);
3520
+ }
3521
+ }
3522
+ return normalized;
3295
3523
  }
3296
- function isAggregateSyntheticName(name) {
3297
- return /^(COUNT|SUM|AVG|MAX|MIN)\(/i.test(name);
3524
+
3525
+ // src/core/scalarCompare.ts
3526
+ function compareScalarValues(op, leftStr, rightStr) {
3527
+ if (op === "=") return leftStr === rightStr;
3528
+ if (op === "!=" || op === "<>") return leftStr !== rightStr;
3529
+ const rightNum = Number(rightStr);
3530
+ if (leftStr === "" && rightStr !== "" && Number.isFinite(rightNum)) {
3531
+ return op === "<" || op === "<=";
3532
+ }
3533
+ const leftNum = Number(leftStr);
3534
+ const numeric = !Number.isNaN(leftNum) && !Number.isNaN(rightNum);
3535
+ switch (op) {
3536
+ case ">":
3537
+ return numeric ? leftNum > rightNum : leftStr > rightStr;
3538
+ case "<":
3539
+ return numeric ? leftNum < rightNum : leftStr < rightStr;
3540
+ case ">=":
3541
+ return numeric ? leftNum >= rightNum : leftStr >= rightStr;
3542
+ case "<=":
3543
+ return numeric ? leftNum <= rightNum : leftStr <= rightStr;
3544
+ }
3298
3545
  }
3299
3546
 
3300
3547
  // src/engine/evalFunc.ts
@@ -3553,6 +3800,9 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType) {
3553
3800
  const pattern = resolveValue(right, row, resolveFieldType);
3554
3801
  return !matchLike(leftStr, pattern);
3555
3802
  }
3803
+ if (op === "KLIKE" || op === "NOT_KLIKE") {
3804
+ 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");
3805
+ }
3556
3806
  const rightStr = resolveValue(right, row, resolveFieldType);
3557
3807
  return compareScalarValues(op, leftStr, rightStr);
3558
3808
  }
@@ -3708,6 +3958,11 @@ function matchLike(value, pattern) {
3708
3958
 
3709
3959
  // src/converter/dmlToKintone.ts
3710
3960
  function assertDmlWhereIsSafe(where) {
3961
+ if (whereHasKlike(where)) {
3962
+ throw new DmlConvertError(
3963
+ "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"
3964
+ );
3965
+ }
3711
3966
  if (!whereHasLike(where)) return;
3712
3967
  throw new DmlConvertError(
3713
3968
  "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"
@@ -4937,6 +5192,7 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
4937
5192
  if (unresolved !== null) {
4938
5193
  throw new Error(`ParseError: variable @${unresolved} is not defined in a batch.`);
4939
5194
  }
5195
+ validateKlikeStatement(stmt);
4940
5196
  switch (stmt.type) {
4941
5197
  case "SELECT":
4942
5198
  return executeSelect(stmt, client, options, cacheContext);
@@ -5073,6 +5329,7 @@ async function executeBatch(sql, client, options = {}) {
5073
5329
  async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables) {
5074
5330
  if (stmt.type === "SET_VARIABLE") {
5075
5331
  const resolvedStmt2 = resolveVariableRefs(stmt, variables);
5332
+ validateKlikeStatement(resolvedStmt2);
5076
5333
  if (resolvedStmt2.expr.type === "SCALAR_SUBQUERY") {
5077
5334
  try {
5078
5335
  const value = await evaluateScalarSubquery(
@@ -5105,6 +5362,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
5105
5362
  return {};
5106
5363
  }
5107
5364
  const resolvedStmt = resolveVariableRefs(stmt, variables);
5365
+ validateKlikeStatement(resolvedStmt);
5108
5366
  if (resolvedStmt.type === "CREATE_TEMP_TABLE") {
5109
5367
  const materializeOptions = {
5110
5368
  ...options,
@@ -6973,7 +7231,9 @@ async function executeDescribe(stmt, client, cacheContext) {
6973
7231
  function parseSql(sql) {
6974
7232
  try {
6975
7233
  const tokens = new Lexer(sql).tokenize();
6976
- return new Parser(tokens).parse();
7234
+ const stmt = new Parser(tokens).parse();
7235
+ validateKlikeStatement(stmt);
7236
+ return stmt;
6977
7237
  } catch (e) {
6978
7238
  if (e instanceof LexError || e instanceof ParseError) {
6979
7239
  throw e;
@@ -7084,6 +7344,7 @@ function buildBatchExplainPlans(sql, injectedVariables) {
7084
7344
  statementCount: statements.length,
7085
7345
  statements: statements.map((stmt, i) => {
7086
7346
  const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveVariableRefs(stmt.expr, variables) } : stmt : resolveVariableRefs(stmt, variables);
7347
+ validateKlikeStatement(planStmt);
7087
7348
  const result = {
7088
7349
  index: i,
7089
7350
  type: analysis.statements[i].statementType,
@@ -7517,11 +7778,15 @@ var OperationCancelledError = class extends Error {
7517
7778
  // src/core/sql.ts
7518
7779
  function parseSqlStatement(sql) {
7519
7780
  const tokens = new Lexer(sql).tokenize();
7520
- return new Parser(tokens).parse();
7781
+ const stmt = new Parser(tokens).parse();
7782
+ validateKlikeStatement(stmt);
7783
+ return stmt;
7521
7784
  }
7522
7785
  function parseSqlStatements(sql) {
7523
7786
  const tokens = new Lexer(sql).tokenize();
7524
- return new Parser(tokens).parseStatements();
7787
+ const statements = new Parser(tokens).parseStatements();
7788
+ statements.forEach(validateKlikeStatement);
7789
+ return statements;
7525
7790
  }
7526
7791
 
7527
7792
  // src/core/displayFormat.ts