Skip to content

Commit baa55ac

Browse files
committed
feat(kernel): wire session-level query tags into KernelBackend.openSession
Ports the session-level query-tags wiring onto the post-#428 lib/kernel path (originally lib/sea/SeaBackend, before the SEA→kernel rename). openSession serializes request.queryTags into the reserved QUERY_TAGS session conf, which the kernel allowlists (SESSION_CONF_ALLOWLIST) and forwards onto the SEA CreateSession session_confs — mirroring ThriftBackend.openSession. queryTags takes precedence over an explicit configuration.QUERY_TAGS. Verified end-to-end against a live warehouse: the tag lands in system.query.history.query_tags. Co-authored-by: Isaac Signed-off-by: Madhavendra Rathore <madhavendra.rathore@databricks.com>
1 parent 26be3be commit baa55ac

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

lib/kernel/KernelBackend.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { ConnectionOptions, OpenSessionRequest } from '../contracts/IDBSQLClient
1919
import { InternalConnectionOptions } from '../contracts/InternalConnectionOptions';
2020
import { LogLevel } from '../contracts/IDBSQLLogger';
2121
import HiveDriverError from '../errors/HiveDriverError';
22+
import { serializeQueryTags } from '../utils';
2223
import { getKernelNative, KernelNativeBinding, KernelConnection } from './KernelNativeLoader';
2324
import { decodeNapiKernelError } from './KernelErrorMapping';
2425
import { buildKernelConnectionOptions, buildKernelRetryOptions, KernelNativeConnectionOptions } from './KernelAuth';
@@ -145,6 +146,20 @@ export default class KernelBackend implements IBackend {
145146
if (request.configuration !== undefined) {
146147
sessionOptions.sessionConf = { ...request.configuration };
147148
}
149+
// Session-level query tags: serialize into the reserved `QUERY_TAGS`
150+
// session conf. The kernel allowlists `QUERY_TAGS` (SESSION_CONF_ALLOWLIST)
151+
// and forwards it onto the SEA `CreateSession` `session_confs`, mirroring
152+
// the Thrift backend's `ThriftBackend.openSession`. Runs after the
153+
// `configuration` merge so `queryTags` takes precedence over an explicit
154+
// `configuration.QUERY_TAGS`, matching the documented contract.
155+
if (request.queryTags !== undefined) {
156+
const serialized = serializeQueryTags(request.queryTags);
157+
if (serialized) {
158+
sessionOptions.sessionConf = { ...(sessionOptions.sessionConf ?? {}), QUERY_TAGS: serialized };
159+
} else if (sessionOptions.sessionConf) {
160+
delete sessionOptions.sessionConf.QUERY_TAGS;
161+
}
162+
}
148163

149164
let nativeConnection: KernelConnection;
150165
try {

tests/unit/kernel/execution.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,36 @@ describe('KernelBackend', () => {
551551
});
552552
});
553553

554+
it('openSession() serializes session-level queryTags into sessionConf.QUERY_TAGS', async () => {
555+
const connection = new FakeNativeConnection();
556+
const binding = makeBinding(connection);
557+
const backend = new KernelBackend({ context: makeContext(), nativeBinding: binding });
558+
await backend.connect({ host: 'h', path: '/p', token: 't' } as ConnectionOptions);
559+
560+
await backend.openSession({ queryTags: { team: 'eng', env: 'prod' } });
561+
562+
// Session-level tags land in the reserved QUERY_TAGS session conf (the
563+
// kernel allowlists it → SEA CreateSession session_confs), mirroring Thrift.
564+
const conf = (binding.openSessionStub.firstCall.args[0] as { sessionConf?: Record<string, string> }).sessionConf;
565+
expect(conf?.QUERY_TAGS).to.be.a('string');
566+
expect(conf?.QUERY_TAGS).to.contain('team:eng').and.to.contain('env:prod');
567+
});
568+
569+
it('openSession() queryTags takes precedence over an explicit configuration.QUERY_TAGS', async () => {
570+
const connection = new FakeNativeConnection();
571+
const binding = makeBinding(connection);
572+
const backend = new KernelBackend({ context: makeContext(), nativeBinding: binding });
573+
await backend.connect({ host: 'h', path: '/p', token: 't' } as ConnectionOptions);
574+
575+
await backend.openSession({
576+
configuration: { QUERY_TAGS: 'manual-raw-value' },
577+
queryTags: { team: 'eng' },
578+
});
579+
580+
const conf = (binding.openSessionStub.firstCall.args[0] as { sessionConf?: Record<string, string> }).sessionConf;
581+
expect(conf?.QUERY_TAGS).to.contain('team:eng').and.to.not.equal('manual-raw-value');
582+
});
583+
554584
it('openSession() returns a KernelSessionBackend wrapping the napi Connection', async () => {
555585
const connection = new FakeNativeConnection();
556586
const binding = makeBinding(connection);

0 commit comments

Comments
 (0)