@rex0220/kintone-sql-tools 3.63.0 → 3.64.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 +305 -55
- package/dist-engine/index.cjs +14 -14
- package/dist-engine/index.mjs +14 -14
- package/dist-engine/ksql-engine.umd.js +14 -14
- package/dist-engine/meta/bundle-baseline.json +7 -7
- package/dist-engine/meta/cjs.json +3 -3
- package/dist-engine/meta/esm.json +3 -3
- package/dist-engine/meta/umd.json +3 -3
- package/dist-mcp/ksql-mcp.js +300 -56
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -24597,6 +24597,10 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
24597
24597
|
for (const cte of withStatement.ctes) {
|
|
24598
24598
|
await preflightExplainRelations(cte.query);
|
|
24599
24599
|
if (cte.query.type === "GENERATE_SERIES") {
|
|
24600
|
+
if (cte.query.args.some((arg) => arg.type === "VARIABLE")) {
|
|
24601
|
+
explainRelations.set(cte.name, { rows: [], columns: [cte.query.columnAlias] });
|
|
24602
|
+
continue;
|
|
24603
|
+
}
|
|
24600
24604
|
const generated = executeGenerateSeries(cte.query);
|
|
24601
24605
|
explainRelations.set(cte.name, {
|
|
24602
24606
|
rows: generated.rows,
|
|
@@ -24637,13 +24641,19 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
24637
24641
|
cacheContext,
|
|
24638
24642
|
explainRelations
|
|
24639
24643
|
);
|
|
24640
|
-
const
|
|
24641
|
-
|
|
24642
|
-
|
|
24643
|
-
cacheContext,
|
|
24644
|
-
explainRelations
|
|
24644
|
+
const sources = [select.from, ...select.joins.map((join2) => join2.table)];
|
|
24645
|
+
const hasUnavailableMaterializedSource = sources.some(
|
|
24646
|
+
(source) => source.cteName !== null && !explainRelations.has(source.cteName)
|
|
24645
24647
|
);
|
|
24646
|
-
if (
|
|
24648
|
+
if (!hasUnavailableMaterializedSource) {
|
|
24649
|
+
const plainPlan = await buildRuntimePlainGroupByPlan(
|
|
24650
|
+
select,
|
|
24651
|
+
tracedClient,
|
|
24652
|
+
cacheContext,
|
|
24653
|
+
explainRelations
|
|
24654
|
+
);
|
|
24655
|
+
if (plainPlan) plainGroupByPlans.set(select, plainPlan);
|
|
24656
|
+
}
|
|
24647
24657
|
return;
|
|
24648
24658
|
}
|
|
24649
24659
|
for (const child of Object.values(typed)) await preflightExplainRelations(child);
|
|
@@ -25172,6 +25182,106 @@ function serverFunctionClientEvaluationLabel(leaves) {
|
|
|
25172
25182
|
(leaf) => leaf.right.type === "KINTONE_FUNC" && isRelativeDateFunctionName(leaf.right.name)
|
|
25173
25183
|
) ? "relative date client evaluations" : "kintone function client evaluations";
|
|
25174
25184
|
}
|
|
25185
|
+
var explainSeriesBindings = /* @__PURE__ */ new WeakMap();
|
|
25186
|
+
function resolveExplainGenerateSeriesDefaults(node, literalDefaults) {
|
|
25187
|
+
if (Array.isArray(node)) {
|
|
25188
|
+
return node.map((value) => resolveExplainGenerateSeriesDefaults(value, literalDefaults));
|
|
25189
|
+
}
|
|
25190
|
+
if (node === null || typeof node !== "object") return node;
|
|
25191
|
+
const object = node;
|
|
25192
|
+
if (object["type"] === "GENERATE_SERIES") {
|
|
25193
|
+
const variableNames = /* @__PURE__ */ new Map();
|
|
25194
|
+
const defaultBoundIndexes = /* @__PURE__ */ new Set();
|
|
25195
|
+
const args = object["args"].map((arg, index) => {
|
|
25196
|
+
if (arg.type !== "STRING" || arg.fromVariable !== true || !arg.value.startsWith("@")) return arg;
|
|
25197
|
+
const name = arg.value.slice(1);
|
|
25198
|
+
variableNames.set(index, name);
|
|
25199
|
+
const defaultValue = literalDefaults.get(name);
|
|
25200
|
+
if (defaultValue === void 0) return { type: "VARIABLE", name };
|
|
25201
|
+
defaultBoundIndexes.add(index);
|
|
25202
|
+
return { type: "STRING", value: defaultValue, fromVariable: true };
|
|
25203
|
+
});
|
|
25204
|
+
const resolved = { ...object, args };
|
|
25205
|
+
explainSeriesBindings.set(resolved, { variableNames, defaultBoundIndexes });
|
|
25206
|
+
return resolved;
|
|
25207
|
+
}
|
|
25208
|
+
return Object.fromEntries(Object.entries(object).map(([key, value]) => [
|
|
25209
|
+
key,
|
|
25210
|
+
resolveExplainGenerateSeriesDefaults(value, literalDefaults)
|
|
25211
|
+
]));
|
|
25212
|
+
}
|
|
25213
|
+
function inferStaticExplainSchema(node, relations) {
|
|
25214
|
+
if (node.type === "SHOW_APPS") return { status: "STATIC", columns: [...SHOW_APPS_COLUMNS] };
|
|
25215
|
+
if (node.type === "DESCRIBE") return { status: "STATIC", columns: [...DESCRIBE_COLUMNS] };
|
|
25216
|
+
if (node.type === "GENERATE_SERIES") {
|
|
25217
|
+
return { status: "STATIC", columns: [node.columnAlias] };
|
|
25218
|
+
}
|
|
25219
|
+
if (node.type === "WITH") {
|
|
25220
|
+
const local = new Map(relations);
|
|
25221
|
+
for (const cte of node.ctes) {
|
|
25222
|
+
const schema = inferStaticExplainSchema(cte.query, local);
|
|
25223
|
+
local.set(cte.name, schema);
|
|
25224
|
+
}
|
|
25225
|
+
return inferStaticExplainSchema(node.query, local);
|
|
25226
|
+
}
|
|
25227
|
+
if (node.type === "UNION") {
|
|
25228
|
+
const left = inferStaticExplainSchema(node.left, relations);
|
|
25229
|
+
const right = inferStaticExplainSchema(node.right, relations);
|
|
25230
|
+
return left.status === "STATIC" && right.status === "STATIC" ? { status: "STATIC", columns: left.columns } : { status: "DEFERRED" };
|
|
25231
|
+
}
|
|
25232
|
+
const sources = [node.from, ...node.joins.map((join2) => join2.table)];
|
|
25233
|
+
const relationSources = sources.filter((source) => source.cteName !== null && source.cteName !== NO_FROM_CTE_NAME);
|
|
25234
|
+
if (relationSources.some((source) => relations.get(source.cteName)?.status !== "STATIC")) {
|
|
25235
|
+
return { status: "DEFERRED" };
|
|
25236
|
+
}
|
|
25237
|
+
const hasWildcard = node.columns.some(
|
|
25238
|
+
(column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
|
|
25239
|
+
);
|
|
25240
|
+
if (hasWildcard) {
|
|
25241
|
+
if (sources.length !== 1 || sources[0].cteName === null) return { status: "DEFERRED" };
|
|
25242
|
+
}
|
|
25243
|
+
const sourceColumns2 = relationSources.flatMap((source) => {
|
|
25244
|
+
const schema = relations.get(source.cteName);
|
|
25245
|
+
return schema?.status === "STATIC" ? [...schema.columns] : [];
|
|
25246
|
+
});
|
|
25247
|
+
const columns = [];
|
|
25248
|
+
for (const column of node.columns) {
|
|
25249
|
+
if (column.type === "WILDCARD") columns.push(...sourceColumns2);
|
|
25250
|
+
else if (column.type === "PARENT_WILDCARD") {
|
|
25251
|
+
columns.push(...sourceColumns2.filter((name) => name.startsWith("_p.")));
|
|
25252
|
+
} else {
|
|
25253
|
+
columns.push(...project([], [column]).columns);
|
|
25254
|
+
}
|
|
25255
|
+
}
|
|
25256
|
+
return { status: "STATIC", columns };
|
|
25257
|
+
}
|
|
25258
|
+
function staticSchemaRelations(ledger) {
|
|
25259
|
+
return new Map([...ledger].flatMap(
|
|
25260
|
+
([name, entry]) => entry.status === "STATIC" ? [[name, entry.relation]] : []
|
|
25261
|
+
));
|
|
25262
|
+
}
|
|
25263
|
+
async function buildStaticTempPlainGroupByPlans(node, client, cacheContext, relations) {
|
|
25264
|
+
const plans = /* @__PURE__ */ new Map();
|
|
25265
|
+
const visit = async (value) => {
|
|
25266
|
+
if (value === null || typeof value !== "object") return;
|
|
25267
|
+
if (Array.isArray(value)) {
|
|
25268
|
+
for (const child of value) await visit(child);
|
|
25269
|
+
return;
|
|
25270
|
+
}
|
|
25271
|
+
const object = value;
|
|
25272
|
+
if (object["type"] === "SELECT") {
|
|
25273
|
+
const select = value;
|
|
25274
|
+
const sources = [select.from, ...select.joins.map((join2) => join2.table)];
|
|
25275
|
+
if (sources.some((source) => source.cteName !== null) && sources.every((source) => source.cteName === NO_FROM_CTE_NAME || source.cteName !== null && relations.has(source.cteName))) {
|
|
25276
|
+
const plan = await buildRuntimePlainGroupByPlan(select, client, cacheContext, relations);
|
|
25277
|
+
if (plan) plans.set(select, plan);
|
|
25278
|
+
}
|
|
25279
|
+
}
|
|
25280
|
+
for (const child of Object.values(object)) await visit(child);
|
|
25281
|
+
};
|
|
25282
|
+
await visit(node);
|
|
25283
|
+
return plans;
|
|
25284
|
+
}
|
|
25175
25285
|
var EXPLAIN_FETCH_PLAN = /* @__PURE__ */ Symbol("ksql.explainFetchPlan");
|
|
25176
25286
|
function setExplainFetchPlan(result, plan) {
|
|
25177
25287
|
result[EXPLAIN_FETCH_PLAN] = plan;
|
|
@@ -25184,19 +25294,27 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
25184
25294
|
const normalizedInjectedVariables = validateDeclaredBatchVariables(statements, injectedVariables);
|
|
25185
25295
|
const relativeDateVariables = prepareRelativeDateVariables(statements, normalizedInjectedVariables);
|
|
25186
25296
|
const variables = /* @__PURE__ */ new Map();
|
|
25297
|
+
const literalDeclareDefaults = /* @__PURE__ */ new Map();
|
|
25298
|
+
const tempSchemaLedger = /* @__PURE__ */ new Map();
|
|
25187
25299
|
const plans = [];
|
|
25188
25300
|
const fetchStatements = [];
|
|
25189
25301
|
for (let i = 0; i < statements.length; i++) {
|
|
25190
25302
|
const stmt = statements[i];
|
|
25191
|
-
const
|
|
25303
|
+
const placeholderResolvedStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveBatchVariableReferences(stmt.expr, variables) } : stmt : resolveBatchVariableReferences(stmt, variables);
|
|
25304
|
+
const planStmt = resolveExplainGenerateSeriesDefaults(
|
|
25305
|
+
placeholderResolvedStmt,
|
|
25306
|
+
literalDeclareDefaults
|
|
25307
|
+
);
|
|
25192
25308
|
validateStatementStatic(planStmt);
|
|
25193
25309
|
const relativeDatePlan = await resolveRelativeDateExecutionPlan(planStmt, client, invocationCacheContext);
|
|
25310
|
+
const initialRelations = staticSchemaRelations(tempSchemaLedger);
|
|
25194
25311
|
const whereAnalysis = resolveMetadata ? await buildExplainWhereAnalysis(
|
|
25195
25312
|
planStmt,
|
|
25196
25313
|
client,
|
|
25197
25314
|
invocationCacheContext,
|
|
25198
25315
|
maxRecords,
|
|
25199
|
-
relativeDatePlan
|
|
25316
|
+
relativeDatePlan,
|
|
25317
|
+
initialRelations
|
|
25200
25318
|
) : {
|
|
25201
25319
|
capabilities: /* @__PURE__ */ new Map(),
|
|
25202
25320
|
orderPlans: /* @__PURE__ */ new Map(),
|
|
@@ -25206,6 +25324,34 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
25206
25324
|
numberPrecisionApps: /* @__PURE__ */ new Set(),
|
|
25207
25325
|
relativeDatePlan
|
|
25208
25326
|
};
|
|
25327
|
+
if (!resolveMetadata) {
|
|
25328
|
+
const staticPlans = await buildStaticTempPlainGroupByPlans(
|
|
25329
|
+
planStmt,
|
|
25330
|
+
client,
|
|
25331
|
+
invocationCacheContext,
|
|
25332
|
+
initialRelations
|
|
25333
|
+
);
|
|
25334
|
+
for (const [select, plan] of staticPlans) whereAnalysis.plainGroupByPlans.set(select, plan);
|
|
25335
|
+
}
|
|
25336
|
+
let createdSchema;
|
|
25337
|
+
if (planStmt.type === "CREATE_TEMP_TABLE") {
|
|
25338
|
+
const relationSchemas = new Map([...tempSchemaLedger].map(([name, entry]) => [
|
|
25339
|
+
name,
|
|
25340
|
+
entry.status === "STATIC" ? { status: "STATIC", columns: entry.columns } : { status: "DEFERRED" }
|
|
25341
|
+
]));
|
|
25342
|
+
const inferred = inferStaticExplainSchema(planStmt.query, relationSchemas);
|
|
25343
|
+
createdSchema = inferred.status === "STATIC" ? {
|
|
25344
|
+
status: "STATIC",
|
|
25345
|
+
columns: inferred.columns,
|
|
25346
|
+
relation: { rows: [], columns: [...inferred.columns] },
|
|
25347
|
+
producerStatement: i + 1
|
|
25348
|
+
} : {
|
|
25349
|
+
status: "DEFERRED",
|
|
25350
|
+
producerStatement: i + 1,
|
|
25351
|
+
reason: "EXPLAIN_TEMP_SCHEMA_UNAVAILABLE"
|
|
25352
|
+
};
|
|
25353
|
+
tempSchemaLedger.set(planStmt.name, createdSchema);
|
|
25354
|
+
}
|
|
25209
25355
|
const fetchCollector = { sources: [] };
|
|
25210
25356
|
const statementPlan = relativeDatePlan.hasServerOnlyWhereFunction && !relativeDatePlan.allowed ? relativeDateExplainLines(relativeDatePlan) : [
|
|
25211
25357
|
...relativeDateExplainLines(relativeDatePlan),
|
|
@@ -25214,9 +25360,12 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
25214
25360
|
analysis.statements[i],
|
|
25215
25361
|
whereAnalysis.capabilities,
|
|
25216
25362
|
whereAnalysis.orderPlans,
|
|
25363
|
+
whereAnalysis.plainGroupByPlans,
|
|
25217
25364
|
dmlMaxRows,
|
|
25218
25365
|
dmlMaxSubtableRows,
|
|
25219
|
-
fetchCollector
|
|
25366
|
+
fetchCollector,
|
|
25367
|
+
tempSchemaLedger,
|
|
25368
|
+
createdSchema
|
|
25220
25369
|
), cursorMaxActive)
|
|
25221
25370
|
];
|
|
25222
25371
|
const metadataPlan = explainMetadataLines(whereAnalysis);
|
|
@@ -25230,8 +25379,15 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
25230
25379
|
fetch: worstExplainFetch(fetchCollector.sources),
|
|
25231
25380
|
sources: fetchCollector.sources
|
|
25232
25381
|
});
|
|
25382
|
+
if (planStmt.type === "DROP_TEMP_TABLE") tempSchemaLedger.delete(planStmt.name);
|
|
25233
25383
|
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
25234
25384
|
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 });
|
|
25385
|
+
if (stmt.type === "DECLARE_VARIABLE" && stmt.annotation === void 0 && (stmt.default.type === "STRING" || stmt.default.type === "NUMBER")) {
|
|
25386
|
+
literalDeclareDefaults.set(
|
|
25387
|
+
stmt.name,
|
|
25388
|
+
stmt.default.type === "STRING" ? stmt.default.value : numberLiteralText(stmt.default)
|
|
25389
|
+
);
|
|
25390
|
+
}
|
|
25235
25391
|
}
|
|
25236
25392
|
}
|
|
25237
25393
|
const result = { statementCount: statements.length, statements: plans };
|
|
@@ -25241,19 +25397,28 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
25241
25397
|
releaseMetadataCacheScope(invocationCacheContext);
|
|
25242
25398
|
}
|
|
25243
25399
|
}
|
|
25244
|
-
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, collector = { sources: [] }) {
|
|
25400
|
+
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGroupByPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, collector = { sources: [] }, tempSchemaLedger = /* @__PURE__ */ new Map(), createdSchema) {
|
|
25245
25401
|
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
25246
25402
|
return [
|
|
25247
25403
|
`CREATE TEMP TABLE ${stmt.name}`,
|
|
25248
25404
|
` scope: batch\uFF08\u30D0\u30C3\u30C1\u7D42\u4E86\u6642\u306B\u81EA\u52D5\u7834\u68C4\uFF09`,
|
|
25405
|
+
...createdSchema?.status === "STATIC" ? [
|
|
25406
|
+
` schema: ${createdSchema.columns.join(", ")}`,
|
|
25407
|
+
` schema source: SELECT output of statement ${createdSchema.producerStatement}`
|
|
25408
|
+
] : createdSchema ? [
|
|
25409
|
+
" schema: deferred (could not be derived statically)",
|
|
25410
|
+
` plan status: deferred (temp table schema; reason=${createdSchema.reason})`
|
|
25411
|
+
] : [],
|
|
25249
25412
|
` 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`,
|
|
25250
25413
|
...buildPlanForBatchQuery(
|
|
25251
25414
|
stmt.query,
|
|
25252
25415
|
info,
|
|
25253
25416
|
capabilities,
|
|
25254
25417
|
orderPlans,
|
|
25418
|
+
plainGroupByPlans,
|
|
25255
25419
|
collector,
|
|
25256
|
-
"main"
|
|
25420
|
+
"main",
|
|
25421
|
+
tempSchemaLedger
|
|
25257
25422
|
).map((l) => ` ${l}`)
|
|
25258
25423
|
];
|
|
25259
25424
|
}
|
|
@@ -25275,7 +25440,10 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
|
|
|
25275
25440
|
subInfo,
|
|
25276
25441
|
capabilities,
|
|
25277
25442
|
orderPlans,
|
|
25278
|
-
|
|
25443
|
+
plainGroupByPlans,
|
|
25444
|
+
collector,
|
|
25445
|
+
"main",
|
|
25446
|
+
tempSchemaLedger
|
|
25279
25447
|
).map((l) => ` ${l}`)
|
|
25280
25448
|
];
|
|
25281
25449
|
}
|
|
@@ -25304,7 +25472,10 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
|
|
|
25304
25472
|
info,
|
|
25305
25473
|
capabilities,
|
|
25306
25474
|
orderPlans,
|
|
25307
|
-
|
|
25475
|
+
plainGroupByPlans,
|
|
25476
|
+
collector,
|
|
25477
|
+
"main",
|
|
25478
|
+
tempSchemaLedger
|
|
25308
25479
|
);
|
|
25309
25480
|
}
|
|
25310
25481
|
if (stmt.type === "ASSERT") {
|
|
@@ -25323,15 +25494,36 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
|
|
|
25323
25494
|
subInfo,
|
|
25324
25495
|
capabilities,
|
|
25325
25496
|
orderPlans,
|
|
25326
|
-
|
|
25497
|
+
plainGroupByPlans,
|
|
25498
|
+
collector,
|
|
25499
|
+
"main",
|
|
25500
|
+
tempSchemaLedger
|
|
25327
25501
|
).map((l) => ` ${l}`));
|
|
25328
25502
|
});
|
|
25329
25503
|
return lines;
|
|
25330
25504
|
}
|
|
25331
25505
|
if (stmt.type === "UPDATE" && (stmt.applyBlocks?.length ?? 0) > 0) {
|
|
25332
|
-
return buildExplainPlan(
|
|
25506
|
+
return buildExplainPlan(
|
|
25507
|
+
stmt,
|
|
25508
|
+
void 0,
|
|
25509
|
+
capabilities,
|
|
25510
|
+
orderPlans,
|
|
25511
|
+
dmlMaxRows,
|
|
25512
|
+
dmlMaxSubtableRows,
|
|
25513
|
+
1e4,
|
|
25514
|
+
plainGroupByPlans
|
|
25515
|
+
);
|
|
25333
25516
|
}
|
|
25334
|
-
return buildPlanForBatchQuery(
|
|
25517
|
+
return buildPlanForBatchQuery(
|
|
25518
|
+
stmt,
|
|
25519
|
+
info,
|
|
25520
|
+
capabilities,
|
|
25521
|
+
orderPlans,
|
|
25522
|
+
plainGroupByPlans,
|
|
25523
|
+
collector,
|
|
25524
|
+
"main",
|
|
25525
|
+
tempSchemaLedger
|
|
25526
|
+
);
|
|
25335
25527
|
}
|
|
25336
25528
|
function hasTempTableRef(node) {
|
|
25337
25529
|
if (Array.isArray(node)) return node.some(hasTempTableRef);
|
|
@@ -25343,7 +25535,7 @@ function hasTempTableRef(node) {
|
|
|
25343
25535
|
}
|
|
25344
25536
|
return false;
|
|
25345
25537
|
}
|
|
25346
|
-
function buildPlanForBatchQuery(query, info, capabilities, orderPlans, collector = { sources: [] }, sourceRole = "main") {
|
|
25538
|
+
function buildPlanForBatchQuery(query, info, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }, sourceRole = "main", tempSchemaLedger = /* @__PURE__ */ new Map()) {
|
|
25347
25539
|
if (info.tempTablesReferenced.length === 0) {
|
|
25348
25540
|
return buildExplainPlan(
|
|
25349
25541
|
query,
|
|
@@ -25353,7 +25545,7 @@ function buildPlanForBatchQuery(query, info, capabilities, orderPlans, collector
|
|
|
25353
25545
|
100,
|
|
25354
25546
|
DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
|
|
25355
25547
|
1e4,
|
|
25356
|
-
|
|
25548
|
+
plainGroupByPlans,
|
|
25357
25549
|
true,
|
|
25358
25550
|
collector,
|
|
25359
25551
|
sourceRole
|
|
@@ -25373,6 +25565,26 @@ function buildPlanForBatchQuery(query, info, capabilities, orderPlans, collector
|
|
|
25373
25565
|
lines.push(
|
|
25374
25566
|
` temp: ${info.tempTablesReferenced.join(", ")}\uFF08\u30A4\u30F3\u30E1\u30E2\u30EA\u8D70\u67FB\u3002\u5B9F\u4F53\u5316\u524D\u306E\u305F\u3081\u884C\u6570\u4E0D\u660E\uFF09`
|
|
25375
25567
|
);
|
|
25568
|
+
const entries = info.tempTablesReferenced.map((name) => [name, tempSchemaLedger.get(name)]);
|
|
25569
|
+
for (const [name, entry] of entries) {
|
|
25570
|
+
if (entry?.status === "STATIC") {
|
|
25571
|
+
lines.push(` source: temp table ${name} (schema from statement ${entry.producerStatement})`);
|
|
25572
|
+
} else {
|
|
25573
|
+
lines.push(` source: temp table ${name}`);
|
|
25574
|
+
lines.push(" schema: deferred (could not be derived statically)");
|
|
25575
|
+
}
|
|
25576
|
+
}
|
|
25577
|
+
lines.push(" rows: runtime (not materialized by EXPLAIN)");
|
|
25578
|
+
const directSelect = query.type === "SELECT" ? query : query.type === "EXPLAIN" && query.query.type === "SELECT" ? query.query : void 0;
|
|
25579
|
+
if (directSelect) {
|
|
25580
|
+
lines.push(...renderPlainGroupByExplainLines(
|
|
25581
|
+
directSelect,
|
|
25582
|
+
plainGroupByPlans?.get(directSelect),
|
|
25583
|
+
entries.some(([, entry]) => entry?.status !== "STATIC")
|
|
25584
|
+
));
|
|
25585
|
+
}
|
|
25586
|
+
lines.push(entries.every(([, entry]) => entry?.status === "STATIC") ? " plan status: static schema / runtime rows" : " plan status: deferred (temp table schema)");
|
|
25587
|
+
lines.push(" records API: none");
|
|
25376
25588
|
const apps = info.appIds.filter(
|
|
25377
25589
|
(a) => query.type !== "INSERT_SELECT" && query.type !== "UPSERT_SELECT" || a !== query.appId
|
|
25378
25590
|
);
|
|
@@ -25642,6 +25854,33 @@ function formatChoiceEqualityRewrite(rewrite) {
|
|
|
25642
25854
|
const normalizedOperator = rewrite.normalizedOperator === "IN" ? "in" : "not in";
|
|
25643
25855
|
return ` pushdown normalized: ${field} ${rewrite.originalOperator} '${originalValue}' -> ${field} ${normalizedOperator} ("${normalizedValue}")`;
|
|
25644
25856
|
}
|
|
25857
|
+
function renderPlainGroupByExplainLines(stmt, plainGroupByPlan, schemaDeferred) {
|
|
25858
|
+
const normalizedGrouping = normalizeGroupingSpec(stmt);
|
|
25859
|
+
if (normalizedGrouping.type !== "PLAIN") return [];
|
|
25860
|
+
const lines = [];
|
|
25861
|
+
if (plainGroupByPlan) {
|
|
25862
|
+
plainGroupByPlan.items.forEach((item, index) => {
|
|
25863
|
+
const key = normalizedGrouping.allItems[index];
|
|
25864
|
+
if (key?.type !== "FIELD_NAME") return;
|
|
25865
|
+
if (item.kind === "PHYSICAL") {
|
|
25866
|
+
lines.push(
|
|
25867
|
+
` group key ${key.name}: PHYSICAL (source=${item.sourceIndex}, field=${item.fieldCode})`
|
|
25868
|
+
);
|
|
25869
|
+
} else if (item.kind === "ALIAS_SAFE") {
|
|
25870
|
+
lines.push(` group key ${key.name}: ALIAS_SAFE (column=${item.columnIndex})`);
|
|
25871
|
+
} else if (item.kind === "EXPRESSION") {
|
|
25872
|
+
lines.push(` group key ${key.name}: EXPRESSION`);
|
|
25873
|
+
}
|
|
25874
|
+
});
|
|
25875
|
+
} else if (schemaDeferred) {
|
|
25876
|
+
for (const key of normalizedGrouping.allItems) {
|
|
25877
|
+
if (key.type === "FIELD_NAME") {
|
|
25878
|
+
lines.push(` group key ${key.name}: DEFERRED (temp table schema unavailable)`);
|
|
25879
|
+
}
|
|
25880
|
+
}
|
|
25881
|
+
}
|
|
25882
|
+
return lines;
|
|
25883
|
+
}
|
|
25645
25884
|
function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlans, allowTotalCountPlan = true, emitFetch = true, collector = { sources: [] }, sourceRole = "main") {
|
|
25646
25885
|
const whereCapability = capabilities?.get(stmt) ?? (capabilities ? [...capabilities].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
25647
25886
|
const orderPlan = orderPlans?.get(stmt) ?? (orderPlans ? [...orderPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
@@ -25691,35 +25930,11 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
25691
25930
|
` grouping output rows: runtime checked (limit: ${groupingMetadata.outputRowLimit}, before HAVING/DISTINCT/LIMIT)`
|
|
25692
25931
|
);
|
|
25693
25932
|
}
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
const key = groupBy[index];
|
|
25700
|
-
if (key?.type !== "FIELD_NAME") return;
|
|
25701
|
-
if (item.kind === "PHYSICAL") {
|
|
25702
|
-
lines.push(
|
|
25703
|
-
` group key ${key.name}: PHYSICAL (source=${item.sourceIndex}, field=${item.fieldCode})`
|
|
25704
|
-
);
|
|
25705
|
-
} else if (item.kind === "ALIAS_SAFE") {
|
|
25706
|
-
lines.push(
|
|
25707
|
-
` group key ${key.name}: ALIAS_SAFE (column=${item.columnIndex})`
|
|
25708
|
-
);
|
|
25709
|
-
} else if (item.kind === "EXPRESSION") {
|
|
25710
|
-
lines.push(` group key ${key.name}: EXPRESSION`);
|
|
25711
|
-
}
|
|
25712
|
-
});
|
|
25713
|
-
} else if ([stmt.from, ...stmt.joins.map((join2) => join2.table)].some((table) => table.cteName !== null)) {
|
|
25714
|
-
for (const key of groupBy) {
|
|
25715
|
-
if (key.type === "FIELD_NAME") {
|
|
25716
|
-
lines.push(
|
|
25717
|
-
` group key ${key.name}: DEFERRED (materialized schema unavailable)`
|
|
25718
|
-
);
|
|
25719
|
-
}
|
|
25720
|
-
}
|
|
25721
|
-
}
|
|
25722
|
-
}
|
|
25933
|
+
lines.push(...renderPlainGroupByExplainLines(
|
|
25934
|
+
stmt,
|
|
25935
|
+
plainGroupByPlan,
|
|
25936
|
+
[stmt.from, ...stmt.joins.map((join2) => join2.table)].some((table) => table.cteName !== null)
|
|
25937
|
+
));
|
|
25723
25938
|
for (const column of stmt.columns) {
|
|
25724
25939
|
if (column.type !== "WINDOW_COL" || column.windowKind === void 0 || column.windowKind === "RANKING") continue;
|
|
25725
25940
|
const clauses = [];
|
|
@@ -26041,7 +26256,9 @@ function populateWithCrossJoinExplain(stmt) {
|
|
|
26041
26256
|
};
|
|
26042
26257
|
for (const cte of stmt.ctes) {
|
|
26043
26258
|
if (cte.query.type === "GENERATE_SERIES") {
|
|
26044
|
-
|
|
26259
|
+
if (!cte.query.args.some((arg) => arg.type === "VARIABLE")) {
|
|
26260
|
+
exactRows.set(cte.name, resolveGenerateSeries(cte.query).rowCount);
|
|
26261
|
+
}
|
|
26045
26262
|
} else if (cte.query.type === "SELECT") {
|
|
26046
26263
|
const rows = analyze(cte.query);
|
|
26047
26264
|
if (rows !== null) exactRows.set(cte.name, rows);
|
|
@@ -26069,18 +26286,45 @@ function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collec
|
|
|
26069
26286
|
));
|
|
26070
26287
|
lines.push("");
|
|
26071
26288
|
} else if (cte.query.type === "GENERATE_SERIES") {
|
|
26072
|
-
const
|
|
26289
|
+
const seriesStatement = cte.query;
|
|
26290
|
+
const binding = explainSeriesBindings.get(seriesStatement);
|
|
26291
|
+
const unresolved = seriesStatement.args.some((arg) => arg.type === "VARIABLE");
|
|
26292
|
+
if (unresolved) {
|
|
26293
|
+
const argumentLabel = (index) => {
|
|
26294
|
+
const arg = seriesStatement.args[index];
|
|
26295
|
+
if (!arg) return index === 2 ? "runtime" : "deferred";
|
|
26296
|
+
if (arg.type === "VARIABLE") return `@${arg.name} (runtime)`;
|
|
26297
|
+
if (index < 2) return "literal";
|
|
26298
|
+
return arg.type === "NUMBER" ? numberLiteralText(arg) : arg.value;
|
|
26299
|
+
};
|
|
26300
|
+
lines.push(
|
|
26301
|
+
`[cte: ${cte.name}]`,
|
|
26302
|
+
" source: GENERATE_SERIES",
|
|
26303
|
+
` column: ${seriesStatement.columnAlias}`,
|
|
26304
|
+
" series type: deferred (variable)",
|
|
26305
|
+
` start: ${argumentLabel(0)}`,
|
|
26306
|
+
` stop: ${argumentLabel(1)}`,
|
|
26307
|
+
` step: ${argumentLabel(2)}`,
|
|
26308
|
+
" rows: runtime",
|
|
26309
|
+
` row guard: runtime / ${GENERATE_SERIES_MAX_ROWS}`,
|
|
26310
|
+
" records API: none",
|
|
26311
|
+
""
|
|
26312
|
+
);
|
|
26313
|
+
continue;
|
|
26314
|
+
}
|
|
26315
|
+
const series = resolveGenerateSeries(seriesStatement);
|
|
26073
26316
|
const step = series.kind === "DATE" ? `${series.step} ${String(series.dateUnit ?? "DAY").toLowerCase()}${Math.abs(series.step) === 1 ? "" : "s"}` : String(series.step);
|
|
26074
26317
|
lines.push(
|
|
26075
26318
|
`[cte: ${cte.name}]`,
|
|
26076
26319
|
" source: GENERATE_SERIES",
|
|
26077
|
-
` column: ${
|
|
26078
|
-
` series type: ${series.kind}`,
|
|
26079
|
-
` start: ${series.start}`,
|
|
26080
|
-
` stop: ${series.stop}`,
|
|
26320
|
+
` column: ${seriesStatement.columnAlias}`,
|
|
26321
|
+
` series type: ${series.kind}${binding?.defaultBoundIndexes.size ? " (DECLARE default)" : ""}`,
|
|
26322
|
+
` start: ${binding?.variableNames.has(0) ? `@${binding.variableNames.get(0)} (DECLARE default; value hidden)` : series.start}`,
|
|
26323
|
+
` stop: ${binding?.variableNames.has(1) ? `@${binding.variableNames.get(1)} (DECLARE default; value hidden)` : series.stop}`,
|
|
26081
26324
|
` step: ${step}`,
|
|
26082
|
-
` rows: ${series.rowCount}`,
|
|
26325
|
+
` rows: ${series.rowCount}${binding?.defaultBoundIndexes.size ? " (DECLARE default estimate)" : ""}`,
|
|
26083
26326
|
` row guard: ${series.rowCount} / ${GENERATE_SERIES_MAX_ROWS}`,
|
|
26327
|
+
...binding?.defaultBoundIndexes.size ? [" binding: DECLARE defaults; runtime injection may change this plan"] : [],
|
|
26084
26328
|
" records API: none",
|
|
26085
26329
|
""
|
|
26086
26330
|
);
|
|
@@ -29204,6 +29448,9 @@ function createDryRunClient() {
|
|
|
29204
29448
|
function hasStaticTypedPushdownCandidate(statement) {
|
|
29205
29449
|
if (statement === null || typeof statement !== "object") return false;
|
|
29206
29450
|
const node = statement;
|
|
29451
|
+
if (node["type"] === "CREATE_TEMP_TABLE") {
|
|
29452
|
+
return hasStaticTypedPushdownCandidate(node["query"]);
|
|
29453
|
+
}
|
|
29207
29454
|
if (node["type"] === "WITH") {
|
|
29208
29455
|
const query = node["query"];
|
|
29209
29456
|
const containsCross = (value) => {
|
|
@@ -29923,7 +30170,10 @@ async function run() {
|
|
|
29923
30170
|
return false;
|
|
29924
30171
|
});
|
|
29925
30172
|
dryRunNeedsMetadata = statements.some(explainNeedsAppMetadata);
|
|
29926
|
-
|
|
30173
|
+
const staticEligible = statements.every(
|
|
30174
|
+
(statement) => !explainNeedsAppMetadata(statement) || hasStaticTypedPushdownCandidate(statement)
|
|
30175
|
+
);
|
|
30176
|
+
dryRunUsesStaticTypedPlan = statements.some(hasStaticTypedPushdownCandidate) && staticEligible && !statements.some(statementUsesRelativeDateResolution);
|
|
29927
30177
|
if (statements.length > 1) {
|
|
29928
30178
|
batchAnalysis = analyzeBatch(statements);
|
|
29929
30179
|
isBatchSql = true;
|