@rex0220/kintone-sql-tools 3.37.1 → 3.39.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
@@ -1175,13 +1175,38 @@ var Parser = class {
1175
1175
  parseDeclareVariable() {
1176
1176
  this.advance();
1177
1177
  const variable = this.expect("VARIABLE" /* VARIABLE */, "DECLARE \u306E\u5F8C\u306B\u306F\u5909\u6570\u540D\uFF08\u4F8B: @name\uFF09\u304C\u5FC5\u8981\u3067\u3059");
1178
+ const relativeDate = this.peek().kind === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "RELATIVE_DATE";
1179
+ if (relativeDate) this.advance();
1178
1180
  this.expect("=" /* EQ */);
1181
+ if (relativeDate) {
1182
+ return {
1183
+ type: "DECLARE_VARIABLE",
1184
+ name: variable.value.slice(1).toLowerCase(),
1185
+ annotation: "RELATIVE_DATE",
1186
+ default: this.parseRelativeDateVariableToken()
1187
+ };
1188
+ }
1179
1189
  const expr = this.parseScalarExpr("DECLARE", false);
1180
1190
  if (expr.type === "SCALAR_SUBQUERY") {
1181
1191
  throw new ParseError("DECLARE \u306E\u65E2\u5B9A\u5024\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
1182
1192
  }
1183
1193
  return { type: "DECLARE_VARIABLE", name: variable.value.slice(1).toLowerCase(), default: expr };
1184
1194
  }
1195
+ /** RELATIVE_DATE 宣言専用。WHERE と同じ関数パーサーを使い、日付系14個だけを許可する。 */
1196
+ parseRelativeDateVariableToken() {
1197
+ const tok = this.peek();
1198
+ const contextualFunction = PARSER_CONTEXTUAL_FUNCTION_TOKEN_MAP[tok.kind];
1199
+ if (contextualFunction === "TODAY" || contextualFunction === "NOW") {
1200
+ return this.parseSqlValue();
1201
+ }
1202
+ if (tok.kind === "IDENT" /* IDENT */ && this.peekAt(1).kind === "(" /* LPAREN */ && isRelativeDateFunctionName(tok.value.toUpperCase())) {
1203
+ return this.parseRelativeDateFunction();
1204
+ }
1205
+ throw new ParseError(
1206
+ "RELATIVE_DATE \u306E\u65E2\u5B9A\u5024\u306B\u306F\u30B5\u30DD\u30FC\u30C8\u5BFE\u8C61\u306E\u76F8\u5BFE\u65E5\u4ED8\u95A2\u6570\u30C8\u30FC\u30AF\u30F3\u304C\u5FC5\u8981\u3067\u3059",
1207
+ tok
1208
+ );
1209
+ }
1185
1210
  /** SET / DECLARE RHS 専用。既存式パーサーで構文を読み、フィールド参照を明示的に拒否する。 */
1186
1211
  parseScalarExpr(context, allowScalarSubquery) {
1187
1212
  const tok = this.peek();
@@ -1925,24 +1950,25 @@ var Parser = class {
1925
1950
  }
1926
1951
  if (this.isGroupingFunctionStart()) {
1927
1952
  const ref = this.parseGroupingRef();
1928
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1929
- return { type: "GROUPING_COL", ref, alias: alias2 };
1953
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1954
+ return this.withAliasDisplay({ type: "GROUPING_COL", ref, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
1930
1955
  }
1931
1956
  if (this.tryAggregateFunc() === null && this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
1932
1957
  const expr = this.parseScalarValueExpr({ allowAggregateArgs: true });
1933
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1934
- return { type: "SCALAR_VALUE_COL", expr, alias: alias2 };
1958
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1959
+ return this.withAliasDisplay({ type: "SCALAR_VALUE_COL", expr, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
1935
1960
  }
1936
1961
  if (this.peek().kind === "VARIABLE" /* VARIABLE */) {
1937
1962
  const variable = this.advance();
1938
1963
  if (!this.consume("AS" /* AS */)) {
1939
1964
  throw new ParseError("SELECT \u5217\u306E\u30D0\u30C3\u30C1\u5909\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
1940
1965
  }
1941
- return {
1966
+ const parsedAlias2 = this.parseAliasName();
1967
+ return this.withAliasDisplay({
1942
1968
  type: "VARIABLE_COL",
1943
1969
  name: variable.value.slice(1).toLowerCase(),
1944
- alias: this.parseAliasName()
1945
- };
1970
+ alias: parsedAlias2.alias
1971
+ }, parsedAlias2);
1946
1972
  }
1947
1973
  const windowFunc = this.tryWindowFunc();
1948
1974
  if (windowFunc !== null) {
@@ -1950,58 +1976,58 @@ var Parser = class {
1950
1976
  }
1951
1977
  if (this.peek().kind === "CASE" /* CASE */) {
1952
1978
  const expr = this.parseCaseWhenExpr(true);
1953
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1954
- return { type: "CASE_COL", expr, alias: alias2 };
1979
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1980
+ return this.withAliasDisplay({ type: "CASE_COL", expr, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
1955
1981
  }
1956
1982
  if (this.peek().kind === "IF" /* IF */) {
1957
1983
  const expr = this.parseIfExpr(true);
1958
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1959
- return { type: "CASE_COL", expr, alias: alias2 };
1984
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1985
+ return this.withAliasDisplay({ type: "CASE_COL", expr, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
1960
1986
  }
1961
1987
  if (this.tryStringFuncName() !== null) {
1962
1988
  const funcExpr = this.parseStringFuncExpr();
1963
1989
  if (this.isArithOp(this.peek().kind)) {
1964
1990
  const node = this.parseSelectArith(() => this.continueArith(funcExpr));
1965
- const alias3 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1966
- return { type: "ARITH_COL", expr: node, alias: alias3 };
1991
+ const parsedAlias3 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1992
+ return this.withAliasDisplay({ type: "ARITH_COL", expr: node, alias: parsedAlias3?.alias ?? null }, parsedAlias3);
1967
1993
  }
1968
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1969
- return { type: "STRFUNC_COL", expr: funcExpr, alias: alias2 };
1994
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1995
+ return this.withAliasDisplay({ type: "STRFUNC_COL", expr: funcExpr, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
1970
1996
  }
1971
1997
  const aggFunc = this.tryAggregateFunc();
1972
1998
  if (aggFunc !== null) {
1973
1999
  const ref = this.parseAggregateRef(aggFunc);
1974
2000
  if (this.isArithOp(this.peek().kind)) {
1975
2001
  const expr = this.continueAggArith(ref);
1976
- const alias3 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1977
- return { type: "ARITH_AGG_COL", expr, alias: alias3 };
2002
+ const parsedAlias3 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2003
+ return this.withAliasDisplay({ type: "ARITH_AGG_COL", expr, alias: parsedAlias3?.alias ?? null }, parsedAlias3);
1978
2004
  }
1979
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1980
- return {
2005
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2006
+ return this.withAliasDisplay({
1981
2007
  type: "AGGREGATE",
1982
2008
  func: ref.func,
1983
2009
  distinct: ref.distinct,
1984
2010
  arg: ref.arg,
1985
2011
  ...ref.separator !== void 0 ? { separator: ref.separator } : {},
1986
- alias: alias2
1987
- };
2012
+ alias: parsedAlias2?.alias ?? null
2013
+ }, parsedAlias2);
1988
2014
  }
1989
2015
  if (this.peek().kind === "(" /* LPAREN */ && this.peekAt(1).kind === "SELECT" /* SELECT */) {
1990
2016
  this.advance();
1991
2017
  const query = this.parseSelect();
1992
2018
  this.expect(")" /* RPAREN */);
1993
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1994
- return { type: "SCALAR_SUBQUERY_COL", query, alias: alias2 };
2019
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2020
+ return this.withAliasDisplay({ type: "SCALAR_SUBQUERY_COL", query, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
1995
2021
  }
1996
2022
  if (this.peek().kind === "STRING" /* STRING */) {
1997
2023
  const value = this.expect("STRING" /* STRING */).value;
1998
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1999
- return { type: "LITERAL_COL", value, alias: alias2 };
2024
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2025
+ return this.withAliasDisplay({ type: "LITERAL_COL", value, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
2000
2026
  }
2001
2027
  if (this.peek().kind === "(" /* LPAREN */ || this.peek().kind === "NUMBER" /* NUMBER */) {
2002
2028
  const node = this.parseSelectArith(() => this.parseArithAddSub());
2003
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2004
- return { type: "ARITH_COL", expr: node, alias: alias2 };
2029
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2030
+ return this.withAliasDisplay({ type: "ARITH_COL", expr: node, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
2005
2031
  }
2006
2032
  const field = this.parseColumnFieldRef();
2007
2033
  if (field === "_p.*") {
@@ -2013,11 +2039,11 @@ var Parser = class {
2013
2039
  if (this.isArithOp(this.peek().kind)) {
2014
2040
  const left = { type: "FIELD_REF", field };
2015
2041
  const node = this.parseSelectArith(() => this.continueArith(left));
2016
- const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2017
- return { type: "ARITH_COL", expr: node, alias: alias2 };
2042
+ const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2043
+ return this.withAliasDisplay({ type: "ARITH_COL", expr: node, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
2018
2044
  }
2019
- const alias = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2020
- return { type: "FIELD", field, alias };
2045
+ const parsedAlias = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
2046
+ return this.withAliasDisplay({ type: "FIELD", field, alias: parsedAlias?.alias ?? null }, parsedAlias);
2021
2047
  }
2022
2048
  tryWindowFunc() {
2023
2049
  return PARSER_WINDOW_FUNCTION_TOKEN_MAP[this.peek().kind] ?? null;
@@ -2045,8 +2071,8 @@ var Parser = class {
2045
2071
  if (!this.consume("AS" /* AS */)) {
2046
2072
  throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
2047
2073
  }
2048
- const alias = this.parseAliasName();
2049
- return { type: "WINDOW_COL", func, partitionBy, orderBy, alias };
2074
+ const parsedAlias = this.parseAliasName();
2075
+ return this.withAliasDisplay({ type: "WINDOW_COL", func, partitionBy, orderBy, alias: parsedAlias.alias }, parsedAlias);
2050
2076
  }
2051
2077
  selectColumnHasAggregate(column) {
2052
2078
  if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
@@ -4195,10 +4221,24 @@ var Parser = class {
4195
4221
  }
4196
4222
  if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */ || KEYWORDS.has(tok.value.toUpperCase())) {
4197
4223
  this.advance();
4198
- return tok.value.toLowerCase();
4224
+ return {
4225
+ alias: tok.value.toLowerCase(),
4226
+ // alias は小文字で統一
4227
+ display: tok.value
4228
+ };
4199
4229
  }
4200
4230
  throw new ParseError("\u30A8\u30A4\u30EA\u30A2\u30B9\u540D\u304C\u5FC5\u8981\u3067\u3059", tok);
4201
4231
  }
4232
+ /** 互換 snapshot を変えず、SELECT 列 AST に表示表記を保持する。 */
4233
+ withAliasDisplay(column, parsedAlias) {
4234
+ if (parsedAlias !== null) {
4235
+ Object.defineProperty(column, "aliasDisplay", {
4236
+ value: parsedAlias.display,
4237
+ enumerable: false
4238
+ });
4239
+ }
4240
+ return column;
4241
+ }
4202
4242
  /** フィールド名または修飾フィールド名(alias.field)を解析する */
4203
4243
  parseFieldPath() {
4204
4244
  const first = this.parseIdentifier();
@@ -6792,9 +6832,10 @@ function collectRefs(node, tempRefs, appIds) {
6792
6832
  for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
6793
6833
  }
6794
6834
  }
6795
- function collectVariableRefs(node, refs) {
6835
+ var RELATIVE_DATE_COMPARISON_OPS = /* @__PURE__ */ new Set(["=", "!=", "<>", ">", "<", ">=", "<="]);
6836
+ function collectVariableRefs(node, refs, inWhere = false) {
6796
6837
  if (Array.isArray(node)) {
6797
- for (const v of node) collectVariableRefs(v, refs);
6838
+ for (const v of node) collectVariableRefs(v, refs, inWhere);
6798
6839
  return;
6799
6840
  }
6800
6841
  if (node !== null && typeof node === "object") {
@@ -6803,13 +6844,27 @@ function collectVariableRefs(node, refs) {
6803
6844
  if ((type === "VARIABLE" || type === "VARIABLE_COL" || type === "VARIABLE_IN_LIST") && typeof obj["name"] === "string") {
6804
6845
  refs.push({
6805
6846
  name: obj["name"],
6806
- kind: type === "VARIABLE" ? "scalar" : type === "VARIABLE_COL" ? "select-column" : "array-in-list"
6847
+ kind: type === "VARIABLE" ? "scalar" : type === "VARIABLE_COL" ? "select-column" : "array-in-list",
6848
+ relativeDateAllowed: inWhere
6807
6849
  });
6808
6850
  return;
6809
6851
  }
6810
- for (const v of Object.values(obj)) collectVariableRefs(v, refs);
6852
+ const preservesWhereContext = type === "BINARY" || type === "LOGICAL" || type === "NOT" || type === "GROUP" || type === "NULL_CHECK" || type === "BOOLEAN";
6853
+ for (const [key, value] of Object.entries(obj)) {
6854
+ const directVariable = value !== null && typeof value === "object" && value["type"] === "VARIABLE";
6855
+ const directComparisonRight = inWhere && type === "BINARY" && key === "right" && directVariable && RELATIVE_DATE_COMPARISON_OPS.has(String(obj["op"]));
6856
+ collectVariableRefs(
6857
+ value,
6858
+ refs,
6859
+ key === "where" ? true : type === "BINARY" && key === "right" && directVariable ? directComparisonRight : preservesWhereContext ? inWhere : false
6860
+ );
6861
+ }
6811
6862
  }
6812
6863
  }
6864
+ function isRelativeDateDmlUse(stmt) {
6865
+ const target = stmt.type === "EXPLAIN" ? stmt.query : stmt;
6866
+ return isDmlType(target.type) || target.type === "VALIDATE";
6867
+ }
6813
6868
  function validateGroupingStaticQueries(node) {
6814
6869
  if (Array.isArray(node)) {
6815
6870
  for (const value of node) validateGroupingStaticQueries(value);
@@ -6904,6 +6959,18 @@ function analyzeBatch(statements) {
6904
6959
  index
6905
6960
  );
6906
6961
  }
6962
+ if (def.relativeDate && isRelativeDateDmlUse(stmt)) {
6963
+ throw new BatchAnalysisError(
6964
+ `ArgumentError: RELATIVE_DATE variable @${use.name} cannot be used in DML or VALIDATE statements.`,
6965
+ index
6966
+ );
6967
+ }
6968
+ if (def.relativeDate && !use.relativeDateAllowed) {
6969
+ throw new BatchAnalysisError(
6970
+ `ArgumentError: RELATIVE_DATE variable @${use.name} can only be used as a WHERE comparison right operand or BETWEEN boundary.`,
6971
+ index
6972
+ );
6973
+ }
6907
6974
  if (!referencedThisStatement.has(use.name)) {
6908
6975
  def.referencedBy.push(index);
6909
6976
  referencedThisStatement.add(use.name);
@@ -6916,6 +6983,7 @@ function analyzeBatch(statements) {
6916
6983
  variableDefs.set(stmt.name, {
6917
6984
  index,
6918
6985
  kind: stmt.type === "SET_VARIABLE" && stmt.expr.type === "ARRAY" ? "array" : "scalar",
6986
+ relativeDate: stmt.type === "DECLARE_VARIABLE" && stmt.annotation === "RELATIVE_DATE",
6919
6987
  referencedBy: []
6920
6988
  });
6921
6989
  variableOrder.push(stmt.name);
@@ -16089,7 +16157,7 @@ function materializedColumnMetaEqual(left, right) {
16089
16157
  if (!left || !right || left.size !== right.size) return false;
16090
16158
  for (const [column, meta] of left) {
16091
16159
  const candidate = right.get(column);
16092
- if (!candidate || candidate.sortKind !== meta.sortKind || candidate.fieldType !== meta.fieldType || !fieldSemanticsEqual(candidate.semantics, meta.semantics)) return false;
16160
+ if (!candidate || candidate.displayName !== meta.displayName || candidate.sortKind !== meta.sortKind || candidate.fieldType !== meta.fieldType || !fieldSemanticsEqual(candidate.semantics, meta.semantics)) return false;
16093
16161
  }
16094
16162
  return true;
16095
16163
  }
@@ -16108,6 +16176,7 @@ async function executeBatch(sql, client, options = {}) {
16108
16176
  throw new Error("UnsupportedError: APPLY mutation requires allowApplyMutation=true");
16109
16177
  }
16110
16178
  const injectedVariables = validateDeclaredBatchVariables(statements, options.variables);
16179
+ const relativeDateVariables = prepareRelativeDateVariables(statements, injectedVariables);
16111
16180
  const batchOptions = { ...options, variables: injectedVariables };
16112
16181
  if (options.continueOnError && analysis.containsDml) {
16113
16182
  throw new Error("ArgumentError: continueOnError is not allowed for batches containing DML.");
@@ -16179,7 +16248,16 @@ async function executeBatch(sql, client, options = {}) {
16179
16248
  );
16180
16249
  const cursorScope = wrapClientWithCursorScope(statementClient);
16181
16250
  const outcome = await runWithDeadline(
16182
- executeBatchStatement(statements[i], info, cursorScope.client, stmtOptions, cacheContext, tempTables, variables),
16251
+ executeBatchStatement(
16252
+ statements[i],
16253
+ info,
16254
+ cursorScope.client,
16255
+ stmtOptions,
16256
+ cacheContext,
16257
+ tempTables,
16258
+ variables,
16259
+ relativeDateVariables
16260
+ ),
16183
16261
  remaining,
16184
16262
  cursorScope.closeActive
16185
16263
  );
@@ -16224,7 +16302,7 @@ function statementHasApplyMutation(statement) {
16224
16302
  }
16225
16303
  return statement.type === "UPSERT" && statement.validateOnly !== true && Boolean(statement.onInsertApplyBlocks?.length || statement.onUpdateApplyBlocks?.length);
16226
16304
  }
16227
- async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables) {
16305
+ async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables, relativeDateVariables) {
16228
16306
  if (stmt.type === "SET_VARIABLE") {
16229
16307
  const resolvedStmt2 = resolveBatchVariableReferences(stmt, variables);
16230
16308
  validateStatementStatic(resolvedStmt2);
@@ -16269,6 +16347,13 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
16269
16347
  return {};
16270
16348
  }
16271
16349
  if (stmt.type === "DECLARE_VARIABLE") {
16350
+ if (stmt.annotation === "RELATIVE_DATE") {
16351
+ variables.set(stmt.name, {
16352
+ type: "relative-date",
16353
+ value: relativeDateVariables.get(stmt.name)
16354
+ });
16355
+ return {};
16356
+ }
16272
16357
  const injected = options.variables ?? {};
16273
16358
  if (Object.prototype.hasOwnProperty.call(injected, stmt.name)) {
16274
16359
  variables.set(stmt.name, { type: "string", value: injected[stmt.name] });
@@ -16368,7 +16453,16 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
16368
16453
  }
16369
16454
  if (info.tempTablesReferenced.length > 0) {
16370
16455
  if (resolvedStmt.type === "SELECT" || resolvedStmt.type === "UNION") {
16371
- return { result: await executeQueryWithCte(resolvedStmt, client, options, tempTables, cacheContext) };
16456
+ return {
16457
+ result: await executeQueryWithCte(
16458
+ resolvedStmt,
16459
+ client,
16460
+ options,
16461
+ tempTables,
16462
+ cacheContext,
16463
+ options.captureColumnMeta === true
16464
+ )
16465
+ };
16372
16466
  }
16373
16467
  if (resolvedStmt.type === "WITH") {
16374
16468
  return { result: await executeWith(resolvedStmt, client, options, cacheContext, tempTables) };
@@ -16483,6 +16577,32 @@ function parseSqlBatch(sql, enableImport = false) {
16483
16577
  const tokens = new Lexer(sql).tokenize();
16484
16578
  return new Parser(tokens, { import: enableImport }).parseStatements();
16485
16579
  }
16580
+ function parseRelativeDateVariableValue(name, value) {
16581
+ try {
16582
+ const statements = parseSqlBatch(`DECLARE @__b111 RELATIVE_DATE = ${value}`);
16583
+ const declaration = statements[0];
16584
+ if (statements.length !== 1 || declaration?.type !== "DECLARE_VARIABLE" || declaration.annotation !== "RELATIVE_DATE") {
16585
+ throw new Error("token was not consumed as one RELATIVE_DATE declaration");
16586
+ }
16587
+ return declaration.default;
16588
+ } catch (error) {
16589
+ const detail = error instanceof Error ? ` ${error.message}` : "";
16590
+ throw new Error(
16591
+ `ArgumentError: RELATIVE_DATE variable @${name} requires one supported relative-date function token.${detail}`
16592
+ );
16593
+ }
16594
+ }
16595
+ function prepareRelativeDateVariables(statements, injectedVariables) {
16596
+ const prepared = /* @__PURE__ */ new Map();
16597
+ for (const stmt of statements) {
16598
+ if (stmt.type !== "DECLARE_VARIABLE" || stmt.annotation !== "RELATIVE_DATE") continue;
16599
+ prepared.set(
16600
+ stmt.name,
16601
+ Object.prototype.hasOwnProperty.call(injectedVariables, stmt.name) ? parseRelativeDateVariableValue(stmt.name, injectedVariables[stmt.name]) : stmt.default
16602
+ );
16603
+ }
16604
+ return prepared;
16605
+ }
16486
16606
  function evaluateScalarExpr(expr) {
16487
16607
  switch (expr.type) {
16488
16608
  case "STRING":
@@ -16519,7 +16639,8 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
16519
16639
  if (value.type === "array") {
16520
16640
  throw new Error(`ParseError: array variable @${obj["name"]} can only be used as IN @${obj["name"]}.`);
16521
16641
  }
16522
- if (numericArithmeticOperand && value.type !== "number" && value.placeholder !== true) {
16642
+ if (value.type === "relative-date") return value.value;
16643
+ if (numericArithmeticOperand && value.type !== "number" && !(value.type === "string" && value.placeholder === true)) {
16523
16644
  throw new Error(
16524
16645
  `ArgumentError: variable @${obj["name"]} is not numeric and cannot be used in arithmetic.`
16525
16646
  );
@@ -16530,7 +16651,11 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
16530
16651
  const value = variables.get(obj["name"]);
16531
16652
  if (value === void 0) throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
16532
16653
  if (value.type === "array") throw new Error(`ParseError: array variable @${obj["name"]} cannot be used as a SELECT column.`);
16533
- return value.type === "number" ? { type: "ARITH_COL", expr: { type: "NUMBER", value: value.value, raw: value.raw ?? String(value.value) }, alias: obj["alias"] } : { type: "LITERAL_COL", value: value.value, alias: obj["alias"] };
16654
+ if (value.type === "relative-date") {
16655
+ throw new Error(`InternalError: RELATIVE_DATE variable @${obj["name"]} reached a SELECT column.`);
16656
+ }
16657
+ const aliasDisplay = typeof obj["aliasDisplay"] === "string" ? { aliasDisplay: obj["aliasDisplay"] } : {};
16658
+ return value.type === "number" ? { type: "ARITH_COL", expr: { type: "NUMBER", value: value.value, raw: value.raw ?? String(value.value) }, alias: obj["alias"], ...aliasDisplay } : { type: "LITERAL_COL", value: value.value, alias: obj["alias"], ...aliasDisplay };
16534
16659
  }
16535
16660
  if (obj["type"] === "VARIABLE_IN_LIST") return obj;
16536
16661
  const resolved = Object.fromEntries(
@@ -16543,6 +16668,9 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
16543
16668
  )
16544
16669
  ])
16545
16670
  );
16671
+ if (typeof obj["aliasDisplay"] === "string") {
16672
+ resolved["aliasDisplay"] = obj["aliasDisplay"];
16673
+ }
16546
16674
  if (resolved["type"] === "BINARY") {
16547
16675
  const right = resolved["right"];
16548
16676
  if (right?.["type"] === "VARIABLE_IN_LIST" && typeof right["name"] === "string") {
@@ -18068,6 +18196,9 @@ function inferAggregateArgMeta(arg, resolveField2) {
18068
18196
  if (arg.elseResult) results.push(caseResultColumnMeta(arg.elseResult, resolveField2));
18069
18197
  return mergeExpressionColumnMeta(results);
18070
18198
  }
18199
+ function withDisplayName(meta, displayName) {
18200
+ return { ...meta ?? {}, displayName };
18201
+ }
18071
18202
  function selectNeedsSourceColumnMeta(stmt) {
18072
18203
  return stmt.columns.some(
18073
18204
  (column) => column.type === "FIELD" || column.type === "WILDCARD" || column.type === "PARENT_WILDCARD" || column.type === "CASE_COL" || column.type === "AGGREGATE" && (column.func === "MIN" || column.func === "MAX" || column.func === "MODE")
@@ -18132,7 +18263,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
18132
18263
  for (const output of outputColumns) {
18133
18264
  const ref = aggregateFieldRef(output);
18134
18265
  const meta = withPublicSource(resolveField2(ref), ref);
18135
- if (meta) inferred.set(output, meta);
18266
+ inferred.set(output, withDisplayName(meta, meta?.displayName ?? output));
18136
18267
  }
18137
18268
  return inferred;
18138
18269
  }
@@ -18140,7 +18271,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
18140
18271
  for (const output of outputColumns) {
18141
18272
  const ref = aggregateFieldRef(output);
18142
18273
  const meta = withPublicSource(resolveField2(ref), ref);
18143
- if (meta) inferred.set(output, meta);
18274
+ inferred.set(output, withDisplayName(meta, meta?.displayName ?? output));
18144
18275
  }
18145
18276
  }
18146
18277
  const explicitColumns = stmt.columns.filter(
@@ -18184,7 +18315,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
18184
18315
  } else if (column.type === "SCALAR_SUBQUERY_COL") {
18185
18316
  meta = unknownStringColumnMeta();
18186
18317
  }
18187
- if (meta) inferred.set(output, meta);
18318
+ inferred.set(output, withDisplayName(meta, column.aliasDisplay ?? output));
18188
18319
  });
18189
18320
  return inferred;
18190
18321
  }
@@ -18196,15 +18327,14 @@ function mergeUnionColumnMeta(left, right) {
18196
18327
  const a = leftMeta?.get(column);
18197
18328
  const rightColumn = right.columns[index];
18198
18329
  const b = rightColumn === void 0 ? void 0 : rightMeta?.get(rightColumn);
18330
+ let meta;
18199
18331
  if (a && b) {
18200
18332
  const combined = mergeExpressionColumnMeta([a, b]);
18201
18333
  const publicSourceApp = a.publicSourceApp === b.publicSourceApp ? a.publicSourceApp : void 0;
18202
18334
  const { publicSourceApp: _discarded, ...withoutPublicSource } = combined;
18203
- merged.set(
18204
- column,
18205
- publicSourceApp === void 0 ? withoutPublicSource : { ...withoutPublicSource, publicSourceApp }
18206
- );
18207
- } else if (a || b) merged.set(column, unknownStringColumnMeta());
18335
+ meta = publicSourceApp === void 0 ? withoutPublicSource : { ...withoutPublicSource, publicSourceApp };
18336
+ } else meta = unknownStringColumnMeta();
18337
+ merged.set(column, withDisplayName(meta, a?.displayName ?? column));
18208
18338
  });
18209
18339
  return merged;
18210
18340
  }
@@ -22643,7 +22773,8 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
22643
22773
  try {
22644
22774
  const statements = parseSqlBatch(sql, enableImport);
22645
22775
  const analysis = analyzeBatch(statements);
22646
- validateDeclaredBatchVariables(statements, injectedVariables);
22776
+ const normalizedInjectedVariables = validateDeclaredBatchVariables(statements, injectedVariables);
22777
+ const relativeDateVariables = prepareRelativeDateVariables(statements, normalizedInjectedVariables);
22647
22778
  const variables = /* @__PURE__ */ new Map();
22648
22779
  const plans = [];
22649
22780
  for (let i = 0; i < statements.length; i++) {
@@ -22676,7 +22807,7 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
22676
22807
  plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
22677
22808
  });
22678
22809
  if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
22679
- variables.set(stmt.name, stmt.type === "SET_VARIABLE" && stmt.expr.type === "ARRAY" ? { type: "array", elements: stmt.expr.elements.map((element) => ({ type: "string", value: element.value })) } : { type: "string", value: `@${stmt.name}`, placeholder: true });
22810
+ variables.set(stmt.name, stmt.type === "DECLARE_VARIABLE" && stmt.annotation === "RELATIVE_DATE" ? { type: "relative-date", value: relativeDateVariables.get(stmt.name) } : stmt.type === "SET_VARIABLE" && stmt.expr.type === "ARRAY" ? { type: "array", elements: stmt.expr.elements.map((element) => ({ type: "string", value: element.value })) } : { type: "string", value: `@${stmt.name}`, placeholder: true });
22680
22811
  }
22681
22812
  }
22682
22813
  return { statementCount: statements.length, statements: plans };
@@ -22715,6 +22846,12 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
22715
22846
  ];
22716
22847
  }
22717
22848
  if (stmt.type === "DECLARE_VARIABLE") {
22849
+ if (stmt.annotation === "RELATIVE_DATE") {
22850
+ return [
22851
+ `DECLARE @${stmt.name} RELATIVE_DATE = <relative-date token>`,
22852
+ " value: \u5916\u90E8\u6CE8\u5165\u304C\u3042\u308C\u3070\u63A1\u7528\u3001\u306A\u3051\u308C\u3070\u65E2\u5B9A\u30C8\u30FC\u30AF\u30F3\u3092\u4F7F\u7528\uFF08\u5024\u306F\u975E\u516C\u958B\uFF09"
22853
+ ];
22854
+ }
22718
22855
  return [
22719
22856
  `DECLARE @${stmt.name} = <default scalar expression>`,
22720
22857
  " value: \u5916\u90E8\u6CE8\u5165\u304C\u3042\u308C\u3070\u63A1\u7528\u3001\u306A\u3051\u308C\u3070\u65E2\u5B9A\u5024\u3092\u5B9F\u884C\u6642\u306B1\u56DE\u8A55\u4FA1\uFF08\u5024\u306F\u975E\u516C\u958B\uFF09"
@@ -25344,13 +25481,17 @@ function restoreSqlDiagnosticValue(value, bindings, options = {}) {
25344
25481
  return `${dmlTarget[1]}${target}`;
25345
25482
  }
25346
25483
  }
25347
- let restored = value;
25348
- for (const binding of bindings.values()) {
25349
- const internal = `APP${binding.mappedAppId}`;
25484
+ if (bindings.size === 0) return value;
25485
+ const mappedIds = [...bindings.keys()].sort((a, b) => String(b).length - String(a).length);
25486
+ const internalApp = new RegExp(
25487
+ `APP(${mappedIds.join("|")})(?!\\d)(\\s+AS\\s+[^\\s()]+)?(?:\\s+\\(\\1\\))?`,
25488
+ "g"
25489
+ );
25490
+ return value.replace(internalApp, (_match, mappedIdText, alias) => {
25491
+ const binding = bindings.get(Number(mappedIdText));
25350
25492
  const display = binding.source === "logical" ? displayMode === "physical" ? `LAPP_${binding.logicalName} -> APP${binding.appId}` : `LAPP_${binding.logicalName}@${binding.profile}` : displayMode === "physical" ? `APP${binding.appId}` : `APP${binding.appId}@${binding.profile}`;
25351
- restored = restored.split(`${internal} (${binding.mappedAppId})`).join(display).split(internal).join(display);
25352
- }
25353
- return restored;
25493
+ return `${display}${alias ?? ""}`;
25494
+ });
25354
25495
  }
25355
25496
  if (Array.isArray(value)) {
25356
25497
  return value.map((item) => restoreSqlDiagnosticValue(item, bindings, options));