@duckcodeailabs/dql-cli 1.10.3 → 1.10.4
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/assets/dql-notebook/assets/{index-VvEaTurJ.js → index-m7ziVzoC.js} +132 -132
- package/dist/assets/dql-notebook/index.html +1 -1
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +15 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/local-runtime.d.ts +8 -0
- package/dist/local-runtime.d.ts.map +1 -1
- package/dist/local-runtime.js +307 -140
- package/dist/local-runtime.js.map +1 -1
- package/dist/package.json +10 -10
- package/dist/semantic-execution/connection-identity.d.ts +11 -0
- package/dist/semantic-execution/connection-identity.d.ts.map +1 -0
- package/dist/semantic-execution/connection-identity.js +81 -0
- package/dist/semantic-execution/connection-identity.js.map +1 -0
- package/dist/semantic-execution/execution-gateway.d.ts +42 -0
- package/dist/semantic-execution/execution-gateway.d.ts.map +1 -0
- package/dist/semantic-execution/execution-gateway.js +203 -0
- package/dist/semantic-execution/execution-gateway.js.map +1 -0
- package/dist/semantic-execution/target-binding.d.ts +44 -0
- package/dist/semantic-execution/target-binding.d.ts.map +1 -0
- package/dist/semantic-execution/target-binding.js +185 -0
- package/dist/semantic-execution/target-binding.js.map +1 -0
- package/dist/semantic-runtime-settings.d.ts +7 -1
- package/dist/semantic-runtime-settings.d.ts.map +1 -1
- package/dist/semantic-runtime-settings.js +8 -1
- package/dist/semantic-runtime-settings.js.map +1 -1
- package/dist/semantic-runtime.d.ts +6 -2
- package/dist/semantic-runtime.d.ts.map +1 -1
- package/dist/semantic-runtime.js +13 -5
- package/dist/semantic-runtime.js.map +1 -1
- package/package.json +10 -10
package/dist/local-runtime.js
CHANGED
|
@@ -35,6 +35,10 @@ import { MetricFlowUnavailableError, hasDbtSemanticManifest, } from "./metricflo
|
|
|
35
35
|
import { ManagedMetricFlowInstaller, isMetricFlowWarehouseAdapter, metricFlowAdapterForDriver, } from './metricflow-installer.js';
|
|
36
36
|
import { applySemanticPathSelection, compileSemanticRuntimeQuery, decodeSemanticPathEvidenceId, describeRuntimeCompatibility, explainMissingSemanticRuntime, getSemanticRuntimeStatus, semanticRuntimeErrorDetails, semanticRuntimeErrorCode, semanticMetricExecutionCapability as runtimeMetricExecutionCapability, SemanticRuntimeRequiredError, testSemanticRuntimeDraft, parseSemanticDimensionSelection, } from './semantic-runtime.js';
|
|
37
37
|
import { getSemanticRuntimeSettings, saveTestedSemanticRuntimeSettings, saveSemanticRuntimePreference, } from './semantic-runtime-settings.js';
|
|
38
|
+
import { observeWarehouseTargetIdentity } from './semantic-execution/connection-identity.js';
|
|
39
|
+
import { configuredWarehouseTargetIdentity } from './semantic-execution/connection-identity.js';
|
|
40
|
+
import { executeTargetBoundSemanticQuery, semanticExecutionFailureCode, semanticExecutionFailureDetails, } from './semantic-execution/execution-gateway.js';
|
|
41
|
+
import { buildSemanticTargetBinding } from './semantic-execution/target-binding.js';
|
|
38
42
|
import { NotebookDatasetWorkspace, } from "./notebook-datasets.js";
|
|
39
43
|
import { prepareBlockInvocation } from './block-invocation.js';
|
|
40
44
|
const NOTEBOOK_EXECUTE_PREVIEW_ROW_LIMIT = 500;
|
|
@@ -585,6 +589,10 @@ export async function startLocalServer(opts) {
|
|
|
585
589
|
: null;
|
|
586
590
|
let connection = configuredConnection ?? resolveDbtProfileRuntimeConnection(projectRoot, projectConfig);
|
|
587
591
|
const projectSnapshots = new ProjectSnapshotService();
|
|
592
|
+
// Server-lifetime registry for exact compiler-owned SQL. The downstream DQL
|
|
593
|
+
// artifact executor uses this to preserve the selected adapter and target
|
|
594
|
+
// rather than treating compiled semantic SQL as unrelated generic SQL.
|
|
595
|
+
const compiledSemanticQueries = new Map();
|
|
588
596
|
const dashboardRunEvidence = new Map();
|
|
589
597
|
const dbtNodeDetailCache = new Map();
|
|
590
598
|
const onboardingJobs = new Map();
|
|
@@ -1282,30 +1290,42 @@ export async function startLocalServer(opts) {
|
|
|
1282
1290
|
}
|
|
1283
1291
|
projectSnapshot();
|
|
1284
1292
|
projectSnapshots.assertCurrent(runProjectSnapshot.snapshotId);
|
|
1285
|
-
const
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
name: binding.timeDimension,
|
|
1290
|
-
granularity: binding.granularity,
|
|
1291
|
-
},
|
|
1292
|
-
orderBy: [{ name: binding.outputField, direction: 'desc' }],
|
|
1293
|
-
limit: 1,
|
|
1294
|
-
}, {
|
|
1293
|
+
const plannedAdapter = await resolvePlannedSemanticAdapter(projectRoot, undefined);
|
|
1294
|
+
const execution = await executeTargetBoundSemanticQuery({
|
|
1295
|
+
executor,
|
|
1296
|
+
connection: semanticConnection,
|
|
1295
1297
|
projectRoot,
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1298
|
+
plannedAdapter,
|
|
1299
|
+
metricFlow: plannedAdapter === 'metricflow-cli'
|
|
1300
|
+
? resolveMetricFlowTargetMetadata(projectRoot, projectConfig)
|
|
1301
|
+
: undefined,
|
|
1302
|
+
compile: () => compileSemanticRuntimeQuery({
|
|
1303
|
+
metrics: [binding.metric],
|
|
1304
|
+
dimensions: [],
|
|
1305
|
+
timeDimension: {
|
|
1306
|
+
name: binding.timeDimension,
|
|
1307
|
+
granularity: binding.granularity,
|
|
1308
|
+
},
|
|
1309
|
+
orderBy: [{ name: binding.outputField, direction: 'desc' }],
|
|
1310
|
+
limit: 1,
|
|
1311
|
+
engine: plannedAdapter,
|
|
1312
|
+
}, {
|
|
1313
|
+
projectRoot,
|
|
1314
|
+
projectConfig,
|
|
1315
|
+
detectedProvider: semanticDetectedProvider,
|
|
1316
|
+
semanticLayer: semanticLayer,
|
|
1317
|
+
driver: semanticDriver,
|
|
1318
|
+
tableMapping: semanticTableMapping,
|
|
1319
|
+
}),
|
|
1320
|
+
prepareSql: (sql) => prepareLocalExecution(sql, semanticConnection, projectRoot, projectConfig),
|
|
1321
|
+
rowBound: 1,
|
|
1301
1322
|
});
|
|
1302
|
-
if (!
|
|
1323
|
+
if (!execution) {
|
|
1303
1324
|
throw Object.assign(new Error('The authorized semantic freshness query could not be compiled.'), {
|
|
1304
1325
|
code: 'COMPILATION_FAILED',
|
|
1305
1326
|
});
|
|
1306
1327
|
}
|
|
1307
|
-
const
|
|
1308
|
-
const result = await executor.executeQuery(prepared.sql, [], runtimeVariables({}), prepared.connection);
|
|
1328
|
+
const result = execution.result;
|
|
1309
1329
|
projectSnapshot();
|
|
1310
1330
|
projectSnapshots.assertCurrent(runProjectSnapshot.snapshotId);
|
|
1311
1331
|
return {
|
|
@@ -1325,9 +1345,27 @@ export async function startLocalServer(opts) {
|
|
|
1325
1345
|
...selection,
|
|
1326
1346
|
dimensions: selection.dimensions ?? [],
|
|
1327
1347
|
};
|
|
1328
|
-
const
|
|
1348
|
+
const requestedSemanticQuery = requestedPath
|
|
1329
1349
|
? applySemanticPathSelection(semanticRequest, requestedPath.authoringReference, requestedPath.entityPath)
|
|
1330
|
-
: semanticRequest
|
|
1350
|
+
: semanticRequest;
|
|
1351
|
+
const plannedAdapter = await resolvePlannedSemanticAdapter(projectRoot, requestedSemanticQuery.engine);
|
|
1352
|
+
const executionTarget = semanticConnection
|
|
1353
|
+
? await observeWarehouseTargetIdentity(executor, semanticConnection)
|
|
1354
|
+
: undefined;
|
|
1355
|
+
const targetBinding = executionTarget
|
|
1356
|
+
? buildSemanticTargetBinding({
|
|
1357
|
+
projectRoot,
|
|
1358
|
+
adapterId: plannedAdapter,
|
|
1359
|
+
executionTarget,
|
|
1360
|
+
metricFlow: plannedAdapter === 'metricflow-cli'
|
|
1361
|
+
? resolveMetricFlowTargetMetadata(projectRoot, projectConfig)
|
|
1362
|
+
: undefined,
|
|
1363
|
+
})
|
|
1364
|
+
: undefined;
|
|
1365
|
+
const compiled = await compileSemanticRuntimeQuery({
|
|
1366
|
+
...requestedSemanticQuery,
|
|
1367
|
+
engine: plannedAdapter,
|
|
1368
|
+
}, {
|
|
1331
1369
|
projectRoot,
|
|
1332
1370
|
projectConfig,
|
|
1333
1371
|
detectedProvider: semanticDetectedProvider,
|
|
@@ -1341,6 +1379,7 @@ export async function startLocalServer(opts) {
|
|
|
1341
1379
|
: projectConfig.dbt?.projectDir;
|
|
1342
1380
|
throw new SemanticRuntimeRequiredError(await explainMissingSemanticRuntime(projectRoot, dbtProjectPath));
|
|
1343
1381
|
}
|
|
1382
|
+
compiledSemanticQueries.set(executionFingerprint(compiled.sql), compiled);
|
|
1344
1383
|
return {
|
|
1345
1384
|
sql: compiled.sql,
|
|
1346
1385
|
engine: compiled.engine,
|
|
@@ -1352,7 +1391,10 @@ export async function startLocalServer(opts) {
|
|
|
1352
1391
|
? { timeDimension: compiled.effectiveRequest.timeDimension }
|
|
1353
1392
|
: {}),
|
|
1354
1393
|
},
|
|
1355
|
-
trace:
|
|
1394
|
+
trace: {
|
|
1395
|
+
...compiled.semanticTrace,
|
|
1396
|
+
...(targetBinding ? { targetBinding } : {}),
|
|
1397
|
+
},
|
|
1356
1398
|
};
|
|
1357
1399
|
},
|
|
1358
1400
|
} : {}),
|
|
@@ -2778,7 +2820,10 @@ export async function startLocalServer(opts) {
|
|
|
2778
2820
|
throw new Error(`I need values for: ${invocation.unresolvedParameters.join(', ')}.`);
|
|
2779
2821
|
}
|
|
2780
2822
|
const activeConnection = requireActiveConnection();
|
|
2781
|
-
const
|
|
2823
|
+
const precompiledSemanticQuery = Boolean(extractBlockStudioSql(source));
|
|
2824
|
+
const tableMapping = !precompiledSemanticQuery
|
|
2825
|
+
? await resolveSemanticTableMapping(executor, activeConnection, semanticLayer)
|
|
2826
|
+
: undefined;
|
|
2782
2827
|
const semanticCompose = semanticLayer
|
|
2783
2828
|
? await composeSemanticBlockSqlForRuntime(source, semanticLayer, {
|
|
2784
2829
|
driver: activeConnection.driver,
|
|
@@ -2807,7 +2852,24 @@ export async function startLocalServer(opts) {
|
|
|
2807
2852
|
const app = loadRuntimeApp(projectRoot, activePersonaAppId());
|
|
2808
2853
|
const sourceDomain = metadata.domain ?? source.match(/\bdomain\s*=\s*"([^"]+)"/i)?.[1];
|
|
2809
2854
|
assertAppAccess({ app, domain: sourceDomain ?? app?.domain, level: 'execute' });
|
|
2810
|
-
const
|
|
2855
|
+
const pinnedSemanticCompile = semanticCompose?.sql
|
|
2856
|
+
? compiledSemanticQueries.get(executionFingerprint(semanticCompose.sql))
|
|
2857
|
+
: undefined;
|
|
2858
|
+
const semanticExecution = pinnedSemanticCompile
|
|
2859
|
+
? await executeTargetBoundSemanticQuery({
|
|
2860
|
+
executor,
|
|
2861
|
+
connection: activeConnection,
|
|
2862
|
+
projectRoot,
|
|
2863
|
+
plannedAdapter: pinnedSemanticCompile.engine,
|
|
2864
|
+
metricFlow: pinnedSemanticCompile.engine === 'metricflow-cli'
|
|
2865
|
+
? resolveMetricFlowTargetMetadata(projectRoot, projectConfig)
|
|
2866
|
+
: undefined,
|
|
2867
|
+
compile: async () => pinnedSemanticCompile,
|
|
2868
|
+
prepareSql: () => ({ sql: executionSql, connection: prepared.connection }),
|
|
2869
|
+
rowBound: invocationInput?.rowLimit ?? pinnedSemanticCompile.effectiveRequest.limit,
|
|
2870
|
+
})
|
|
2871
|
+
: null;
|
|
2872
|
+
const rawResult = semanticExecution?.result ?? await executor.executeQuery(executionSql, plan?.sqlParams ?? [], runtimeVariables({ ...(plan?.variables ?? {}), ...invocation.values }), prepared.connection);
|
|
2811
2873
|
const normalized = normalizeQueryResult(rawResult);
|
|
2812
2874
|
const executionReceipt = createDqlArtifactExecutionReceipt(source, executionSql, invocation.values, normalized);
|
|
2813
2875
|
return {
|
|
@@ -2822,6 +2884,11 @@ export async function startLocalServer(opts) {
|
|
|
2822
2884
|
parameters: invocation.resolvedParameters,
|
|
2823
2885
|
auditId: invocation.auditId,
|
|
2824
2886
|
executionReceipt,
|
|
2887
|
+
...(semanticExecution ? {
|
|
2888
|
+
semanticExecutionReceipt: semanticExecution.executionReceipt,
|
|
2889
|
+
semanticTargetBinding: semanticExecution.targetBinding,
|
|
2890
|
+
semanticTrace: semanticExecution.semanticTrace,
|
|
2891
|
+
} : {}),
|
|
2825
2892
|
};
|
|
2826
2893
|
};
|
|
2827
2894
|
const executeCertifiedBlockByNameForAgent = async (blockName, invocationInput, requireCertified = false) => {
|
|
@@ -3010,14 +3077,10 @@ export async function startLocalServer(opts) {
|
|
|
3010
3077
|
const scanRuntimeSchema = async () => {
|
|
3011
3078
|
if (!connection)
|
|
3012
3079
|
return { ranked: [], snapshot: [] };
|
|
3013
|
-
const result = await executor.
|
|
3014
|
-
FROM information_schema.columns
|
|
3015
|
-
WHERE UPPER(table_schema) NOT IN ('INFORMATION_SCHEMA', 'PG_CATALOG')
|
|
3016
|
-
ORDER BY table_schema, table_name, ordinal_position
|
|
3017
|
-
LIMIT 2000`, [], runtimeVariables({}), connection);
|
|
3080
|
+
const result = await executor.executePositional(buildRuntimeSchemaSearchSql(question), [], connection, { maxRows: 600, maxBytes: 2 * 1024 * 1024, batchSize: 200, deadlineMs: 30_000 });
|
|
3018
3081
|
return {
|
|
3019
3082
|
ranked: buildAgentSchemaContext(question, result.rows),
|
|
3020
|
-
snapshot: buildAgentSchemaContext(question, result.rows, { includeUnscored: true, limit:
|
|
3083
|
+
snapshot: buildAgentSchemaContext(question, result.rows, { includeUnscored: true, limit: 100 }),
|
|
3021
3084
|
};
|
|
3022
3085
|
};
|
|
3023
3086
|
const catalogContext = await buildAgentSchemaContextFromCatalog(projectRoot, question, preparedContextPack).catch(() => []);
|
|
@@ -3039,7 +3102,7 @@ export async function startLocalServer(opts) {
|
|
|
3039
3102
|
const enriched = valueGrounding.mode === 'safe_automatic'
|
|
3040
3103
|
? await enrichAgentSchemaContextWithValueMatches(question, schemaContext.ranked, executor, connection, valueGrounding.searchSafeColumns)
|
|
3041
3104
|
: schemaContext.ranked;
|
|
3042
|
-
recordAgentRuntimeSchemaSnapshot(projectRoot, schemaContext.snapshot, '
|
|
3105
|
+
recordAgentRuntimeSchemaSnapshot(projectRoot, schemaContext.snapshot, 'question-scoped information_schema search');
|
|
3043
3106
|
return enriched;
|
|
3044
3107
|
}
|
|
3045
3108
|
catch {
|
|
@@ -7443,8 +7506,15 @@ export async function startLocalServer(opts) {
|
|
|
7443
7506
|
refreshedAt: dataset.refreshedAt,
|
|
7444
7507
|
trustState: dataset.trustState,
|
|
7445
7508
|
}));
|
|
7509
|
+
const schemaLimit = Math.min(500, Math.max(1, Number(url.searchParams.get('limit')) || 200));
|
|
7510
|
+
const schemaOffset = Math.max(0, Number(url.searchParams.get('offset')) || 0);
|
|
7511
|
+
const schemaSearch = (url.searchParams.get('q') ?? '').trim();
|
|
7446
7512
|
const { tables, columnsByPath } = connection
|
|
7447
|
-
? await introspectSchema(executor, connection
|
|
7513
|
+
? await introspectSchema(executor, connection, {
|
|
7514
|
+
limit: schemaLimit,
|
|
7515
|
+
offset: schemaOffset,
|
|
7516
|
+
search: schemaSearch,
|
|
7517
|
+
})
|
|
7448
7518
|
: { tables: [], columnsByPath: new Map() };
|
|
7449
7519
|
const dbTables = tables.map((t) => ({
|
|
7450
7520
|
name: t.path,
|
|
@@ -9342,7 +9412,9 @@ export async function startLocalServer(opts) {
|
|
|
9342
9412
|
try {
|
|
9343
9413
|
const body = await readJSON(req);
|
|
9344
9414
|
const result = await testSemanticRuntimeDraft(projectRoot, body);
|
|
9345
|
-
const
|
|
9415
|
+
const targetConnection = requireActiveConnection(connection);
|
|
9416
|
+
const executionTarget = await observeWarehouseTargetIdentity(executor, targetConnection);
|
|
9417
|
+
const settings = saveTestedSemanticRuntimeSettings(projectRoot, body, result, executionTarget);
|
|
9346
9418
|
const runtime = await getSemanticRuntimeStatus(projectRoot);
|
|
9347
9419
|
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
9348
9420
|
res.end(serializeJSON({ ok: true, ...settings, runtime }));
|
|
@@ -10411,25 +10483,41 @@ export async function startLocalServer(opts) {
|
|
|
10411
10483
|
const { metrics = [], dimensions = [], filters = [], limit, timeDimension, orderBy, savedQuery, engine } = body;
|
|
10412
10484
|
// Resolve which connection to use — request can override default
|
|
10413
10485
|
const targetConnection = requireActiveConnection(isConnectionConfig(body.connection) ? body.connection : connection);
|
|
10414
|
-
const
|
|
10415
|
-
const
|
|
10416
|
-
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
|
|
10421
|
-
timeDimension,
|
|
10422
|
-
orderBy,
|
|
10423
|
-
savedQuery,
|
|
10424
|
-
engine,
|
|
10425
|
-
}, semanticLayer, {
|
|
10486
|
+
const plannedAdapter = await resolvePlannedSemanticAdapter(projectRoot, engine);
|
|
10487
|
+
const metricFlow = plannedAdapter === 'metricflow-cli'
|
|
10488
|
+
? resolveMetricFlowTargetMetadata(projectRoot, projectConfig)
|
|
10489
|
+
: undefined;
|
|
10490
|
+
const execution = await executeTargetBoundSemanticQuery({
|
|
10491
|
+
executor,
|
|
10492
|
+
connection: targetConnection,
|
|
10426
10493
|
projectRoot,
|
|
10427
|
-
|
|
10428
|
-
|
|
10429
|
-
|
|
10430
|
-
|
|
10494
|
+
plannedAdapter,
|
|
10495
|
+
metricFlow,
|
|
10496
|
+
compile: async () => {
|
|
10497
|
+
const tableMapping = plannedAdapter === 'native'
|
|
10498
|
+
? await resolveSemanticTableMapping(executor, targetConnection, semanticLayer)
|
|
10499
|
+
: undefined;
|
|
10500
|
+
return composeRuntimeSemanticQuery({
|
|
10501
|
+
metrics,
|
|
10502
|
+
dimensions,
|
|
10503
|
+
filters,
|
|
10504
|
+
limit,
|
|
10505
|
+
timeDimension,
|
|
10506
|
+
orderBy,
|
|
10507
|
+
savedQuery,
|
|
10508
|
+
engine: plannedAdapter,
|
|
10509
|
+
}, semanticLayer, {
|
|
10510
|
+
projectRoot,
|
|
10511
|
+
projectConfig,
|
|
10512
|
+
detectedProvider: semanticDetectedProvider,
|
|
10513
|
+
driver: targetConnection.driver,
|
|
10514
|
+
tableMapping,
|
|
10515
|
+
});
|
|
10516
|
+
},
|
|
10517
|
+
prepareSql: (sql) => prepareLocalExecution(sql, targetConnection, projectRoot, projectConfig),
|
|
10518
|
+
rowBound: limit,
|
|
10431
10519
|
});
|
|
10432
|
-
if (!
|
|
10520
|
+
if (!execution) {
|
|
10433
10521
|
const provider = semanticConfig?.provider ?? semanticDetectedProvider ?? 'dql';
|
|
10434
10522
|
const semanticRuntime = await getSemanticRuntimeStatus(projectRoot, { probeConfiguredCloud: true });
|
|
10435
10523
|
const blocked = metrics.map((metricName) => ({
|
|
@@ -10446,20 +10534,20 @@ export async function startLocalServer(opts) {
|
|
|
10446
10534
|
}));
|
|
10447
10535
|
return;
|
|
10448
10536
|
}
|
|
10449
|
-
// Execute the composed SQL against the resolved connection
|
|
10450
|
-
const prepared = prepareLocalExecution(composed.sql, targetConnection, projectRoot, projectConfig);
|
|
10451
|
-
const result = await executor.executeQuery(prepared.sql, [], {}, prepared.connection);
|
|
10452
10537
|
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
10453
10538
|
res.end(serializeJSON({
|
|
10454
|
-
sql:
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10539
|
+
sql: execution.compiled.sql,
|
|
10540
|
+
executedSql: execution.preparedSql,
|
|
10541
|
+
tables: execution.compiled.tables,
|
|
10542
|
+
joins: execution.compiled.joins,
|
|
10543
|
+
engine: execution.compiled.engine,
|
|
10544
|
+
effectiveRequest: execution.compiled.effectiveRequest,
|
|
10545
|
+
runtimeRequest: execution.compiled.runtimeRequest,
|
|
10546
|
+
semanticTrace: execution.semanticTrace,
|
|
10547
|
+
warnings: execution.compiled.warnings,
|
|
10548
|
+
targetBinding: execution.targetBinding,
|
|
10549
|
+
executionReceipt: execution.executionReceipt,
|
|
10550
|
+
result: normalizeQueryResult(execution.result),
|
|
10463
10551
|
}));
|
|
10464
10552
|
}
|
|
10465
10553
|
catch (error) {
|
|
@@ -10468,13 +10556,13 @@ export async function startLocalServer(opts) {
|
|
|
10468
10556
|
res.end(serializeJSON({ error: error.message, code: 'unauthorized' }));
|
|
10469
10557
|
return;
|
|
10470
10558
|
}
|
|
10471
|
-
const runtimeCode = semanticRuntimeErrorCode(error);
|
|
10472
|
-
const status = runtimeCode ? 400 : 500;
|
|
10559
|
+
const runtimeCode = semanticExecutionFailureCode(error) ?? semanticRuntimeErrorCode(error);
|
|
10560
|
+
const status = runtimeCode === 'EXECUTION_TARGET_MISMATCH' ? 409 : runtimeCode ? 400 : 500;
|
|
10473
10561
|
res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
10474
10562
|
res.end(serializeJSON({
|
|
10475
10563
|
error: error instanceof Error ? error.message : String(error),
|
|
10476
10564
|
code: runtimeCode,
|
|
10477
|
-
details: semanticRuntimeErrorDetails(error),
|
|
10565
|
+
details: semanticExecutionFailureDetails(error) ?? semanticRuntimeErrorDetails(error),
|
|
10478
10566
|
hint: runtimeCode === 'SEMANTIC_RUNTIME_REQUIRED'
|
|
10479
10567
|
? 'Configure dbt Cloud Semantic Layer in Project & dbt settings, or install a compatible local MetricFlow runtime.'
|
|
10480
10568
|
: undefined,
|
|
@@ -10492,25 +10580,41 @@ export async function startLocalServer(opts) {
|
|
|
10492
10580
|
const body = await readJSON(req);
|
|
10493
10581
|
const { metrics = [], dimensions = [], filters = [], limit, timeDimension, orderBy, savedQuery, engine } = body;
|
|
10494
10582
|
const targetConnection = requireActiveConnection(isConnectionConfig(body.connection) ? body.connection : connection);
|
|
10495
|
-
const
|
|
10496
|
-
const
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
timeDimension,
|
|
10503
|
-
orderBy,
|
|
10504
|
-
savedQuery,
|
|
10505
|
-
engine,
|
|
10506
|
-
}, semanticLayer, {
|
|
10583
|
+
const plannedAdapter = await resolvePlannedSemanticAdapter(projectRoot, engine);
|
|
10584
|
+
const metricFlow = plannedAdapter === 'metricflow-cli'
|
|
10585
|
+
? resolveMetricFlowTargetMetadata(projectRoot, projectConfig)
|
|
10586
|
+
: undefined;
|
|
10587
|
+
const execution = await executeTargetBoundSemanticQuery({
|
|
10588
|
+
executor,
|
|
10589
|
+
connection: targetConnection,
|
|
10507
10590
|
projectRoot,
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10591
|
+
plannedAdapter,
|
|
10592
|
+
metricFlow,
|
|
10593
|
+
compile: async () => {
|
|
10594
|
+
const tableMapping = plannedAdapter === 'native'
|
|
10595
|
+
? await resolveSemanticTableMapping(executor, targetConnection, semanticLayer)
|
|
10596
|
+
: undefined;
|
|
10597
|
+
return composeRuntimeSemanticQuery({
|
|
10598
|
+
metrics,
|
|
10599
|
+
dimensions,
|
|
10600
|
+
filters,
|
|
10601
|
+
limit,
|
|
10602
|
+
timeDimension,
|
|
10603
|
+
orderBy,
|
|
10604
|
+
savedQuery,
|
|
10605
|
+
engine: plannedAdapter,
|
|
10606
|
+
}, semanticLayer, {
|
|
10607
|
+
projectRoot,
|
|
10608
|
+
projectConfig,
|
|
10609
|
+
detectedProvider: semanticDetectedProvider,
|
|
10610
|
+
driver: targetConnection.driver,
|
|
10611
|
+
tableMapping,
|
|
10612
|
+
});
|
|
10613
|
+
},
|
|
10614
|
+
prepareSql: (sql) => prepareLocalExecution(sql, targetConnection, projectRoot, projectConfig),
|
|
10615
|
+
rowBound: limit,
|
|
10512
10616
|
});
|
|
10513
|
-
if (!
|
|
10617
|
+
if (!execution) {
|
|
10514
10618
|
const provider = semanticConfig?.provider ?? semanticDetectedProvider ?? 'dql';
|
|
10515
10619
|
const semanticRuntime = await getSemanticRuntimeStatus(projectRoot, { probeConfiguredCloud: true });
|
|
10516
10620
|
const blocked = metrics.map((metricName) => ({
|
|
@@ -10527,29 +10631,30 @@ export async function startLocalServer(opts) {
|
|
|
10527
10631
|
}));
|
|
10528
10632
|
return;
|
|
10529
10633
|
}
|
|
10530
|
-
const prepared = prepareLocalExecution(composed.sql, targetConnection, projectRoot, projectConfig);
|
|
10531
|
-
const result = await executor.executeQuery(prepared.sql, [], {}, prepared.connection);
|
|
10532
10634
|
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
10533
10635
|
res.end(serializeJSON({
|
|
10534
|
-
sql:
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10636
|
+
sql: execution.compiled.sql,
|
|
10637
|
+
executedSql: execution.preparedSql,
|
|
10638
|
+
joins: execution.compiled.joins,
|
|
10639
|
+
tables: execution.compiled.tables,
|
|
10640
|
+
engine: execution.compiled.engine,
|
|
10641
|
+
effectiveRequest: execution.compiled.effectiveRequest,
|
|
10642
|
+
runtimeRequest: execution.compiled.runtimeRequest,
|
|
10643
|
+
semanticTrace: execution.semanticTrace,
|
|
10644
|
+
warnings: execution.compiled.warnings,
|
|
10645
|
+
targetBinding: execution.targetBinding,
|
|
10646
|
+
executionReceipt: execution.executionReceipt,
|
|
10647
|
+
result: normalizeQueryResult(execution.result),
|
|
10543
10648
|
}));
|
|
10544
10649
|
}
|
|
10545
10650
|
catch (error) {
|
|
10546
|
-
const runtimeCode = semanticRuntimeErrorCode(error);
|
|
10547
|
-
const status = runtimeCode ? 400 : 500;
|
|
10651
|
+
const runtimeCode = semanticExecutionFailureCode(error) ?? semanticRuntimeErrorCode(error);
|
|
10652
|
+
const status = runtimeCode === 'EXECUTION_TARGET_MISMATCH' ? 409 : runtimeCode ? 400 : 500;
|
|
10548
10653
|
res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
10549
10654
|
res.end(serializeJSON({
|
|
10550
10655
|
error: error instanceof Error ? error.message : String(error),
|
|
10551
10656
|
code: runtimeCode,
|
|
10552
|
-
details: semanticRuntimeErrorDetails(error),
|
|
10657
|
+
details: semanticExecutionFailureDetails(error) ?? semanticRuntimeErrorDetails(error),
|
|
10553
10658
|
hint: runtimeCode === 'SEMANTIC_RUNTIME_REQUIRED'
|
|
10554
10659
|
? 'Configure dbt Cloud Semantic Layer in Project & dbt settings, or install a compatible local MetricFlow runtime.'
|
|
10555
10660
|
: undefined,
|
|
@@ -11108,7 +11213,24 @@ export async function startLocalServer(opts) {
|
|
|
11108
11213
|
const prepared = prepareLocalExecution(executableSql, cellConnection, projectRoot, projectConfig);
|
|
11109
11214
|
const app = loadRuntimeApp(projectRoot, typeof body.appId === 'string' ? body.appId : activePersonaAppId());
|
|
11110
11215
|
assertAppAccess({ app, domain: resolved.domain ?? app?.domain, level: 'execute' });
|
|
11111
|
-
const
|
|
11216
|
+
const semanticExecution = semanticCompose?.compiled
|
|
11217
|
+
? await executeTargetBoundSemanticQuery({
|
|
11218
|
+
executor,
|
|
11219
|
+
connection: cellConnection,
|
|
11220
|
+
projectRoot,
|
|
11221
|
+
plannedAdapter: semanticCompose.compiled.engine,
|
|
11222
|
+
metricFlow: semanticCompose.compiled.engine === 'metricflow-cli'
|
|
11223
|
+
? resolveMetricFlowTargetMetadata(projectRoot, projectConfig)
|
|
11224
|
+
: undefined,
|
|
11225
|
+
// Compilation already produced the exact pinned adapter result
|
|
11226
|
+
// used by the plan. The gateway validates target identity before
|
|
11227
|
+
// accepting that result for preflight and execution.
|
|
11228
|
+
compile: async () => semanticCompose.compiled,
|
|
11229
|
+
prepareSql: () => ({ sql: prepared.sql, connection: prepared.connection }),
|
|
11230
|
+
rowBound: semanticCompose.compiled.effectiveRequest.limit,
|
|
11231
|
+
})
|
|
11232
|
+
: null;
|
|
11233
|
+
const rawResult = semanticExecution?.result ?? await executor.executeQuery(prepared.sql, plan?.sqlParams ?? [], runtimeVariables({ ...(plan?.variables ?? {}), ...(invocation?.values ?? {}) }), prepared.connection);
|
|
11112
11234
|
const normalized = normalizeQueryResult(rawResult);
|
|
11113
11235
|
// Enforce the block's declared invariants against the result set. This
|
|
11114
11236
|
// is additive: blocks without invariants produce `null` and the
|
|
@@ -11146,6 +11268,12 @@ export async function startLocalServer(opts) {
|
|
|
11146
11268
|
chartConfig: plan?.chartConfig,
|
|
11147
11269
|
tests: plan?.tests,
|
|
11148
11270
|
result: normalized,
|
|
11271
|
+
...(semanticExecution ? {
|
|
11272
|
+
semanticTrace: semanticExecution.semanticTrace,
|
|
11273
|
+
targetBinding: semanticExecution.targetBinding,
|
|
11274
|
+
executionReceipt: semanticExecution.executionReceipt,
|
|
11275
|
+
executedSql: semanticExecution.preparedSql,
|
|
11276
|
+
} : {}),
|
|
11149
11277
|
...(invocation ? {
|
|
11150
11278
|
invocation: {
|
|
11151
11279
|
resolvedParameters: invocation.resolvedParameters,
|
|
@@ -11178,8 +11306,13 @@ export async function startLocalServer(opts) {
|
|
|
11178
11306
|
error: error instanceof Error ? error.message : String(error),
|
|
11179
11307
|
});
|
|
11180
11308
|
}
|
|
11181
|
-
|
|
11182
|
-
res.
|
|
11309
|
+
const code = semanticExecutionFailureCode(error) ?? semanticRuntimeErrorCode(error);
|
|
11310
|
+
res.writeHead(code === 'EXECUTION_TARGET_MISMATCH' ? 409 : 500, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
11311
|
+
res.end(serializeJSON({
|
|
11312
|
+
error: error instanceof Error ? error.message : String(error),
|
|
11313
|
+
code,
|
|
11314
|
+
details: semanticExecutionFailureDetails(error) ?? semanticRuntimeErrorDetails(error),
|
|
11315
|
+
}));
|
|
11183
11316
|
}
|
|
11184
11317
|
return;
|
|
11185
11318
|
}
|
|
@@ -14431,15 +14564,25 @@ function readUserPrefs(userPrefsPath) {
|
|
|
14431
14564
|
function writeUserPrefs(userPrefsPath, prefs) {
|
|
14432
14565
|
writeFileSync(userPrefsPath, JSON.stringify(prefs, null, 2) + '\n', 'utf-8');
|
|
14433
14566
|
}
|
|
14434
|
-
async function introspectSchema(executor, connection) {
|
|
14567
|
+
async function introspectSchema(executor, connection, options = {}) {
|
|
14435
14568
|
let tables = [];
|
|
14436
|
-
|
|
14437
|
-
|
|
14569
|
+
const columnsByPath = new Map();
|
|
14570
|
+
const limit = Math.min(1_000, Math.max(1, Math.floor(options.limit ?? 200)));
|
|
14571
|
+
const offset = Math.max(0, Math.floor(options.offset ?? 0));
|
|
14572
|
+
const escapedSearch = options.search?.trim().replace(/'/g, "''");
|
|
14573
|
+
const searchPredicate = escapedSearch
|
|
14574
|
+
? ` AND (LOWER(table_schema) LIKE LOWER('%${escapedSearch}%') OR LOWER(table_name) LIKE LOWER('%${escapedSearch}%'))`
|
|
14575
|
+
: '';
|
|
14576
|
+
// Runtime inventory is table-first and bounded. Columns are loaded only for
|
|
14577
|
+
// a selected table through /api/describe-table; constructing one account-wide
|
|
14578
|
+
// table+column tree is an enterprise-scale OOM risk (PERF-001 / CTX-005).
|
|
14438
14579
|
try {
|
|
14439
14580
|
const catalogRows = await executor.executeQuery(`SELECT table_schema, table_name, table_type
|
|
14440
14581
|
FROM information_schema.tables
|
|
14441
14582
|
WHERE UPPER(table_schema) NOT IN ('INFORMATION_SCHEMA', 'PG_CATALOG')
|
|
14442
|
-
|
|
14583
|
+
${searchPredicate}
|
|
14584
|
+
ORDER BY table_schema, table_name
|
|
14585
|
+
LIMIT ${limit} OFFSET ${offset}`, [], {}, connection);
|
|
14443
14586
|
tables = catalogRows.rows.map((row) => {
|
|
14444
14587
|
const schema = String(row['table_schema'] ?? row['TABLE_SCHEMA'] ?? 'default');
|
|
14445
14588
|
const name = String(row['table_name'] ?? row['TABLE_NAME'] ?? '');
|
|
@@ -14447,22 +14590,6 @@ async function introspectSchema(executor, connection) {
|
|
|
14447
14590
|
const path = schema ? `${schema}.${name}` : name;
|
|
14448
14591
|
return { schema, name, path, type };
|
|
14449
14592
|
});
|
|
14450
|
-
const columnRows = await executor.executeQuery(`SELECT table_schema, table_name, column_name, data_type
|
|
14451
|
-
FROM information_schema.columns
|
|
14452
|
-
WHERE UPPER(table_schema) NOT IN ('INFORMATION_SCHEMA', 'PG_CATALOG')
|
|
14453
|
-
ORDER BY table_schema, table_name, ordinal_position`, [], {}, connection);
|
|
14454
|
-
columnsByPath = columnRows.rows.reduce((map, row) => {
|
|
14455
|
-
const schema = String(row['table_schema'] ?? row['TABLE_SCHEMA'] ?? 'default');
|
|
14456
|
-
const tableName = String(row['table_name'] ?? row['TABLE_NAME'] ?? '');
|
|
14457
|
-
const path = schema ? `${schema}.${tableName}` : tableName;
|
|
14458
|
-
const next = map.get(path) ?? [];
|
|
14459
|
-
next.push({
|
|
14460
|
-
name: String(row['column_name'] ?? row['COLUMN_NAME'] ?? ''),
|
|
14461
|
-
type: String(row['data_type'] ?? row['DATA_TYPE'] ?? ''),
|
|
14462
|
-
});
|
|
14463
|
-
map.set(path, next);
|
|
14464
|
-
return map;
|
|
14465
|
-
}, new Map());
|
|
14466
14593
|
return { tables, columnsByPath };
|
|
14467
14594
|
}
|
|
14468
14595
|
catch {
|
|
@@ -14473,23 +14600,18 @@ async function introspectSchema(executor, connection) {
|
|
|
14473
14600
|
const connector = await executor.getConnector(connection);
|
|
14474
14601
|
if (typeof connector.listTables === 'function') {
|
|
14475
14602
|
const rawTables = await connector.listTables();
|
|
14476
|
-
|
|
14603
|
+
const normalizedSearch = options.search?.trim().toLowerCase();
|
|
14604
|
+
tables = rawTables
|
|
14605
|
+
.filter((table) => !normalizedSearch
|
|
14606
|
+
|| table.schema.toLowerCase().includes(normalizedSearch)
|
|
14607
|
+
|| table.name.toLowerCase().includes(normalizedSearch))
|
|
14608
|
+
.slice(offset, offset + limit)
|
|
14609
|
+
.map((t) => {
|
|
14477
14610
|
const schema = t.schema || 'default';
|
|
14478
14611
|
const path = t.schema ? `${t.schema}.${t.name}` : t.name;
|
|
14479
14612
|
return { schema, name: t.name, path, type: t.type };
|
|
14480
14613
|
});
|
|
14481
14614
|
}
|
|
14482
|
-
if (typeof connector.listColumns === 'function') {
|
|
14483
|
-
const rawColumns = await connector.listColumns();
|
|
14484
|
-
columnsByPath = rawColumns.reduce((map, col) => {
|
|
14485
|
-
const schema = col.schema || 'default';
|
|
14486
|
-
const path = schema ? `${schema}.${col.table}` : col.table;
|
|
14487
|
-
const next = map.get(path) ?? [];
|
|
14488
|
-
next.push({ name: col.name, type: col.dataType });
|
|
14489
|
-
map.set(path, next);
|
|
14490
|
-
return map;
|
|
14491
|
-
}, new Map());
|
|
14492
|
-
}
|
|
14493
14615
|
}
|
|
14494
14616
|
catch {
|
|
14495
14617
|
// Tier 3: tables only, no columns — already have what we have
|
|
@@ -14499,9 +14621,9 @@ async function introspectSchema(executor, connection) {
|
|
|
14499
14621
|
function buildDatabaseSchemaTree(projectRoot, executor, connection) {
|
|
14500
14622
|
return (async () => {
|
|
14501
14623
|
const dataFiles = scanDataFiles(projectRoot);
|
|
14502
|
-
const
|
|
14503
|
-
? await introspectSchema(executor, connection)
|
|
14504
|
-
:
|
|
14624
|
+
const dbTables = connection
|
|
14625
|
+
? (await introspectSchema(executor, connection, { limit: 1_000 })).tables
|
|
14626
|
+
: [];
|
|
14505
14627
|
const schemaMap = new Map();
|
|
14506
14628
|
for (const table of dbTables) {
|
|
14507
14629
|
const schemaName = table.schema || 'default';
|
|
@@ -14523,13 +14645,8 @@ function buildDatabaseSchemaTree(projectRoot, executor, connection) {
|
|
|
14523
14645
|
kind: 'table',
|
|
14524
14646
|
path: table.path,
|
|
14525
14647
|
type: table.type,
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
label: column.name,
|
|
14529
|
-
kind: 'column',
|
|
14530
|
-
path: table.path,
|
|
14531
|
-
type: column.type,
|
|
14532
|
-
})),
|
|
14648
|
+
// Warehouse columns are loaded lazily for the selected table.
|
|
14649
|
+
children: [],
|
|
14533
14650
|
})),
|
|
14534
14651
|
}));
|
|
14535
14652
|
// Eagerly resolve file columns via DuckDB DESCRIBE
|
|
@@ -14698,6 +14815,28 @@ function isDbtSemanticRuntime(projectConfig, detectedProvider, semanticLayer) {
|
|
|
14698
14815
|
return true;
|
|
14699
14816
|
return Boolean(semanticLayer?.listMetrics().some((metric) => metric.source?.provider === 'dbt'));
|
|
14700
14817
|
}
|
|
14818
|
+
async function resolvePlannedSemanticAdapter(projectRoot, requested) {
|
|
14819
|
+
if (requested === 'dbt-cloud')
|
|
14820
|
+
return 'dbt-cloud';
|
|
14821
|
+
if (requested === 'metricflow' || requested === 'metricflow-cli')
|
|
14822
|
+
return 'metricflow-cli';
|
|
14823
|
+
if (requested === 'native')
|
|
14824
|
+
return 'native';
|
|
14825
|
+
return (await getSemanticRuntimeStatus(projectRoot, { probeConfiguredCloud: true })).active;
|
|
14826
|
+
}
|
|
14827
|
+
function resolveMetricFlowTargetMetadata(projectRoot, projectConfig) {
|
|
14828
|
+
const candidates = discoverDbtProfileConnections(projectRoot, projectConfig)
|
|
14829
|
+
.filter((candidate) => candidate.missingFields.length === 0);
|
|
14830
|
+
const candidate = candidates.find((item) => !item.warnings.some((warning) => warning.startsWith('Not the default dbt target'))) ?? (candidates.length === 1 ? candidates[0] : undefined);
|
|
14831
|
+
if (!candidate)
|
|
14832
|
+
return undefined;
|
|
14833
|
+
return {
|
|
14834
|
+
expectedTarget: configuredWarehouseTargetIdentity(candidate.connection),
|
|
14835
|
+
profileName: candidate.profileName,
|
|
14836
|
+
targetName: candidate.targetName,
|
|
14837
|
+
profilesPath: candidate.path,
|
|
14838
|
+
};
|
|
14839
|
+
}
|
|
14701
14840
|
async function composeRuntimeSemanticQuery(request, semanticLayer, context) {
|
|
14702
14841
|
return compileSemanticRuntimeQuery(request, {
|
|
14703
14842
|
projectRoot: context.projectRoot,
|
|
@@ -14898,6 +15037,7 @@ async function composeSemanticBlockSqlForRuntime(source, semanticLayer, options)
|
|
|
14898
15037
|
// no longer true for this run.
|
|
14899
15038
|
diagnostics: native.diagnostics.filter((diagnostic) => diagnostic.code !== 'semantic_compose_failed'),
|
|
14900
15039
|
semanticRefs: native.semanticRefs,
|
|
15040
|
+
compiled,
|
|
14901
15041
|
};
|
|
14902
15042
|
}
|
|
14903
15043
|
catch (error) {
|
|
@@ -20573,6 +20713,33 @@ export function buildAgentSchemaContext(question, rows, options = {}) {
|
|
|
20573
20713
|
.slice(0, limit)
|
|
20574
20714
|
.map((entry) => entry.table);
|
|
20575
20715
|
}
|
|
20716
|
+
const RUNTIME_SCHEMA_SEARCH_STOPWORDS = new Set([
|
|
20717
|
+
'what', 'which', 'where', 'when', 'who', 'why', 'how', 'show', 'give', 'find',
|
|
20718
|
+
'from', 'with', 'without', 'this', 'that', 'these', 'those', 'current', 'today',
|
|
20719
|
+
'yesterday', 'last', 'year', 'month', 'week', 'day', 'top', 'bottom', 'their',
|
|
20720
|
+
'have', 'does', 'into', 'than', 'then', 'also', 'all', 'the', 'and', 'for',
|
|
20721
|
+
]);
|
|
20722
|
+
/**
|
|
20723
|
+
* Physical catalog evidence fallback. This is deliberately question-scoped and
|
|
20724
|
+
* result-bounded: dbt/DQL metadata remains the planning authority, while
|
|
20725
|
+
* information_schema confirms discoverable relations/columns in the selected
|
|
20726
|
+
* execution target. Tokens are reduced to safe identifier characters before
|
|
20727
|
+
* interpolation, so user text cannot become SQL syntax.
|
|
20728
|
+
*/
|
|
20729
|
+
export function buildRuntimeSchemaSearchSql(question) {
|
|
20730
|
+
const terms = Array.from(agentSchemaTokens(question))
|
|
20731
|
+
.map((term) => term.toLowerCase().replace(/[^a-z0-9_]/g, ''))
|
|
20732
|
+
.filter((term) => term.length >= 3 && !RUNTIME_SCHEMA_SEARCH_STOPWORDS.has(term))
|
|
20733
|
+
.slice(0, 8);
|
|
20734
|
+
const predicate = terms.length > 0
|
|
20735
|
+
? `\n AND (\n${terms.map((term) => ` LOWER(table_name) LIKE '%${term}%' OR LOWER(column_name) LIKE '%${term}%'`).join(' OR\n')}\n )`
|
|
20736
|
+
: '';
|
|
20737
|
+
return `SELECT table_schema, table_name, column_name, data_type
|
|
20738
|
+
FROM information_schema.columns
|
|
20739
|
+
WHERE UPPER(table_schema) NOT IN ('INFORMATION_SCHEMA', 'PG_CATALOG')${predicate}
|
|
20740
|
+
ORDER BY table_schema, table_name, ordinal_position
|
|
20741
|
+
LIMIT 600`;
|
|
20742
|
+
}
|
|
20576
20743
|
function mergeAgentSchemaContexts(...contexts) {
|
|
20577
20744
|
const byRelation = new Map();
|
|
20578
20745
|
for (const table of contexts.flat()) {
|