[#706] [#2324] Reverting workarounds for Postgres JDBC driver's

inability to fetch a ref cursor if connection.getAutoCommit() == true
This commit is contained in:
Lukas Eder 2013-05-22 21:46:18 +02:00
parent bc7f29922e
commit 9512ff8a68
2 changed files with 194 additions and 210 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}