diff --git a/src/connectors/__tests__/sqlserver.integration.test.ts b/src/connectors/__tests__/sqlserver.integration.test.ts index acbc260c..d534cfef 100644 --- a/src/connectors/__tests__/sqlserver.integration.test.ts +++ b/src/connectors/__tests__/sqlserver.integration.test.ts @@ -584,7 +584,7 @@ describe('SQL Server Connector Integration Tests', () => { expect(result.rows[0].value).toBe(1); expect(result.messages).toBeDefined(); expect(result.messages!.length).toBeGreaterThan(0); - expect(result.messages).toContain('hello from sql server'); + expect(result.messages!.some(msg => msg.text === 'hello from sql server')).toBe(true); }); it('should capture SET STATISTICS TIME output in messages', async () => { @@ -598,7 +598,7 @@ describe('SQL Server Connector Integration Tests', () => { expect(result.messages!.length).toBeGreaterThan(0); // STATISTICS TIME emits messages containing "CPU time" and "elapsed time" const hasTimingMessage = result.messages!.some( - msg => msg.includes('CPU time') || msg.includes('elapsed time') + msg => msg.text.includes('CPU time') || msg.text.includes('elapsed time') ); expect(hasTimingMessage).toBe(true); }); diff --git a/src/connectors/interface.ts b/src/connectors/interface.ts index c64feaab..48f7671b 100644 --- a/src/connectors/interface.ts +++ b/src/connectors/interface.ts @@ -7,11 +7,28 @@ export type ConnectorType = "postgres" | "mysql" | "mariadb" | "sqlite" | "sqlse * Database Connector Interface * This defines the contract that all database connectors must implement. */ +/** + * An informational (non-error) message emitted by the database during query + * execution, e.g. SQL Server STATISTICS TIME/IO and PRINT output, or + * PostgreSQL NOTICE/WARNING. Modeled to be cross-database: only `text` is + * guaranteed, the rest are populated when the driver exposes them. + */ +export interface DatabaseMessage { + /** Human-readable message text */ + text: string; + /** Severity indicator where available; interpret per database (PostgreSQL: level name like NOTICE/WARNING; SQL Server: numeric severity class as a string) */ + severity?: string; + /** Database-specific message code (PostgreSQL: SQLSTATE; SQL Server: message number) */ + code?: string | number; + /** 1-based line number within the SQL batch that produced the message, when reported */ + line?: number; +} + export interface SQLResult { rows: any[]; rowCount: number; /** Informational messages from the database (e.g. SQL Server STATISTICS TIME/IO, PRINT output) */ - messages?: string[]; + messages?: DatabaseMessage[]; } export interface TableColumn { diff --git a/src/connectors/sqlserver/index.ts b/src/connectors/sqlserver/index.ts index 766ef4b7..a5c85f2c 100644 --- a/src/connectors/sqlserver/index.ts +++ b/src/connectors/sqlserver/index.ts @@ -5,6 +5,7 @@ import { ConnectorRegistry, DSNParser, SQLResult, + DatabaseMessage, TableColumn, TableIndex, StoredProcedure, @@ -610,10 +611,19 @@ export class SQLServerConnector implements Connector { // Create request and collect informational messages (e.g. SET STATISTICS TIME/IO, PRINT) const request = this.connection.request(); - const messages: string[] = []; - request.on('info', (info: { message: string }) => { - messages.push(info.message); - }); + const messages: DatabaseMessage[] = []; + request.on( + 'info', + (info: { message: string; number?: number; class?: number; lineNumber?: number }) => { + messages.push({ + text: info.message, + // SQL Server reports severity as a numeric class; info messages are < 10. + severity: info.class !== undefined ? String(info.class) : undefined, + code: info.number, + line: info.lineNumber, + }); + } + ); if (parameters && parameters.length > 0) { // SQL Server uses @p1, @p2, etc. for parameters