@rex0220/kintone-sql-tools 3.68.0 → 3.70.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
@@ -677,6 +677,75 @@ function resolveGroupingSpec(stmt, resolve2) {
677
677
  };
678
678
  }
679
679
 
680
+ // src/core/asOfClock.ts
681
+ var AS_OF_FUNCTION_NAMES = [
682
+ "NOW",
683
+ "TODAY",
684
+ "MONTH_START",
685
+ "NEXT_MONTH_START"
686
+ ];
687
+ var AS_OF_VARIABLE_PREFIX = "\0as-of:";
688
+ function asOfVariableName(name) {
689
+ return `${AS_OF_VARIABLE_PREFIX}${name}`;
690
+ }
691
+ function asOfFunctionNameFromVariable(name) {
692
+ if (!name.startsWith(AS_OF_VARIABLE_PREFIX)) return null;
693
+ const candidate = name.slice(AS_OF_VARIABLE_PREFIX.length);
694
+ return isAsOfFunctionName(candidate) ? candidate : null;
695
+ }
696
+ function isAsOfFunctionName(name) {
697
+ return AS_OF_FUNCTION_NAMES.includes(name);
698
+ }
699
+ function createAsOfClock(asOf = /* @__PURE__ */ new Date(), timezone) {
700
+ if (!(asOf instanceof Date) || !Number.isFinite(asOf.getTime())) {
701
+ throw new Error("ArgumentError: asOf must be a valid Date.");
702
+ }
703
+ let formatter;
704
+ try {
705
+ formatter = new Intl.DateTimeFormat("en-CA", {
706
+ ...timezone === void 0 ? {} : { timeZone: timezone },
707
+ year: "numeric",
708
+ month: "2-digit",
709
+ day: "2-digit"
710
+ });
711
+ formatter.format(asOf);
712
+ } catch {
713
+ throw new Error(`ArgumentError: invalid IANA timezone: ${timezone ?? ""}.`);
714
+ }
715
+ const parts = formatter.formatToParts(asOf);
716
+ const year = partNumber(parts, "year");
717
+ const month = partNumber(parts, "month");
718
+ const day = partNumber(parts, "day");
719
+ const today = `${pad4(year)}-${pad2(month)}-${pad2(day)}`;
720
+ const monthStart = `${pad4(year)}-${pad2(month)}-01`;
721
+ const nextYear = month === 12 ? year + 1 : year;
722
+ const nextMonth = month === 12 ? 1 : month + 1;
723
+ return {
724
+ asOf: new Date(asOf.getTime()),
725
+ ...timezone === void 0 ? {} : { timezone },
726
+ values: {
727
+ NOW: asOf.toISOString(),
728
+ TODAY: today,
729
+ MONTH_START: monthStart,
730
+ NEXT_MONTH_START: `${pad4(nextYear)}-${pad2(nextMonth)}-01`
731
+ }
732
+ };
733
+ }
734
+ function partNumber(parts, type) {
735
+ const value = parts.find((part) => part.type === type)?.value;
736
+ const parsed = Number(value);
737
+ if (!Number.isInteger(parsed)) {
738
+ throw new Error(`InternalError: Intl.DateTimeFormat did not return ${type}.`);
739
+ }
740
+ return parsed;
741
+ }
742
+ function pad2(value) {
743
+ return String(value).padStart(2, "0");
744
+ }
745
+ function pad4(value) {
746
+ return String(value).padStart(4, "0");
747
+ }
748
+
680
749
  // src/core/aggregateExpression.ts
681
750
  function quote(value) {
682
751
  return `'${value.replace(/'/g, "''")}'`;
@@ -1095,6 +1164,19 @@ var Parser = class {
1095
1164
  this.activeCteDefinition = null;
1096
1165
  this.provisionalRecursiveCte = null;
1097
1166
  this.allowSelectArithVariable = false;
1167
+ if (capabilities.dialect1) {
1168
+ for (let index = 0; index + 1 < tokens.length; index++) {
1169
+ const token = tokens[index];
1170
+ if (token.kind !== "VARIABLE" /* VARIABLE */ || tokens[index + 1].kind !== "(" /* LPAREN */) continue;
1171
+ const name = token.value.slice(1).toUpperCase();
1172
+ if (!isAsOfFunctionName(name)) {
1173
+ throw new ParseError(
1174
+ `\u4F7F\u7528\u53EF\u80FD\u306A as-of \u95A2\u6570\u306F ${AS_OF_FUNCTION_NAMES.map((item) => `@${item}`).join("/")} \u3067\u3059`,
1175
+ token
1176
+ );
1177
+ }
1178
+ }
1179
+ }
1098
1180
  }
1099
1181
  // ----------------------------------------------------------
1100
1182
  // 公開 API
@@ -1264,6 +1346,10 @@ var Parser = class {
1264
1346
  parseScalarExpr(context, allowScalarSubquery) {
1265
1347
  const tok = this.peek();
1266
1348
  if (tok.kind === "VARIABLE" /* VARIABLE */) {
1349
+ if (this.peekAt(1).kind === "(" /* LPAREN */ && this.capabilities.dialect1) {
1350
+ this.advance();
1351
+ return this.finishVariableReference(tok);
1352
+ }
1267
1353
  throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F\u4ED6\u306E\u5909\u6570\u3092\u53C2\u7167\u3067\u304D\u307E\u305B\u3093`, tok);
1268
1354
  }
1269
1355
  if (tok.kind === "NULL" /* NULL */) {
@@ -1803,12 +1889,28 @@ var Parser = class {
1803
1889
  throw new ParseError("\u3053\u306E\u69CB\u6587\u306B\u306F -- @ksql dialect: 1 \u306E\u5BA3\u8A00\u304C\u5FC5\u8981\u3067\u3059", tok);
1804
1890
  }
1805
1891
  }
1892
+ /** VARIABLE + `()` is the dialect-1 as-of call syntax; a bare VARIABLE stays unchanged. */
1893
+ finishVariableReference(tok) {
1894
+ const ordinary = { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
1895
+ if (this.peek().kind !== "(" /* LPAREN */) return ordinary;
1896
+ if (!this.capabilities.dialect1) return ordinary;
1897
+ const name = tok.value.slice(1).toUpperCase();
1898
+ if (!isAsOfFunctionName(name)) {
1899
+ throw new ParseError(
1900
+ `\u4F7F\u7528\u53EF\u80FD\u306A as-of \u95A2\u6570\u306F ${AS_OF_FUNCTION_NAMES.map((item) => `@${item}`).join("/")} \u3067\u3059`,
1901
+ tok
1902
+ );
1903
+ }
1904
+ this.advance();
1905
+ this.expect(")" /* RPAREN */, `@${name} \u306F\u5F15\u6570\u306A\u3057\u306E () \u3067\u547C\u3073\u51FA\u3057\u3066\u304F\u3060\u3055\u3044`);
1906
+ return { type: "VARIABLE", name: asOfVariableName(name) };
1907
+ }
1806
1908
  /** ASSERT のオペランド: 文字列 / スカラーサブクエリ / 数値算術式 */
1807
1909
  parseAssertOperand() {
1808
1910
  const tok = this.peek();
1809
1911
  if (tok.kind === "VARIABLE" /* VARIABLE */) {
1810
1912
  this.advance();
1811
- return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
1913
+ return this.finishVariableReference(tok);
1812
1914
  }
1813
1915
  if (tok.kind === "STRING" /* STRING */) {
1814
1916
  this.advance();
@@ -2182,7 +2284,7 @@ var Parser = class {
2182
2284
  }
2183
2285
  if (tok.kind === "VARIABLE" /* VARIABLE */) {
2184
2286
  this.advance();
2185
- args.push({ type: "VARIABLE", name: tok.value.slice(1).toLowerCase() });
2287
+ args.push(this.finishVariableReference(tok));
2186
2288
  continue;
2187
2289
  }
2188
2290
  let sign = "";
@@ -2267,15 +2369,21 @@ var Parser = class {
2267
2369
  return this.withAliasDisplay({ type: "SCALAR_VALUE_COL", expr, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
2268
2370
  }
2269
2371
  if (this.peek().kind === "VARIABLE" /* VARIABLE */) {
2270
- const variable = this.advance();
2271
- if (!this.consume("AS" /* AS */)) {
2272
- throw new ParseError("SELECT \u5217\u306E\u30D0\u30C3\u30C1\u5909\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
2372
+ const variable = this.finishVariableReference(this.advance());
2373
+ const asOfFunction = asOfFunctionNameFromVariable(variable.name);
2374
+ let parsedAlias2 = null;
2375
+ if (asOfFunction === null) {
2376
+ if (!this.consume("AS" /* AS */)) {
2377
+ throw new ParseError("SELECT \u5217\u306E\u30D0\u30C3\u30C1\u5909\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
2378
+ }
2379
+ parsedAlias2 = this.parseAliasName();
2380
+ } else if (this.consume("AS" /* AS */)) {
2381
+ parsedAlias2 = this.parseAliasName();
2273
2382
  }
2274
- const parsedAlias2 = this.parseAliasName();
2275
2383
  return this.withAliasDisplay({
2276
2384
  type: "VARIABLE_COL",
2277
- name: variable.value.slice(1).toLowerCase(),
2278
- alias: parsedAlias2.alias
2385
+ name: variable.name,
2386
+ alias: parsedAlias2?.alias ?? null
2279
2387
  }, parsedAlias2);
2280
2388
  }
2281
2389
  const windowFunc = this.tryWindowFunc();
@@ -2611,7 +2719,7 @@ var Parser = class {
2611
2719
  }
2612
2720
  if (this.peek().kind === "VARIABLE" /* VARIABLE */) {
2613
2721
  const tok = this.advance();
2614
- return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
2722
+ return this.finishVariableReference(tok);
2615
2723
  }
2616
2724
  const aggFunc = this.tryAggregateFunc();
2617
2725
  if (aggFunc !== null) {
@@ -2771,7 +2879,7 @@ var Parser = class {
2771
2879
  }
2772
2880
  if (tok.kind === "VARIABLE" /* VARIABLE */) {
2773
2881
  this.advance();
2774
- return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
2882
+ return this.finishVariableReference(tok);
2775
2883
  }
2776
2884
  if (tok.kind === "CASE" /* CASE */) {
2777
2885
  if (!allowCase) throw new ParseError("\u3053\u306E\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u3067\u306F CASE \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
@@ -2871,7 +2979,7 @@ var Parser = class {
2871
2979
  }
2872
2980
  if (this.allowSelectArithVariable && tok.kind === "VARIABLE" /* VARIABLE */) {
2873
2981
  this.advance();
2874
- return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
2982
+ return this.finishVariableReference(tok);
2875
2983
  }
2876
2984
  if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
2877
2985
  this.advance();
@@ -3479,7 +3587,7 @@ var Parser = class {
3479
3587
  }
3480
3588
  if (tok.kind === "VARIABLE" /* VARIABLE */) {
3481
3589
  this.advance();
3482
- return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
3590
+ return this.finishVariableReference(tok);
3483
3591
  }
3484
3592
  throw new ParseError(
3485
3593
  "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",
@@ -3672,7 +3780,7 @@ var Parser = class {
3672
3780
  const tok = this.peek();
3673
3781
  if (tok.kind === "VARIABLE" /* VARIABLE */) {
3674
3782
  this.advance();
3675
- return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
3783
+ return this.finishVariableReference(tok);
3676
3784
  }
3677
3785
  if (tok.kind === "STRING" /* STRING */) {
3678
3786
  this.advance();
@@ -3728,6 +3836,9 @@ var Parser = class {
3728
3836
  "VARIABLE" /* VARIABLE */,
3729
3837
  "IN / NOT IN \u306E\u5F8C\u306B\u306F (\u5024\u30EA\u30B9\u30C8\u307E\u305F\u306F SELECT) \u304B\u914D\u5217\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059"
3730
3838
  );
3839
+ if (this.peek().kind === "(" /* LPAREN */ && this.capabilities.dialect1) {
3840
+ return { type: "IN_LIST", values: [this.finishVariableReference(variable)] };
3841
+ }
3731
3842
  return { type: "VARIABLE_IN_LIST", name: variable.value.slice(1).toLowerCase() };
3732
3843
  }
3733
3844
  parseInListOrSubquery() {
@@ -3759,7 +3870,7 @@ var Parser = class {
3759
3870
  const sign = tok.kind === "-" /* MINUS */ ? "-" : "+";
3760
3871
  values.push(makeNumberLiteral(`${sign}${number.value}`));
3761
3872
  } else if (tok.kind === "VARIABLE" /* VARIABLE */) {
3762
- values.push({ type: "VARIABLE", name: tok.value.slice(1).toLowerCase() });
3873
+ values.push(this.finishVariableReference(tok));
3763
3874
  } else if (tok.kind === "LOGINUSER" /* LOGINUSER */) {
3764
3875
  if (values.length > 0) {
3765
3876
  throw new ParseError(mixedLoginUserMessage, tok);
@@ -9282,6 +9393,7 @@ function collectVariableRefs(node, refs, inWhere = false) {
9282
9393
  const obj = node;
9283
9394
  const type = obj["type"];
9284
9395
  if ((type === "VARIABLE" || type === "VARIABLE_COL" || type === "VARIABLE_IN_LIST") && typeof obj["name"] === "string") {
9396
+ if (asOfFunctionNameFromVariable(obj["name"]) !== null) return;
9285
9397
  refs.push({
9286
9398
  name: obj["name"],
9287
9399
  kind: type === "VARIABLE" ? "scalar" : type === "VARIABLE_COL" ? "select-column" : "array-in-list",
@@ -16465,7 +16577,14 @@ var DiagnosticCodes = {
16465
16577
  HEADER_INVALID_DIALECT: "KSQL1006",
16466
16578
  LOGICAL_APP_UNRESOLVED: "KSQL1101",
16467
16579
  LEX_ERROR: "KSQL1201",
16468
- PARSE_ERROR: "KSQL1202"
16580
+ PARSE_ERROR: "KSQL1202",
16581
+ DIALECT1_REQUIRED: "KSQL1203",
16582
+ UPDATE_KEY_COMPOSITE: "KSQL1301",
16583
+ UPDATE_KEY_FIELD_TYPE: "KSQL1302",
16584
+ UPDATE_KEY_NOT_UNIQUE: "KSQL1303",
16585
+ SUBTABLE_DML_FORBIDDEN: "KSQL1304",
16586
+ BARE_INSERT_NOT_IDEMPOTENT: "KSQL1305",
16587
+ SERVER_TIME_FUNCTION_NOT_AS_OF: "KSQL1306"
16469
16588
  };
16470
16589
  function sourceLocationAt(source, offset) {
16471
16590
  const target = Math.max(0, Math.min(offset, source.length));
@@ -16596,6 +16715,86 @@ function findLineEnd(source, start) {
16596
16715
  return { contentEnd, next: i };
16597
16716
  }
16598
16717
 
16718
+ // src/core/sql.ts
16719
+ function parseSqlStatements(sql, capabilities = {}) {
16720
+ const tokens = new Lexer(sql).tokenize();
16721
+ const statements = new Parser(tokens, capabilities).parseStatements();
16722
+ statements.forEach(validateStatementStatic);
16723
+ return statements;
16724
+ }
16725
+ function parseSqlStatementsForScript(sql, capabilities = {}) {
16726
+ const header = parseScriptHeader(sql);
16727
+ const headerError = header.diagnostics.find((diagnostic2) => diagnostic2.severity === "error");
16728
+ if (header.hasDirectives && headerError) {
16729
+ throw new Error(`${headerError.code}: ${headerError.message} (${headerError.line}:${headerError.column})`);
16730
+ }
16731
+ const scriptSql = header.hasDirectives ? sql.slice(header.headerEnd) : sql;
16732
+ const scriptCapabilities = header.hasDirectives ? { ...capabilities, dialect1: header.meta.dialect === 1 } : capabilities;
16733
+ return {
16734
+ statements: parseSqlStatements(scriptSql, scriptCapabilities),
16735
+ meta: header.meta
16736
+ };
16737
+ }
16738
+
16739
+ // src/core/dialect1Validation.ts
16740
+ var DIALECT1_SERVER_TIME_FUNCTION_WARNING = "bare \u306E\u6642\u523B\u4F9D\u5B58\u95A2\u6570\u306F kintone \u30B5\u30FC\u30D0\u30FC\u8A55\u4FA1\u306E\u305F\u3081 as-of \u306E\u5BFE\u8C61\u5916\u3067\u3059\u3002\u518D\u73FE\u6027\u304C\u5FC5\u8981\u306A\u3089 @ \u4ED8\u304D\u95A2\u6570\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
16741
+ function validateDialect1UpdateKey(statement, fieldInfos) {
16742
+ if (fieldInfos === void 0) {
16743
+ return statement.keyFields.length === 1 ? [] : [{
16744
+ code: DiagnosticCodes.UPDATE_KEY_COMPOSITE,
16745
+ severity: "error",
16746
+ message: "dialect 1 \u306E UPSERT / MERGE \u306E\u30AD\u30FC\u306F\u5358\u4E00\u30D5\u30A3\u30FC\u30EB\u30C9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u8907\u5408\u30AD\u30FC\u306E\u4EE3\u308F\u308A\u306B\u3001\u9023\u7D50\u30AD\u30FC\u30D5\u30A3\u30FC\u30EB\u30C9\uFF08\u4F8B: \u9867\u5BA2\u30B3\u30FC\u30C9_\u5E74\u6708\uFF09\u3092\u30A2\u30D7\u30EA\u5074\u306B\u7528\u610F\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
16747
+ }];
16748
+ }
16749
+ if (statement.keyFields.length !== 1) return [];
16750
+ const key = statement.keyFields[0];
16751
+ const field = fieldInfos.find((candidate) => candidate.code === key);
16752
+ const issues = [];
16753
+ if (field === void 0 || field.fieldType !== "SINGLE_LINE_TEXT" && field.fieldType !== "NUMBER") {
16754
+ issues.push({
16755
+ code: DiagnosticCodes.UPDATE_KEY_FIELD_TYPE,
16756
+ severity: "error",
16757
+ message: field === void 0 ? `UPSERT / MERGE \u306E\u30AD\u30FC\u300C${key}\u300D\u304C APP${statement.appId} \u306E\u30D5\u30A9\u30FC\u30E0\u306B\u5B58\u5728\u3057\u307E\u305B\u3093\u3002\u91CD\u8907\u7981\u6B62\u3092\u8A2D\u5B9A\u3057\u305F\u6587\u5B57\u5217\uFF081\u884C\uFF09\u307E\u305F\u306F\u6570\u5024\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u30AD\u30FC\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002` : `UPSERT / MERGE \u306E\u30AD\u30FC\u300C${key}\u300D\u306E\u578B ${field.fieldType} \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u91CD\u8907\u7981\u6B62\u3092\u8A2D\u5B9A\u3057\u305F\u6587\u5B57\u5217\uFF081\u884C\uFF09\u307E\u305F\u306F\u6570\u5024\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u30AD\u30FC\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
16758
+ });
16759
+ }
16760
+ if (field?.isUnique === false) {
16761
+ issues.push({
16762
+ code: DiagnosticCodes.UPDATE_KEY_NOT_UNIQUE,
16763
+ severity: "error",
16764
+ message: `UPSERT / MERGE \u306E\u30AD\u30FC\u300C${key}\u300D\u306F\u91CD\u8907\u7981\u6B62\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u30A2\u30D7\u30EA\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u8A2D\u5B9A\u3067\u300C\u5024\u306E\u91CD\u8907\u3092\u7981\u6B62\u3059\u308B\u300D\u3092\u6709\u52B9\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
16765
+ });
16766
+ } else if (field !== void 0 && field.isUnique === void 0) {
16767
+ issues.push({
16768
+ code: DiagnosticCodes.UPDATE_KEY_NOT_UNIQUE,
16769
+ severity: "warning",
16770
+ message: `UPSERT / MERGE \u306E\u30AD\u30FC\u300C${key}\u300D\u306E\u91CD\u8907\u7981\u6B62\u8A2D\u5B9A\u3092 schema resolver \u304B\u3089\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002isUnique \u3092\u8FD4\u3059 resolver \u3092\u4F7F\u7528\u3057\u3001\u30A2\u30D7\u30EA\u5074\u3067\u300C\u5024\u306E\u91CD\u8907\u3092\u7981\u6B62\u3059\u308B\u300D\u304C\u6709\u52B9\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
16771
+ });
16772
+ }
16773
+ return issues;
16774
+ }
16775
+ function statementHasBareServerTimeFunctionInWhere(statement) {
16776
+ let found = false;
16777
+ const visit = (node) => {
16778
+ if (found || node === null || typeof node !== "object") return;
16779
+ if (Array.isArray(node)) {
16780
+ node.forEach(visit);
16781
+ return;
16782
+ }
16783
+ const value = node;
16784
+ const where = value["where"];
16785
+ if (where !== null && typeof where === "object") {
16786
+ const names = serverOnlyFunctionOccurrencesInWhere(where);
16787
+ if (names.some((name) => name === "TODAY" || name === "NOW" || isRelativeDateFunctionName(name))) {
16788
+ found = true;
16789
+ return;
16790
+ }
16791
+ }
16792
+ Object.values(value).forEach(visit);
16793
+ };
16794
+ visit(statement);
16795
+ return found;
16796
+ }
16797
+
16599
16798
  // src/core/dmlPrevalidation.ts
16600
16799
  function collectDmlPrevalidationSnapshotFields(fieldIndex) {
16601
16800
  return [
@@ -18526,7 +18725,7 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
18526
18725
  if (stmt.type !== "EXPLAIN") assertRelativeDatePushdownPlan(relativeDatePlan);
18527
18726
  const unresolved = findVariableRef(stmt);
18528
18727
  if (unresolved !== null && !isApplyParentKlikeStatement(stmt)) {
18529
- throw new Error(`ParseError: variable @${unresolved} is not defined in a batch.`);
18728
+ throw new Error(undefinedBatchVariableMessage(unresolved, "in a batch"));
18530
18729
  }
18531
18730
  assertApplyScope("phase15b", stmt);
18532
18731
  assertApplyExecutionScope("phase15b", stmt);
@@ -18885,17 +19084,10 @@ var BatchTimeoutError = class extends Error {
18885
19084
  }
18886
19085
  };
18887
19086
  async function executeBatch(sql, client, options = {}) {
19087
+ const asOfClock = createAsOfClock(options.asOf ?? /* @__PURE__ */ new Date(), options.timezone);
18888
19088
  resolveRecursiveCteLimits(options);
18889
- const header = parseScriptHeader(sql);
18890
- const headerError = header.diagnostics.find((diagnostic2) => diagnostic2.severity === "error");
18891
- if (header.hasDirectives && headerError) {
18892
- throw new Error(`${headerError.code}: ${headerError.message} (${headerError.line}:${headerError.column})`);
18893
- }
18894
- const statements = parseSqlBatch(
18895
- header.hasDirectives ? sql.slice(header.headerEnd) : sql,
18896
- options.enableImport === true,
18897
- header.hasDirectives && header.meta.dialect === 1
18898
- );
19089
+ const { statements, meta } = parseSqlStatementsForScript(sql, { import: options.enableImport === true });
19090
+ const dialect1Warnings = meta.dialect === 1 && statements.some(statementHasBareServerTimeFunctionInWhere) ? [DIALECT1_SERVER_TIME_FUNCTION_WARNING] : [];
18899
19091
  const analysis = analyzeBatch(statements);
18900
19092
  statements.forEach((statement) => assertApplyExecutionScope("phase15b", statement));
18901
19093
  if (options.allowApplyMutation !== true && statements.some(
@@ -18929,6 +19121,9 @@ async function executeBatch(sql, client, options = {}) {
18929
19121
  try {
18930
19122
  const tempTables = /* @__PURE__ */ new Map();
18931
19123
  const variables = /* @__PURE__ */ new Map();
19124
+ for (const [name, value] of Object.entries(asOfClock.values)) {
19125
+ variables.set(asOfVariableName(name), { type: "string", value });
19126
+ }
18932
19127
  const results = [];
18933
19128
  const failed = /* @__PURE__ */ new Set();
18934
19129
  let aborted = null;
@@ -18985,7 +19180,8 @@ async function executeBatch(sql, client, options = {}) {
18985
19180
  tempTables,
18986
19181
  variables,
18987
19182
  relativeDateVariables,
18988
- clock: statementEvaluationContext(boundOptions)
19183
+ clock: statementEvaluationContext(boundOptions),
19184
+ dialect: meta.dialect
18989
19185
  };
18990
19186
  const outcome = await runWithDeadline(
18991
19187
  executeBatchStatement(statementContext),
@@ -18994,6 +19190,9 @@ async function executeBatch(sql, client, options = {}) {
18994
19190
  );
18995
19191
  if (outcome.result) {
18996
19192
  outcome.result = attachSearchAbortWarning(outcome.result, searchAbortCollector);
19193
+ if (dialect1Warnings.length > 0 && statementHasBareServerTimeFunctionInWhere(statements[i]) && outcome.result.type === "SELECT") {
19194
+ outcome.result = mergeSelectWarnings(outcome.result, dialect1Warnings);
19195
+ }
18997
19196
  }
18998
19197
  const { exitTriggered, ...statementOutcome } = outcome;
18999
19198
  results.push({ ...base, status: "success", ...statementOutcome });
@@ -19023,7 +19222,8 @@ async function executeBatch(sql, client, options = {}) {
19023
19222
  statementCount: statements.length,
19024
19223
  statements: results,
19025
19224
  analysis,
19026
- metrics
19225
+ metrics,
19226
+ ...dialect1Warnings.length > 0 ? { warnings: dialect1Warnings } : {}
19027
19227
  };
19028
19228
  } finally {
19029
19229
  releaseMetadataCacheScope(cacheContext);
@@ -19045,7 +19245,8 @@ async function executeBatchStatement(context) {
19045
19245
  tempTables,
19046
19246
  variables,
19047
19247
  relativeDateVariables,
19048
- clock
19248
+ clock,
19249
+ dialect
19049
19250
  } = context;
19050
19251
  if (stmt.type === "SET_VARIABLE") {
19051
19252
  const resolvedStmt2 = resolveBatchVariableReferences(stmt, variables);
@@ -19117,6 +19318,18 @@ async function executeBatchStatement(context) {
19117
19318
  assertApplyScope("phase15b", resolvedStmt);
19118
19319
  assertApplyExecutionScope("phase15b", resolvedStmt);
19119
19320
  validateStatementStatic(resolvedStmt);
19321
+ if (dialect === 1 && (resolvedStmt.type === "INSERT" || resolvedStmt.type === "UPDATE" || resolvedStmt.type === "DELETE") && resolvedStmt.subtableCode) {
19322
+ throw new Error(
19323
+ "ArgumentError: dialect 1 \u3067\u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u4EEE\u60F3\u30C6\u30FC\u30D6\u30EB\u3078\u306E DML \u306F\u3067\u304D\u307E\u305B\u3093\u3002SELECT \u306F\u53EF\u80FD\u3067\u3059\u3002\u89AA\u30A2\u30D7\u30EA\u3092\u5BFE\u8C61\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
19324
+ );
19325
+ }
19326
+ if (dialect === 1 && (resolvedStmt.type === "UPSERT" || resolvedStmt.type === "UPSERT_SELECT")) {
19327
+ const staticIssue = validateDialect1UpdateKey(resolvedStmt)[0];
19328
+ if (staticIssue) throw new Error(`ArgumentError: ${staticIssue.message}`);
19329
+ const fieldInfos = await getFieldsCached(resolvedStmt.appId, client, cacheContext);
19330
+ const schemaIssue = validateDialect1UpdateKey(resolvedStmt, fieldInfos)[0];
19331
+ if (schemaIssue) throw new Error(`ArgumentError: ${schemaIssue.message}`);
19332
+ }
19120
19333
  await assertRelativeDateExecutionPlan(resolvedStmt, client, cacheContext);
19121
19334
  if (resolvedStmt.type === "VALIDATE") {
19122
19335
  const result = await executeExistingRecordValidationCore(
@@ -19377,11 +19590,16 @@ function evaluateScalarExpr(expr, evaluationContext = {}) {
19377
19590
  }
19378
19591
  return { type: "number", value, raw: String(value) };
19379
19592
  }
19593
+ case "VARIABLE":
19594
+ throw new Error(`InternalError: unresolved variable @${expr.name} reached scalar evaluation.`);
19380
19595
  }
19381
19596
  }
19382
19597
  function resolveBatchVariableReferences(node, variables) {
19383
19598
  return resolveBatchVariableReferencesInternal(node, variables, false);
19384
19599
  }
19600
+ function undefinedBatchVariableMessage(name, location2) {
19601
+ return asOfFunctionNameFromVariable(name) === null ? `ParseError: variable @${name} is not defined ${location2}.` : `ParseError: @NOW() \u306A\u3069\u306E as-of \u95A2\u6570\u306F\u57FA\u6E96\u6642\u523B\u304C\u521D\u671F\u5316\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002`;
19602
+ }
19385
19603
  function resolveBatchVariableReferencesInternal(node, variables, numericArithmeticOperand) {
19386
19604
  if (Array.isArray(node)) {
19387
19605
  return node.map((v) => resolveBatchVariableReferencesInternal(v, variables, false));
@@ -19391,7 +19609,7 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
19391
19609
  if (obj["type"] === "VARIABLE" && typeof obj["name"] === "string") {
19392
19610
  const value = variables.get(obj["name"]);
19393
19611
  if (value === void 0) {
19394
- throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
19612
+ throw new Error(undefinedBatchVariableMessage(obj["name"], "in this batch"));
19395
19613
  }
19396
19614
  if (value.type === "array") {
19397
19615
  throw new Error(`ParseError: array variable @${obj["name"]} can only be used as IN @${obj["name"]}.`);
@@ -19412,9 +19630,9 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
19412
19630
  raw: numericArithmeticOperand === "AGG_ARITH" ? `@${obj["name"]}` : value.raw ?? String(value.value)
19413
19631
  } : { type: "STRING", value: value.value, fromVariable: true };
19414
19632
  }
19415
- if (obj["type"] === "VARIABLE_COL" && typeof obj["name"] === "string" && typeof obj["alias"] === "string") {
19633
+ if (obj["type"] === "VARIABLE_COL" && typeof obj["name"] === "string" && (typeof obj["alias"] === "string" || obj["alias"] === null)) {
19416
19634
  const value = variables.get(obj["name"]);
19417
- if (value === void 0) throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
19635
+ if (value === void 0) throw new Error(undefinedBatchVariableMessage(obj["name"], "in this batch"));
19418
19636
  if (value.type === "array") throw new Error(`ParseError: array variable @${obj["name"]} cannot be used as a SELECT column.`);
19419
19637
  if (value.type === "relative-date") {
19420
19638
  throw new Error(`InternalError: RELATIVE_DATE variable @${obj["name"]} reached a SELECT column.`);
@@ -19440,7 +19658,7 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
19440
19658
  const right = resolved["right"];
19441
19659
  if (right?.["type"] === "VARIABLE_IN_LIST" && typeof right["name"] === "string") {
19442
19660
  const value = variables.get(right["name"]);
19443
- if (value === void 0) throw new Error(`ParseError: variable @${right["name"]} is not defined in this batch.`);
19661
+ if (value === void 0) throw new Error(undefinedBatchVariableMessage(right["name"], "in this batch"));
19444
19662
  if (value.type !== "array") {
19445
19663
  throw new Error(`ParseError: scalar variable @${right["name"]} cannot be used as IN @${right["name"]}; use IN (@${right["name"]}) instead.`);
19446
19664
  }
@@ -26886,7 +27104,8 @@ var EXPLAIN_FETCH_PLAN = /* @__PURE__ */ Symbol("ksql.explainFetchPlan");
26886
27104
  function setExplainFetchPlan(result, plan) {
26887
27105
  result[EXPLAIN_FETCH_PLAN] = plan;
26888
27106
  }
26889
- async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, resolveMetadata = true, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions) {
27107
+ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, resolveMetadata = true, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions, asOf, timezone) {
27108
+ const asOfClock = createAsOfClock(asOf ?? /* @__PURE__ */ new Date(), timezone);
26890
27109
  const recursiveLimits = resolveRecursiveCteLimits({
26891
27110
  recursiveCteMaxDepth,
26892
27111
  recursiveCteMaxRows,
@@ -26894,20 +27113,14 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
26894
27113
  });
26895
27114
  const invocationCacheContext = createInvocationCacheContext(cacheContext);
26896
27115
  try {
26897
- const header = parseScriptHeader(sql);
26898
- const headerError = header.diagnostics.find((diagnostic2) => diagnostic2.severity === "error");
26899
- if (header.hasDirectives && headerError) {
26900
- throw new Error(`${headerError.code}: ${headerError.message} (${headerError.line}:${headerError.column})`);
26901
- }
26902
- const statements = parseSqlBatch(
26903
- header.hasDirectives ? sql.slice(header.headerEnd) : sql,
26904
- enableImport,
26905
- header.hasDirectives && header.meta.dialect === 1
26906
- );
27116
+ const { statements, meta } = parseSqlStatementsForScript(sql, { import: enableImport });
26907
27117
  const analysis = analyzeBatch(statements);
26908
27118
  const normalizedInjectedVariables = validateDeclaredBatchVariables(statements, injectedVariables);
26909
27119
  const relativeDateVariables = prepareRelativeDateVariables(statements, normalizedInjectedVariables);
26910
27120
  const variables = /* @__PURE__ */ new Map();
27121
+ for (const [name, value] of Object.entries(asOfClock.values)) {
27122
+ variables.set(asOfVariableName(name), { type: "string", value });
27123
+ }
26911
27124
  const literalDeclareDefaults = /* @__PURE__ */ new Map();
26912
27125
  const tempSchemaLedger = /* @__PURE__ */ new Map();
26913
27126
  const plans = [];
@@ -26984,10 +27197,16 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
26984
27197
  ), cursorMaxActive)
26985
27198
  ];
26986
27199
  const metadataPlan = explainMetadataLines(whereAnalysis);
27200
+ const dialect1Estimate = meta.dialect === 1 ? buildDialect1ApiEstimateLines(
27201
+ planStmt,
27202
+ analysis.statements[i],
27203
+ maxRecords,
27204
+ dmlMaxRows
27205
+ ) : [];
26987
27206
  plans.push({
26988
27207
  index: i,
26989
27208
  type: analysis.statements[i].statementType,
26990
- plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
27209
+ plan: statementPlan.length === 0 ? [...metadataPlan, ...dialect1Estimate] : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1), ...dialect1Estimate]
26991
27210
  });
26992
27211
  fetchStatements.push({
26993
27212
  index: i,
@@ -27012,6 +27231,63 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
27012
27231
  releaseMetadataCacheScope(invocationCacheContext);
27013
27232
  }
27014
27233
  }
27234
+ function buildDialect1ApiEstimateLines(statement, analysis, maxRecords, dmlMaxRows) {
27235
+ const lines = [" estimated API consumption (dialect 1):"];
27236
+ const sources = collectPhysicalExplainSources(statement);
27237
+ if ((statement.type === "UPDATE" || statement.type === "DELETE") && !sources.includes(`APP${statement.appId}`)) {
27238
+ sources.unshift(`APP${statement.appId}`);
27239
+ }
27240
+ const maxReadRequests = Math.ceil(maxRecords / 500);
27241
+ for (const source of sources) {
27242
+ lines.push(
27243
+ ` read ${source}: \u4E0D\u660E\uFF08\u4E0A\u9650 maxRecords=${maxRecords} \u3068\u4EEE\u5B9A: \u6700\u5927 ${maxReadRequests} \u56DE\u3001500 \u4EF6/\u56DE\uFF09`
27244
+ );
27245
+ }
27246
+ const metadataApps = [.../* @__PURE__ */ new Set([
27247
+ ...analysis.appIds,
27248
+ ...analysis.targetAppId === null ? [] : [analysis.targetAppId]
27249
+ ])];
27250
+ lines.push(
27251
+ ` metadata: GET form fields \xD7 ${metadataApps.length} \u30A2\u30D7\u30EA\uFF08\u30AD\u30E3\u30C3\u30B7\u30E5\u6E08\u307F\u306F\u8FFD\u52A0 0 \u56DE\uFF09`
27252
+ );
27253
+ if (statement.type === "UPSERT" || statement.type === "UPSERT_SELECT") {
27254
+ if (statement.type === "UPSERT") {
27255
+ lines.push(
27256
+ ` UPSERT pre-read: ${Math.ceil(statement.values.length / UPSERT_IN_CHUNK_SIZE)} \u56DE\uFF08${statement.values.length} \u884C\u3001${UPSERT_IN_CHUNK_SIZE} \u30AD\u30FC/\u56DE\uFF09`
27257
+ );
27258
+ } else {
27259
+ lines.push(
27260
+ ` UPSERT pre-read: \u4E0D\u660E\uFF08\u4E0A\u9650 dmlMaxRows=${dmlMaxRows} \u3068\u4EEE\u5B9A: \u6700\u5927 ${Math.ceil(dmlMaxRows / UPSERT_IN_CHUNK_SIZE)} \u56DE\u3001${UPSERT_IN_CHUNK_SIZE} \u30AD\u30FC/\u56DE\uFF09`
27261
+ );
27262
+ }
27263
+ }
27264
+ const knownRows = statement.type === "INSERT" || statement.type === "UPSERT" ? statement.values.length : null;
27265
+ if (statement.type === "INSERT" || statement.type === "INSERT_SELECT" || statement.type === "UPSERT" || statement.type === "UPSERT_SELECT" || statement.type === "UPDATE" || statement.type === "DELETE") {
27266
+ lines.push(knownRows === null ? ` write: \u4E0D\u660E\uFF08\u4E0A\u9650 dmlMaxRows=${dmlMaxRows} \u3068\u4EEE\u5B9A: \u6700\u5927 ${Math.ceil(dmlMaxRows / 100)} \u56DE\u3001100 \u4EF6/HTTP \u30EA\u30AF\u30A8\u30B9\u30C8\uFF09` : ` write: ${Math.ceil(knownRows / 100)} \u56DE\uFF08${knownRows} \u884C\u3001100 \u4EF6/HTTP \u30EA\u30AF\u30A8\u30B9\u30C8\uFF09`);
27267
+ lines.push(" reference: bulkRequest \u306F\u672A\u5B9F\u88C5\u3002\u66F8\u8FBC\u30B5\u30D6\u30EA\u30AF\u30A8\u30B9\u30C8\u6570\u306F HTTP \u66F8\u8FBC\u56DE\u6570\u3068\u540C\u3058");
27268
+ }
27269
+ return lines;
27270
+ }
27271
+ function collectPhysicalExplainSources(statement) {
27272
+ const sources = [];
27273
+ const visit = (node) => {
27274
+ if (Array.isArray(node)) {
27275
+ node.forEach(visit);
27276
+ return;
27277
+ }
27278
+ if (node === null || typeof node !== "object") return;
27279
+ const value = node;
27280
+ if (typeof value["appId"] === "number" && Object.prototype.hasOwnProperty.call(value, "alias") && Object.prototype.hasOwnProperty.call(value, "cteName") && value["cteName"] === null && value["appId"] > 0) {
27281
+ const app = `APP${value["appId"]}`;
27282
+ const subtable = typeof value["subtableCode"] === "string" ? `$${value["subtableCode"]}` : "";
27283
+ const alias = typeof value["alias"] === "string" && value["alias"] !== app ? ` AS ${value["alias"]}` : "";
27284
+ sources.push(`${app}${subtable}${alias}`);
27285
+ }
27286
+ Object.values(value).forEach(visit);
27287
+ };
27288
+ visit(statement);
27289
+ return sources;
27290
+ }
27015
27291
  function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGroupByPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, collector = { sources: [] }, tempSchemaLedger = /* @__PURE__ */ new Map(), createdSchema, explainContext = defaultRecursiveExplainContext()) {
27016
27292
  if (stmt.type === "CREATE_TEMP_TABLE") {
27017
27293
  return [
@@ -28491,20 +28767,6 @@ var OperationCancelledError = class extends Error {
28491
28767
  }
28492
28768
  };
28493
28769
 
28494
- // src/core/sql.ts
28495
- function parseSqlStatement(sql, capabilities = {}) {
28496
- const tokens = new Lexer(sql).tokenize();
28497
- const stmt = new Parser(tokens, capabilities).parse();
28498
- validateStatementStatic(stmt);
28499
- return stmt;
28500
- }
28501
- function parseSqlStatements(sql, capabilities = {}) {
28502
- const tokens = new Lexer(sql).tokenize();
28503
- const statements = new Parser(tokens, capabilities).parseStatements();
28504
- statements.forEach(validateStatementStatic);
28505
- return statements;
28506
- }
28507
-
28508
28770
  // src/core/displayFormat.ts
28509
28771
  var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
28510
28772
  var DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/;
@@ -30217,7 +30479,7 @@ function toParseInput(sql) {
30217
30479
  }
30218
30480
  function tryParseStatements(sql) {
30219
30481
  try {
30220
- const stmts = new Parser(new Lexer(toParseInput(sql)).tokenize()).parseStatements();
30482
+ const { statements: stmts } = parseSqlStatementsForScript(toParseInput(sql));
30221
30483
  return {
30222
30484
  kind: "ok",
30223
30485
  count: stmts.length,
@@ -30232,7 +30494,11 @@ function tryParseStatements(sql) {
30232
30494
  if (e instanceof ParseError) {
30233
30495
  return { kind: "fail", continuable: e.token.kind === "EOF" /* EOF */, message: e.message };
30234
30496
  }
30235
- throw e;
30497
+ return {
30498
+ kind: "fail",
30499
+ continuable: false,
30500
+ message: e instanceof Error ? e.message : String(e)
30501
+ };
30236
30502
  }
30237
30503
  }
30238
30504
 
@@ -31421,7 +31687,7 @@ async function confirmDmlInConsole(sql, opts, queue, defaultProfile = "dev", res
31421
31687
  if (!opts.allowDml || opts.yes || opts.dryRun) return true;
31422
31688
  try {
31423
31689
  const normalized = normalizeSqlAppProfiles(sql, defaultProfile, resolutionContext);
31424
- const statements = parseSqlStatements(normalized.normalizedSql);
31690
+ const { statements } = parseSqlStatementsForScript(normalized.normalizedSql);
31425
31691
  if (statements.length > 1) {
31426
31692
  const analysis = analyzeBatch(statements);
31427
31693
  if (!analysis.containsDml) return true;
@@ -31871,7 +32137,7 @@ async function run() {
31871
32137
  }
31872
32138
  const importEnabled = Object.keys(args.importCsv).length > 0 || Object.keys(args.importJson).length > 0;
31873
32139
  try {
31874
- const statements = parseSqlStatements(sql, { import: importEnabled });
32140
+ const { statements } = parseSqlStatementsForScript(sql, { import: importEnabled });
31875
32141
  parsedStatements = statements;
31876
32142
  const hasApply = (statement) => statement.type === "UPDATE" || statement.type === "INSERT" ? (statement.applyBlocks?.length ?? 0) > 0 : statement.type === "UPSERT" ? (statement.onInsertApplyBlocks?.length ?? 0) > 0 || (statement.onUpdateApplyBlocks?.length ?? 0) > 0 : false;
31877
32143
  containsApplyStatement = statements.some(hasApply);
@@ -31892,7 +32158,7 @@ async function run() {
31892
32158
  isBatchSql = true;
31893
32159
  batchContainsDml = batchAnalysis.containsDml;
31894
32160
  } else {
31895
- const stmt = parseSqlStatement(sql, { import: importEnabled });
32161
+ const stmt = statements[0];
31896
32162
  parsedStmt = stmt;
31897
32163
  stmtType = getStatementType(stmt);
31898
32164
  isDmlStatement = writesKintone(stmt);