inability to fetch a ref cursor if connection.getAutoCommit() == true
This commit is contained in:
parent
bc7f29922e
commit
9512ff8a68
@ -1207,178 +1207,190 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
return;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// The one cursor function
|
||||
// ---------------------------------------------------------------------
|
||||
{
|
||||
Object integerArray = null;
|
||||
// [#706] [#2324] Postgres JDBC needs two separate queries to fetch a
|
||||
// cursor from a result set. This is only possible in a single
|
||||
// transaction. This was previously fixed by jOOQ, but jOOQ's the wrong
|
||||
// place to fix such things.
|
||||
boolean autoCommit = getConnection().getAutoCommit();
|
||||
try {
|
||||
getConnection().setAutoCommit(false);
|
||||
|
||||
// Get an empty cursor
|
||||
// -------------------
|
||||
Result<Record> bFromCursor = invoke(cRoutines(), "fGetOneCursor", create().configuration(), integerArray);
|
||||
// ---------------------------------------------------------------------
|
||||
// The one cursor function
|
||||
// ---------------------------------------------------------------------
|
||||
{
|
||||
Object integerArray = null;
|
||||
|
||||
assertNotNull(bFromCursor);
|
||||
assertTrue(bFromCursor.isEmpty());
|
||||
assertEquals(0, bFromCursor.size());
|
||||
// Get an empty cursor
|
||||
// -------------------
|
||||
Result<Record> bFromCursor = invoke(cRoutines(), "fGetOneCursor", create().configuration(), integerArray);
|
||||
|
||||
// Get a filled cursor
|
||||
// -------------------
|
||||
if (TArrays_STRING_R() != null) {
|
||||
ArrayRecord<Integer> i = newNUMBER_R();
|
||||
i.set(1, 2, 4, 6);
|
||||
integerArray = i;
|
||||
}
|
||||
else if (TArrays_STRING() != null) {
|
||||
integerArray = new Integer[] { 1, 2, 4, 6 };
|
||||
assertNotNull(bFromCursor);
|
||||
assertTrue(bFromCursor.isEmpty());
|
||||
assertEquals(0, bFromCursor.size());
|
||||
|
||||
// Get a filled cursor
|
||||
// -------------------
|
||||
if (TArrays_STRING_R() != null) {
|
||||
ArrayRecord<Integer> i = newNUMBER_R();
|
||||
i.set(1, 2, 4, 6);
|
||||
integerArray = i;
|
||||
}
|
||||
else if (TArrays_STRING() != null) {
|
||||
integerArray = new Integer[] { 1, 2, 4, 6 };
|
||||
}
|
||||
|
||||
bFromCursor = invoke(cRoutines(), "fGetOneCursor", create().configuration(), integerArray);
|
||||
|
||||
Result<B> bFromTable = create()
|
||||
.selectFrom(TBook())
|
||||
.where(TBook_ID().in(1, 2, 4))
|
||||
.orderBy(TBook_ID()).fetch();
|
||||
|
||||
assertNotNull(bFromCursor);
|
||||
assertFalse(bFromCursor.isEmpty());
|
||||
assertEquals(3, bFromCursor.size());
|
||||
|
||||
compareBookResults(bFromCursor, bFromTable);
|
||||
}
|
||||
|
||||
bFromCursor = invoke(cRoutines(), "fGetOneCursor", create().configuration(), integerArray);
|
||||
// ---------------------------------------------------------------------
|
||||
// The one cursor function used in SQL
|
||||
// ---------------------------------------------------------------------
|
||||
{
|
||||
|
||||
Result<B> bFromTable = create()
|
||||
.selectFrom(TBook())
|
||||
.where(TBook_ID().in(1, 2, 4))
|
||||
.orderBy(TBook_ID()).fetch();
|
||||
// Get an empty cursor
|
||||
// -------------------
|
||||
Field<Result<Record>> field = FGetOneCursorField(null);
|
||||
Result<Record> bFromCursor;
|
||||
|
||||
assertNotNull(bFromCursor);
|
||||
assertFalse(bFromCursor.isEmpty());
|
||||
assertEquals(3, bFromCursor.size());
|
||||
switch (dialect()) {
|
||||
case HSQLDB:
|
||||
bFromCursor = create().select().from(table(field)).fetch();
|
||||
break;
|
||||
|
||||
compareBookResults(bFromCursor, bFromTable);
|
||||
}
|
||||
default:
|
||||
bFromCursor = create().select(field).fetchOne(field);
|
||||
break;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// The one cursor function used in SQL
|
||||
// ---------------------------------------------------------------------
|
||||
{
|
||||
assertNotNull(bFromCursor);
|
||||
assertTrue(bFromCursor.isEmpty());
|
||||
assertEquals(0, bFromCursor.size());
|
||||
|
||||
// Get an empty cursor
|
||||
// -------------------
|
||||
Field<Result<Record>> field = FGetOneCursorField(null);
|
||||
Result<Record> bFromCursor;
|
||||
// Get a filled cursor
|
||||
// -------------------
|
||||
field = FGetOneCursorField(new Integer[] { 1, 2, 4, 6 });
|
||||
|
||||
switch (dialect()) {
|
||||
case HSQLDB:
|
||||
bFromCursor = create().select().from(table(field)).fetch();
|
||||
break;
|
||||
switch (dialect()) {
|
||||
case HSQLDB:
|
||||
bFromCursor = create().select().from(table(field)).fetch();
|
||||
break;
|
||||
|
||||
default:
|
||||
bFromCursor = create().select(field).fetchOne(field);
|
||||
break;
|
||||
default:
|
||||
bFromCursor = create().select(field).fetchOne(field);
|
||||
break;
|
||||
}
|
||||
|
||||
Result<B> bFromTable = create()
|
||||
.selectFrom(TBook())
|
||||
.where(TBook_ID().in(1, 2, 4))
|
||||
.orderBy(TBook_ID()).fetch();
|
||||
|
||||
assertNotNull(bFromCursor);
|
||||
assertFalse(bFromCursor.isEmpty());
|
||||
assertEquals(3, bFromCursor.size());
|
||||
|
||||
compareBookResults(bFromCursor, bFromTable);
|
||||
}
|
||||
|
||||
assertNotNull(bFromCursor);
|
||||
assertTrue(bFromCursor.isEmpty());
|
||||
assertEquals(0, bFromCursor.size());
|
||||
|
||||
// Get a filled cursor
|
||||
// -------------------
|
||||
field = FGetOneCursorField(new Integer[] { 1, 2, 4, 6 });
|
||||
|
||||
switch (dialect()) {
|
||||
case HSQLDB:
|
||||
bFromCursor = create().select().from(table(field)).fetch();
|
||||
break;
|
||||
|
||||
default:
|
||||
bFromCursor = create().select(field).fetchOne(field);
|
||||
break;
|
||||
if (dialect() == SQLDialect.HSQLDB) {
|
||||
log.info("SKIPPING", "Cursor OUT parameter tests");
|
||||
return;
|
||||
}
|
||||
|
||||
Result<B> bFromTable = create()
|
||||
.selectFrom(TBook())
|
||||
.where(TBook_ID().in(1, 2, 4))
|
||||
.orderBy(TBook_ID()).fetch();
|
||||
// ---------------------------------------------------------------------
|
||||
// The one cursor procedure
|
||||
// ---------------------------------------------------------------------
|
||||
if (supportsOUTParameters()) {
|
||||
Object integerArray = null;
|
||||
|
||||
assertNotNull(bFromCursor);
|
||||
assertFalse(bFromCursor.isEmpty());
|
||||
assertEquals(3, bFromCursor.size());
|
||||
// Get an empty cursor
|
||||
// -------------------
|
||||
Object result = invoke(cRoutines(), "pGetOneCursor", create().configuration(), integerArray);
|
||||
|
||||
compareBookResults(bFromCursor, bFromTable);
|
||||
}
|
||||
assertNotNull(result);
|
||||
assertEquals("0", "" + invoke(result, "getTotal"));
|
||||
|
||||
if (dialect() == SQLDialect.HSQLDB) {
|
||||
log.info("SKIPPING", "Cursor OUT parameter tests");
|
||||
return;
|
||||
}
|
||||
Result<Record> bFromCursor = invoke(result, "getBooks");
|
||||
assertTrue(bFromCursor.isEmpty());
|
||||
assertEquals(0, bFromCursor.size());
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// The one cursor procedure
|
||||
// ---------------------------------------------------------------------
|
||||
if (supportsOUTParameters()) {
|
||||
Object integerArray = null;
|
||||
// Get a filled cursor
|
||||
// -------------------
|
||||
if (TArrays_STRING_R() != null) {
|
||||
ArrayRecord<Integer> i = newNUMBER_R();
|
||||
i.set(1, 2, 4, 6);
|
||||
integerArray = i;
|
||||
}
|
||||
else if (TArrays_STRING() != null) {
|
||||
integerArray = new Integer[] { 1, 2, 4, 6 };
|
||||
}
|
||||
|
||||
// Get an empty cursor
|
||||
// -------------------
|
||||
Object result = invoke(cRoutines(), "pGetOneCursor", create().configuration(), integerArray);
|
||||
result = invoke(cRoutines(), "pGetOneCursor", create().configuration(), integerArray);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("0", "" + invoke(result, "getTotal"));
|
||||
assertEquals("3", "" + invoke(result, "getTotal"));
|
||||
bFromCursor = invoke(result, "getBooks");
|
||||
|
||||
Result<Record> bFromCursor = invoke(result, "getBooks");
|
||||
assertTrue(bFromCursor.isEmpty());
|
||||
assertEquals(0, bFromCursor.size());
|
||||
Result<B> bFromTable = create()
|
||||
.selectFrom(TBook())
|
||||
.where(TBook_ID().in(1, 2, 4))
|
||||
.orderBy(TBook_ID()).fetch();
|
||||
|
||||
// Get a filled cursor
|
||||
// -------------------
|
||||
if (TArrays_STRING_R() != null) {
|
||||
ArrayRecord<Integer> i = newNUMBER_R();
|
||||
i.set(1, 2, 4, 6);
|
||||
integerArray = i;
|
||||
assertNotNull(bFromCursor);
|
||||
assertFalse(bFromCursor.isEmpty());
|
||||
assertEquals(3, bFromCursor.size());
|
||||
|
||||
compareBookResults(bFromCursor, bFromTable);
|
||||
}
|
||||
else if (TArrays_STRING() != null) {
|
||||
integerArray = new Integer[] { 1, 2, 4, 6 };
|
||||
else {
|
||||
log.info("SKIPPING", "One cursor OUT parameter test");
|
||||
}
|
||||
|
||||
result = invoke(cRoutines(), "pGetOneCursor", create().configuration(), integerArray);
|
||||
// ---------------------------------------------------------------------
|
||||
// The two cursor procedure
|
||||
// ---------------------------------------------------------------------
|
||||
if (dialect() == SQLDialect.POSTGRES) {
|
||||
|
||||
assertEquals("3", "" + invoke(result, "getTotal"));
|
||||
bFromCursor = invoke(result, "getBooks");
|
||||
// TODO [#707] This fails for Postgres, as UDT's are not correctly
|
||||
// deserialised
|
||||
log.info("SKIPPING", "UDT/Enum types returned in refcursor (see [#707])");
|
||||
}
|
||||
else if (supportsOUTParameters()) {
|
||||
Object result = invoke(cRoutines(), "pGetTwoCursors", create().configuration());
|
||||
assertNotNull(result);
|
||||
|
||||
Result<B> bFromTable = create()
|
||||
.selectFrom(TBook())
|
||||
.where(TBook_ID().in(1, 2, 4))
|
||||
.orderBy(TBook_ID()).fetch();
|
||||
Result<A> aFromTable = create().selectFrom(TAuthor()).orderBy(TAuthor_ID()).fetch();
|
||||
Result<B> bFromTable = create().selectFrom(TBook()).orderBy(TBook_ID()).fetch();
|
||||
|
||||
assertNotNull(bFromCursor);
|
||||
assertFalse(bFromCursor.isEmpty());
|
||||
assertEquals(3, bFromCursor.size());
|
||||
Result<Record> aFromCursor = invoke(result, "getAuthors");
|
||||
Result<Record> bFromCursor = invoke(result, "getBooks");
|
||||
assertNotNull(aFromCursor);
|
||||
assertNotNull(bFromCursor);
|
||||
assertEquals(2, aFromCursor.size());
|
||||
assertEquals(4, bFromCursor.size());
|
||||
assertFalse(aFromCursor.isEmpty());
|
||||
assertFalse(bFromCursor.isEmpty());
|
||||
|
||||
compareBookResults(bFromCursor, bFromTable);
|
||||
compareAuthorResults(aFromCursor, aFromTable);
|
||||
compareBookResults(bFromCursor, bFromTable);
|
||||
}
|
||||
else {
|
||||
log.info("SKIPPING", "Two cursor OUT parameter test");
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info("SKIPPING", "One cursor OUT parameter test");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// The two cursor procedure
|
||||
// ---------------------------------------------------------------------
|
||||
if (dialect() == SQLDialect.POSTGRES) {
|
||||
|
||||
// TODO [#707] This fails for Postgres, as UDT's are not correctly
|
||||
// deserialised
|
||||
log.info("SKIPPING", "UDT/Enum types returned in refcursor (see [#707])");
|
||||
}
|
||||
else if (supportsOUTParameters()) {
|
||||
Object result = invoke(cRoutines(), "pGetTwoCursors", create().configuration());
|
||||
assertNotNull(result);
|
||||
|
||||
Result<A> aFromTable = create().selectFrom(TAuthor()).orderBy(TAuthor_ID()).fetch();
|
||||
Result<B> bFromTable = create().selectFrom(TBook()).orderBy(TBook_ID()).fetch();
|
||||
|
||||
Result<Record> aFromCursor = invoke(result, "getAuthors");
|
||||
Result<Record> bFromCursor = invoke(result, "getBooks");
|
||||
assertNotNull(aFromCursor);
|
||||
assertNotNull(bFromCursor);
|
||||
assertEquals(2, aFromCursor.size());
|
||||
assertEquals(4, bFromCursor.size());
|
||||
assertFalse(aFromCursor.isEmpty());
|
||||
assertFalse(bFromCursor.isEmpty());
|
||||
|
||||
compareAuthorResults(aFromCursor, aFromTable);
|
||||
compareBookResults(bFromCursor, bFromTable);
|
||||
}
|
||||
else {
|
||||
log.info("SKIPPING", "Two cursor OUT parameter test");
|
||||
finally {
|
||||
getConnection().setAutoCommit(autoCommit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,6 @@ import static org.jooq.SQLDialect.CUBRID;
|
||||
import static org.jooq.SQLDialect.SQLSERVER;
|
||||
import static org.jooq.impl.Utils.DATA_LOCK_ROWS_FOR_UPDATE;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
@ -74,7 +73,6 @@ import org.jooq.RecordHandler;
|
||||
import org.jooq.RecordMapper;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.ResultQuery;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.tools.Convert;
|
||||
@ -266,88 +264,62 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
|
||||
|
||||
@Override
|
||||
protected final int execute(ExecuteContext ctx, ExecuteListener listener) throws SQLException {
|
||||
Connection connection = ctx.connection();
|
||||
boolean autoCommit = false;
|
||||
listener.executeStart(ctx);
|
||||
|
||||
// [#706] Postgres requires two separate queries running in the same
|
||||
// transaction to be executed when fetching refcursor types
|
||||
if (ctx.configuration().dialect() == SQLDialect.POSTGRES && isSelectingRefCursor()) {
|
||||
autoCommit = connection.getAutoCommit();
|
||||
// JTDS doesn't seem to implement PreparedStatement.execute()
|
||||
// correctly, at least not for sp_help
|
||||
if (ctx.configuration().dialect() == ASE) {
|
||||
ctx.resultSet(ctx.statement().executeQuery());
|
||||
}
|
||||
|
||||
if (autoCommit) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Unsetting auto-commit", false);
|
||||
// [#1232] Avoid executeQuery() in order to handle queries that may
|
||||
// not return a ResultSet, e.g. SQLite's pragma foreign_key_list(table)
|
||||
else if (ctx.statement().execute()) {
|
||||
ctx.resultSet(ctx.statement().getResultSet());
|
||||
}
|
||||
|
||||
connection.setAutoCommit(false);
|
||||
listener.executeEnd(ctx);
|
||||
|
||||
// Fetch a single result set
|
||||
if (!many) {
|
||||
if (ctx.resultSet() != null) {
|
||||
Field<?>[] fields = getFields(ctx.resultSet().getMetaData());
|
||||
cursor = new CursorImpl<R>(ctx, listener, fields, internIndexes(fields), keepStatement(), keepResultSet(), keepResultSetMode, getRecordType());
|
||||
|
||||
if (!lazy) {
|
||||
result = cursor.fetch();
|
||||
cursor = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = new ResultImpl<R>(ctx.configuration(), null);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
listener.executeStart(ctx);
|
||||
// Fetch several result sets
|
||||
else {
|
||||
results = new ArrayList<Result<Record>>();
|
||||
boolean anyResults = false;
|
||||
|
||||
// JTDS doesn't seem to implement PreparedStatement.execute()
|
||||
// correctly, at least not for sp_help
|
||||
if (ctx.configuration().dialect() == ASE) {
|
||||
ctx.resultSet(ctx.statement().executeQuery());
|
||||
}
|
||||
while (ctx.resultSet() != null) {
|
||||
anyResults = true;
|
||||
|
||||
// [#1232] Avoid executeQuery() in order to handle queries that may
|
||||
// not return a ResultSet, e.g. SQLite's pragma foreign_key_list(table)
|
||||
else if (ctx.statement().execute()) {
|
||||
ctx.resultSet(ctx.statement().getResultSet());
|
||||
}
|
||||
Field<?>[] fields = new MetaDataFieldProvider(ctx.configuration(), ctx.resultSet().getMetaData()).getFields();
|
||||
Cursor<Record> c = new CursorImpl<Record>(ctx, listener, fields, internIndexes(fields), true, false, CLOSE_AFTER_FETCH);
|
||||
results.add(c.fetch());
|
||||
|
||||
listener.executeEnd(ctx);
|
||||
|
||||
// Fetch a single result set
|
||||
if (!many) {
|
||||
if (ctx.resultSet() != null) {
|
||||
Field<?>[] fields = getFields(ctx.resultSet().getMetaData());
|
||||
cursor = new CursorImpl<R>(ctx, listener, fields, internIndexes(fields), keepStatement(), keepResultSet(), keepResultSetMode, getRecordType());
|
||||
|
||||
if (!lazy) {
|
||||
result = cursor.fetch();
|
||||
cursor = null;
|
||||
}
|
||||
if (ctx.statement().getMoreResults()) {
|
||||
ctx.resultSet(ctx.statement().getResultSet());
|
||||
}
|
||||
else {
|
||||
result = new ResultImpl<R>(ctx.configuration(), null);
|
||||
ctx.resultSet(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch several result sets
|
||||
else {
|
||||
results = new ArrayList<Result<Record>>();
|
||||
boolean anyResults = false;
|
||||
|
||||
while (ctx.resultSet() != null) {
|
||||
anyResults = true;
|
||||
|
||||
Field<?>[] fields = new MetaDataFieldProvider(ctx.configuration(), ctx.resultSet().getMetaData()).getFields();
|
||||
Cursor<Record> c = new CursorImpl<Record>(ctx, listener, fields, internIndexes(fields), true, false, CLOSE_AFTER_FETCH);
|
||||
results.add(c.fetch());
|
||||
|
||||
if (ctx.statement().getMoreResults()) {
|
||||
ctx.resultSet(ctx.statement().getResultSet());
|
||||
}
|
||||
else {
|
||||
ctx.resultSet(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Call this only when there was at least one ResultSet.
|
||||
// Otherwise, this call is not supported by ojdbc...
|
||||
if (anyResults) {
|
||||
ctx.statement().getMoreResults(Statement.CLOSE_ALL_RESULTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (autoCommit) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Resetting auto-commit", autoCommit);
|
||||
|
||||
connection.setAutoCommit(autoCommit);
|
||||
// Call this only when there was at least one ResultSet.
|
||||
// Otherwise, this call is not supported by ojdbc...
|
||||
if (anyResults) {
|
||||
ctx.statement().getMoreResults(Statement.CLOSE_ALL_RESULTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user