Description
Issue description
Calling manager.query(EXEC MySP
, [param1]) only returns the first recordset
Expected Behavior
I expect it to return exactly what sql returns. If I pass in a single statement it should return that result, if I pass in multiple, it should return all recordsets.
Let me know if this is by design.
Actual Behavior
Calling manager.query(EXEC MySP
, [param1]) (or anywhere you can call query()) will return whatever your first statemement returns. If you're returning multiple recordsets, they are not all returned.
The EXEC example was the first one I tried as I happened to need to call an SP, however, the same applies for any query with multiple statements inside it.
For example a plain SELECT:
manager.query( SELECT * FROM Table1 SELECT * FROM Table 2 )
You only get whatever is inside Table1.
Steps to reproduce
EntityManager is exactly that from typeorm. Nothing special here:
const result = await EntityManager.query(
EXEC api.Test ${params.map((_, index) => @${index}
).join(', ')}`, ['param1', 'param2'])
`
Minimal stored procedure returning two recordsets:
`USE SomeDatabase
GO
/****** Object: StoredProcedure [api].[Test] Script Date: 9/07/2025 6:39:13 am ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [api].[Test]
@param1 nvarchar,
@Param2 nvarchar
AS
BEGIN
SET NOCOUNT ON;
SELECT @param1 as Parameter1
SELECT @param2 as Parameter2
END
`
The results should be an array of arrays or however typeorm wants to deconstruct the response from sql (if it doesn't just pass it back but here's what I get instead:
[ { Parameter1: 'v' } ]
My Environment
Dependency | Version |
---|---|
Operating System | Windows 11 |
Node.js version | 22.14.0 |
Typescript version | 5.8.2 |
TypeORM version | 0.3.25 |
Additional Context
The underlying mssql driver returns recordset and recordsets (contains all recordsets returned from a query) and rowsAffected. It needs to check for recordsets the same way it checks for recordset and rowsAffected.
I can see in the SqlServerQueryRunner.ts, in the query() method, it currently checks for recordset and rowsAffected:
`
const raw = await new Promise((ok, fail) => {
request.query(query, (err: any, raw: any) => {
// log slow queries if maxQueryExecution time is set
const maxQueryExecutionTime =
this.driver.options.maxQueryExecutionTime
const queryEndTime = Date.now()
const queryExecutionTime = queryEndTime - queryStartTime
this.broadcaster.broadcastAfterQueryEvent(
broadcasterResult,
query,
parameters,
true,
queryExecutionTime,
raw,
undefined,
)
if (
maxQueryExecutionTime &&
queryExecutionTime > maxQueryExecutionTime
) {
this.driver.connection.logger.logQuerySlow(
queryExecutionTime,
query,
parameters,
this,
)
}
if (err) {
fail(new QueryFailedError(query, parameters, err))
}
ok(raw)
})
})
const result = new QueryResult()
if (raw?.hasOwnProperty("recordset")) {
result.records = raw.recordset
}
if (raw?.hasOwnProperty("rowsAffected")) {
result.affected = raw.rowsAffected[0]
}
const queryType = query.slice(0, query.indexOf(" "))
switch (queryType) {
case "DELETE":
// for DELETE query additionally return number of affected rows
result.raw = [raw.recordset, raw.rowsAffected[0]]
break
default:
result.raw = raw.recordset
}
if (useStructuredResult) {
return result
} else {
return result.raw
}
`
The QueryResult class would need to have the appropriate key added to support this property too.
The return would need to be modified to support this. The useStructuredResult isn't exposed as far as DataSource.query()
so one would need to fallback to DataSource.createQueryRunner.query(query, params, true)
So there's some options. It would be nice if useStructuredResult was exposed to DataSource.query() and with the modified QueryResult and the setting of recordSets we'll be able to pull out recordSets and see the full response.
Relevant Database Driver(s)
- aurora-mysql
- aurora-postgres
- better-sqlite3
- cockroachdb
- cordova
- expo
- mongodb
- mysql
- nativescript
- oracle
- postgres
- react-native
- sap
- spanner
- sqlite
- sqlite-abstract
- sqljs
- sqlserver
Are you willing to resolve this issue by submitting a Pull Request?
Yes, I have the time, and I know how to start.