@rex0220/kintone-sql-tools 3.58.0 → 3.59.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
@@ -1169,6 +1169,12 @@ var Parser = class {
1169
1169
  if (upper === "DROP") return this.parseDropTempTable();
1170
1170
  if (upper === "DECLARE") return this.parseDeclareVariable();
1171
1171
  if (upper === "VALIDATE") return this.parseValidate();
1172
+ if (upper === "GENERATE_SERIES") {
1173
+ throw new ParseError(
1174
+ "GENERATE_SERIES \u306F WITH \u306E CTE \u672C\u4F53\u306B\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\u3002\u4F8B: WITH s AS (GENERATE_SERIES(1, 5)) SELECT generate_series FROM s",
1175
+ tok
1176
+ );
1177
+ }
1172
1178
  if (upper === "IMPORT") {
1173
1179
  if (!this.capabilities.import) {
1174
1180
  throw new ParseError("IMPORT is not supported (capability is disabled).", tok);
@@ -1928,6 +1934,8 @@ var Parser = class {
1928
1934
  query2 = this.parseShow();
1929
1935
  } else if (inner === "DESCRIBE" /* DESCRIBE */ || inner === "DESC" /* DESC */) {
1930
1936
  query2 = this.parseDescribe();
1937
+ } else if (inner === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "GENERATE_SERIES") {
1938
+ query2 = this.parseGenerateSeries();
1931
1939
  } else {
1932
1940
  query2 = this.tryParseUnionChain(this.parseSelect());
1933
1941
  }
@@ -1939,6 +1947,43 @@ var Parser = class {
1939
1947
  this.cteNames.clear();
1940
1948
  return { type: "WITH", ctes, query };
1941
1949
  }
1950
+ parseGenerateSeries() {
1951
+ const name = this.advance();
1952
+ if (name.kind !== "IDENT" /* IDENT */ || name.value.toUpperCase() !== "GENERATE_SERIES") {
1953
+ throw new ParseError("GENERATE_SERIES \u304C\u5FC5\u8981\u3067\u3059", name);
1954
+ }
1955
+ this.expect("(" /* LPAREN */);
1956
+ const args = [];
1957
+ if (this.peek().kind !== ")" /* RPAREN */) {
1958
+ do {
1959
+ const tok = this.peek();
1960
+ if (tok.kind === "STRING" /* STRING */) {
1961
+ this.advance();
1962
+ args.push({ type: "STRING", value: tok.value });
1963
+ continue;
1964
+ }
1965
+ if (tok.kind === "VARIABLE" /* VARIABLE */) {
1966
+ this.advance();
1967
+ args.push({ type: "VARIABLE", name: tok.value.slice(1).toLowerCase() });
1968
+ continue;
1969
+ }
1970
+ let sign = "";
1971
+ if (tok.kind === "+" /* PLUS */ || tok.kind === "-" /* MINUS */) {
1972
+ sign = tok.kind === "-" /* MINUS */ ? "-" : "+";
1973
+ this.advance();
1974
+ }
1975
+ const number = this.peek();
1976
+ if (number.kind !== "NUMBER" /* NUMBER */) {
1977
+ throw new ParseError("GENERATE_SERIES \u306E\u5F15\u6570\u306B\u306F\u6570\u5024\u3001\u6587\u5B57\u5217\u3001\u307E\u305F\u306F\u30D0\u30C3\u30C1\u5909\u6570\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044", number);
1978
+ }
1979
+ this.advance();
1980
+ args.push(makeNumberLiteral(`${sign}${number.value}`));
1981
+ } while (this.consume("," /* COMMA */));
1982
+ }
1983
+ this.expect(")" /* RPAREN */);
1984
+ const columnAlias = this.consume("AS" /* AS */) ? this.parseIdentifier() : "generate_series";
1985
+ return { type: "GENERATE_SERIES", args, columnAlias };
1986
+ }
1942
1987
  // ----------------------------------------------------------
1943
1988
  // UNION / UNION ALL チェーン
1944
1989
  // ----------------------------------------------------------
@@ -2923,6 +2968,12 @@ var Parser = class {
2923
2968
  // ----------------------------------------------------------
2924
2969
  parseTableRef() {
2925
2970
  const nameTok = this.peek();
2971
+ if (nameTok.kind === "IDENT" /* IDENT */ && nameTok.value.toUpperCase() === "GENERATE_SERIES" && this.peekAt(1).kind === "(" /* LPAREN */) {
2972
+ throw new ParseError(
2973
+ "GENERATE_SERIES \u306F WITH \u306E CTE \u672C\u4F53\u306B\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\u3002\u4F8B: WITH s AS (GENERATE_SERIES(1, 5)) SELECT generate_series FROM s",
2974
+ nameTok
2975
+ );
2976
+ }
2926
2977
  const name = this.parseTableName();
2927
2978
  if (nameTok.kind === "IDENT" /* IDENT */ && name.startsWith("#")) {
2928
2979
  this.tempTableRefs.push(this.prev());
@@ -4698,7 +4749,9 @@ function completeInputReasons(stmt) {
4698
4749
  break;
4699
4750
  case "WITH":
4700
4751
  for (const cte of stmt.ctes) {
4701
- addReasons(reasons, completeInputReasons(cte.query));
4752
+ if (cte.query.type !== "GENERATE_SERIES") {
4753
+ addReasons(reasons, completeInputReasons(cte.query));
4754
+ }
4702
4755
  }
4703
4756
  addReasons(reasons, completeInputReasons(stmt.query));
4704
4757
  break;
@@ -7649,11 +7702,231 @@ function assertStringFunctionArity(func, args) {
7649
7702
  }
7650
7703
  }
7651
7704
 
7705
+ // src/core/generateSeries.ts
7706
+ var GENERATE_SERIES_MAX_ROWS = 1e4;
7707
+ var argumentError = (message) => new Error(`ArgumentError: ${message}`);
7708
+ var isVariable = (arg) => arg.type === "VARIABLE";
7709
+ var isResolvedVariable = (arg) => arg?.type === "STRING" && arg.fromVariable === true;
7710
+ function literalValue(arg) {
7711
+ return arg.type === "NUMBER" ? Number(numberLiteralText(arg)) : arg.value;
7712
+ }
7713
+ function dateParts(value) {
7714
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
7715
+ if (!match) return null;
7716
+ const year = Number(match[1]);
7717
+ const month = Number(match[2]);
7718
+ const day = Number(match[3]);
7719
+ if (year < 1 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31) return null;
7720
+ const date = /* @__PURE__ */ new Date(0);
7721
+ date.setUTCHours(0, 0, 0, 0);
7722
+ date.setUTCFullYear(year, month - 1, day);
7723
+ return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day ? { year, month, day } : null;
7724
+ }
7725
+ function dateOrdinal(value) {
7726
+ const parts = dateParts(value);
7727
+ const date = /* @__PURE__ */ new Date(0);
7728
+ date.setUTCHours(0, 0, 0, 0);
7729
+ date.setUTCFullYear(parts.year, parts.month - 1, parts.day);
7730
+ return Math.trunc(date.getTime() / 864e5);
7731
+ }
7732
+ function dateFromOrdinal(ordinal) {
7733
+ const date = new Date(ordinal * 864e5);
7734
+ const year = date.getUTCFullYear();
7735
+ if (year < 1 || year > 9999) {
7736
+ throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8\u5F15\u6570\u306B\u306F\u5B9F\u5728\u3059\u308B YYYY-MM-DD \u5F62\u5F0F\u306E DATE \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
7737
+ }
7738
+ return `${String(year).padStart(4, "0")}-${String(date.getUTCMonth() + 1).padStart(2, "0")}-${String(date.getUTCDate()).padStart(2, "0")}`;
7739
+ }
7740
+ function parseDateStep(value) {
7741
+ const trimmed = value.trim();
7742
+ const match = /^([+-]?\d+)\s+(day|days)$/i.exec(trimmed);
7743
+ if (!match) {
7744
+ if (/^[+-]?\d+\s+\S+$/i.test(trimmed)) {
7745
+ throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8 step \u306F day \u307E\u305F\u306F days \u306E\u307F\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u3059\u3002");
7746
+ }
7747
+ throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
7748
+ }
7749
+ const step = Number(match[1]);
7750
+ if (!Number.isSafeInteger(step)) {
7751
+ throw argumentError("GENERATE_SERIES \u306E\u6570\u5024\u7CFB\u5217\u306F\u6574\u6570\u306E start\u3001stop\u3001step \u306E\u307F\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
7752
+ }
7753
+ if (step === 0) throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8 step \u306B 0 day \u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002");
7754
+ return step;
7755
+ }
7756
+ function integerValue(value) {
7757
+ if (typeof value === "number") return Number.isSafeInteger(value) ? value : null;
7758
+ if (!/^[+-]?\d+$/.test(value)) return null;
7759
+ const parsed = Number(value);
7760
+ return Number.isSafeInteger(parsed) ? parsed : null;
7761
+ }
7762
+ function integerNumberLiteral(arg) {
7763
+ const decimal = parseExactDecimal(arg.raw ?? String(arg.value));
7764
+ if (decimal === null || decimal.scale > 0) return null;
7765
+ if (decimal.sign === 0) return 0;
7766
+ const digits = decimal.coefficient.length - decimal.scale;
7767
+ if (digits > 16) return null;
7768
+ const magnitude = `${decimal.coefficient}${"0".repeat(-decimal.scale)}`;
7769
+ if (magnitude.length === 16 && magnitude > "9007199254740991") return null;
7770
+ const value = Number(magnitude) * decimal.sign;
7771
+ return Number.isSafeInteger(value) ? value : null;
7772
+ }
7773
+ function isUnsupportedTemporal(value) {
7774
+ return typeof value === "string" && (/^\d{4}-\d{2}-\d{2}T/.test(value) || /^\d{2}:\d{2}(?::\d{2})?$/.test(value));
7775
+ }
7776
+ function countRows(start, stop, step) {
7777
+ if (start === stop) return 1;
7778
+ if (start < stop && step < 0 || start > stop && step > 0) return 0;
7779
+ const distance = step > 0 ? BigInt(stop) - BigInt(start) : BigInt(start) - BigInt(stop);
7780
+ return Number(distance / BigInt(Math.abs(step)) + 1n);
7781
+ }
7782
+ function planResolved(stmt) {
7783
+ if (stmt.args.length < 2 || stmt.args.length > 3) {
7784
+ throw argumentError("GENERATE_SERIES \u306F start\u3001stop \u3068\u7701\u7565\u53EF\u80FD\u306A step \u306E2\u500B\u307E\u305F\u306F3\u500B\u306E\u5F15\u6570\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
7785
+ }
7786
+ const values = stmt.args.map((arg) => literalValue(arg));
7787
+ ["start", "stop", "step"].forEach((name, index) => {
7788
+ if (values[index] === "") throw argumentError(`GENERATE_SERIES \u306E ${name} \u306B\u7A7A\u6587\u5B57\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002`);
7789
+ });
7790
+ const [startRaw, stopRaw, stepRaw] = values;
7791
+ const [startArg, stopArg, stepArg] = stmt.args;
7792
+ const startDate = typeof startRaw === "string" ? dateParts(startRaw) : null;
7793
+ const stopDate = typeof stopRaw === "string" ? dateParts(stopRaw) : null;
7794
+ const dateLikeStart = typeof startRaw === "string" && /^\d{4}-/.test(startRaw);
7795
+ const dateLikeStop = typeof stopRaw === "string" && /^\d{4}-/.test(stopRaw);
7796
+ if ([startRaw, stopRaw].some(isUnsupportedTemporal)) {
7797
+ throw argumentError("GENERATE_SERIES \u306F Phase 1 \u3067\u306F\u6574\u6570\u3068 DATE \u306E\u307F\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u3059\u3002DATETIME \u3068 TIME \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002");
7798
+ }
7799
+ if (startDate || stopDate || dateLikeStart || dateLikeStop || typeof startRaw === "string" && typeof stopRaw === "string" && !(isResolvedVariable(startArg) && isResolvedVariable(stopArg) && integerValue(startRaw) !== null && integerValue(stopRaw) !== null)) {
7800
+ if (!startDate || !stopDate) {
7801
+ if (startDate && typeof stopRaw !== "string" || stopDate && typeof startRaw !== "string") {
7802
+ throw argumentError("GENERATE_SERIES \u306E start \u3068 stop \u306F\u3001\u4E21\u65B9\u3092\u6574\u6570\u307E\u305F\u306F\u4E21\u65B9\u3092 DATE \u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
7803
+ }
7804
+ throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8\u5F15\u6570\u306B\u306F\u5B9F\u5728\u3059\u308B YYYY-MM-DD \u5F62\u5F0F\u306E DATE \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
7805
+ }
7806
+ if (stepRaw !== void 0 && typeof stepRaw !== "string") {
7807
+ throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
7808
+ }
7809
+ const step2 = stepRaw === void 0 ? 1 : parseDateStep(stepRaw);
7810
+ const start2 = startRaw;
7811
+ const stop2 = stopRaw;
7812
+ return { kind: "DATE", start: start2, stop: stop2, step: step2, rowCount: countRows(dateOrdinal(start2), dateOrdinal(stop2), step2) };
7813
+ }
7814
+ const startInteger = startArg.type === "NUMBER" ? integerNumberLiteral(startArg) : isResolvedVariable(startArg) ? integerValue(startRaw) : null;
7815
+ const stopInteger = stopArg.type === "NUMBER" ? integerNumberLiteral(stopArg) : isResolvedVariable(stopArg) ? integerValue(stopRaw) : null;
7816
+ if (startInteger === null || stopInteger === null) {
7817
+ if ((startArg.type === "NUMBER" || isResolvedVariable(startArg)) && (stopArg.type === "NUMBER" || isResolvedVariable(stopArg))) {
7818
+ throw argumentError("GENERATE_SERIES \u306E\u6570\u5024\u7CFB\u5217\u306F\u6574\u6570\u306E start\u3001stop\u3001step \u306E\u307F\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
7819
+ }
7820
+ throw argumentError("GENERATE_SERIES \u306E start \u3068 stop \u306F\u3001\u4E21\u65B9\u3092\u6574\u6570\u307E\u305F\u306F\u4E21\u65B9\u3092 DATE \u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
7821
+ }
7822
+ const resolvedStep = stepRaw === void 0 ? 1 : stepArg?.type === "NUMBER" ? integerNumberLiteral(stepArg) : isResolvedVariable(stepArg) ? integerValue(stepRaw) : null;
7823
+ if (resolvedStep === null) {
7824
+ if (stepArg?.type === "NUMBER" || isResolvedVariable(stepArg)) {
7825
+ throw argumentError("GENERATE_SERIES \u306E\u6570\u5024\u7CFB\u5217\u306F\u6574\u6570\u306E start\u3001stop\u3001step \u306E\u307F\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
7826
+ }
7827
+ throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
7828
+ }
7829
+ const start = startInteger;
7830
+ const stop = stopInteger;
7831
+ const step = resolvedStep;
7832
+ if (step === 0) throw argumentError("GENERATE_SERIES \u306E step \u306B 0 \u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002");
7833
+ return { kind: "INTEGER", start, stop, step, rowCount: countRows(start, stop, step) };
7834
+ }
7835
+ function validateGenerateSeriesStatement(stmt) {
7836
+ if (stmt.args.length < 2 || stmt.args.length > 3) {
7837
+ throw argumentError("GENERATE_SERIES \u306F start\u3001stop \u3068\u7701\u7565\u53EF\u80FD\u306A step \u306E2\u500B\u307E\u305F\u306F3\u500B\u306E\u5F15\u6570\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
7838
+ }
7839
+ if (stmt.args.some(isVariable)) {
7840
+ ["start", "stop", "step"].forEach((name, index) => {
7841
+ const arg = stmt.args[index];
7842
+ if (arg?.type === "STRING" && arg.value === "") {
7843
+ throw argumentError(`GENERATE_SERIES \u306E ${name} \u306B\u7A7A\u6587\u5B57\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002`);
7844
+ }
7845
+ if (arg?.type === "NUMBER" && integerNumberLiteral(arg) === null) {
7846
+ throw argumentError("GENERATE_SERIES \u306E\u6570\u5024\u7CFB\u5217\u306F\u6574\u6570\u306E start\u3001stop\u3001step \u306E\u307F\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
7847
+ }
7848
+ if (index < 2 && arg?.type === "STRING") {
7849
+ if (isUnsupportedTemporal(arg.value)) {
7850
+ throw argumentError("GENERATE_SERIES \u306F Phase 1 \u3067\u306F\u6574\u6570\u3068 DATE \u306E\u307F\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u3059\u3002DATETIME \u3068 TIME \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002");
7851
+ }
7852
+ if (/^\d{4}-/.test(arg.value) && dateParts(arg.value) === null) {
7853
+ throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8\u5F15\u6570\u306B\u306F\u5B9F\u5728\u3059\u308B YYYY-MM-DD \u5F62\u5F0F\u306E DATE \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
7854
+ }
7855
+ }
7856
+ });
7857
+ const step = stmt.args[2];
7858
+ if (step?.type === "NUMBER") {
7859
+ const value = integerNumberLiteral(step);
7860
+ if (value === null) throw argumentError("GENERATE_SERIES \u306E\u6570\u5024\u7CFB\u5217\u306F\u6574\u6570\u306E start\u3001stop\u3001step \u306E\u307F\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
7861
+ if (value === 0) throw argumentError("GENERATE_SERIES \u306E step \u306B 0 \u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002");
7862
+ } else if (step?.type === "STRING") {
7863
+ parseDateStep(step.value);
7864
+ }
7865
+ return null;
7866
+ }
7867
+ const plan = planResolved(stmt);
7868
+ if (plan.rowCount > GENERATE_SERIES_MAX_ROWS) {
7869
+ throw argumentError(`GENERATE_SERIES \u306E\u751F\u6210\u4EF6\u6570 ${plan.rowCount} \u884C\u304C\u4E0A\u9650 ${GENERATE_SERIES_MAX_ROWS} \u884C\u3092\u8D85\u3048\u3066\u3044\u307E\u3059\u3002`);
7870
+ }
7871
+ return plan.rowCount;
7872
+ }
7873
+ function validateGenerateSeriesInStatement(node) {
7874
+ const visit = (value) => {
7875
+ if (value === null || typeof value !== "object") return;
7876
+ if (Array.isArray(value)) {
7877
+ value.forEach(visit);
7878
+ return;
7879
+ }
7880
+ const obj = value;
7881
+ if (obj.type === "WITH") {
7882
+ let total = 0;
7883
+ let complete = true;
7884
+ for (const cte of obj.ctes) {
7885
+ if (cte.query.type === "GENERATE_SERIES") {
7886
+ const count = validateGenerateSeriesStatement(cte.query);
7887
+ if (count === null) complete = false;
7888
+ else total += count;
7889
+ } else visit(cte.query);
7890
+ }
7891
+ if (complete && total > GENERATE_SERIES_MAX_ROWS) {
7892
+ throw argumentError(`\u3053\u306E WITH \u6587\u306E GENERATE_SERIES \u751F\u6210\u4EF6\u6570\u5408\u8A08 ${total} \u884C\u304C\u4E0A\u9650 ${GENERATE_SERIES_MAX_ROWS} \u884C\u3092\u8D85\u3048\u3066\u3044\u307E\u3059\u3002`);
7893
+ }
7894
+ visit(obj.query);
7895
+ return;
7896
+ }
7897
+ Object.values(obj).forEach(visit);
7898
+ };
7899
+ visit(node);
7900
+ }
7901
+ function resolveGenerateSeries(stmt) {
7902
+ const plan = planResolved(stmt);
7903
+ if (plan.rowCount > GENERATE_SERIES_MAX_ROWS) {
7904
+ throw argumentError(`GENERATE_SERIES \u306E\u751F\u6210\u4EF6\u6570 ${plan.rowCount} \u884C\u304C\u4E0A\u9650 ${GENERATE_SERIES_MAX_ROWS} \u884C\u3092\u8D85\u3048\u3066\u3044\u307E\u3059\u3002`);
7905
+ }
7906
+ const values = [];
7907
+ if (plan.kind === "INTEGER") {
7908
+ let current = plan.start;
7909
+ for (let index = 0; index < plan.rowCount; index++) {
7910
+ values.push(String(current));
7911
+ if (index + 1 < plan.rowCount) {
7912
+ const next = current + plan.step;
7913
+ if (!Number.isSafeInteger(next)) throw argumentError("GENERATE_SERIES \u306E\u6570\u5024\u7CFB\u5217\u306F\u6574\u6570\u306E start\u3001stop\u3001step \u306E\u307F\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
7914
+ current = next;
7915
+ }
7916
+ }
7917
+ } else {
7918
+ const startOrdinal = dateOrdinal(plan.start);
7919
+ for (let index = 0; index < plan.rowCount; index++) values.push(dateFromOrdinal(startOrdinal + index * plan.step));
7920
+ }
7921
+ return { ...plan, values };
7922
+ }
7923
+
7652
7924
  // src/core/statementValidation.ts
7653
7925
  function validateStatementStatic(stmt) {
7654
7926
  validateStringFunctionArities(stmt);
7655
7927
  validatePrimaryOrganizationDmlStatement(stmt);
7656
7928
  validateKlikeStatement(stmt);
7929
+ validateGenerateSeriesInStatement(stmt);
7657
7930
  }
7658
7931
  function validateStringFunctionArities(stmt) {
7659
7932
  const visit = (value) => {
@@ -17767,7 +18040,7 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
17767
18040
  type: "NUMBER",
17768
18041
  value: value.value,
17769
18042
  raw: numericArithmeticOperand === "AGG_ARITH" ? `@${obj["name"]}` : value.raw ?? String(value.value)
17770
- } : { type: "STRING", value: value.value };
18043
+ } : { type: "STRING", value: value.value, fromVariable: true };
17771
18044
  }
17772
18045
  if (obj["type"] === "VARIABLE_COL" && typeof obj["name"] === "string" && typeof obj["alias"] === "string") {
17773
18046
  const value = variables.get(obj["name"]);
@@ -18083,10 +18356,16 @@ function hasDefaultRangeAggregateWindow(stmt) {
18083
18356
  function hasWindowNeedingOrderProof(stmt) {
18084
18357
  return hasDefaultRangeAggregateWindow(stmt) || stmt.columns.some((column) => column.type === "WINDOW_COL" && column.windowKind === "VALUE");
18085
18358
  }
18086
- function canProveTotalWindowOrder(stmt, orderBy, resolveField2, context) {
18087
- if (context !== "DIRECT" || stmt.joins.length > 0 || stmt.from.cteName !== null || stmt.from.subtableCode != null) {
18088
- return false;
18359
+ function canProveTotalWindowOrder(stmt, orderBy, resolveField2, context, generatedColumn) {
18360
+ if (generatedColumn !== void 0 && stmt.joins.length === 0 && stmt.from.cteName !== null) {
18361
+ return orderBy.some((item) => {
18362
+ if (item.key.type !== "FIELD_NAME") return false;
18363
+ const ref = aggregateFieldRef(item.key.name);
18364
+ if (ref.field !== generatedColumn) return false;
18365
+ return ref.tableAlias === null || ref.tableAlias === effectiveTableAlias(stmt.from);
18366
+ });
18089
18367
  }
18368
+ if (context !== "DIRECT" || stmt.joins.length > 0 || stmt.from.cteName !== null || stmt.from.subtableCode != null) return false;
18090
18369
  return orderBy.some((item) => {
18091
18370
  if (item.key.type !== "FIELD_NAME") return false;
18092
18371
  const ref = aggregateFieldRef(item.key.name);
@@ -18099,18 +18378,18 @@ function tieBreakAdvice(context, kind) {
18099
18378
  }
18100
18379
  return kind === "RANGE" ? "ORDER BY \u306B\u30EC\u30B3\u30FC\u30C9\u756A\u53F7\u306A\u3069\u306E\u30BF\u30A4\u30D6\u30EC\u30FC\u30AF\u30AD\u30FC\u3092\u8DB3\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : "\u30EC\u30B3\u30FC\u30C9\u756A\u53F7\u7B49\u3092 ORDER BY \u306B\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
18101
18380
  }
18102
- function collectDefaultRangeWindowWarnings(stmt, resolveField2, context) {
18381
+ function collectDefaultRangeWindowWarnings(stmt, resolveField2, context, generatedColumn) {
18103
18382
  const warnings = [];
18104
18383
  for (const column of stmt.columns) {
18105
18384
  if (column.type !== "WINDOW_COL" || column.windowKind !== "AGGREGATE" || column.orderBy.length === 0 || column.frame?.source !== "DEFAULT") continue;
18106
- if (canProveTotalWindowOrder(stmt, column.orderBy, resolveField2, context)) continue;
18385
+ if (canProveTotalWindowOrder(stmt, column.orderBy, resolveField2, context, generatedColumn)) continue;
18107
18386
  warnings.push(
18108
18387
  `${column.alias} \u306F\u65E2\u5B9A\u30D5\u30EC\u30FC\u30E0\uFF08RANGE\uFF09\u3067\u8A55\u4FA1\u3055\u308C\u307E\u3059\u3002ORDER BY \u306E\u5024\u304C\u540C\u3058\u884C\u306F\u3059\u3079\u3066\u540C\u3058\u5024\u306B\u306A\u308A\u307E\u3059\u3002\u884C\u3054\u3068\u306E\u5024\u304C\u5FC5\u8981\u306A\u3089 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW \u3092\u660E\u793A\u3059\u308B\u304B\u3001` + tieBreakAdvice(context, "RANGE")
18109
18388
  );
18110
18389
  }
18111
18390
  for (const column of stmt.columns) {
18112
18391
  if (column.type !== "WINDOW_COL" || column.windowKind !== "VALUE") continue;
18113
- if (canProveTotalWindowOrder(stmt, column.orderBy, resolveField2, context)) continue;
18392
+ if (canProveTotalWindowOrder(stmt, column.orderBy, resolveField2, context, generatedColumn)) continue;
18114
18393
  warnings.push(
18115
18394
  `${column.alias} \u306E ORDER BY \u306F\u5168\u9806\u5E8F\u3067\u306A\u3044\u305F\u3081\u3001\u540C\u9806\u5185\u306E\u524D\u5F8C\u95A2\u4FC2\u306F\u672A\u898F\u5B9A\u3067\u3059\u3002` + tieBreakAdvice(context, "VALUE")
18116
18395
  );
@@ -20041,6 +20320,8 @@ async function executeWith(stmt, client, options, cacheContext, seed, captureCol
20041
20320
  result2 = await executeShowApps(client);
20042
20321
  } else if (cte.query.type === "DESCRIBE") {
20043
20322
  result2 = await executeDescribe(cte.query, client, cacheContext);
20323
+ } else if (cte.query.type === "GENERATE_SERIES") {
20324
+ result2 = executeGenerateSeries(cte.query);
20044
20325
  } else {
20045
20326
  result2 = await executeQueryWithCte(cte.query, client, options, cteCache, cacheContext, true);
20046
20327
  }
@@ -20048,7 +20329,8 @@ async function executeWith(stmt, client, options, cacheContext, seed, captureCol
20048
20329
  cteCache.set(cte.name, {
20049
20330
  rows: result2.rows,
20050
20331
  columns: result2.columns,
20051
- columnMeta: materializedMetaBySelectResult.get(result2)
20332
+ columnMeta: materializedMetaBySelectResult.get(result2),
20333
+ ...cte.query.type === "GENERATE_SERIES" ? { uniqueGeneratedColumn: cte.query.columnAlias } : {}
20052
20334
  });
20053
20335
  }
20054
20336
  const result = await executeQueryWithCte(
@@ -20061,6 +20343,27 @@ async function executeWith(stmt, client, options, cacheContext, seed, captureCol
20061
20343
  );
20062
20344
  return mergeSelectWarnings(result, [...warnings]);
20063
20345
  }
20346
+ function executeGenerateSeries(stmt) {
20347
+ const series = resolveGenerateSeries(stmt);
20348
+ const result = {
20349
+ type: "SELECT",
20350
+ columns: [stmt.columnAlias],
20351
+ rows: series.values.map((value) => ({ [stmt.columnAlias]: value })),
20352
+ rowCount: series.rowCount,
20353
+ warnings: []
20354
+ };
20355
+ const meta = series.kind === "INTEGER" ? {
20356
+ sortKind: "number",
20357
+ fieldType: "NUMBER",
20358
+ semantics: resolveFieldSemantics({ fieldType: "NUMBER" })
20359
+ } : {
20360
+ sortKind: "string",
20361
+ fieldType: "DATE",
20362
+ semantics: resolveFieldSemantics({ fieldType: "DATE" })
20363
+ };
20364
+ materializedMetaBySelectResult.set(result, /* @__PURE__ */ new Map([[stmt.columnAlias, meta]]));
20365
+ return result;
20366
+ }
20064
20367
  async function executeQueryWithCte(query, client, options, cteCache, cacheContext, captureColumnMeta = false, b86PreflightComplete = false) {
20065
20368
  if (!b86PreflightComplete) {
20066
20369
  await preflightB86QueryWithCte(query, client, cteCache, cacheContext);
@@ -20167,7 +20470,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
20167
20470
  const defaultRangeWarnings = collectDefaultRangeWindowWarnings(
20168
20471
  stmt,
20169
20472
  choiceAndWindowResolver,
20170
- "DERIVED"
20473
+ "DERIVED",
20474
+ stmt.joins.length === 0 && stmt.from.cteName !== null ? cteCache.get(stmt.from.cteName)?.uniqueGeneratedColumn : void 0
20171
20475
  );
20172
20476
  const maxRecords = options.maxRecords ?? 1e4;
20173
20477
  const warnings = /* @__PURE__ */ new Set();
@@ -23840,6 +24144,9 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
23840
24144
  }
23841
24145
  if (typed["type"] === "SHOW_APPS") return [...SHOW_APPS_COLUMNS];
23842
24146
  if (typed["type"] === "DESCRIBE") return [...DESCRIBE_COLUMNS];
24147
+ if (typed["type"] === "GENERATE_SERIES") {
24148
+ return [node.columnAlias];
24149
+ }
23843
24150
  throw new Error("ArgumentError: EXPLAIN could not determine the relation output schema.");
23844
24151
  };
23845
24152
  const preflightExplainRelations = async (node) => {
@@ -25133,6 +25440,22 @@ function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collec
25133
25440
  "cte"
25134
25441
  ));
25135
25442
  lines.push("");
25443
+ } else if (cte.query.type === "GENERATE_SERIES") {
25444
+ const series = resolveGenerateSeries(cte.query);
25445
+ const step = series.kind === "DATE" ? `${series.step} ${Math.abs(series.step) === 1 ? "day" : "days"}` : String(series.step);
25446
+ lines.push(
25447
+ `[cte: ${cte.name}]`,
25448
+ " source: GENERATE_SERIES",
25449
+ ` column: ${cte.query.columnAlias}`,
25450
+ ` series type: ${series.kind}`,
25451
+ ` start: ${series.start}`,
25452
+ ` stop: ${series.stop}`,
25453
+ ` step: ${step}`,
25454
+ ` rows: ${series.rowCount}`,
25455
+ ` row guard: ${series.rowCount} / ${GENERATE_SERIES_MAX_ROWS}`,
25456
+ " records API: none",
25457
+ ""
25458
+ );
25136
25459
  }
25137
25460
  }
25138
25461
  if (stmt.query.type === "SELECT" || stmt.query.type === "UNION") {
@@ -26083,19 +26406,19 @@ function normalizeSqlAppProfiles(sql, defaultProfile = "dev", resolutionContext)
26083
26406
  var PHYSICAL_APP_KEY_RE = /^APP\d+$/i;
26084
26407
  var NUMERIC_APP_KEY_RE = /^\d+$/;
26085
26408
  var LOGICAL_SQL_KEY_RE = /^LAPP_/i;
26086
- function argumentError(message) {
26409
+ function argumentError2(message) {
26087
26410
  return new Error(`ArgumentError: ${message}`);
26088
26411
  }
26089
26412
  function normalizeLogicalApps(profileName, value) {
26090
26413
  if (value === void 0) return void 0;
26091
26414
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
26092
- throw argumentError(`logicalApps for profile "${profileName}" must be an object.`);
26415
+ throw argumentError2(`logicalApps for profile "${profileName}" must be an object.`);
26093
26416
  }
26094
26417
  const normalized = {};
26095
26418
  const physicalIdOwners = /* @__PURE__ */ new Map();
26096
26419
  for (const [rawName, rawAppId] of Object.entries(value)) {
26097
26420
  if (PHYSICAL_APP_KEY_RE.test(rawName) || NUMERIC_APP_KEY_RE.test(rawName) || LOGICAL_SQL_KEY_RE.test(rawName)) {
26098
- throw argumentError(
26421
+ throw argumentError2(
26099
26422
  `logical app key "${rawName}" in profile "${profileName}" must be a logical name without APP, numeric, or LAPP_ syntax.`
26100
26423
  );
26101
26424
  }
@@ -26103,23 +26426,23 @@ function normalizeLogicalApps(profileName, value) {
26103
26426
  try {
26104
26427
  logicalName = canonicalizeLogicalAppName(rawName);
26105
26428
  } catch {
26106
- throw argumentError(
26429
+ throw argumentError2(
26107
26430
  `logical app key "${rawName}" in profile "${profileName}" must match the logical app name rules.`
26108
26431
  );
26109
26432
  }
26110
26433
  if (Object.prototype.hasOwnProperty.call(normalized, logicalName)) {
26111
- throw argumentError(
26434
+ throw argumentError2(
26112
26435
  `logical app name "${logicalName}" is duplicated after case normalization in profile "${profileName}".`
26113
26436
  );
26114
26437
  }
26115
26438
  if (typeof rawAppId !== "number" || !Number.isSafeInteger(rawAppId) || rawAppId <= 0) {
26116
- throw argumentError(
26439
+ throw argumentError2(
26117
26440
  `physical app ID for logical app "${logicalName}" in profile "${profileName}" must be a positive safe integer.`
26118
26441
  );
26119
26442
  }
26120
26443
  const existingName = physicalIdOwners.get(rawAppId);
26121
26444
  if (existingName !== void 0) {
26122
- throw argumentError(
26445
+ throw argumentError2(
26123
26446
  `logical apps "${existingName}" and "${logicalName}" in profile "${profileName}" map to the same physical app ID ${rawAppId}; physical app aliases are not supported yet.`
26124
26447
  );
26125
26448
  }
@@ -26130,31 +26453,31 @@ function normalizeLogicalApps(profileName, value) {
26130
26453
  }
26131
26454
  function validateKsqlConfig(config) {
26132
26455
  if (config === null || typeof config !== "object" || Array.isArray(config)) {
26133
- throw argumentError("config must be an object.");
26456
+ throw argumentError2("config must be an object.");
26134
26457
  }
26135
26458
  if (config.profiles === void 0) return config;
26136
26459
  if (config.profiles === null || typeof config.profiles !== "object" || Array.isArray(config.profiles)) {
26137
- throw argumentError("profiles must be an object.");
26460
+ throw argumentError2("profiles must be an object.");
26138
26461
  }
26139
26462
  for (const [profileName, profile] of Object.entries(config.profiles)) {
26140
26463
  if (profile === null || typeof profile !== "object" || Array.isArray(profile)) {
26141
- throw argumentError(`profile "${profileName}" must be an object.`);
26464
+ throw argumentError2(`profile "${profileName}" must be an object.`);
26142
26465
  }
26143
26466
  if (profile.allowPhysicalAppRefs !== void 0 && typeof profile.allowPhysicalAppRefs !== "boolean") {
26144
- throw argumentError(`allowPhysicalAppRefs for profile "${profileName}" must be boolean.`);
26467
+ throw argumentError2(`allowPhysicalAppRefs for profile "${profileName}" must be boolean.`);
26145
26468
  }
26146
26469
  const logicalApps = normalizeLogicalApps(profileName, profile.logicalApps);
26147
26470
  if (logicalApps !== void 0) profile.logicalApps = logicalApps;
26148
26471
  if (profile.query?.cursorMaxActive !== void 0) {
26149
26472
  const value = profile.query.cursorMaxActive;
26150
26473
  if (!Number.isSafeInteger(value) || value < 1 || value > 5) {
26151
- throw argumentError(`query.cursorMaxActive for profile "${profileName}" must be an integer from 1 to 5.`);
26474
+ throw argumentError2(`query.cursorMaxActive for profile "${profileName}" must be an integer from 1 to 5.`);
26152
26475
  }
26153
26476
  }
26154
26477
  if (profile.query?.dmlMaxSubtableRows !== void 0) {
26155
26478
  const value = profile.query.dmlMaxSubtableRows;
26156
26479
  if (!Number.isSafeInteger(value) || value <= 0) {
26157
- throw argumentError(`query.dmlMaxSubtableRows for profile "${profileName}" must be a positive safe integer.`);
26480
+ throw argumentError2(`query.dmlMaxSubtableRows for profile "${profileName}" must be a positive safe integer.`);
26158
26481
  }
26159
26482
  }
26160
26483
  }
@@ -26174,7 +26497,7 @@ function createAppResolutionContext(config, defaultProfile) {
26174
26497
  function requireProfile(profileName) {
26175
26498
  const profile = profiles[profileName];
26176
26499
  if (!profile && profileName === defaultProfile) return implicitDefaultProfile;
26177
- if (!profile) throw argumentError(`profile "${profileName}" is not defined.`);
26500
+ if (!profile) throw argumentError2(`profile "${profileName}" is not defined.`);
26178
26501
  return profile;
26179
26502
  }
26180
26503
  return {
@@ -26184,11 +26507,11 @@ function createAppResolutionContext(config, defaultProfile) {
26184
26507
  try {
26185
26508
  logicalName = canonicalizeLogicalAppName(name);
26186
26509
  } catch {
26187
- throw argumentError(`logical app name "${name}" must match the logical app name rules.`);
26510
+ throw argumentError2(`logical app name "${name}" must match the logical app name rules.`);
26188
26511
  }
26189
26512
  const appId = requireProfile(profileName).logicalApps?.[logicalName];
26190
26513
  if (appId === void 0) {
26191
- throw argumentError(`logical app LAPP_${logicalName}@${profileName} is not defined.`);
26514
+ throw argumentError2(`logical app LAPP_${logicalName}@${profileName} is not defined.`);
26192
26515
  }
26193
26516
  return appId;
26194
26517
  },
@@ -26196,7 +26519,7 @@ function createAppResolutionContext(config, defaultProfile) {
26196
26519
  const profileName = profile || defaultProfile;
26197
26520
  if (!profiles[profileName]) return;
26198
26521
  if (requireProfile(profileName).allowPhysicalAppRefs === false) {
26199
- throw argumentError(
26522
+ throw argumentError2(
26200
26523
  `physical app references are not allowed for profile "${profileName}"; use LAPP_<NAME>.`
26201
26524
  );
26202
26525
  }