@rex0220/kintone-sql-tools 3.39.0 → 3.40.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
@@ -22768,6 +22768,10 @@ function serverFunctionClientEvaluationLabel(leaves) {
22768
22768
  (leaf) => leaf.right.type === "KINTONE_FUNC" && isRelativeDateFunctionName(leaf.right.name)
22769
22769
  ) ? "relative date client evaluations" : "kintone function client evaluations";
22770
22770
  }
22771
+ var EXPLAIN_FETCH_PLAN = /* @__PURE__ */ Symbol("ksql.explainFetchPlan");
22772
+ function setExplainFetchPlan(result, plan) {
22773
+ result[EXPLAIN_FETCH_PLAN] = plan;
22774
+ }
22771
22775
  async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS) {
22772
22776
  const invocationCacheContext = createInvocationCacheContext(cacheContext);
22773
22777
  try {
@@ -22777,6 +22781,7 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
22777
22781
  const relativeDateVariables = prepareRelativeDateVariables(statements, normalizedInjectedVariables);
22778
22782
  const variables = /* @__PURE__ */ new Map();
22779
22783
  const plans = [];
22784
+ const fetchStatements = [];
22780
22785
  for (let i = 0; i < statements.length; i++) {
22781
22786
  const stmt = statements[i];
22782
22787
  const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveBatchVariableReferences(stmt.expr, variables) } : stmt : resolveBatchVariableReferences(stmt, variables);
@@ -22789,6 +22794,7 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
22789
22794
  maxRecords,
22790
22795
  relativeDatePlan
22791
22796
  );
22797
+ const fetchCollector = { sources: [] };
22792
22798
  const statementPlan = relativeDatePlan.hasServerOnlyWhereFunction && !relativeDatePlan.allowed ? relativeDateExplainLines(relativeDatePlan) : [
22793
22799
  ...relativeDateExplainLines(relativeDatePlan),
22794
22800
  ...addCursorConcurrency(buildBatchStatementPlan(
@@ -22797,7 +22803,8 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
22797
22803
  whereAnalysis.capabilities,
22798
22804
  whereAnalysis.orderPlans,
22799
22805
  dmlMaxRows,
22800
- dmlMaxSubtableRows
22806
+ dmlMaxSubtableRows,
22807
+ fetchCollector
22801
22808
  ), cursorMaxActive)
22802
22809
  ];
22803
22810
  const metadataPlan = explainMetadataLines(whereAnalysis);
@@ -22806,22 +22813,36 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
22806
22813
  type: analysis.statements[i].statementType,
22807
22814
  plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
22808
22815
  });
22816
+ fetchStatements.push({
22817
+ index: i,
22818
+ fetch: worstExplainFetch(fetchCollector.sources),
22819
+ sources: fetchCollector.sources
22820
+ });
22809
22821
  if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
22810
22822
  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 });
22811
22823
  }
22812
22824
  }
22813
- return { statementCount: statements.length, statements: plans };
22825
+ const result = { statementCount: statements.length, statements: plans };
22826
+ setExplainFetchPlan(result, { statements: fetchStatements });
22827
+ return result;
22814
22828
  } finally {
22815
22829
  releaseMetadataCacheScope(invocationCacheContext);
22816
22830
  }
22817
22831
  }
22818
- function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS) {
22832
+ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, collector = { sources: [] }) {
22819
22833
  if (stmt.type === "CREATE_TEMP_TABLE") {
22820
22834
  return [
22821
22835
  `CREATE TEMP TABLE ${stmt.name}`,
22822
22836
  ` scope: batch\uFF08\u30D0\u30C3\u30C1\u7D42\u4E86\u6642\u306B\u81EA\u52D5\u7834\u68C4\uFF09`,
22823
22837
  ` rows: \u5B9F\u4F53\u5316\u524D\u306E\u305F\u3081\u4E0D\u660E\uFF08\u65E2\u5B9A\u4E0A\u9650 ${TEMP_TABLE_MAX_ROWS} \u884C\u3001tempTableMaxRows \u3067\u5909\u66F4\u53EF\u3001\u8D85\u904E\u306F\u30A8\u30E9\u30FC\uFF09`,
22824
- ...buildPlanForBatchQuery(stmt.query, info, capabilities, orderPlans).map((l) => ` ${l}`)
22838
+ ...buildPlanForBatchQuery(
22839
+ stmt.query,
22840
+ info,
22841
+ capabilities,
22842
+ orderPlans,
22843
+ collector,
22844
+ "main"
22845
+ ).map((l) => ` ${l}`)
22825
22846
  ];
22826
22847
  }
22827
22848
  if (stmt.type === "DROP_TEMP_TABLE") {
@@ -22837,7 +22858,13 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
22837
22858
  `SET @${stmt.name} = (SELECT ...)`,
22838
22859
  " value: \u30B5\u30D6\u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u6642\u306B1\u56DE\u8A55\u4FA1\uFF081\u884C1\u5217\u30FB\u30D0\u30C3\u30C1\u5185\u5B9A\u6570\u30FB\u7D50\u679C\u30E1\u30BF\u30C7\u30FC\u30BF\u306B\u306F\u975E\u516C\u958B\uFF09",
22839
22860
  " subquery:",
22840
- ...buildPlanForBatchQuery(stmt.expr.query, subInfo, capabilities, orderPlans).map((l) => ` ${l}`)
22861
+ ...buildPlanForBatchQuery(
22862
+ stmt.expr.query,
22863
+ subInfo,
22864
+ capabilities,
22865
+ orderPlans,
22866
+ collector
22867
+ ).map((l) => ` ${l}`)
22841
22868
  ];
22842
22869
  }
22843
22870
  return [
@@ -22859,7 +22886,15 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
22859
22886
  }
22860
22887
  if (stmt.type === "SHOW_APPS") return ["SHOW APPS\uFF08\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\uFF09"];
22861
22888
  if (stmt.type === "DESCRIBE") return [`DESCRIBE APP${stmt.appId}\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\uFF09`];
22862
- if (stmt.type === "EXPLAIN") return buildPlanForBatchQuery(stmt.query, info, capabilities, orderPlans);
22889
+ if (stmt.type === "EXPLAIN") {
22890
+ return buildPlanForBatchQuery(
22891
+ stmt.query,
22892
+ info,
22893
+ capabilities,
22894
+ orderPlans,
22895
+ collector
22896
+ );
22897
+ }
22863
22898
  if (stmt.type === "ASSERT") {
22864
22899
  const lines = [
22865
22900
  `ASSERT ${stmt.text}`,
@@ -22871,14 +22906,20 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
22871
22906
  subqueries.forEach((sq, i) => {
22872
22907
  lines.push(subqueries.length > 1 ? ` subquery[${i + 1}]:` : " subquery:");
22873
22908
  const subInfo = hasTempTableRef(sq.query) ? info : { ...info, tempTablesReferenced: [] };
22874
- lines.push(...buildPlanForBatchQuery(sq.query, subInfo, capabilities, orderPlans).map((l) => ` ${l}`));
22909
+ lines.push(...buildPlanForBatchQuery(
22910
+ sq.query,
22911
+ subInfo,
22912
+ capabilities,
22913
+ orderPlans,
22914
+ collector
22915
+ ).map((l) => ` ${l}`));
22875
22916
  });
22876
22917
  return lines;
22877
22918
  }
22878
22919
  if (stmt.type === "UPDATE" && (stmt.applyBlocks?.length ?? 0) > 0) {
22879
22920
  return buildExplainPlan(stmt, void 0, capabilities, orderPlans, dmlMaxRows, dmlMaxSubtableRows);
22880
22921
  }
22881
- return buildPlanForBatchQuery(stmt, info, capabilities, orderPlans);
22922
+ return buildPlanForBatchQuery(stmt, info, capabilities, orderPlans, collector);
22882
22923
  }
22883
22924
  function hasTempTableRef(node) {
22884
22925
  if (Array.isArray(node)) return node.some(hasTempTableRef);
@@ -22890,9 +22931,21 @@ function hasTempTableRef(node) {
22890
22931
  }
22891
22932
  return false;
22892
22933
  }
22893
- function buildPlanForBatchQuery(query, info, capabilities, orderPlans) {
22934
+ function buildPlanForBatchQuery(query, info, capabilities, orderPlans, collector = { sources: [] }, sourceRole = "main") {
22894
22935
  if (info.tempTablesReferenced.length === 0) {
22895
- return buildExplainPlan(query, void 0, capabilities, orderPlans);
22936
+ return buildExplainPlan(
22937
+ query,
22938
+ void 0,
22939
+ capabilities,
22940
+ orderPlans,
22941
+ 100,
22942
+ DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
22943
+ 1e4,
22944
+ void 0,
22945
+ true,
22946
+ collector,
22947
+ sourceRole
22948
+ );
22896
22949
  }
22897
22950
  const lines = [];
22898
22951
  if (query.type === "INSERT_SELECT") {
@@ -22926,8 +22979,9 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
22926
22979
  maxRecords,
22927
22980
  sharedPlan
22928
22981
  );
22982
+ const fetchCollector = { sources: [] };
22929
22983
  const relativeLines = relativeDateExplainLines(sharedPlan);
22930
- const lines = sharedPlan.hasServerOnlyWhereFunction && !sharedPlan.allowed ? [...explainMetadataLines(analysis), ...relativeLines] : [
22984
+ const planLines = sharedPlan.hasServerOnlyWhereFunction && !sharedPlan.allowed ? [...explainMetadataLines(analysis), ...relativeLines] : [
22931
22985
  ...explainMetadataLines(analysis),
22932
22986
  ...relativeLines,
22933
22987
  ...addCursorConcurrency(
@@ -22939,17 +22993,28 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
22939
22993
  dmlMaxRows,
22940
22994
  dmlMaxSubtableRows,
22941
22995
  maxRecords,
22942
- analysis.plainGroupByPlans
22996
+ analysis.plainGroupByPlans,
22997
+ true,
22998
+ fetchCollector
22943
22999
  ),
22944
23000
  cursorMaxActive
22945
23001
  )
22946
23002
  ];
22947
- return {
23003
+ const lines = addFetchSummary(planLines, fetchCollector.sources);
23004
+ const result = {
22948
23005
  type: "SELECT",
22949
23006
  columns: ["plan"],
22950
23007
  rows: lines.map((line) => ({ plan: line })),
22951
23008
  rowCount: lines.length
22952
23009
  };
23010
+ setExplainFetchPlan(result, {
23011
+ statements: [{
23012
+ index: 0,
23013
+ fetch: worstExplainFetch(fetchCollector.sources),
23014
+ sources: fetchCollector.sources
23015
+ }]
23016
+ });
23017
+ return result;
22953
23018
  }
22954
23019
  function addCursorConcurrency(lines, cursorMaxActive) {
22955
23020
  const result = [];
@@ -22962,9 +23027,28 @@ function addCursorConcurrency(lines, cursorMaxActive) {
22962
23027
  }
22963
23028
  return result;
22964
23029
  }
22965
- function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4, plainGroupByPlans) {
22966
- if (query.type === "UNION") return buildUnionPlan(query, capabilities, orderPlans, plainGroupByPlans);
22967
- if (query.type === "WITH") return buildWithPlan(query, capabilities, orderPlans, plainGroupByPlans);
23030
+ function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4, plainGroupByPlans, includeFetchSummary = true, collector, sourceRole = "main") {
23031
+ const fetchCollector = collector ?? { sources: [] };
23032
+ if (query.type === "UNION") {
23033
+ const lines2 = buildUnionPlan(
23034
+ query,
23035
+ capabilities,
23036
+ orderPlans,
23037
+ plainGroupByPlans,
23038
+ fetchCollector
23039
+ );
23040
+ return includeFetchSummary ? addFetchSummary(lines2, fetchCollector.sources) : lines2;
23041
+ }
23042
+ if (query.type === "WITH") {
23043
+ const lines2 = buildWithPlan(
23044
+ query,
23045
+ capabilities,
23046
+ orderPlans,
23047
+ plainGroupByPlans,
23048
+ fetchCollector
23049
+ );
23050
+ return includeFetchSummary ? addFetchSummary(lines2, fetchCollector.sources) : lines2;
23051
+ }
22968
23052
  if (query.type === "INSERT") return buildInsertPlan(query, label, dmlMaxRows, dmlMaxSubtableRows);
22969
23053
  if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label, capabilities, orderPlans, plainGroupByPlans);
22970
23054
  if (query.type === "UPSERT") return buildUpsertPlan(query, label, dmlMaxRows, dmlMaxSubtableRows);
@@ -23054,7 +23138,62 @@ function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 1
23054
23138
  ` duplicateKey: preflight before lookup/write (requires load)`
23055
23139
  ];
23056
23140
  }
23057
- return buildSelectPlan(query, label, capabilities, orderPlans, plainGroupByPlans);
23141
+ const lines = buildSelectPlan(
23142
+ query,
23143
+ label,
23144
+ capabilities,
23145
+ orderPlans,
23146
+ plainGroupByPlans,
23147
+ true,
23148
+ true,
23149
+ fetchCollector,
23150
+ sourceRole
23151
+ );
23152
+ return includeFetchSummary ? addFetchSummary(lines, fetchCollector.sources) : lines;
23153
+ }
23154
+ var EXPLAIN_FETCH_VALUE_RANK = {
23155
+ none: 0,
23156
+ exact: 1,
23157
+ prefiltered: 2,
23158
+ all: 3
23159
+ };
23160
+ function worstExplainFetch(sources) {
23161
+ return sources.reduce(
23162
+ (worst, source) => EXPLAIN_FETCH_VALUE_RANK[worst] >= EXPLAIN_FETCH_VALUE_RANK[source.fetch] ? worst : source.fetch,
23163
+ "none"
23164
+ );
23165
+ }
23166
+ function addFetchSummary(lines, sources) {
23167
+ const detailLines = lines.filter((line) => !line.startsWith("fetch summary:"));
23168
+ if (sources.length === 0) return detailLines;
23169
+ return [`fetch summary: ${worstExplainFetch(sources).toUpperCase()}`, ...detailLines];
23170
+ }
23171
+ function pushedQueryLimit(query) {
23172
+ const match = /(?:^|\s)limit\s+(\d+)(?:\s|$)/i.exec(query);
23173
+ return match ? Number(match[1]) : null;
23174
+ }
23175
+ function createExplainFetchSource(collector, app, alias, role, scope, query, pending = false) {
23176
+ const source = {
23177
+ app,
23178
+ alias,
23179
+ role,
23180
+ fetch: scope.toLowerCase(),
23181
+ pending,
23182
+ kintoneQuery: query === "(\u5168\u4EF6\u53D6\u5F97)" || query === "(\u306A\u3057)" || query === "" ? null : query,
23183
+ limit: pushedQueryLimit(query)
23184
+ };
23185
+ collector.sources.push(source);
23186
+ return source;
23187
+ }
23188
+ function formatFetchScope(source) {
23189
+ return [
23190
+ source.fetch.toUpperCase(),
23191
+ ...source.limit === null ? [] : [`(limit ${source.limit})`],
23192
+ ...source.pending ? ["(\u672A\u78BA\u5B9A)"] : []
23193
+ ].join(" ");
23194
+ }
23195
+ function renderFetchScope(source) {
23196
+ return ` fetch: ${formatFetchScope(source)}`;
23058
23197
  }
23059
23198
  function buildValidatePlan(stmt, label) {
23060
23199
  const info = validateExplainInfo.get(stmt);
@@ -23081,7 +23220,7 @@ function buildValidatePlan(stmt, label) {
23081
23220
  lines.push(" records/mutation API during EXPLAIN: none; violation count unavailable");
23082
23221
  return lines;
23083
23222
  }
23084
- function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlans, allowTotalCountPlan = true) {
23223
+ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlans, allowTotalCountPlan = true, emitFetch = true, collector = { sources: [] }, sourceRole = "main") {
23085
23224
  const whereCapability = capabilities?.get(stmt) ?? (capabilities ? [...capabilities].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
23086
23225
  const orderPlan = orderPlans?.get(stmt) ?? (orderPlans ? [...orderPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
23087
23226
  const plainGroupByPlan = plainGroupByPlans?.get(stmt) ?? (plainGroupByPlans ? [...plainGroupByPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
@@ -23139,6 +23278,17 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
23139
23278
  lines.push(
23140
23279
  ` kintone query: ${baseQuery}${baseQuery ? " " : ""}limit 1`
23141
23280
  );
23281
+ if (emitFetch) {
23282
+ const source = createExplainFetchSource(
23283
+ collector,
23284
+ stmt.from.appId,
23285
+ stmt.from.alias,
23286
+ sourceRole,
23287
+ "NONE",
23288
+ `${baseQuery}${baseQuery ? " " : ""}limit 1`
23289
+ );
23290
+ lines.push(renderFetchScope(source));
23291
+ }
23142
23292
  lines.push(" fields: $id");
23143
23293
  lines.push(" fetch API: GET records.json (totalCount=true)");
23144
23294
  lines.push(" REST execution: single GET");
@@ -23185,6 +23335,17 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
23185
23335
  lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);
23186
23336
  const displayedQuery = orderPlan?.kind === "KORDER_CURSOR" ? buildKorderCursorQuery(stmt) : params.query;
23187
23337
  lines.push(` kintone query: ${displayedQuery || "(\u306A\u3057)"}`);
23338
+ if (emitFetch && stmt.from.cteName === null) {
23339
+ const fetchScope = displayedQuery ? "EXACT" : "ALL";
23340
+ lines.push(renderFetchScope(createExplainFetchSource(
23341
+ collector,
23342
+ stmt.from.appId,
23343
+ stmt.from.alias,
23344
+ sourceRole,
23345
+ fetchScope,
23346
+ displayedQuery
23347
+ )));
23348
+ }
23188
23349
  lines.push(` fields: ${params.fields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : params.fields.join(", ")}`);
23189
23350
  } else {
23190
23351
  const runtimeJoinPlan = explainJoinPushdownPlans.get(stmt);
@@ -23234,6 +23395,19 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
23234
23395
  const mainFunctionConsumption = runtimeJoinPlan?.joinPlan.serverFunctionConsumptions.find(
23235
23396
  (consumption) => consumption.targetAlias === stmt.from.alias
23236
23397
  );
23398
+ if (emitFetch && stmt.from.cteName === null) {
23399
+ const mainPending = !runtimeJoinPlan && mainCandidate !== null;
23400
+ const mainFetchScope = mainQ === "(\u5168\u4EF6\u53D6\u5F97)" ? "ALL" : mainPending ? "PREFILTERED" : mainJoinItem?.relation === "exact" || mainFunctionConsumption || exactOriginalWhere !== "" ? "EXACT" : "PREFILTERED";
23401
+ lines.push(renderFetchScope(createExplainFetchSource(
23402
+ collector,
23403
+ stmt.from.appId,
23404
+ stmt.from.alias,
23405
+ sourceRole,
23406
+ mainFetchScope,
23407
+ mainQ,
23408
+ mainPending
23409
+ )));
23410
+ }
23237
23411
  if (mainJoinItem || mainFunctionConsumption) {
23238
23412
  lines.push(` pushdown applied: ${mainBoundQuery}`);
23239
23413
  lines.push(` relation: ${mainJoinItem?.relation ?? "exact"}`);
@@ -23257,6 +23431,19 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
23257
23431
  const joinFunctionConsumption = runtimeJoinPlan?.joinPlan.serverFunctionConsumptions.find(
23258
23432
  (consumption) => consumption.targetAlias === join2.table.alias
23259
23433
  );
23434
+ if (emitFetch && join2.table.cteName === null) {
23435
+ const joinPending = !runtimeJoinPlan && joinCandidate !== null;
23436
+ const joinFetchScope = joinQ === "(\u5168\u4EF6\u53D6\u5F97)" ? "ALL" : joinPending ? "PREFILTERED" : joinPlanItem?.relation === "exact" || joinFunctionConsumption ? "EXACT" : "PREFILTERED";
23437
+ lines.push(renderFetchScope(createExplainFetchSource(
23438
+ collector,
23439
+ join2.table.appId,
23440
+ join2.table.alias,
23441
+ "join",
23442
+ joinFetchScope,
23443
+ joinQ,
23444
+ joinPending
23445
+ )));
23446
+ }
23260
23447
  if (joinPlanItem || joinFunctionConsumption) {
23261
23448
  lines.push(` pushdown applied: ${joinBoundQuery}`);
23262
23449
  lines.push(` relation: ${joinPlanItem?.relation ?? "exact"}`);
@@ -23266,10 +23453,16 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
23266
23453
  lines.push(` fields: ${joinFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : joinFields.join(", ")}`);
23267
23454
  }
23268
23455
  }
23269
- lines.push(...collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans));
23456
+ lines.push(...collectSubqueryPlans(
23457
+ stmt,
23458
+ capabilities,
23459
+ orderPlans,
23460
+ plainGroupByPlans,
23461
+ collector
23462
+ ));
23270
23463
  return lines;
23271
23464
  }
23272
- function buildUnionPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
23465
+ function buildUnionPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }) {
23273
23466
  const selects = [];
23274
23467
  const collect = (u) => {
23275
23468
  if (u.type === "SELECT") {
@@ -23283,15 +23476,35 @@ function buildUnionPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
23283
23476
  const lines = [];
23284
23477
  selects.forEach((sel, i) => {
23285
23478
  if (i > 0) lines.push("");
23286
- lines.push(...buildSelectPlan(sel, `[union:${i + 1}]`, capabilities, orderPlans, plainGroupByPlans, true));
23479
+ lines.push(...buildSelectPlan(
23480
+ sel,
23481
+ `[union:${i + 1}]`,
23482
+ capabilities,
23483
+ orderPlans,
23484
+ plainGroupByPlans,
23485
+ true,
23486
+ true,
23487
+ collector,
23488
+ "union"
23489
+ ));
23287
23490
  });
23288
23491
  return lines;
23289
23492
  }
23290
- function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
23493
+ function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }) {
23291
23494
  const lines = [];
23292
23495
  for (const cte of stmt.ctes) {
23293
23496
  if (cte.query.type === "SELECT") {
23294
- lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]`, capabilities, orderPlans, plainGroupByPlans, false));
23497
+ lines.push(...buildSelectPlan(
23498
+ cte.query,
23499
+ `[cte: ${cte.name}]`,
23500
+ capabilities,
23501
+ orderPlans,
23502
+ plainGroupByPlans,
23503
+ false,
23504
+ true,
23505
+ collector,
23506
+ "cte"
23507
+ ));
23295
23508
  lines.push("");
23296
23509
  }
23297
23510
  }
@@ -23304,13 +23517,25 @@ function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
23304
23517
  100,
23305
23518
  DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
23306
23519
  1e4,
23307
- plainGroupByPlans
23520
+ plainGroupByPlans,
23521
+ false,
23522
+ collector
23308
23523
  ));
23309
23524
  }
23310
23525
  if (canInlineSingleCte(stmt)) {
23311
23526
  lines.push("");
23312
23527
  const inlined = buildInlinedQuery(stmt);
23313
- lines.push(...buildSelectPlan(inlined, "[effective: inlined CTE]", capabilities, orderPlans, plainGroupByPlans, false));
23528
+ lines.push(...buildSelectPlan(
23529
+ inlined,
23530
+ "[effective: inlined CTE]",
23531
+ capabilities,
23532
+ orderPlans,
23533
+ plainGroupByPlans,
23534
+ false,
23535
+ true,
23536
+ collector,
23537
+ "cte"
23538
+ ));
23314
23539
  }
23315
23540
  return lines;
23316
23541
  }
@@ -23343,7 +23568,7 @@ function collectFullScanReasons(stmt) {
23343
23568
  r.push("ORDER BY \u306B\u5F0F");
23344
23569
  return r;
23345
23570
  }
23346
- function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans) {
23571
+ function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }) {
23347
23572
  const lines = [];
23348
23573
  let idx = 1;
23349
23574
  const visitWhere = (w) => {
@@ -23352,16 +23577,16 @@ function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans)
23352
23577
  case "BINARY":
23353
23578
  if (w.right.type === "SCALAR_SUBQUERY") {
23354
23579
  lines.push("");
23355
- lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false));
23580
+ lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false, true, collector, "subquery"));
23356
23581
  }
23357
23582
  if (w.right.type === "SUBQUERY_IN_LIST") {
23358
23583
  lines.push("");
23359
- lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false));
23584
+ lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false, true, collector, "subquery"));
23360
23585
  }
23361
23586
  break;
23362
23587
  case "EXISTS":
23363
23588
  lines.push("");
23364
- lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false));
23589
+ lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false, true, collector, "subquery"));
23365
23590
  break;
23366
23591
  case "LOGICAL":
23367
23592
  visitWhere(w.left);
@@ -23381,7 +23606,7 @@ function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans)
23381
23606
  for (const col of stmt.columns) {
23382
23607
  if (col.type === "SCALAR_SUBQUERY_COL") {
23383
23608
  lines.push("");
23384
- lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false));
23609
+ lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false, true, collector, "subquery"));
23385
23610
  }
23386
23611
  }
23387
23612
  if (stmt.having) visitWhere(stmt.having);
@@ -23407,7 +23632,15 @@ function buildInsertSelectPlan(stmt, label, capabilities, orderPlans, plainGroup
23407
23632
  lines.push(` fields: ${stmt.fields.join(", ")}`);
23408
23633
  lines.push(` api: POST /k/v1/records.json\uFF08\u4EF6\u6570\u306F SELECT \u7D50\u679C\u306B\u4F9D\u5B58\u3001100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`);
23409
23634
  lines.push("");
23410
- lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans, plainGroupByPlans, false));
23635
+ lines.push(...buildSelectPlan(
23636
+ stmt.select,
23637
+ "[source SELECT]",
23638
+ capabilities,
23639
+ orderPlans,
23640
+ plainGroupByPlans,
23641
+ false,
23642
+ false
23643
+ ));
23411
23644
  return lines;
23412
23645
  }
23413
23646
  function buildUpdatePlan(stmt, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4) {
@@ -23454,7 +23687,15 @@ function buildUpdatePlan(stmt, label, capabilities, orderPlans, dmlMaxRows = 100
23454
23687
  for (const a of stmt.assignments) {
23455
23688
  if (a.value.type === "SCALAR_SUBQUERY") {
23456
23689
  lines.push("");
23457
- lines.push(...buildSelectPlan(a.value.query, `[subquery: ${a.field}]`, capabilities, orderPlans, void 0, false));
23690
+ lines.push(...buildSelectPlan(
23691
+ a.value.query,
23692
+ `[subquery: ${a.field}]`,
23693
+ capabilities,
23694
+ orderPlans,
23695
+ void 0,
23696
+ false,
23697
+ false
23698
+ ));
23458
23699
  }
23459
23700
  }
23460
23701
  return lines;
@@ -23571,7 +23812,15 @@ function buildUpsertSelectPlan(stmt, label, capabilities, orderPlans, plainGroup
23571
23812
  ` api: GET /k/v1/records.json\uFF08\u91CD\u8907\u5224\u5B9A\uFF09\u2192 POST \u307E\u305F\u306F PUT /k/v1/records.json\uFF08100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`,
23572
23813
  ``
23573
23814
  ];
23574
- lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans, plainGroupByPlans, false));
23815
+ lines.push(...buildSelectPlan(
23816
+ stmt.select,
23817
+ "[source SELECT]",
23818
+ capabilities,
23819
+ orderPlans,
23820
+ plainGroupByPlans,
23821
+ false,
23822
+ false
23823
+ ));
23575
23824
  return lines;
23576
23825
  }
23577
23826
  function buildReorderPlan(stmt, label) {