Skip to content

Commit f72fe1a

Browse files
committed
Handle multiple result sets (implicit cursor) with Oracle driver
Oracle driver... ... throws `SQLException` with no good reason when calling `Statement#getResultSet()`. `SQLException` is thrown "if a database access error occurs or this method is called on a closed Statement". https://docs.oracle.com/en/java/javase/23/docs/api/java.sql/java/sql/Statement.html#getResultSet() https://stackoverflow.com/q/42091653/1261766 ... always returns `false` from `DatabaseMetaData#supportsMultipleResultSets()` even though it apparently does.
1 parent 6d18873 commit f72fe1a

File tree

2 files changed

+36
-24
lines changed

2 files changed

+36
-24
lines changed

src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -247,34 +247,49 @@ public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException
247247
}
248248

249249
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
250-
ResultSet rs = stmt.getResultSet();
251-
while (rs == null) {
252-
// move forward to get the first resultset in case the driver
253-
// doesn't return the resultset as the first result (HSQLDB)
254-
if (stmt.getMoreResults()) {
255-
rs = stmt.getResultSet();
256-
} else if (stmt.getUpdateCount() == -1) {
257-
// no more results. Must be no resultset
258-
break;
250+
ResultSet rs = null;
251+
SQLException e1 = null;
252+
253+
try {
254+
rs = stmt.getResultSet();
255+
} catch (SQLException e) {
256+
// Oracle throws ORA-17283 for implicit cursor
257+
e1 = e;
258+
}
259+
260+
try {
261+
while (rs == null) {
262+
// move forward to get the first resultset in case the driver
263+
// doesn't return the resultset as the first result (HSQLDB)
264+
if (stmt.getMoreResults()) {
265+
rs = stmt.getResultSet();
266+
} else if (stmt.getUpdateCount() == -1) {
267+
// no more results. Must be no resultset
268+
break;
269+
}
259270
}
271+
} catch (SQLException e) {
272+
throw e1 != null ? e1 : e;
260273
}
274+
261275
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
262276
}
263277

264278
private ResultSetWrapper getNextResultSet(Statement stmt) {
265279
// Making this method tolerant of bad JDBC drivers
266280
try {
267-
if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
268-
// Crazy Standard JDBC way of determining if there are more results
269-
// DO NOT try to 'improve' the condition even if IDE tells you to!
270-
// It's important that getUpdateCount() is called here.
271-
if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
272-
ResultSet rs = stmt.getResultSet();
273-
if (rs == null) {
274-
return getNextResultSet(stmt);
275-
} else {
276-
return new ResultSetWrapper(rs, configuration);
277-
}
281+
// We stopped checking DatabaseMetaData#supportsMultipleResultSets()
282+
// because Oracle driver (incorrectly) returns false
283+
284+
// Crazy Standard JDBC way of determining if there are more results
285+
// DO NOT try to 'improve' the condition even if IDE tells you to!
286+
// It's important that getUpdateCount() is called here.
287+
if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
288+
ResultSet rs = stmt.getResultSet();
289+
if (rs == null) {
290+
return getNextResultSet(stmt);
291+
} else {
292+
return new ResultSetWrapper(rs, configuration);
278293
}
279294
}
280295
} catch (Exception e) {

src/test/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandlerTest.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2024 the original author or authors.
2+
* Copyright 2009-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -92,9 +92,6 @@ void shouldRetainColumnNameCase() throws Exception {
9292
when(rsmd.getColumnLabel(1)).thenReturn("CoLuMn1");
9393
when(rsmd.getColumnType(1)).thenReturn(Types.INTEGER);
9494
when(rsmd.getColumnClassName(1)).thenReturn(Integer.class.getCanonicalName());
95-
when(stmt.getConnection()).thenReturn(conn);
96-
when(conn.getMetaData()).thenReturn(dbmd);
97-
when(dbmd.supportsMultipleResultSets()).thenReturn(false); // for simplicity.
9895

9996
final List<Object> results = fastResultSetHandler.handleResultSets(stmt);
10097
assertEquals(1, results.size());

0 commit comments

Comments
 (0)