@rex0220/kintone-sql-tools 3.10.0 → 3.12.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/README.md CHANGED
@@ -71,6 +71,8 @@ npm run build:plugin
71
71
  - 一時テーブルで中間結果をサーバー内に保持し、AI のコンテキスト消費を抑えたい場合
72
72
  - validation / EXPLAIN で論理名から最終的な物理アプリ ID への解決を確認したい場合
73
73
 
74
+ 言語リファレンス・レシピは MCP resources(`ksql://language-reference` / `ksql://recipes`)に加えて、read-only ツール **`ksql_docs`** でも読めます。中継環境(リモート接続のプロキシ等)が resources を通さないクライアントでは、`ksql_docs` を引数なしで呼ぶと全章キーの索引が返るので、必要な章だけ `{"section":"language-reference/05-string-number-functions"}` の形で取得してください。
75
+
74
76
  注意:
75
77
 
76
78
  - `APP@profile` と `LAPP_<NAME>[@profile]` は Node.js runtime(CLI / MCP)の拡張です。plugin 側では非対応です。
package/dist-cli/ksql.js CHANGED
@@ -577,6 +577,87 @@ function numberLiteralText(node) {
577
577
 
578
578
  // src/parser/parser.ts
579
579
  var MAX_BATCH_STATEMENTS = 20;
580
+ var PARSER_SCALAR_FUNCTION_TOKEN_MAP = Object.freeze({
581
+ ["UPPER" /* UPPER */]: "UPPER",
582
+ ["LOWER" /* LOWER */]: "LOWER",
583
+ ["TRIM" /* TRIM */]: "TRIM",
584
+ ["LTRIM" /* LTRIM */]: "LTRIM",
585
+ ["RTRIM" /* RTRIM */]: "RTRIM",
586
+ ["LENGTH" /* LENGTH */]: "LENGTH",
587
+ ["LENGTH_CHAR" /* LENGTH_CHAR */]: "LENGTH_CHAR",
588
+ ["SUBSTRING" /* SUBSTRING */]: "SUBSTRING",
589
+ ["SUBSTR" /* SUBSTR */]: "SUBSTRING",
590
+ ["LEFT" /* LEFT */]: "LEFT",
591
+ ["RIGHT" /* RIGHT */]: "RIGHT",
592
+ ["INSTR" /* INSTR */]: "INSTR",
593
+ ["CONCAT" /* CONCAT */]: "CONCAT",
594
+ ["REPLACE" /* REPLACE */]: "REPLACE",
595
+ ["REGEXP_LIKE" /* REGEXP_LIKE */]: "REGEXP_LIKE",
596
+ ["REGEXP_REPLACE" /* REGEXP_REPLACE */]: "REGEXP_REPLACE",
597
+ ["REGEXP_SUBSTR" /* REGEXP_SUBSTR */]: "REGEXP_SUBSTR",
598
+ ["TRANSLATE" /* TRANSLATE */]: "TRANSLATE",
599
+ ["COALESCE" /* COALESCE */]: "COALESCE",
600
+ ["ISNULL" /* ISNULL */]: "ISNULL",
601
+ ["NULLIF" /* NULLIF */]: "NULLIF",
602
+ ["GREATEST" /* GREATEST */]: "GREATEST",
603
+ ["LEAST" /* LEAST */]: "LEAST",
604
+ ["LPAD" /* LPAD */]: "LPAD",
605
+ ["RPAD" /* RPAD */]: "RPAD",
606
+ ["ROUND" /* ROUND */]: "ROUND",
607
+ ["FLOOR" /* FLOOR */]: "FLOOR",
608
+ ["CEIL" /* CEIL */]: "CEIL",
609
+ ["CEILING" /* CEILING */]: "CEIL",
610
+ ["TRUNCATE" /* TRUNCATE */]: "TRUNCATE",
611
+ ["TRUNC" /* TRUNC */]: "TRUNCATE",
612
+ ["ABS" /* ABS */]: "ABS",
613
+ ["MOD" /* MOD */]: "MOD",
614
+ ["POWER" /* POWER */]: "POWER",
615
+ ["POW" /* POW */]: "POWER",
616
+ ["SQRT" /* SQRT */]: "SQRT",
617
+ ["FORMAT" /* FORMAT */]: "FORMAT",
618
+ ["CAST" /* CAST */]: "CAST",
619
+ ["CONVERT" /* CONVERT */]: "CAST",
620
+ ["YEAR" /* YEAR */]: "YEAR",
621
+ ["MONTH" /* MONTH */]: "MONTH",
622
+ ["DAY" /* DAY */]: "DAY",
623
+ ["DATE_FORMAT" /* DATE_FORMAT */]: "DATE_FORMAT",
624
+ ["DATEDIFF" /* DATEDIFF */]: "DATEDIFF",
625
+ ["DATE_ADD" /* DATE_ADD */]: "DATE_ADD",
626
+ ["LAST_DAY" /* LAST_DAY */]: "LAST_DAY"
627
+ });
628
+ var PARSER_IDENT_SCALAR_FUNCTIONS = Object.freeze([
629
+ "CURRENT_DATE",
630
+ "CURRENT_TIMESTAMP"
631
+ ]);
632
+ var PARSER_AGGREGATE_FUNCTION_TOKEN_MAP = Object.freeze({
633
+ ["COUNT" /* COUNT */]: "COUNT",
634
+ ["SUM" /* SUM */]: "SUM",
635
+ ["AVG" /* AVG */]: "AVG",
636
+ ["MAX" /* MAX */]: "MAX",
637
+ ["MIN" /* MIN */]: "MIN",
638
+ ["GROUP_CONCAT" /* GROUP_CONCAT */]: "GROUP_CONCAT"
639
+ });
640
+ var PARSER_WINDOW_FUNCTION_TOKEN_MAP = Object.freeze({
641
+ ["ROW_NUMBER" /* ROW_NUMBER */]: "ROW_NUMBER",
642
+ ["RANK" /* RANK */]: "RANK",
643
+ ["DENSE_RANK" /* DENSE_RANK */]: "DENSE_RANK"
644
+ });
645
+ var PARSER_CONTEXTUAL_FUNCTION_TOKEN_MAP = Object.freeze({
646
+ ["TODAY" /* TODAY */]: "TODAY",
647
+ ["NOW" /* NOW */]: "NOW",
648
+ ["LOGINUSER" /* LOGINUSER */]: "LOGINUSER"
649
+ });
650
+ function isContextualFunctionToken(kind) {
651
+ return PARSER_CONTEXTUAL_FUNCTION_TOKEN_MAP[kind] !== void 0;
652
+ }
653
+ var PARSER_FUNCTION_SPELLINGS = Object.freeze(Array.from(/* @__PURE__ */ new Set([
654
+ ...Object.keys(PARSER_SCALAR_FUNCTION_TOKEN_MAP),
655
+ ...PARSER_IDENT_SCALAR_FUNCTIONS,
656
+ ...Object.keys(PARSER_AGGREGATE_FUNCTION_TOKEN_MAP),
657
+ ...Object.keys(PARSER_WINDOW_FUNCTION_TOKEN_MAP),
658
+ ...Object.keys(PARSER_CONTEXTUAL_FUNCTION_TOKEN_MAP),
659
+ "IF"
660
+ ])));
580
661
  var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
581
662
  "IDENT" /* IDENT */,
582
663
  "BIDENT" /* BIDENT */,
@@ -820,13 +901,14 @@ var Parser = class {
820
901
  this.advance();
821
902
  return { type: "STRING", value: tok.value };
822
903
  }
823
- if (tok.kind === "LOGINUSER" /* LOGINUSER */) {
904
+ const contextualFunction = PARSER_CONTEXTUAL_FUNCTION_TOKEN_MAP[tok.kind];
905
+ if (contextualFunction === "LOGINUSER") {
824
906
  throw new ParseError(
825
907
  `${context} \u306E\u53F3\u8FBA\u3067 LOGINUSER() \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\uFF08\u5B9F\u884C\u74B0\u5883\u5171\u901A\u306E\u30ED\u30B0\u30A4\u30F3\u30E6\u30FC\u30B6\u30FC\u89E3\u6C7A\u306F\u672A\u5BFE\u5FDC\u3067\u3059\uFF09`,
826
908
  tok
827
909
  );
828
910
  }
829
- if (tok.kind === "TODAY" /* TODAY */ || tok.kind === "NOW" /* NOW */) {
911
+ if (contextualFunction !== void 0) {
830
912
  return this.parseSqlValue();
831
913
  }
832
914
  const expr = this.parseArithAddSub();
@@ -1581,16 +1663,7 @@ var Parser = class {
1581
1663
  return { type: "FIELD", field, alias };
1582
1664
  }
1583
1665
  tryWindowFunc() {
1584
- switch (this.peek().kind) {
1585
- case "ROW_NUMBER" /* ROW_NUMBER */:
1586
- return "ROW_NUMBER";
1587
- case "RANK" /* RANK */:
1588
- return "RANK";
1589
- case "DENSE_RANK" /* DENSE_RANK */:
1590
- return "DENSE_RANK";
1591
- default:
1592
- return null;
1593
- }
1666
+ return PARSER_WINDOW_FUNCTION_TOKEN_MAP[this.peek().kind] ?? null;
1594
1667
  }
1595
1668
  parseWindowColumn(func) {
1596
1669
  this.advance();
@@ -1947,64 +2020,14 @@ var Parser = class {
1947
2020
  // ──────────────────────────────────────────────────
1948
2021
  tryStringFuncName() {
1949
2022
  if (this.peekAt(1).kind === "(" /* LPAREN */) {
1950
- if (this.peek().kind === "LEFT" /* LEFT */) return "LEFT";
1951
- if (this.peek().kind === "RIGHT" /* RIGHT */) return "RIGHT";
1952
- }
1953
- const map = {
1954
- ["UPPER" /* UPPER */]: "UPPER",
1955
- ["LOWER" /* LOWER */]: "LOWER",
1956
- ["TRIM" /* TRIM */]: "TRIM",
1957
- ["LTRIM" /* LTRIM */]: "LTRIM",
1958
- ["RTRIM" /* RTRIM */]: "RTRIM",
1959
- ["LENGTH" /* LENGTH */]: "LENGTH",
1960
- ["LENGTH_CHAR" /* LENGTH_CHAR */]: "LENGTH_CHAR",
1961
- ["SUBSTRING" /* SUBSTRING */]: "SUBSTRING",
1962
- ["SUBSTR" /* SUBSTR */]: "SUBSTRING",
1963
- ["CONCAT" /* CONCAT */]: "CONCAT",
1964
- ["REPLACE" /* REPLACE */]: "REPLACE",
1965
- ["REGEXP_LIKE" /* REGEXP_LIKE */]: "REGEXP_LIKE",
1966
- ["REGEXP_REPLACE" /* REGEXP_REPLACE */]: "REGEXP_REPLACE",
1967
- ["REGEXP_SUBSTR" /* REGEXP_SUBSTR */]: "REGEXP_SUBSTR",
1968
- ["TRANSLATE" /* TRANSLATE */]: "TRANSLATE",
1969
- ["COALESCE" /* COALESCE */]: "COALESCE",
1970
- ["NULLIF" /* NULLIF */]: "NULLIF",
1971
- ["ISNULL" /* ISNULL */]: "ISNULL",
1972
- ["INSTR" /* INSTR */]: "INSTR",
1973
- ["GREATEST" /* GREATEST */]: "GREATEST",
1974
- ["LEAST" /* LEAST */]: "LEAST",
1975
- ["LPAD" /* LPAD */]: "LPAD",
1976
- ["RPAD" /* RPAD */]: "RPAD",
1977
- ["CAST" /* CAST */]: "CAST",
1978
- ["CONVERT" /* CONVERT */]: "CAST",
1979
- // CONVERT → CAST に正規化
1980
- ["FORMAT" /* FORMAT */]: "FORMAT",
1981
- ["ROUND" /* ROUND */]: "ROUND",
1982
- ["FLOOR" /* FLOOR */]: "FLOOR",
1983
- ["CEIL" /* CEIL */]: "CEIL",
1984
- ["CEILING" /* CEILING */]: "CEIL",
1985
- // CEILING → CEIL に正規化
1986
- ["TRUNCATE" /* TRUNCATE */]: "TRUNCATE",
1987
- ["TRUNC" /* TRUNC */]: "TRUNCATE",
1988
- // TRUNC → TRUNCATE に正規化
1989
- ["YEAR" /* YEAR */]: "YEAR",
1990
- ["MONTH" /* MONTH */]: "MONTH",
1991
- ["DAY" /* DAY */]: "DAY",
1992
- ["DATE_FORMAT" /* DATE_FORMAT */]: "DATE_FORMAT",
1993
- ["DATEDIFF" /* DATEDIFF */]: "DATEDIFF",
1994
- ["DATE_ADD" /* DATE_ADD */]: "DATE_ADD",
1995
- ["LAST_DAY" /* LAST_DAY */]: "LAST_DAY",
1996
- ["ABS" /* ABS */]: "ABS",
1997
- ["MOD" /* MOD */]: "MOD",
1998
- ["POWER" /* POWER */]: "POWER",
1999
- ["POW" /* POW */]: "POWER",
2000
- // POW → POWER に正規化
2001
- ["SQRT" /* SQRT */]: "SQRT"
2002
- };
2003
- const byKind = map[this.peek().kind] ?? null;
2004
- if (byKind !== null) return byKind;
2023
+ const conditional = PARSER_SCALAR_FUNCTION_TOKEN_MAP[this.peek().kind];
2024
+ if (conditional === "LEFT" || conditional === "RIGHT") return conditional;
2025
+ }
2026
+ const byKind = PARSER_SCALAR_FUNCTION_TOKEN_MAP[this.peek().kind] ?? null;
2027
+ if (byKind !== null && byKind !== "LEFT" && byKind !== "RIGHT") return byKind;
2005
2028
  if (this.peek().kind === "IDENT" /* IDENT */) {
2006
2029
  const name = this.peek().value.toUpperCase();
2007
- if (name === "CURRENT_DATE" || name === "CURRENT_TIMESTAMP") {
2030
+ if (PARSER_IDENT_SCALAR_FUNCTIONS.includes(name)) {
2008
2031
  if (this.peekAt(1).kind === "(" /* LPAREN */) {
2009
2032
  return name;
2010
2033
  }
@@ -2094,16 +2117,7 @@ var Parser = class {
2094
2117
  return false;
2095
2118
  }
2096
2119
  tryAggregateFunc() {
2097
- const map = {
2098
- ["COUNT" /* COUNT */]: "COUNT",
2099
- ["SUM" /* SUM */]: "SUM",
2100
- ["AVG" /* AVG */]: "AVG",
2101
- ["MAX" /* MAX */]: "MAX",
2102
- ["MIN" /* MIN */]: "MIN",
2103
- ["GROUP_CONCAT" /* GROUP_CONCAT */]: "GROUP_CONCAT"
2104
- };
2105
- const kind = this.peek().kind;
2106
- return map[kind] ?? null;
2120
+ return PARSER_AGGREGATE_FUNCTION_TOKEN_MAP[this.peek().kind] ?? null;
2107
2121
  }
2108
2122
  /** 集計関数参照を読む。SELECT 列の alias は呼び出し側で式全体の後に処理する。 */
2109
2123
  parseAggregateRef(func) {
@@ -2464,13 +2478,13 @@ var Parser = class {
2464
2478
  this.advance();
2465
2479
  return { type: "STRING", value: tok.value };
2466
2480
  }
2467
- if (tok.kind === "TODAY" /* TODAY */ || tok.kind === "NOW" /* NOW */ || tok.kind === "LOGINUSER" /* LOGINUSER */) {
2481
+ if (isContextualFunctionToken(tok.kind)) {
2468
2482
  this.advance();
2469
2483
  this.expect("(" /* LPAREN */);
2470
2484
  this.expect(")" /* RPAREN */);
2471
2485
  return {
2472
2486
  type: "KINTONE_FUNC",
2473
- name: tok.value
2487
+ name: PARSER_CONTEXTUAL_FUNCTION_TOKEN_MAP[tok.kind]
2474
2488
  };
2475
2489
  }
2476
2490
  if (tok.kind === "CASE" /* CASE */) {
@@ -3267,7 +3281,7 @@ var Parser = class {
3267
3281
  }
3268
3282
  if (tok.kind === "VARIABLE" /* VARIABLE */) return this.parseSqlValue();
3269
3283
  if (tok.kind === "STRING" /* STRING */) return this.parseSqlValue();
3270
- if (tok.kind === "TODAY" /* TODAY */ || tok.kind === "NOW" /* NOW */ || tok.kind === "LOGINUSER" /* LOGINUSER */) return this.parseSqlValue();
3284
+ if (isContextualFunctionToken(tok.kind)) return this.parseSqlValue();
3271
3285
  if (tok.kind === "IN" /* IN */) return this.parseSqlValue();
3272
3286
  if (tok.kind === "CASE" /* CASE */ || tok.kind === "IF" /* IF */) {
3273
3287
  return this.parseSqlValue();
@@ -4930,6 +4944,9 @@ function canInlineSingleCte(stmt) {
4930
4944
  if (stmt.ctes.length !== 1) return false;
4931
4945
  const cteDef = stmt.ctes[0];
4932
4946
  if (cteDef.query.type !== "SELECT" || resolveSelectMode(cteDef.query) !== "SIMPLE") return false;
4947
+ if (!cteDef.query.columns.every(
4948
+ (column) => column.type === "WILDCARD" || column.type === "FIELD" && (column.alias === null || column.alias === column.field)
4949
+ )) return false;
4933
4950
  const finalQuery = stmt.query;
4934
4951
  if (finalQuery.type !== "SELECT") return false;
4935
4952
  if (finalQuery.from.cteName !== cteDef.name || finalQuery.joins.length > 0) return false;
@@ -9700,10 +9717,12 @@ function flatten(record, alias) {
9700
9717
  }
9701
9718
  return row;
9702
9719
  }
9703
- function applyJoin(leftRows, rightRows, join2) {
9720
+ function applyJoin(leftRows, rightRows, join2, columns = {}) {
9704
9721
  const { on, type: joinType } = join2;
9705
9722
  const leftKey = on.left.tableAlias ? `${on.left.tableAlias}.${on.left.field}` : on.left.field;
9706
9723
  const rightKey = on.right.tableAlias ? `${on.right.tableAlias}.${on.right.field}` : on.right.field;
9724
+ assertJoinKeyAvailable(leftRows, leftKey, columns.leftColumns);
9725
+ assertJoinKeyAvailable(rightRows, rightKey, columns.rightColumns);
9707
9726
  if (joinType === "RIGHT") {
9708
9727
  const leftIndex = /* @__PURE__ */ new Map();
9709
9728
  for (const lRow of leftRows) {
@@ -9713,7 +9732,7 @@ function applyJoin(leftRows, rightRows, join2) {
9713
9732
  else leftIndex.set(k, [lRow]);
9714
9733
  }
9715
9734
  const emptyLeft = {};
9716
- for (const key of Object.keys(leftRows[0] ?? {})) emptyLeft[key] = "";
9735
+ for (const key of columns.leftColumns ?? Object.keys(leftRows[0] ?? {})) emptyLeft[key] = "";
9717
9736
  const result2 = [];
9718
9737
  for (const rRow of rightRows) {
9719
9738
  const k = rRow[rightKey] ?? "";
@@ -9735,7 +9754,7 @@ function applyJoin(leftRows, rightRows, join2) {
9735
9754
  }
9736
9755
  const result = [];
9737
9756
  const emptyRight = {};
9738
- for (const key of Object.keys(rightRows[0] ?? {})) emptyRight[key] = "";
9757
+ for (const key of columns.rightColumns ?? Object.keys(rightRows[0] ?? {})) emptyRight[key] = "";
9739
9758
  for (const lRow of leftRows) {
9740
9759
  const k = lRow[leftKey] ?? "";
9741
9760
  const matched = rightIndex.get(k) ?? [];
@@ -9749,6 +9768,12 @@ function applyJoin(leftRows, rightRows, join2) {
9749
9768
  }
9750
9769
  return result;
9751
9770
  }
9771
+ function assertJoinKeyAvailable(rows, key, savedColumns) {
9772
+ const missing = rows.length > 0 ? rows.some((row) => !Object.prototype.hasOwnProperty.call(row, key)) : savedColumns !== void 0 && !savedColumns.includes(key);
9773
+ if (missing) {
9774
+ throw new Error(`ArgumentError: JOIN key ${key} is not available in the materialized table.`);
9775
+ }
9776
+ }
9752
9777
  function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
9753
9778
  if (where === null) return rows;
9754
9779
  return rows.filter((row) => evalWhere(where, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2));
@@ -10047,9 +10072,12 @@ function applyLimit(rows, limit, offset) {
10047
10072
  if (limit === null) return rows.slice(start);
10048
10073
  return rows.slice(start, start + limit);
10049
10074
  }
10050
- function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2) {
10075
+ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2, hiddenQualifiedAliases) {
10051
10076
  if (columns.length === 1 && columns[0].type === "WILDCARD") {
10052
- const projected2 = rows.map((row) => stripParentShortcutColumns(row));
10077
+ const projected2 = rows.map((row) => stripHiddenQualifiedColumns(
10078
+ stripParentShortcutColumns(row),
10079
+ hiddenQualifiedAliases
10080
+ ));
10053
10081
  const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
10054
10082
  return { rows: projected2, columns: cols };
10055
10083
  }
@@ -10069,7 +10097,10 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, re
10069
10097
  case "VARIABLE_COL":
10070
10098
  throw new Error(`internal error: unresolved SELECT variable @${col.name}`);
10071
10099
  case "WILDCARD":
10072
- Object.assign(out, stripParentShortcutColumns(row));
10100
+ Object.assign(out, stripHiddenQualifiedColumns(
10101
+ stripParentShortcutColumns(row),
10102
+ hiddenQualifiedAliases
10103
+ ));
10073
10104
  break;
10074
10105
  case "PARENT_WILDCARD": {
10075
10106
  const parentKeys = Object.keys(row).filter((k) => k.startsWith("_p.")).sort();
@@ -10322,6 +10353,27 @@ function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
10322
10353
  args: expr.args.map((arg) => resolveAggInStringFuncArg(arg, rows, resolveAggSortKind))
10323
10354
  };
10324
10355
  }
10356
+ function stripHiddenQualifiedColumns(row, hiddenQualifiedAliases) {
10357
+ if (!hiddenQualifiedAliases || hiddenQualifiedAliases.size === 0) return row;
10358
+ const out = {};
10359
+ for (const [key, value] of Object.entries(row)) {
10360
+ if ([...hiddenQualifiedAliases].some((alias) => key.startsWith(`${alias}.`))) continue;
10361
+ out[key] = value;
10362
+ }
10363
+ return out;
10364
+ }
10365
+ function flattenedColumns(columns, alias) {
10366
+ if (columns === void 0) return void 0;
10367
+ return alias ? columns.flatMap((column) => [`${alias}.${column}`, column]) : [...columns];
10368
+ }
10369
+ function mergeKnownColumns(left, right, rows) {
10370
+ if (left === void 0 && right === void 0 && rows.length === 0) return void 0;
10371
+ return [.../* @__PURE__ */ new Set([
10372
+ ...left ?? [],
10373
+ ...right ?? [],
10374
+ ...Object.keys(rows[0] ?? {})
10375
+ ])];
10376
+ }
10325
10377
  function deriveOutputOrderSemantics(columns) {
10326
10378
  const result = /* @__PURE__ */ new Map();
10327
10379
  for (const column of columns) {
@@ -10356,7 +10408,9 @@ function runFullScan(input) {
10356
10408
  havingFieldSemanticsResolver,
10357
10409
  aggregateSortKindResolver,
10358
10410
  appliedKlikes,
10359
- sourceColumns
10411
+ sourceColumns,
10412
+ tableColumns,
10413
+ hiddenQualifiedAliases
10360
10414
  } = input;
10361
10415
  const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
10362
10416
  for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
@@ -10364,11 +10418,25 @@ function runFullScan(input) {
10364
10418
  const mainAlias = stmt.from.alias;
10365
10419
  const mainRecords = tables.get(mainAlias) ?? tables.get(null) ?? [];
10366
10420
  rows = mainRecords.map((r) => flatten(r, mainAlias));
10421
+ let knownColumns = mergeKnownColumns(
10422
+ flattenedColumns(tableColumns?.get(mainAlias), mainAlias),
10423
+ void 0,
10424
+ rows
10425
+ );
10367
10426
  for (const join2 of stmt.joins) {
10368
10427
  const rightAlias = join2.table.alias;
10369
10428
  const rightRecords = tables.get(rightAlias) ?? [];
10370
10429
  const rightRows = rightRecords.map((r) => flatten(r, rightAlias));
10371
- rows = applyJoin(rows, rightRows, join2);
10430
+ const rightColumns = mergeKnownColumns(
10431
+ flattenedColumns(tableColumns?.get(rightAlias), rightAlias),
10432
+ void 0,
10433
+ rightRows
10434
+ );
10435
+ rows = applyJoin(rows, rightRows, join2, {
10436
+ leftColumns: knownColumns,
10437
+ rightColumns
10438
+ });
10439
+ knownColumns = mergeKnownColumns(knownColumns, rightColumns, rows);
10372
10440
  }
10373
10441
  rows = applyFilter(rows, stmt.where, fieldTypeResolver, appliedKlikes, fieldSemanticsResolver);
10374
10442
  if (stmt.groupBy.length > 0 || hasAggregateColumns(stmt.columns)) {
@@ -10381,7 +10449,15 @@ function runFullScan(input) {
10381
10449
  }
10382
10450
  rows = applyOrderBy(rows, stmt.orderBy, optionOrders, sortKinds, effectiveOrderSemantics);
10383
10451
  rows = applyLimit(rows, stmt.limit, stmt.offset);
10384
- return project(rows, stmt.columns, scalarCache, fieldTypeResolver, sourceColumns, fieldSemanticsResolver);
10452
+ return project(
10453
+ rows,
10454
+ stmt.columns,
10455
+ scalarCache,
10456
+ fieldTypeResolver,
10457
+ sourceColumns,
10458
+ fieldSemanticsResolver,
10459
+ hiddenQualifiedAliases
10460
+ );
10385
10461
  }
10386
10462
 
10387
10463
  // src/converter/subtableAdapter.ts
@@ -12693,7 +12769,7 @@ async function buildWhereFieldSemanticsResolver(stmt, client, cacheContext, mate
12693
12769
  if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
12694
12770
  return fromPhysical(stmt.from, field.field, false);
12695
12771
  }
12696
- const table = tables.find((candidate) => candidate.alias === field.tableAlias);
12772
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === field.tableAlias);
12697
12773
  if (!table) return void 0;
12698
12774
  if (table.cteName !== null) {
12699
12775
  return materializedTables?.get(table.cteName)?.columnMeta?.get(field.field)?.semantics ?? syntheticSemantics("string");
@@ -13127,8 +13203,11 @@ function collectSelectTypedInFieldRefs(stmt) {
13127
13203
  }
13128
13204
  return refs;
13129
13205
  }
13206
+ function effectiveTableAlias(table) {
13207
+ return table.alias ?? table.cteName;
13208
+ }
13130
13209
  function findTableForAlias(stmt, alias) {
13131
- return [stmt.from, ...stmt.joins.map((join2) => join2.table)].find((table) => table.alias === alias);
13210
+ return [stmt.from, ...stmt.joins.map((join2) => join2.table)].find((table) => effectiveTableAlias(table) === alias);
13132
13211
  }
13133
13212
  function physicalSelectTables(stmt) {
13134
13213
  return [stmt.from, ...stmt.joins.map((join2) => join2.table)].filter((table) => table.cteName === null);
@@ -13280,7 +13359,7 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
13280
13359
  if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
13281
13360
  info = fieldInfosByApp.get(stmt.from.appId)?.get(ref.field);
13282
13361
  } else {
13283
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
13362
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
13284
13363
  if (!table) return void 0;
13285
13364
  if (table.cteName !== null) {
13286
13365
  return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.semantics ?? syntheticSemantics("string");
@@ -13305,7 +13384,7 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materia
13305
13384
  return matches[0];
13306
13385
  }
13307
13386
  if (!info) return void 0;
13308
- const sourceTable = ref.tableAlias !== null ? tables.find((table) => table.alias === ref.tableAlias) : stmt.joins.length === 0 ? stmt.from : void 0;
13387
+ const sourceTable = ref.tableAlias !== null ? tables.find((table) => effectiveTableAlias(table) === ref.tableAlias) : stmt.joins.length === 0 ? stmt.from : void 0;
13309
13388
  return semanticsForInfo(info, sourceTable?.appId ?? stmt.from.appId);
13310
13389
  };
13311
13390
  }
@@ -13435,7 +13514,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
13435
13514
  const info2 = physicalInfos.get(stmt.from.appId)?.get(ref.field);
13436
13515
  return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
13437
13516
  }
13438
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
13517
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
13439
13518
  if (!table) return void 0;
13440
13519
  if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
13441
13520
  const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
@@ -13540,7 +13619,7 @@ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
13540
13619
  if (field.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
13541
13620
  return fieldTypesByApp.get(stmt.from.appId)?.get(field.field);
13542
13621
  }
13543
- const table = tables.find((candidate) => candidate.alias === field.tableAlias);
13622
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === field.tableAlias);
13544
13623
  if (!table || table.cteName !== null) return void 0;
13545
13624
  return subtableSystemFieldType(table, field.field) ?? fieldTypesByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, field.field));
13546
13625
  }
@@ -13765,6 +13844,37 @@ async function executeQueryWithCte(query, client, options, cteCache, cacheContex
13765
13844
  return result;
13766
13845
  }
13767
13846
  async function executeFullScanWithCte(stmt, client, options, cteCache, cacheContext) {
13847
+ const hiddenQualifiedAliases = /* @__PURE__ */ new Set();
13848
+ const withEffectiveAlias = (table) => {
13849
+ if (table.alias !== null || table.cteName === null) return table;
13850
+ const alias = effectiveTableAlias(table);
13851
+ hiddenQualifiedAliases.add(alias);
13852
+ return { ...table, alias };
13853
+ };
13854
+ stmt = {
13855
+ ...stmt,
13856
+ from: withEffectiveAlias(stmt.from),
13857
+ joins: stmt.joins.map((join2) => ({ ...join2, table: withEffectiveAlias(join2.table) }))
13858
+ };
13859
+ const aliases = /* @__PURE__ */ new Set();
13860
+ for (const table of [stmt.from, ...stmt.joins.map((join2) => join2.table)]) {
13861
+ const alias = effectiveTableAlias(table);
13862
+ if (alias === null) continue;
13863
+ if (aliases.has(alias)) {
13864
+ throw new Error(`ArgumentError: effective alias ${alias} is used by multiple tables.`);
13865
+ }
13866
+ aliases.add(alias);
13867
+ }
13868
+ const requireMaterializedTable = (name) => {
13869
+ const table = cteCache.get(name);
13870
+ if (!table) {
13871
+ throw new Error(`ArgumentError: materialized source ${name} is not available.`);
13872
+ }
13873
+ return table;
13874
+ };
13875
+ for (const table of [stmt.from, ...stmt.joins.map((join2) => join2.table)]) {
13876
+ if (table.cteName !== null) requireMaterializedTable(table.cteName);
13877
+ }
13768
13878
  const maxRecords = options.maxRecords ?? 1e4;
13769
13879
  const warnings = /* @__PURE__ */ new Set();
13770
13880
  const parallel = options.fetchParallel ?? 1;
@@ -13811,9 +13921,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
13811
13921
  orderByMetaPromise.catch(() => {
13812
13922
  });
13813
13923
  const tables = /* @__PURE__ */ new Map();
13924
+ const tableColumns = /* @__PURE__ */ new Map();
13814
13925
  if (stmt.from.cteName != null) {
13815
- const table = cteCache.get(stmt.from.cteName);
13816
- tables.set(stmt.from.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
13926
+ const table = requireMaterializedTable(stmt.from.cteName);
13927
+ tables.set(stmt.from.alias, table.rows.map(processRowToKintoneRecord));
13928
+ tableColumns.set(stmt.from.alias, table.columns);
13817
13929
  } else {
13818
13930
  const mainRecords = await fetchTableRecordsForFullScan(
13819
13931
  stmt,
@@ -13831,8 +13943,9 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
13831
13943
  }
13832
13944
  const joinFetches = stmt.joins.map(async (join2) => {
13833
13945
  if (join2.table.cteName != null) {
13834
- const table = cteCache.get(join2.table.cteName);
13835
- tables.set(join2.table.alias, (table?.rows ?? []).map(processRowToKintoneRecord));
13946
+ const table = requireMaterializedTable(join2.table.cteName);
13947
+ tables.set(join2.table.alias, table.rows.map(processRowToKintoneRecord));
13948
+ tableColumns.set(join2.table.alias, table.columns);
13836
13949
  } else {
13837
13950
  const pushDownCond = join2.table.alias ? pushdownPlan.joinConditions.get(join2.table.alias) ?? null : null;
13838
13951
  const optimized = await tryFetchJoinRecordsBySourceKeys(
@@ -13863,7 +13976,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
13863
13976
  await Promise.all(joinFetches);
13864
13977
  const scalarCache = await scalarCachePromise;
13865
13978
  const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
13866
- const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? cteCache.get(stmt.from.cteName)?.columns : void 0;
13979
+ const sourceColumns = stmt.joins.length === 0 && stmt.from.cteName != null ? requireMaterializedTable(stmt.from.cteName).columns : void 0;
13867
13980
  const { rows, columns } = runFullScan({
13868
13981
  tables,
13869
13982
  stmt,
@@ -13877,7 +13990,9 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
13877
13990
  havingFieldSemanticsResolver,
13878
13991
  aggregateSortKindResolver,
13879
13992
  appliedKlikes: pushdownPlan.appliedKlikes,
13880
- sourceColumns
13993
+ sourceColumns,
13994
+ tableColumns,
13995
+ hiddenQualifiedAliases
13881
13996
  });
13882
13997
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
13883
13998
  }
@@ -14179,7 +14294,7 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
14179
14294
  const info2 = infosByApp.get(stmt.from.appId)?.get(ref.field);
14180
14295
  return info2 ? materializedMetaFromFieldInfo(info2, stmt.from.appId) : void 0;
14181
14296
  }
14182
- const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
14297
+ const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
14183
14298
  if (!table) return void 0;
14184
14299
  if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
14185
14300
  const info = infosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));