From e669a3f83d0f49b3c417fcb847490de4b553ed16 Mon Sep 17 00:00:00 2001 From: Vu Anh Phung Date: Tue, 29 Sep 2026 23:02:04 +0000 Subject: [PATCH] Validate required getFunctions functionName Signed-off-by: Vu Anh Phung --- lib/DBSQLSession.ts | 10 +++++++++- tests/unit/DBSQLSession.test.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/DBSQLSession.ts b/lib/DBSQLSession.ts index 1de9458d..18588ac3 100644 --- a/lib/DBSQLSession.ts +++ b/lib/DBSQLSession.ts @@ -22,6 +22,7 @@ import InfoValue from './dto/InfoValue'; import CloseableCollection from './utils/CloseableCollection'; import { LogLevel } from './contracts/IDBSQLLogger'; import HiveDriverError from './errors/HiveDriverError'; +import ParameterError from './errors/ParameterError'; import StagingError from './errors/StagingError'; import IClientContext from './contracts/IClientContext'; import ISessionBackend from './contracts/ISessionBackend'; @@ -293,7 +294,14 @@ export default class DBSQLSession implements IDBSQLSession { * @returns DBSQLOperation */ public async getFunctions(request: FunctionsRequest): Promise { - return this.wrapOperation(await this.runBackend(() => this.backend.getFunctions(request))); + return this.wrapOperation( + await this.runBackend(() => { + if (typeof request?.functionName !== 'string') { + throw new ParameterError('functionName must be a string'); + } + return this.backend.getFunctions(request); + }), + ); } public async getPrimaryKeys(request: PrimaryKeysRequest): Promise { diff --git a/tests/unit/DBSQLSession.test.ts b/tests/unit/DBSQLSession.test.ts index 51b27133..59c19813 100644 --- a/tests/unit/DBSQLSession.test.ts +++ b/tests/unit/DBSQLSession.test.ts @@ -5,6 +5,8 @@ import DBSQLSession, { numberToInt64 } from '../../lib/DBSQLSession'; import InfoValue from '../../lib/dto/InfoValue'; import Status from '../../lib/dto/Status'; import DBSQLOperation from '../../lib/DBSQLOperation'; +import ISessionBackend from '../../lib/contracts/ISessionBackend'; +import ParameterError from '../../lib/errors/ParameterError'; import { TSessionHandle, TProtocolVersion } from '../../thrift/TCLIService_types'; import ClientContextStub from './.stubs/ClientContextStub'; import { createSessionForTest } from './.stubs/createSessionForTest'; @@ -450,6 +452,28 @@ describe('DBSQLSession', () => { }); describe('getFunctions', () => { + it('rejects a missing or non-string functionName before calling the backend', async () => { + const getFunctions = sinon.stub(); + const session = new DBSQLSession({ + backend: { id: 'test', getFunctions } as unknown as ISessionBackend, + context: new ClientContextStub(), + }); + const invalidRequests = [undefined, null, {}, { functionName: null }, { functionName: 123 }]; + + await Promise.all( + invalidRequests.map(async (request) => { + try { + await session.getFunctions(request as unknown as Parameters[0]); + expect.fail('Expected getFunctions to reject an invalid functionName'); + } catch (error) { + expect(error).instanceOf(ParameterError); + expect((error as Error).message).equal('functionName must be a string'); + } + }), + ); + expect(getFunctions.called).false; + }); + it('should run operation', async () => { const session = createSessionForTest({ handle: sessionHandleStub, context: new ClientContextStub() }); const result = await session.getFunctions({ @@ -460,6 +484,12 @@ describe('DBSQLSession', () => { expect(result).instanceOf(DBSQLOperation); }); + it('accepts an empty functionName string', async () => { + const session = createSessionForTest({ handle: sessionHandleStub, context: new ClientContextStub() }); + const result = await session.getFunctions({ functionName: '' }); + expect(result).instanceOf(DBSQLOperation); + }); + it('should use direct results', async () => { const session = createSessionForTest({ handle: sessionHandleStub, context: new ClientContextStub() }); const result = await session.getFunctions({