From 9512ff8a68fab7783fca272525c7fe35a7183ddb Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 22 May 2013 21:46:18 +0200 Subject: [PATCH] [#706] [#2324] Reverting workarounds for Postgres JDBC driver's inability to fetch a ref cursor if connection.getAutoCommit() == true --- .../test/_/testcases/RoutineAndUDTTests.java | 292 +++++++++--------- .../org/jooq/impl/AbstractResultQuery.java | 112 +++---- 2 files changed, 194 insertions(+), 210 deletions(-) diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/RoutineAndUDTTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/RoutineAndUDTTests.java index bc3870e095..a3999daf08 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/RoutineAndUDTTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/RoutineAndUDTTests.java @@ -1207,178 +1207,190 @@ extends BaseTest 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 bFromCursor = invoke(cRoutines(), "fGetOneCursor", create().configuration(), integerArray); - // Get a filled cursor - // ------------------- - if (TArrays_STRING_R() != null) { - ArrayRecord 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 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 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 bFromTable = create() - .selectFrom(TBook()) - .where(TBook_ID().in(1, 2, 4)) - .orderBy(TBook_ID()).fetch(); + // Get an empty cursor + // ------------------- + Field> field = FGetOneCursorField(null); + Result 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> field = FGetOneCursorField(null); - Result 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 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 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 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 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 bFromCursor = invoke(result, "getBooks"); - assertTrue(bFromCursor.isEmpty()); - assertEquals(0, bFromCursor.size()); + Result 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 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 bFromTable = create() - .selectFrom(TBook()) - .where(TBook_ID().in(1, 2, 4)) - .orderBy(TBook_ID()).fetch(); + Result aFromTable = create().selectFrom(TAuthor()).orderBy(TAuthor_ID()).fetch(); + Result bFromTable = create().selectFrom(TBook()).orderBy(TBook_ID()).fetch(); - assertNotNull(bFromCursor); - assertFalse(bFromCursor.isEmpty()); - assertEquals(3, bFromCursor.size()); + Result aFromCursor = invoke(result, "getAuthors"); + Result 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 aFromTable = create().selectFrom(TAuthor()).orderBy(TAuthor_ID()).fetch(); - Result bFromTable = create().selectFrom(TBook()).orderBy(TBook_ID()).fetch(); - - Result aFromCursor = invoke(result, "getAuthors"); - Result 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); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java index 783e98c62e..0081c60480 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java @@ -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 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(ctx, listener, fields, internIndexes(fields), keepStatement(), keepResultSet(), keepResultSetMode, getRecordType()); + + if (!lazy) { + result = cursor.fetch(); + cursor = null; + } + } + else { + result = new ResultImpl(ctx.configuration(), null); } } - try { - listener.executeStart(ctx); + // Fetch several result sets + else { + results = new ArrayList>(); + 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 c = new CursorImpl(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(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(ctx.configuration(), null); + ctx.resultSet(null); } } - // Fetch several result sets - else { - results = new ArrayList>(); - boolean anyResults = false; - - while (ctx.resultSet() != null) { - anyResults = true; - - Field[] fields = new MetaDataFieldProvider(ctx.configuration(), ctx.resultSet().getMetaData()).getFields(); - Cursor c = new CursorImpl(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); } }