@rex0220/kintone-sql-tools 3.32.0 → 3.34.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
@@ -4260,6 +4260,15 @@ function containsStatisticalAggregate(value, seen = /* @__PURE__ */ new Set()) {
4260
4260
  if (record.type === "FIELD" && typeof record.field === "string" && /^(STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/i.test(record.field)) return true;
4261
4261
  return Object.values(record).some((child) => Array.isArray(child) ? child.some((entry) => containsStatisticalAggregate(entry, seen)) : containsStatisticalAggregate(child, seen));
4262
4262
  }
4263
+ function containsAggregate(value, seen = /* @__PURE__ */ new Set()) {
4264
+ if (value === null || typeof value !== "object") return false;
4265
+ if (seen.has(value)) return false;
4266
+ seen.add(value);
4267
+ const record = value;
4268
+ if ((record.type === "AGGREGATE" || record.type === "AGG_REF") && typeof record.func === "string" && !STATISTICAL_AGGREGATES.has(record.func)) return true;
4269
+ if (record.type === "FIELD" && typeof record.field === "string" && /^(COUNT|SUM|AVG|MIN|MAX|GROUP_CONCAT)\(/i.test(record.field)) return true;
4270
+ return Object.values(record).some((child) => Array.isArray(child) ? child.some((entry) => containsAggregate(entry, seen)) : containsAggregate(child, seen));
4271
+ }
4263
4272
  function completeInputReasons(stmt) {
4264
4273
  const reasons = /* @__PURE__ */ new Set();
4265
4274
  if (isDmlType(stmt.type)) {
@@ -4289,6 +4298,7 @@ function completeInputReasons(stmt) {
4289
4298
  break;
4290
4299
  }
4291
4300
  if (containsStatisticalAggregate(stmt)) reasons.add("STATISTICAL_AGGREGATE");
4301
+ if (containsAggregate(stmt)) reasons.add("AGGREGATE");
4292
4302
  return reasons;
4293
4303
  }
4294
4304
  function requiresCompleteInput(stmt) {
@@ -4297,11 +4307,15 @@ function requiresCompleteInput(stmt) {
4297
4307
  function unionCompleteInputReasons(stmt) {
4298
4308
  const reasons = stmt.left.type === "SELECT" ? selectCompleteInputReasons(stmt.left) : unionCompleteInputReasons(stmt.left);
4299
4309
  addReasons(reasons, selectCompleteInputReasons(stmt.right));
4310
+ if (!stmt.all) reasons.add("DISTINCT");
4300
4311
  return reasons;
4301
4312
  }
4302
4313
  function selectCompleteInputReasons(stmt) {
4303
4314
  const reasons = /* @__PURE__ */ new Set();
4304
- if (normalizeGroupingSpec(stmt).type === "GROUPING_SETS") reasons.add("GROUPING_SETS");
4315
+ const grouping = normalizeGroupingSpec(stmt);
4316
+ if (grouping.type === "GROUPING_SETS") reasons.add("GROUPING_SETS");
4317
+ if (grouping.type === "PLAIN") reasons.add("GROUP_BY");
4318
+ if (stmt.distinct) reasons.add("DISTINCT");
4305
4319
  if (stmt.orderBy.length > 0) reasons.add("LOCAL_ORDER");
4306
4320
  for (const column of stmt.columns) {
4307
4321
  if (column.type === "WINDOW_COL" && column.orderBy.length > 0) reasons.add("WINDOW_ORDER");
@@ -4313,6 +4327,7 @@ function selectCompleteInputReasons(stmt) {
4313
4327
  addReasons(reasons, whereCompleteInputReasons(stmt.where));
4314
4328
  addReasons(reasons, whereCompleteInputReasons(stmt.having));
4315
4329
  if (containsStatisticalAggregate(stmt)) reasons.add("STATISTICAL_AGGREGATE");
4330
+ if (containsAggregate(stmt)) reasons.add("AGGREGATE");
4316
4331
  return reasons;
4317
4332
  }
4318
4333
  function whereCompleteInputReasons(where) {
@@ -6505,19 +6520,19 @@ function collectNonAggregateFieldRefs(node, out) {
6505
6520
  }
6506
6521
  Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
6507
6522
  }
6508
- function containsAggregate(node) {
6523
+ function containsAggregate2(node) {
6509
6524
  if (node === null || typeof node !== "object") return false;
6510
- if (Array.isArray(node)) return node.some(containsAggregate);
6525
+ if (Array.isArray(node)) return node.some(containsAggregate2);
6511
6526
  const value = node;
6512
6527
  if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
6513
6528
  if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
6514
- return Object.values(value).some(containsAggregate);
6529
+ return Object.values(value).some(containsAggregate2);
6515
6530
  }
6516
6531
  function isAggregateMaterializedAlias(column) {
6517
6532
  if (!("alias" in column) || column.alias === null) return false;
6518
6533
  if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
6519
6534
  if (column.type === "STRFUNC_COL" || column.type === "SCALAR_VALUE_COL") {
6520
- return containsAggregate(column);
6535
+ return containsAggregate2(column);
6521
6536
  }
6522
6537
  return false;
6523
6538
  }
@@ -10680,6 +10695,19 @@ function statementContainsOuterJoin(statement) {
10680
10695
  };
10681
10696
  return visit(statement);
10682
10697
  }
10698
+ function isOuterJoinNonPreservedTable(statement, table, isMainTable) {
10699
+ if (isMainTable) {
10700
+ return table === statement.from && statement.joins.some((join2) => join2.type === "RIGHT");
10701
+ }
10702
+ for (let index = 0; index < statement.joins.length; index += 1) {
10703
+ const join2 = statement.joins[index];
10704
+ if (join2.type === "LEFT" && table === join2.table) return true;
10705
+ if (join2.type === "RIGHT" && statement.joins.slice(0, index).some((previousJoin) => table === previousJoin.table)) {
10706
+ return true;
10707
+ }
10708
+ }
10709
+ return false;
10710
+ }
10683
10711
 
10684
10712
  // src/core/explainMetadata.ts
10685
10713
  function buildGroupingExplainMetadata(statement, canonicalItemCount) {
@@ -10893,8 +10921,9 @@ function getLastId(records) {
10893
10921
  return Number.isFinite(id) ? id : 0;
10894
10922
  }
10895
10923
  var FetchAllLimitError = class extends Error {
10896
- constructor(message) {
10924
+ constructor(message, completeInputWrapped = false) {
10897
10925
  super(message);
10926
+ this.completeInputWrapped = completeInputWrapped;
10898
10927
  this.name = "FetchAllLimitError";
10899
10928
  }
10900
10929
  };
@@ -12405,7 +12434,7 @@ function classifyPreGroupAlias(column) {
12405
12434
  case "STRFUNC_COL":
12406
12435
  case "SCALAR_VALUE_COL":
12407
12436
  case "SCALAR_SUBQUERY_COL":
12408
- return containsAggregate(column) || containsAggregateColumnNode(column) ? "AGGREGATE_DEPENDENT" : "SAFE";
12437
+ return containsAggregate2(column) || containsAggregateColumnNode(column) ? "AGGREGATE_DEPENDENT" : "SAFE";
12409
12438
  }
12410
12439
  }
12411
12440
  var SUBTABLE_SYSTEM_COLUMNS = ["_pid", "_rid", "_idx"];
@@ -17064,11 +17093,21 @@ async function validateSelectGroupingPlanning(stmt, client, cacheContext, materi
17064
17093
  }
17065
17094
  function completeInputErrorPrefix(reasons) {
17066
17095
  const reasonList = [...reasons].join(", ");
17067
- const subject = reasons.size === 1 && reasons.has("STATISTICAL_AGGREGATE") ? "\u7D71\u8A08\u96C6\u7D04\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("GROUPING_SETS") ? "\u5C0F\u8A08\u30FB\u7DCF\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.has("GROUPING_SETS") ? "\u30AF\u30A8\u30EA\u306E\u6B63\u3057\u3044\u7D50\u679C" : "ORDER BY\u306E\u6B63\u3057\u3044\u7D50\u679C";
17096
+ const aggregateSubjects = [
17097
+ ["GROUPING_SETS", "\u5C0F\u8A08\u30FB\u7DCF\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
17098
+ ["STATISTICAL_AGGREGATE", "\u7D71\u8A08\u96C6\u7D04\u306E\u6B63\u3057\u3044\u7D50\u679C"],
17099
+ ["AGGREGATE", "\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
17100
+ ["GROUP_BY", "\u30B0\u30EB\u30FC\u30D7\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
17101
+ ["DISTINCT", "DISTINCT \u306E\u6B63\u3057\u3044\u7D50\u679C"]
17102
+ ];
17103
+ const hasAggregateReason = aggregateSubjects.some(([reason]) => reasons.has(reason));
17104
+ const hasOrderReason = reasons.has("LOCAL_ORDER") || reasons.has("WINDOW_ORDER");
17105
+ const legacySubject = reasons.size === 1 && reasons.has("STATISTICAL_AGGREGATE") ? "\u7D71\u8A08\u96C6\u7D04\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("GROUPING_SETS") ? "\u5C0F\u8A08\u30FB\u7DCF\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("AGGREGATE") ? "\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("GROUP_BY") ? "\u30B0\u30EB\u30FC\u30D7\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("DISTINCT") ? "DISTINCT \u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.has("GROUPING_SETS") ? "\u30AF\u30A8\u30EA\u306E\u6B63\u3057\u3044\u7D50\u679C" : "ORDER BY\u306E\u6B63\u3057\u3044\u7D50\u679C";
17106
+ const subject = reasons.has("DML") || reasons.has("VALIDATE") ? legacySubject : hasAggregateReason && hasOrderReason ? "\u30AF\u30A8\u30EA\u306E\u6B63\u3057\u3044\u7D50\u679C" : hasAggregateReason ? aggregateSubjects.find(([reason]) => reasons.has(reason))[1] : "ORDER BY\u306E\u6B63\u3057\u3044\u7D50\u679C";
17068
17107
  return `${subject}\u306B\u306F\u5B8C\u5168\u306A\u5019\u88DC\u96C6\u5408\u304C\u5FC5\u8981\u3067\u3059\u3002complete input reason: ${reasonList}\u3002`;
17069
17108
  }
17070
17109
  function buildCompleteInputPolicy(stmt, options, orderPlan) {
17071
- const reasons = orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" || orderPlan?.kind === "KORDER_CURSOR" ? completeInputReasons({ ...stmt, orderBy: [] }) : completeInputReasons(stmt);
17110
+ const reasons = stmt.type === "SELECT" && (orderPlan?.kind === "CANONICAL_REST_TOP_N" || orderPlan?.kind === "KORDER_NATIVE" || orderPlan?.kind === "KORDER_CURSOR") ? completeInputReasons({ ...stmt, orderBy: [] }) : completeInputReasons(stmt);
17072
17111
  const truncateWasDisabled = reasons.size > 0 && options.onLimitReached === "truncate";
17073
17112
  return {
17074
17113
  reasons,
@@ -17077,9 +17116,10 @@ function buildCompleteInputPolicy(stmt, options, orderPlan) {
17077
17116
  };
17078
17117
  }
17079
17118
  function throwCompleteInputError(policy, error) {
17080
- if (policy.reasons.size > 0 && error instanceof FetchAllLimitError) {
17119
+ if (policy.reasons.size > 0 && error instanceof FetchAllLimitError && !error.completeInputWrapped) {
17081
17120
  throw new FetchAllLimitError(
17082
- completeInputErrorPrefix(policy.reasons) + (policy.truncateWasDisabled ? "onLimit=truncate\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002" : "") + error.message
17121
+ completeInputErrorPrefix(policy.reasons) + (policy.truncateWasDisabled ? "onLimit=truncate\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002" : "") + error.message,
17122
+ true
17083
17123
  );
17084
17124
  }
17085
17125
  throw error;
@@ -18312,26 +18352,53 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
18312
18352
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
18313
18353
  }
18314
18354
  async function executeUnion(stmt, client, options, cacheContext, captureColumnMeta = false, forLibraryCapture = false) {
18315
- const [leftResult, rightResult] = await Promise.all([
18316
- stmt.left.type === "UNION" ? executeUnion(stmt.left, client, options, cacheContext, captureColumnMeta, forLibraryCapture) : executeSelect(stmt.left, client, options, cacheContext, void 0, captureColumnMeta, forLibraryCapture),
18317
- executeSelect(stmt.right, client, options, cacheContext, void 0, captureColumnMeta, forLibraryCapture)
18318
- ]);
18319
- const leftCols = leftResult.columns;
18320
- const rightCols = rightResult.columns;
18321
- const remappedRight = rightResult.rows.map((row) => {
18322
- const mapped = {};
18323
- leftCols.forEach((col, i) => {
18324
- mapped[col] = row[rightCols[i] ?? col] ?? "";
18355
+ const completePolicy = buildCompleteInputPolicy(stmt, options, null);
18356
+ return withCompleteInputPolicy(completePolicy, async () => {
18357
+ const effectiveOptions = completePolicy.effectiveOptions;
18358
+ const [leftResult, rightResult] = await Promise.all([
18359
+ stmt.left.type === "UNION" ? executeUnion(
18360
+ stmt.left,
18361
+ client,
18362
+ effectiveOptions,
18363
+ cacheContext,
18364
+ captureColumnMeta,
18365
+ forLibraryCapture
18366
+ ) : executeSelect(
18367
+ stmt.left,
18368
+ client,
18369
+ effectiveOptions,
18370
+ cacheContext,
18371
+ void 0,
18372
+ captureColumnMeta,
18373
+ forLibraryCapture
18374
+ ),
18375
+ executeSelect(
18376
+ stmt.right,
18377
+ client,
18378
+ effectiveOptions,
18379
+ cacheContext,
18380
+ void 0,
18381
+ captureColumnMeta,
18382
+ forLibraryCapture
18383
+ )
18384
+ ]);
18385
+ const leftCols = leftResult.columns;
18386
+ const rightCols = rightResult.columns;
18387
+ const remappedRight = rightResult.rows.map((row) => {
18388
+ const mapped = {};
18389
+ leftCols.forEach((col, i) => {
18390
+ mapped[col] = row[rightCols[i] ?? col] ?? "";
18391
+ });
18392
+ return mapped;
18325
18393
  });
18326
- return mapped;
18394
+ const combined = [...leftResult.rows, ...remappedRight];
18395
+ const rows = stmt.all ? combined : deduplicateRows(combined, leftCols);
18396
+ const result = { type: "SELECT", rows, columns: leftCols, rowCount: rows.length };
18397
+ if (captureColumnMeta) {
18398
+ materializedMetaBySelectResult.set(result, mergeUnionColumnMeta(leftResult, rightResult));
18399
+ }
18400
+ return result;
18327
18401
  });
18328
- const combined = [...leftResult.rows, ...remappedRight];
18329
- const rows = stmt.all ? combined : deduplicateRows(combined, leftCols);
18330
- const result = { type: "SELECT", rows, columns: leftCols, rowCount: rows.length };
18331
- if (captureColumnMeta) {
18332
- materializedMetaBySelectResult.set(result, mergeUnionColumnMeta(leftResult, rightResult));
18333
- }
18334
- return result;
18335
18402
  }
18336
18403
  function deduplicateRows(rows, columns) {
18337
18404
  const seen = /* @__PURE__ */ new Set();
@@ -18600,6 +18667,12 @@ async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords, par
18600
18667
  const onTruncate = (max) => {
18601
18668
  warnings.add(`\u53D6\u5F97\u4E0A\u9650\uFF08${max} \u4EF6\uFF09\u306B\u9054\u3057\u305F\u305F\u3081\u3001${max} \u4EF6\u3067\u6253\u3061\u5207\u3063\u3066\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002`);
18602
18669
  markLimitReached(client, table.appId);
18670
+ if (isOuterJoinNonPreservedTable(stmt, table, isMainTable)) {
18671
+ throw new FetchAllLimitError(
18672
+ `\u5916\u90E8\u7D50\u5408\u306E\u6B63\u3057\u3044\u7D50\u679C\u306B\u306F\u5B8C\u5168\u306A\u5019\u88DC\u96C6\u5408\u304C\u5FC5\u8981\u3067\u3059\u3002complete input reason: OUTER_JOIN_NON_PRESERVED\uFF08APP${table.appId}\uFF09\u3002onLimit=truncate\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u53D6\u5F97\u4EF6\u6570\u304C\u4E0A\u9650\uFF08${max} \u4EF6\uFF09\u3092\u8D85\u3048\u307E\u3057\u305F\u3002WHERE \u53E5\u3067\u7D5E\u308A\u8FBC\u3080\u304B\u3001maxRecords \u3092\u5F15\u304D\u4E0A\u3052\u3066\u304F\u3060\u3055\u3044\u3002`,
18673
+ true
18674
+ );
18675
+ }
18603
18676
  };
18604
18677
  if (!table.subtableCode) {
18605
18678
  const baseQuery = isMainTable && allowOriginalWherePushdown ? selectToFetchAllParams(stmt, table.appId).query : "";