diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/dml/result/PostgreSqlResultIterator.java b/src/main/java/com/feedzai/commons/sql/abstraction/dml/result/PostgreSqlResultIterator.java index d36e5400..9632f05d 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/dml/result/PostgreSqlResultIterator.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/dml/result/PostgreSqlResultIterator.java @@ -62,4 +62,9 @@ public ResultColumn createResultColumn(String name, Object value) { protected QueryExceptionHandler getQueryExceptionHandler() { return PG_QUERY_EXCEPTION_HANDLER; } + + @Override + protected boolean needsWrapInTransaction(final int fetchSize) { + return fetchSize > 0; + } } diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/dml/result/ResultIterator.java b/src/main/java/com/feedzai/commons/sql/abstraction/dml/result/ResultIterator.java index ea9e0d0e..4eb99f97 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/dml/result/ResultIterator.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/dml/result/ResultIterator.java @@ -20,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; @@ -56,20 +57,31 @@ public abstract class ResultIterator implements AutoCloseable { /** * The list of columns names for the given query. */ - private final List columnNames; + private final List columnNames = new ArrayList<>(); + /** - * Signals if the result set is already close. + * Signals if the result set is already closed. */ private boolean closed = false; /** - * Signals if statement in place is closeable. E.g. Prepared statements must no be closed. + * Signals if statement in place is closeable. E.g. Prepared statements must not be closed. */ - private boolean statementCloseable; + private final boolean statementCloseable; /** * The number of rows processed by the iterator so far. */ - private int currentRowCount; + private int currentRowCount = 0; + + /** + * Signals whether the iterator query was wrapped in a transaction before being sent to the database. + */ + private final boolean isWrappedInTransaction; + + /** + * Flag to keep the previous state of the {@link Connection#getAutoCommit() conection autocommit}. + */ + private final boolean previousAutocommit; /** * Creates a new instance of {@link ResultIterator} for regular statements (on-demand query). @@ -82,14 +94,21 @@ public abstract class ResultIterator implements AutoCloseable { * @param isPreparedStatement True if the given statement is a {@link PreparedStatement}. * @throws DatabaseEngineException If a database access error occurs. */ - private ResultIterator(Statement statement, String sql, boolean isPreparedStatement) throws DatabaseEngineException { + private ResultIterator(final Statement statement, final String sql, final boolean isPreparedStatement) throws DatabaseEngineException { this.statement = statement; - this.columnNames = new ArrayList<>(); - this.currentRowCount = 0; // Process column names. try { long start = System.currentTimeMillis(); + + final Connection connection = statement.getConnection(); + this.previousAutocommit = connection.getAutoCommit(); + this.isWrappedInTransaction = needsWrapInTransaction(statement.getFetchSize()); + + if (isWrappedInTransaction) { + connection.setAutoCommit(false); + } + if (isPreparedStatement) { this.resultSet = ((PreparedStatement) statement).executeQuery(); this.statementCloseable = false; @@ -136,8 +155,7 @@ public ResultIterator(PreparedStatement statement) throws DatabaseEngineExceptio * Retrieves the number of rows processed by the iterator so far. If the iteration * hasn't started, this method returns 0. * - * @return The number of rows processed by the iterator so far or 0 if the - * iteration hasn't started. + * @return The number of rows processed by the iterator so far or 0 if the iteration hasn't started. */ public int getCurrentRowCount() { return this.currentRowCount; @@ -147,13 +165,10 @@ public int getCurrentRowCount() { * Retrieves the next row in the result set. *

* This method also closes the result set upon the last call on the result set. - *

*

* If the statement in place is not a {@link PreparedStatement} it also closes the statement. - *

*

* If an exception is thrown the calling thread is responsible for repeating the action in place. - *

* * @return The result row. * @throws DatabaseEngineException If a database access error occurs. @@ -250,11 +265,11 @@ public List getColumnNames() { /** * Attempts to cancel the current query. This relies on the JDBC driver supporting * {@link Statement#cancel()}, which is not guaranteed on all drivers. - * + *

* A possible use case for this method is to implement a timeout; If that's the case, see also * {@link com.feedzai.commons.sql.abstraction.engine.AbstractDatabaseEngine#iterator(String, int, int)} for * an alternative way to accomplish this. - * + *

* This method is expected to be invoked from a thread distinct of the one that is reading * from the result set. * @@ -278,22 +293,34 @@ public boolean cancel() { @Override public void close() { // Check for previous closed. - if (!closed) { + if (closed) { + return; + } + + if (statement != null && isWrappedInTransaction) { try { - if (resultSet != null) { - resultSet.close(); - } + statement.getConnection().setAutoCommit(previousAutocommit); + } catch (final Exception e) { + logger.warn("Could not reset autocommit.", e); + } + } + + if (resultSet != null) { + try { + resultSet.close(); } catch (final Exception e) { logger.warn("Could not close result set.", e); } - if (statementCloseable && statement != null) { - try { - statement.close(); - } catch (final Exception e) { - logger.warn("Could not close statement.", e); - } + } + + if (statementCloseable && statement != null) { + try { + statement.close(); + } catch (final Exception e) { + logger.warn("Could not close statement.", e); } } + // Assume closed even if it fails. closed = true; } @@ -333,4 +360,17 @@ private DatabaseEngineException closeAndHandleException(final Exception exceptio protected QueryExceptionHandler getQueryExceptionHandler() { return DEFAULT_QUERY_EXCEPTION_HANDLER; } + + /** + * Indicates whether this iterator needs to run inside a transaction. + * + * PostgreSQL (and also CockroachDB) need this in order to keep a cursor on the server, otherwise the fetchsize + * setting is ignored and all results are fetched from the database into memory at once. + * + * @param fetchSize The fetch size for result sets obtained in this iterator. + * @return Whether this iterator needs to run inside a transaction. + */ + protected boolean needsWrapInTransaction(final int fetchSize) { + return false; + } } diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java index 824100ac..8c09c432 100644 --- a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java @@ -19,9 +19,11 @@ import com.feedzai.commons.sql.abstraction.ddl.DbEntity; import com.feedzai.commons.sql.abstraction.ddl.DbEntityType; import com.feedzai.commons.sql.abstraction.dml.result.ResultColumn; +import com.feedzai.commons.sql.abstraction.dml.result.ResultIterator; import com.feedzai.commons.sql.abstraction.engine.AbstractDatabaseEngine; import com.feedzai.commons.sql.abstraction.engine.ConnectionResetException; import com.feedzai.commons.sql.abstraction.engine.DatabaseEngine; +import com.feedzai.commons.sql.abstraction.engine.DatabaseEngineDriver; import com.feedzai.commons.sql.abstraction.engine.DatabaseEngineException; import com.feedzai.commons.sql.abstraction.engine.DatabaseFactory; import com.feedzai.commons.sql.abstraction.engine.DatabaseFactoryException; @@ -61,6 +63,8 @@ import static com.feedzai.commons.sql.abstraction.engine.impl.abs.AbstractEngineSchemaTest.Ieee754Support.UNSUPPORTED; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; @@ -188,6 +192,57 @@ public void udfTimesTwoTest() throws Exception { } } + /** + * Tests that the different DB engines respect the fetch size set in a query. + * + * @throws Exception If any error occurs, thus failing the test. + */ + @Test + public void testFetchSize() throws Exception { + final DatabaseEngineDriver engineDriver = DatabaseEngineDriver.fromEngine(properties.getProperty(ENGINE)); + + final TestRouter testRouter = new TestRouter(engineDriver.defaultPort()); + testRouter.init(); + + final Properties testProps = TestRouter.getPatchedDbProperties(properties, testRouter.getDbPort(), testRouter.getLocalPort()); + testProps.setProperty(PdbProperties.SOCKET_TIMEOUT, "2"); + testProps.setProperty(PdbProperties.CHECK_CONNECTION_TIMEOUT, "2"); + + try (final DatabaseEngine engine = DatabaseFactory.getConnection(testProps)) { + final DbEntity entity = createSpecialValuesEntity(); + engine.addEntity(entity); + final String entityName = entity.getName(); + + for (int i = 0; i < 10; i++) { + engine.persist(entityName, entry().set(ID_COL, i).build()); + } + + // besides the connection timeouts, also set 2 seconds timeout for the query; fetch size = 3 + try (ResultIterator iterator = engine.iterator(select(all()).from(table(entityName)), 3, 2)) { + // if the first 3 rows aren't fetched immediately on the query, they will be fetched next + iterator.next(); + + // break the connection to the DB + testRouter.breakConnections(); + + // get next result, which should already have been fetched; connection shouldn't be needed and this shouldn't fail + assertThatCode(iterator::next) + .doesNotThrowAnyException(); + + // same as previous; ensures that the 3rd result is already fetched, and retries don't prevent from getting it + assertThatCode(iterator::next) + .doesNotThrowAnyException(); + + // 4th row should be fetched now, but since the connection is broken it should fail + // (unless the driver already fetched all results, which should fail the test) + assertThatThrownBy(iterator::next) + .isInstanceOf(DatabaseEngineException.class); + } + } finally { + testRouter.close(); + } + } + /** * After changing the oracle double data type from DOUBLE PRECISION to BINARY_DOUBLE the special * value 'NaN' should be inserted into the database without any error. diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/TestRouter.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/TestRouter.java new file mode 100644 index 00000000..afd29336 --- /dev/null +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/TestRouter.java @@ -0,0 +1,183 @@ +/* + * Copyright 2022 Feedzai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.feedzai.commons.sql.abstraction.engine.impl.abs; + +import com.feedzai.commons.sql.abstraction.engine.DatabaseEngine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Closeable; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static com.feedzai.commons.sql.abstraction.engine.configuration.PdbProperties.JDBC; + +/** + * A class that acts as a router, to forward data sent between a {@link DatabaseEngine} and the DB. + *

+ * When running tests, this offers the possibility of interrupting connections without closing them. + * + * @author José Fidalgo (jose.fidalgo@feedzai.com) + */ +public class TestRouter implements Closeable { + + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(TestRouter.class); + + /** + * The {@link ServerSocket} that will accept connections from PDB engines to this {@link TestRouter}. + */ + private final ServerSocket serverSocket = new ServerSocket(0); + + /** + * The {@link Socket} to connect this {@link TestRouter} to the database. + */ + private final Socket socketRouterToDb = new Socket(); + + /** + * An {@link ExecutorService} to handle asynchronous tasks. + */ + private final ExecutorService executor = Executors.newFixedThreadPool(3); + + /** + * The database port. + */ + private final int dbPort; + + /** + * Whether this {@link TestRouter} is running. + */ + private volatile boolean isRunning = true; + + /** + * Constructor for this class. + * + * @param dbPort The real DB server port. + * @throws IOException if some problem occurs creating a new {@link ServerSocket}. + */ + public TestRouter(final int dbPort) throws IOException { + this.dbPort = dbPort; + } + + /** + * Gets new DB properties with the JDBC URL patched to replace the default DB port with a new one. + * + * @param dbProperties The original DB properties. + * @param defaultPort The default DB port. + * @param newPort The port to use as replacement in the JDBC URL for the default DB port. + * @return The patched DB properties. + * @implNote This parses the JDBC URL assuming that the DB host is "localhost". + */ + public static Properties getPatchedDbProperties(final Properties dbProperties, final int defaultPort, final int newPort) { + final Properties testProps = new Properties(); + testProps.putAll(dbProperties); + + final String patchedJdbc = dbProperties.getProperty(JDBC) + .replace("localhost:" + defaultPort, "localhost:" + newPort); + testProps.setProperty(JDBC, patchedJdbc); + + return testProps; + } + + /** + * Gets the local port (that will act as the DB server port for the DB engine). + * + * @return the local port. + */ + public int getLocalPort() { + return serverSocket.getLocalPort(); + } + + /** + * Gets the database port (the port where the DB server being tested is listening). + * + * @return the database port. + */ + public int getDbPort() { + return dbPort; + } + + /** + * Initializes connections to/from the DB server. + * + * @throws IOException if there is a problem establishing connections. + */ + public void init() throws IOException { + socketRouterToDb.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), dbPort)); + + final Future socketFuture = executor.submit(serverSocket::accept); + + executor.submit(() -> { + final Socket socketTestToRouter = socketFuture.get(); + logger.info("Test-to-DB established"); + while (isRunning) { + int read = socketTestToRouter.getInputStream().read(); + socketRouterToDb.getOutputStream().write(read); + } + return null; + } + ); + + executor.submit(() -> { + final Socket socketTestToDb = socketFuture.get(); + logger.info("DB-to-Test established"); + while (isRunning) { + int read = socketRouterToDb.getInputStream().read(); + socketTestToDb.getOutputStream().write(read); + } + return null; + } + ); + } + + /** + * Terminates the forwarding of data to/from the DB server, thus breaking the connections (without closing them). + */ + public void breakConnections() { + isRunning = false; + logger.info("Connections broken"); + } + + @Override + public void close() { + closeSilently(socketRouterToDb); + closeSilently(serverSocket); + executor.shutdownNow(); + } + + /** + * Closes an {@link AutoCloseable} and ignores any exceptions. + * + * @param autoCloseable The AutoCloseable. + */ + private void closeSilently(final AutoCloseable autoCloseable) { + try { + autoCloseable.close(); + } catch (final Exception e) { + // ignore + } + } +} diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/TimeoutsTest.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/TimeoutsTest.java index 720303c3..11c83447 100644 --- a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/TimeoutsTest.java +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/TimeoutsTest.java @@ -21,25 +21,18 @@ import com.feedzai.commons.sql.abstraction.engine.DatabaseFactoryException; import com.feedzai.commons.sql.abstraction.engine.testconfig.DatabaseConfiguration; import com.feedzai.commons.sql.abstraction.engine.testconfig.DatabaseTestUtil; -import java.time.Duration; -import java.util.concurrent.Callable; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.io.Closeable; import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; import java.sql.DriverManager; +import java.time.Duration; import java.util.Collection; import java.util.Properties; +import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -70,11 +63,6 @@ @RunWith(Parameterized.class) public class TimeoutsTest { - /** - * The logger for this class. - */ - private static final Logger logger = LoggerFactory.getLogger(TimeoutsTest.class); - /** * An executor to run actions asynchronously. */ @@ -153,17 +141,14 @@ public void setupTest() throws IOException { engine != DatabaseEngineDriver.H2 && engine != DatabaseEngineDriver.H2V2 ); - testRouter = new TestRouter(executor, engine.defaultPort()); + testRouter = new TestRouter(engine.defaultPort()); } @After public void cleanResources() { - try { + if (testRouter != null) { testRouter.close(); - } catch (final Exception ex) { - // ignore } - executor.shutdownNow(); } @@ -210,7 +195,7 @@ public void testInvalidTimeoutsConfigured() throws Exception { */ @Test public void testLoginTimeout() { - final Properties testProps = getPatchedDbProperties(dbProps, testRouter.getDbPort(), testRouter.getLocalPort()); + final Properties testProps = TestRouter.getPatchedDbProperties(dbProps, testRouter.getDbPort(), testRouter.getLocalPort()); final Future dbEngineFuture = executor.submit(() -> DatabaseFactory.getConnection(testProps)); assertThatCode(() -> dbEngineFuture.get(LOGIN_TIMEOUT_SECONDS + TIMEOUT_TOLERANCE_SECONDS, TimeUnit.SECONDS)) @@ -235,7 +220,7 @@ public void testNetworkTimeout() throws Exception { props.put(CHECK_CONNECTION_TIMEOUT_SECONDS, 0); testRouter.init(); - final Properties testProps = getPatchedDbProperties(props, testRouter.getDbPort(), testRouter.getLocalPort()); + final Properties testProps = TestRouter.getPatchedDbProperties(props, testRouter.getDbPort(), testRouter.getLocalPort()); final DatabaseEngine dbEngine = executor.submit(() -> DatabaseFactory.getConnection(testProps)) .get(LOGIN_TIMEOUT_SECONDS + TIMEOUT_TOLERANCE_SECONDS, TimeUnit.SECONDS); @@ -271,7 +256,7 @@ we want to make sure that the login timeout (which is usually lower than socket @Test public void testConnectionVerificationTimeout() throws Exception { testRouter.init(); - final Properties testProps = getPatchedDbProperties(dbProps, + final Properties testProps = TestRouter.getPatchedDbProperties(dbProps, testRouter.getDbPort(), testRouter.getLocalPort()); @@ -301,115 +286,4 @@ we want to make sure that the login timeout (which is usually lower than socket assertFalse("PDB should detect that it is not connected to the server before the socket timeout", connCheckFuture.get(CHECK_CONNECTION_TIMEOUT_SECONDS - LOGIN_TIMEOUT_SECONDS, TimeUnit.SECONDS)); } - - /** - * Gets new DB properties with the JDBC URL patched to replace the default DB port with a new one. - * - * @param dbProperties The original DB properties. - * @param defaultPort The default DB port. - * @param newPort The port to use as replacement in the JDBC URL for the default DB port. - * @return The patched DB properties. - */ - private Properties getPatchedDbProperties(final Properties dbProperties, final int defaultPort, final int newPort) { - final Properties testProps = new Properties(); - testProps.putAll(dbProperties); - - final String patchedJdbc = dbProperties.getProperty(JDBC) - .replace("localhost:" + defaultPort, "localhost:" + newPort); - testProps.setProperty(JDBC, patchedJdbc); - - return testProps; - } - - /** - * A class that acts as a router, to forwards data sent between a {@link DatabaseEngine} in this test and the DB. - * This offers the possibility of interrupting the connections without closing them. - */ - private static class TestRouter implements Closeable { - - private final ServerSocket serverSocket = new ServerSocket(0); - private final Socket socketRouterToDb = new Socket(); - private final ExecutorService executor; - private final int dbPort; - private volatile boolean isRunning = true; - - /** - * Constructor for this class. - * - * @param executor An {@link ExecutorService} to run tasks asynchronously. - * @param dbPort The real DB server port. - * @throws IOException if some problem occurs creating a new {@link ServerSocket}. - */ - private TestRouter(final ExecutorService executor, final int dbPort) throws IOException { - this.executor = executor; - this.dbPort = dbPort; - } - - /** - * Gets the local port (that will act as the DB server port for the DB engine). - * - * @return the local port. - */ - public int getLocalPort() { - return serverSocket.getLocalPort(); - } - - /** - * Gets the database port (the port where the DB server being tested is listening). - * - * @return the database port. - */ - public int getDbPort() { - return dbPort; - } - - /** - * Initializes connections to/from the DB server. - * - * @throws IOException if there is a problem establishing connections. - */ - public void init() throws IOException { - socketRouterToDb.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), dbPort)); - - final Future socketFuture = executor.submit(serverSocket::accept); - - executor.submit(() -> { - final Socket socketTestToRouter = socketFuture.get(); - logger.info("Test-to-DB established"); - while (isRunning) { - int read = socketTestToRouter.getInputStream().read(); - socketRouterToDb.getOutputStream().write(read); - } - return null; - } - ); - - executor.submit(() -> { - final Socket socketTestToDb = socketFuture.get(); - logger.info("DB-to-Test established"); - while (isRunning) { - int read = socketRouterToDb.getInputStream().read(); - socketTestToDb.getOutputStream().write(read); - } - return null; - } - ); - } - - /** - * Terminates the forwarding of data to/from the DB server, thus breaking the connections (without closing them). - */ - public void breakConnections() { - isRunning = false; - } - - @Override - public void close() throws IOException { - try { - socketRouterToDb.close(); - } finally { - serverSocket.close(); - } - } - } } diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/h2/H2EngineSchemaTest.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/h2/H2EngineSchemaTest.java index 7cdec236..7c725c04 100644 --- a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/h2/H2EngineSchemaTest.java +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/h2/H2EngineSchemaTest.java @@ -21,6 +21,8 @@ import com.feedzai.commons.sql.abstraction.engine.impl.abs.AbstractEngineSchemaTest; import com.feedzai.commons.sql.abstraction.engine.testconfig.DatabaseConfiguration; import com.feedzai.commons.sql.abstraction.engine.testconfig.DatabaseTestUtil; +import org.junit.Ignore; +import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -45,6 +47,12 @@ protected Ieee754Support getIeee754Support() { return SUPPORTED_STRINGS; } + @Override + @Test + @Ignore("H2 respects the fetch size, but takes a *very* long time to timeout on closing the DatabaseEngine/ResultSet") + public void testFetchSize() { + } + @Override protected void defineUDFGetOne(final DatabaseEngine engine) throws DatabaseEngineException { engine.executeUpdate("DROP ALIAS IF EXISTS GetOne"); diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/mysql/MySqlEngineSchemaTest.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/mysql/MySqlEngineSchemaTest.java index ab417647..3a52fc1e 100644 --- a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/mysql/MySqlEngineSchemaTest.java +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/mysql/MySqlEngineSchemaTest.java @@ -20,6 +20,8 @@ import com.feedzai.commons.sql.abstraction.engine.impl.abs.AbstractEngineSchemaTest; import com.feedzai.commons.sql.abstraction.engine.testconfig.DatabaseConfiguration; import com.feedzai.commons.sql.abstraction.engine.testconfig.DatabaseTestUtil; +import org.junit.Ignore; +import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -37,6 +39,15 @@ public static Collection data() throws Exception { return DatabaseTestUtil.loadConfigurations("mysql"); } + @Override + @Test + @Ignore("MySQL doesn't respect fetch size unless we use a server cursor, which can be enabled by setting the property" + + " 'useCursorFetch' to true in the JDBC URL. However, when server cursor is enabled, the query timeouts are" + + " not respected." + + "See https://bugs.mysql.com/bug.php?id=106465") + public void testFetchSize() { + } + @Override protected void defineUDFGetOne(final DatabaseEngine engine) throws DatabaseEngineException { engine.executeUpdate("DROP FUNCTION IF EXISTS GetOne"); diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/sqlserver/SqlServerEngineSchemaTest.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/sqlserver/SqlServerEngineSchemaTest.java index 4311eb37..64fa9b95 100644 --- a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/sqlserver/SqlServerEngineSchemaTest.java +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/sqlserver/SqlServerEngineSchemaTest.java @@ -46,6 +46,14 @@ public static Collection data() throws Exception { public void udfTimesTwoTest() { } + @Override + @Test + @Ignore("Microsoft Sql Server doesn't respect fetch size unless we use a server cursor, but that seems unnecessary" + + " because by default it uses adaptative buffering and doesn't fetch all results into memory." + + "See https://docs.microsoft.com/en-us/sql/connect/jdbc/using-adaptive-buffering") + public void testFetchSize() { + } + @Override @Test @Ignore("Microsoft Sql Server doesn't support setting schema per session")