57 lines
3.1 KiB
Plaintext
Executable File
57 lines
3.1 KiB
Plaintext
Executable File
=== Raw JDBC probe (no Hibernate), HSQLDB 2.7.3, DYNAMIC RESULT SETS procedure ===
|
|
--- CallableStatement.execute() then getUpdateCount()/getResultSet() ---
|
|
execute() returned=false
|
|
getUpdateCount=0
|
|
getResultSet() = org.hsqldb.jdbc.JDBCResultSet@5649fd9b
|
|
row: 1 Alice 50000.00
|
|
row: 2 Bob 60000.00
|
|
getMoreResults=false
|
|
|
|
--- Statement.execute("CALL ...") vs CallableStatement.executeQuery() ---
|
|
--- via plain Statement.execute(CALL ...) ---
|
|
Statement.execute returned=false
|
|
getResultSet=null
|
|
--- via CallableStatement.executeQuery() ---
|
|
executeQuery ok, rs=org.hsqldb.jdbc.JDBCResultSet@5649fd9b
|
|
row via executeQuery: 1
|
|
row via executeQuery: 2
|
|
--- metadata: getMetaData() on CallableStatement before execute ---
|
|
getMetaData()=null
|
|
|
|
CONCLUSION: CallableStatement.execute() returns false (per JDBC spec this should mean
|
|
'no ResultSet, check update count'), and getUpdateCount() also returns 0 (not -1).
|
|
Yet CallableStatement.getResultSet() DOES return a live, iterable ResultSet with the
|
|
cursor's rows, and CallableStatement.executeQuery() works correctly end-to-end.
|
|
Statement.execute("CALL ...") is worse: execute()=false AND getResultSet()=null (the
|
|
result set is only reachable through the CallableStatement form).
|
|
Hibernate 7.4.5's ProcedureCallImpl (org.hibernate.procedure.internal.ProcedureCallImpl
|
|
/ StandardCallableStatementSupport) drives the call via execute() and trusts its boolean
|
|
to decide whether to attach a ResultSetOutput. Since HSQLDB's driver misreports that
|
|
boolean, getResultList() on a DYNAMIC RESULT SETS procedure fails with:
|
|
java.lang.IllegalStateException: Current CallableStatement was not a ResultSet, but getResultList was called
|
|
This reproduces identically through @NamedStoredProcedureQuery(resultClasses=...) and
|
|
through createStoredProcedureQuery(name, sqlResultSetMappingName) -- see
|
|
StoredProcedureHappyPathTest#resultSetProcedure_mappedToEntity_hitsHsqldbDriverIncompatibility
|
|
and #resultSetProcedure_mappedToDto_alsoHitsHsqldbDriverIncompatibility.
|
|
|
|
=== OUT parameter vs result-set consumption ORDER (raw JDBC, procedure with BOTH) ===
|
|
Procedure: combo(IN emp_id, OUT tax_amount) READS SQL DATA DYNAMIC RESULT SETS 1, opens a cursor
|
|
AND sets the OUT parameter.
|
|
|
|
Reading the OUT parameter BEFORE consuming the ResultSet:
|
|
execute()=false
|
|
OUT tax_amount = 7500.00 <- succeeds, no exception
|
|
(then) getResultSet() still returns the cursor with its rows intact
|
|
(then) OUT tax_amount read AGAIN = 7500.00 <- still succeeds
|
|
|
|
Reading the OUT parameter AFTER fully consuming the ResultSet:
|
|
rows consumed first
|
|
OUT tax_amount = 9000.00 <- also succeeds
|
|
|
|
CONCLUSION: unlike some JDBC drivers (historically SQL Server's, and some Oracle configurations)
|
|
that require a stored procedure's result set(s) to be fully consumed before OUT parameters
|
|
become readable, HSQLDB 2.7.3's driver imposes NO such ordering constraint. Reading the OUT
|
|
value before, interleaved with, or after draining the cursor all work identically. The
|
|
"ordering trap" described in stored-procedure folklore is real on SOME databases/drivers but
|
|
is NOT reproducible on HSQLDB -- worth stating explicitly rather than assuming it's universal.
|