Skip to content

Commit 47e601a

Browse files
committed
feat(thrift): per-statement metricViewMetadata knob on ExecuteStatementOptions
Add `metricViewMetadata?: boolean` to `ExecuteStatementOptions`. When true, the Thrift backend forwards `spark.databricks.optimizer.enableMetricViewMetadata=true` via the request `confOverlay`, alongside any `query_tags` already serialized there. The option is per-statement only and does not persist across queries. The SEA backend will route the same key through napi `statementConf` once the kernel statement-options surface lands; until then the option is honored only on Thrift. Documented in the public option JSDoc so users do not silently lose the conf on SEA. Unit tests assert the option appears in the outgoing `TExecuteStatementReq` when set, is omitted when unset or `false`, and coexists with `queryTags` in the same `confOverlay`. Audit refs: rows 1.17 and 2.18 of sea-workflow/audits/2026-05-28-cross-driver-audit.md (F12 in the PR #347 audit). Co-authored-by: Isaac Signed-off-by: Madhavendra Rathore <madhavendra.rathore@databricks.com>
1 parent e200a1b commit 47e601a

3 files changed

Lines changed: 76 additions & 0 deletions

File tree

lib/DBSQLSession.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,13 @@ export default class DBSQLSession implements IDBSQLSession {
236236
request.confOverlay = { ...request.confOverlay, query_tags: serializedQueryTags };
237237
}
238238

239+
if (options.metricViewMetadata === true) {
240+
request.confOverlay = {
241+
...request.confOverlay,
242+
'spark.databricks.optimizer.enableMetricViewMetadata': 'true',
243+
};
244+
}
245+
239246
if (ProtocolVersion.supportsCloudFetch(this.serverProtocolVersion)) {
240247
request.canDownloadResult = options.useCloudFetch ?? clientConfig.useCloudFetch;
241248
}

lib/contracts/IDBSQLSession.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ export type ExecuteStatementOptions = {
2727
* These tags apply only to this statement and do not persist across queries.
2828
*/
2929
queryTags?: Record<string, string | null | undefined>;
30+
/**
31+
* Enable metric-view metadata expansion for this statement. When `true`, the
32+
* Spark conf `spark.databricks.optimizer.enableMetricViewMetadata=true` is
33+
* forwarded via the Thrift `confOverlay`. Applies to a single statement only;
34+
* does not persist across queries.
35+
*
36+
* Equivalent SEA wiring will route the same key through napi `statementConf`
37+
* once the kernel statement-options surface lands — until then this knob is
38+
* honored only on the Thrift backend.
39+
*/
40+
metricViewMetadata?: boolean;
3041
};
3142

3243
export type TypeInfoRequest = {

tests/unit/DBSQLSession.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,64 @@ describe('DBSQLSession', () => {
297297
});
298298
});
299299

300+
describe('executeStatement with metricViewMetadata', () => {
301+
const metricViewConfKey = 'spark.databricks.optimizer.enableMetricViewMetadata';
302+
303+
it('should forward the metric-view conf via confOverlay when metricViewMetadata is true', async () => {
304+
const context = new ClientContextStub();
305+
const driver = sinon.spy(context.driver);
306+
const session = new DBSQLSession({ handle: sessionHandleStub, context });
307+
308+
await session.executeStatement('SELECT * FROM my_metric_view', { metricViewMetadata: true });
309+
310+
expect(driver.executeStatement.callCount).to.eq(1);
311+
const req = driver.executeStatement.firstCall.args[0];
312+
expect(req.confOverlay).to.deep.include({ [metricViewConfKey]: 'true' });
313+
});
314+
315+
it('should not set the metric-view conf when metricViewMetadata is omitted', async () => {
316+
const context = new ClientContextStub();
317+
const driver = sinon.spy(context.driver);
318+
const session = new DBSQLSession({ handle: sessionHandleStub, context });
319+
320+
await session.executeStatement('SELECT 1');
321+
322+
expect(driver.executeStatement.callCount).to.eq(1);
323+
const req = driver.executeStatement.firstCall.args[0];
324+
expect(req.confOverlay?.[metricViewConfKey]).to.be.undefined;
325+
});
326+
327+
it('should not set the metric-view conf when metricViewMetadata is false', async () => {
328+
const context = new ClientContextStub();
329+
const driver = sinon.spy(context.driver);
330+
const session = new DBSQLSession({ handle: sessionHandleStub, context });
331+
332+
await session.executeStatement('SELECT 1', { metricViewMetadata: false });
333+
334+
expect(driver.executeStatement.callCount).to.eq(1);
335+
const req = driver.executeStatement.firstCall.args[0];
336+
expect(req.confOverlay?.[metricViewConfKey]).to.be.undefined;
337+
});
338+
339+
it('should coexist with queryTags in the same confOverlay', async () => {
340+
const context = new ClientContextStub();
341+
const driver = sinon.spy(context.driver);
342+
const session = new DBSQLSession({ handle: sessionHandleStub, context });
343+
344+
await session.executeStatement('SELECT 1', {
345+
metricViewMetadata: true,
346+
queryTags: { team: 'eng' },
347+
});
348+
349+
expect(driver.executeStatement.callCount).to.eq(1);
350+
const req = driver.executeStatement.firstCall.args[0];
351+
expect(req.confOverlay).to.deep.include({
352+
[metricViewConfKey]: 'true',
353+
query_tags: 'team:eng',
354+
});
355+
});
356+
});
357+
300358
describe('getTypeInfo', () => {
301359
it('should run operation', async () => {
302360
const session = new DBSQLSession({ handle: sessionHandleStub, context: new ClientContextStub() });

0 commit comments

Comments
 (0)