@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 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");
3231
- }
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
- }
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;
3244
- }
3245
- if (col.type === "LITERAL_COL") {
3246
- names.add(col.alias ?? `'${col.value}'`);
3247
- continue;
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);
3340
+ }
3341
+ }
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;
3354
+ }
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);
3361
+ }
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
+ );
3368
+ }
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);
3248
3393
  }
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;
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
+ }
3253
3406
  }
3254
- if (col.type === "ARITH_AGG_COL") {
3255
- if (col.alias) names.add(col.alias);
3256
- 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);
3257
3412
  }
3258
- if (col.type === "ARITH_COL") {
3259
- if (col.alias) names.add(col.alias);
3260
- 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;
3261
3419
  }
3262
- if (col.type === "CASE_COL") {
3263
- names.add(col.alias ?? "case");
3264
- continue;
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);
3265
3429
  }
3266
- if (col.type === "STRFUNC_COL") {
3267
- if (col.alias) names.add(col.alias);
3268
- continue;
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
+ }
3269
3446
  }
3270
- if (col.type === "SCALAR_SUBQUERY_COL") {
3271
- names.add(col.alias ?? "(subquery)");
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);
3272
3458
  }
3273
- }
3274
- return names;
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"
@@ -4236,7 +4491,8 @@ var SELECTION_IN_FIELD_TYPES = /* @__PURE__ */ new Set([
4236
4491
  "DROP_DOWN",
4237
4492
  "RADIO_BUTTON",
4238
4493
  "CHECK_BOX",
4239
- "MULTI_SELECT"
4494
+ "MULTI_SELECT",
4495
+ "STATUS"
4240
4496
  ]);
4241
4497
  function isSelectionInComparison(expr, options) {
4242
4498
  if (!isSelectionInCandidate(expr, options)) return false;
@@ -4887,6 +5143,7 @@ function createEmptyMetrics() {
4887
5143
  deleteCalls: 0,
4888
5144
  fieldCalls: 0,
4889
5145
  appsCalls: 0,
5146
+ processStatusCalls: 0,
4890
5147
  fetchedRows: 0,
4891
5148
  elapsedMs: 0
4892
5149
  };
@@ -4918,6 +5175,10 @@ function wrapClientWithMetrics(client, metrics) {
4918
5175
  getFields: (appId) => {
4919
5176
  metrics.fieldCalls += 1;
4920
5177
  return client.getFields(appId);
5178
+ },
5179
+ getProcessStatuses: (appId) => {
5180
+ metrics.processStatusCalls += 1;
5181
+ return client.getProcessStatuses(appId);
4921
5182
  }
4922
5183
  };
4923
5184
  }
@@ -4931,6 +5192,7 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
4931
5192
  if (unresolved !== null) {
4932
5193
  throw new Error(`ParseError: variable @${unresolved} is not defined in a batch.`);
4933
5194
  }
5195
+ validateKlikeStatement(stmt);
4934
5196
  switch (stmt.type) {
4935
5197
  case "SELECT":
4936
5198
  return executeSelect(stmt, client, options, cacheContext);
@@ -5067,6 +5329,7 @@ async function executeBatch(sql, client, options = {}) {
5067
5329
  async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables) {
5068
5330
  if (stmt.type === "SET_VARIABLE") {
5069
5331
  const resolvedStmt2 = resolveVariableRefs(stmt, variables);
5332
+ validateKlikeStatement(resolvedStmt2);
5070
5333
  if (resolvedStmt2.expr.type === "SCALAR_SUBQUERY") {
5071
5334
  try {
5072
5335
  const value = await evaluateScalarSubquery(
@@ -5099,6 +5362,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
5099
5362
  return {};
5100
5363
  }
5101
5364
  const resolvedStmt = resolveVariableRefs(stmt, variables);
5365
+ validateKlikeStatement(resolvedStmt);
5102
5366
  if (resolvedStmt.type === "CREATE_TEMP_TABLE") {
5103
5367
  const materializeOptions = {
5104
5368
  ...options,
@@ -5524,22 +5788,36 @@ function extractMainTypedPushdownCandidate(stmt) {
5524
5788
  return extractTypedPushdownCandidates(stmt.where, { tableAlias: stmt.from.alias });
5525
5789
  }
5526
5790
  async function loadTypedPushdownMeta(stmt, client, cacheContext) {
5527
- const appIds = /* @__PURE__ */ new Set();
5528
- if (extractMainTypedPushdownCandidate(stmt) !== null) appIds.add(stmt.from.appId);
5791
+ const candidatesByApp = /* @__PURE__ */ new Map();
5792
+ const addCandidate = (appId, candidate) => {
5793
+ if (candidate === null) return;
5794
+ const existing = candidatesByApp.get(appId);
5795
+ if (existing) existing.push(candidate);
5796
+ else candidatesByApp.set(appId, [candidate]);
5797
+ };
5798
+ addCandidate(stmt.from.appId, extractMainTypedPushdownCandidate(stmt));
5529
5799
  if (stmt.where !== null) {
5530
5800
  for (const join2 of stmt.joins) {
5531
5801
  if (!join2.table.alias || join2.table.subtableCode || join2.table.cteName !== null) continue;
5532
5802
  const candidate = extractTypedPushdownCandidates(stmt.where, {
5533
5803
  tableAlias: join2.table.alias
5534
5804
  });
5535
- if (candidate !== null) appIds.add(join2.table.appId);
5805
+ addCandidate(join2.table.appId, candidate);
5536
5806
  }
5537
5807
  }
5538
- const entries = await Promise.all([...appIds].map(async (appId) => {
5808
+ const entries = await Promise.all([...candidatesByApp.entries()].map(async ([appId, candidates]) => {
5539
5809
  const [fieldTypes, fieldOptions] = await Promise.all([
5540
5810
  getFieldTypeMap(appId, client, cacheContext),
5541
5811
  getFieldOptionSetMapByApp(appId, client, cacheContext)
5542
5812
  ]);
5813
+ const statusFields = collectCandidateFieldCodes(candidates).filter((fieldCode) => fieldTypes.get(fieldCode) === "STATUS");
5814
+ if (statusFields.length > 0) {
5815
+ const process2 = await getProcessStatusesCached(appId, client, cacheContext);
5816
+ if (process2.enable && process2.states.length > 0) {
5817
+ const states = new Set(process2.states);
5818
+ for (const fieldCode of statusFields) fieldOptions.set(fieldCode, states);
5819
+ }
5820
+ }
5543
5821
  return [appId, fieldTypes, fieldOptions];
5544
5822
  }));
5545
5823
  return {
@@ -5547,6 +5825,23 @@ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
5547
5825
  fieldOptionsByApp: new Map(entries.map(([appId, , fieldOptions]) => [appId, fieldOptions]))
5548
5826
  };
5549
5827
  }
5828
+ function collectCandidateFieldCodes(candidates) {
5829
+ const fields = /* @__PURE__ */ new Set();
5830
+ const visit = (expr) => {
5831
+ if (expr.type === "BINARY") {
5832
+ if (expr.left.type === "FIELD") fields.add(expr.left.field);
5833
+ return;
5834
+ }
5835
+ if (expr.type === "LOGICAL") {
5836
+ visit(expr.left);
5837
+ visit(expr.right);
5838
+ return;
5839
+ }
5840
+ if (expr.type === "GROUP" || expr.type === "NOT") visit(expr.expr);
5841
+ };
5842
+ for (const candidate of candidates) visit(candidate);
5843
+ return [...fields];
5844
+ }
5550
5845
  function collectTypedInFieldRefs(expr, out) {
5551
5846
  if (expr === null) return;
5552
5847
  switch (expr.type) {
@@ -6172,6 +6467,7 @@ var fieldTypeCache = /* @__PURE__ */ new Map();
6172
6467
  var optionOrderCache = /* @__PURE__ */ new Map();
6173
6468
  var sortKindCache = /* @__PURE__ */ new Map();
6174
6469
  var fieldInfoCache = /* @__PURE__ */ new Map();
6470
+ var processStatusCache = /* @__PURE__ */ new Map();
6175
6471
  function getScopedCacheValue(root, cacheContext, appId) {
6176
6472
  return root.get(cacheContext)?.get(appId);
6177
6473
  }
@@ -6193,6 +6489,13 @@ async function getFieldsCached(appId, client, cacheContext) {
6193
6489
  setScopedCacheValue(fieldInfoCache, cacheContext, appId, loading);
6194
6490
  return loading;
6195
6491
  }
6492
+ async function getProcessStatusesCached(appId, client, cacheContext) {
6493
+ const cached = getScopedCacheValue(processStatusCache, cacheContext, appId);
6494
+ if (cached) return cached;
6495
+ const loading = client.getProcessStatuses(appId);
6496
+ setScopedCacheValue(processStatusCache, cacheContext, appId, loading);
6497
+ return loading;
6498
+ }
6196
6499
  async function getFieldTypeMap(appId, client, cacheContext) {
6197
6500
  const cached = getScopedCacheValue(fieldTypeCache, cacheContext, appId);
6198
6501
  if (cached) return cached;
@@ -6928,7 +7231,9 @@ async function executeDescribe(stmt, client, cacheContext) {
6928
7231
  function parseSql(sql) {
6929
7232
  try {
6930
7233
  const tokens = new Lexer(sql).tokenize();
6931
- return new Parser(tokens).parse();
7234
+ const stmt = new Parser(tokens).parse();
7235
+ validateKlikeStatement(stmt);
7236
+ return stmt;
6932
7237
  } catch (e) {
6933
7238
  if (e instanceof LexError || e instanceof ParseError) {
6934
7239
  throw e;
@@ -7039,6 +7344,7 @@ function buildBatchExplainPlans(sql, injectedVariables) {
7039
7344
  statementCount: statements.length,
7040
7345
  statements: statements.map((stmt, i) => {
7041
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);
7042
7348
  const result = {
7043
7349
  index: i,
7044
7350
  type: analysis.statements[i].statementType,
@@ -7472,11 +7778,15 @@ var OperationCancelledError = class extends Error {
7472
7778
  // src/core/sql.ts
7473
7779
  function parseSqlStatement(sql) {
7474
7780
  const tokens = new Lexer(sql).tokenize();
7475
- return new Parser(tokens).parse();
7781
+ const stmt = new Parser(tokens).parse();
7782
+ validateKlikeStatement(stmt);
7783
+ return stmt;
7476
7784
  }
7477
7785
  function parseSqlStatements(sql) {
7478
7786
  const tokens = new Lexer(sql).tokenize();
7479
- return new Parser(tokens).parseStatements();
7787
+ const statements = new Parser(tokens).parseStatements();
7788
+ statements.forEach(validateKlikeStatement);
7789
+ return statements;
7480
7790
  }
7481
7791
 
7482
7792
  // src/core/displayFormat.ts
@@ -7861,6 +8171,7 @@ function withRequestGate(client, gate) {
7861
8171
  getRecords: (params) => gate.runReadOnly(() => client.getRecords(params)),
7862
8172
  getApps: () => gate.runReadOnly(() => client.getApps()),
7863
8173
  getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
8174
+ getProcessStatuses: (appId) => gate.runReadOnly(() => client.getProcessStatuses(appId)),
7864
8175
  postRecords: (params) => gate.runMutation(() => client.postRecords(params)),
7865
8176
  putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
7866
8177
  deleteRecords: (params) => gate.runMutation(() => client.deleteRecords(params))
@@ -8095,6 +8406,16 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
8095
8406
  appId
8096
8407
  );
8097
8408
  return flattenFormFieldProperties(res.properties);
8409
+ },
8410
+ async getProcessStatuses(appId) {
8411
+ const qs = new URLSearchParams();
8412
+ qs.set("app", String(appId));
8413
+ qs.set("lang", "user");
8414
+ const res = await requestJson(`${apiBasePath}/app/status.json?${qs.toString()}`, { method: "GET" }, appId);
8415
+ return {
8416
+ enable: res.enable,
8417
+ states: Object.values(res.states ?? {}).map((state) => state.name)
8418
+ };
8098
8419
  }
8099
8420
  };
8100
8421
  }
@@ -9182,7 +9503,10 @@ function createDryRunClient() {
9182
9503
  putRecords: notUsed,
9183
9504
  deleteRecords: notUsed,
9184
9505
  getApps: notUsed,
9185
- getFields: notUsed
9506
+ getFields: notUsed,
9507
+ async getProcessStatuses() {
9508
+ return { enable: false, states: [] };
9509
+ }
9186
9510
  };
9187
9511
  }
9188
9512
  async function runDiagnosticRecordGet(params) {
@@ -10199,6 +10523,13 @@ async function run() {
10199
10523
  if (!routed) throw new Error(`AuthError: profile "${pName}" is not resolved for APP${appId}.`);
10200
10524
  return routed.getFields(binding.appId);
10201
10525
  },
10526
+ getProcessStatuses: (appId) => {
10527
+ const binding = appBindingByMappedApp.get(appId) ?? { appId, profile: profileName.toLowerCase() };
10528
+ const pName = binding.profile;
10529
+ const routed = profileClientMap.get(pName);
10530
+ if (!routed) throw new Error(`AuthError: profile "${pName}" is not resolved for APP${appId}.`);
10531
+ return routed.getProcessStatuses(binding.appId);
10532
+ },
10202
10533
  getApps: () => defaultClient.getApps()
10203
10534
  };
10204
10535
  }