factor out subprojects: oracle, postgresql, mariadb, fix pool tests

main
Jörg Prante 2 years ago
parent 1409d0e42d
commit ca784dc6cf

@ -6,13 +6,13 @@ java {
}
compileJava {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
compileTestJava {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
jar {
@ -35,7 +35,7 @@ artifacts {
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:all,-fallthrough'
options.compilerArgs << '-Xlint:all,-fallthrough,-exports,-try'
}
javadoc {

@ -1,6 +1,6 @@
module org.xbib.jdbc.connection.pool {
requires java.logging;
requires transitive java.sql;
requires java.sql;
exports org.xbib.jdbc.connection.pool;
exports org.xbib.jdbc.connection.pool.util;
}

@ -16,14 +16,6 @@ public class PoolConfig {
private static final AtomicLong POOL_COUNTER = new AtomicLong();
private static final long CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
private static final long VALIDATION_TIMEOUT = TimeUnit.SECONDS.toMillis(5);
private static final long IDLE_TIMEOUT = TimeUnit.MINUTES.toMillis(10);
private static final long MAX_LIFETIME = TimeUnit.MINUTES.toMillis(30);
private static final int DEFAULT_POOL_SIZE = 8;
private final Properties properties;
@ -100,20 +92,28 @@ public class PoolConfig {
this.properties = properties;
this.minIdle = -1;
this.maxPoolSize = -1;
this.maxLifetime = MAX_LIFETIME;
this.connectionTimeout = CONNECTION_TIMEOUT;
this.validationTimeout = VALIDATION_TIMEOUT;
this.idleTimeout = IDLE_TIMEOUT;
this.maxLifetime = TimeUnit.MINUTES.toMillis(30);
this.connectionTimeout = TimeUnit.SECONDS.toMillis(30);
this.validationTimeout = TimeUnit.SECONDS.toMillis(5);
this.idleTimeout = TimeUnit.MINUTES.toMillis(1);
this.initializationFailTimeout = -1;
this.isAutoCommit = true;
this.isAutoCommit = true; // JDBC convention
this.aliveBypassWindowMs = TimeUnit.MILLISECONDS.toMillis(500);
this.housekeepingPeriodMs = TimeUnit.SECONDS.toMillis(30);
}
/**
* Set the JDBC URL.
* @param url the JDBC url as string
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Get the JDBC URL.
* @return the JDBC URL as string
*/
public String getUrl() {
return url;
}
@ -407,7 +407,7 @@ public class PoolConfig {
* case that a connection cannot be obtained. However, upon start the pool will
* attempt to obtain a connection and validate that the {@code connectionTestQuery}
* and {@code connectionInitSql} are valid. If those validations fail, an exception
* will be thrown. If a connection cannot be obtained, the validation is skipped
* will be thrown. If a connection cannot be obtained, the validation is skipped
* and the the pool will start and continue to try to obtain connections in the
* background. This can mean that callers to {@code DataSource#getConnection()} may
* encounter exceptions. </li>
@ -432,7 +432,7 @@ public class PoolConfig {
/**
* Determine whether internal pool queries, principally aliveness checks, will be isolated in their own transaction
* via {@link Connection#rollback()}. Defaults to {@code false}.
* via {@link Connection#rollback()}. Defaults to {@code false}.
*
* @return {@code true} if internal pool queries are isolated, {@code false} if not
*/
@ -442,7 +442,7 @@ public class PoolConfig {
/**
* Configure whether internal pool queries, principally aliveness checks, will be isolated in their own transaction
* via {@link Connection#rollback()}. Defaults to {@code false}.
* via {@link Connection#rollback()}. Defaults to {@code false}.
*
* @param isolate {@code true} if internal pool queries should be isolated, {@code false} if not
*/
@ -450,15 +450,6 @@ public class PoolConfig {
this.isIsolateInternalQueries = isolate;
}
/**
* Determine whether the Connections in the pool are in read-only mode.
*
* @return {@code true} if the Connections in the pool are read-only, {@code false} if not
*/
public boolean isReadOnly() {
return isReadOnly;
}
/**
* Configures the Connections to be added to the pool as read-only Connections.
*
@ -468,8 +459,13 @@ public class PoolConfig {
this.isReadOnly = readOnly;
}
public String getPoolName() {
return poolName;
/**
* Determine whether the Connections in the pool are in read-only mode.
*
* @return {@code true} if the Connections in the pool are read-only, {@code false} if not
*/
public boolean isReadOnly() {
return isReadOnly;
}
/**
@ -482,6 +478,10 @@ public class PoolConfig {
this.poolName = poolName;
}
public String getPoolName() {
return poolName;
}
/**
* Get the ScheduledExecutorService used for housekeeping.
*
@ -628,26 +628,26 @@ public class PoolConfig {
private void validateNumerics() {
if (maxLifetime != 0 && maxLifetime < TimeUnit.SECONDS.toMillis(30)) {
logger.log(Level.WARNING, "maxLifetime is less than 30000ms, setting to default ms: " +
poolName + " " + MAX_LIFETIME);
maxLifetime = MAX_LIFETIME;
logger.log(Level.WARNING, "maxLifetime is less than 30s, setting to default ms: " +
poolName + " " + TimeUnit.SECONDS.toMillis(30));
maxLifetime = TimeUnit.SECONDS.toMillis(30);
}
if (leakDetectionThreshold > 0) {
if (leakDetectionThreshold < TimeUnit.SECONDS.toMillis(2) || (leakDetectionThreshold > maxLifetime && maxLifetime > 0)) {
logger.log(Level.WARNING, "leakDetectionThreshold is less than 2000ms or more than maxLifetime, disabling it: " +
logger.log(Level.WARNING, "leakDetectionThreshold is less than 2s or more than maxLifetime, disabling it: " +
poolName);
leakDetectionThreshold = 0;
}
}
if (connectionTimeout < 250) {
logger.log(Level.WARNING, "connectionTimeout is less than 250ms, setting to ms: " +
poolName + " " + CONNECTION_TIMEOUT);
connectionTimeout = CONNECTION_TIMEOUT;
poolName + " " + TimeUnit.MILLISECONDS.toMillis(250));
connectionTimeout = TimeUnit.MILLISECONDS.toMillis(250);
}
if (validationTimeout < 250) {
logger.log(Level.WARNING, "validationTimeout is less than 250ms, setting to ms" +
poolName + " " + VALIDATION_TIMEOUT);
validationTimeout = VALIDATION_TIMEOUT;
poolName + " " + TimeUnit.MILLISECONDS.toMillis(250));
validationTimeout = TimeUnit.MILLISECONDS.toMillis(250);
}
if (maxPoolSize < 1) {
maxPoolSize = DEFAULT_POOL_SIZE;
@ -659,10 +659,10 @@ public class PoolConfig {
logger.log(Level.WARNING, "idleTimeout is close to or more than maxLifetime, disabling it:" + poolName);
idleTimeout = 0;
} else if (idleTimeout != 0 && idleTimeout < TimeUnit.SECONDS.toMillis(10) && minIdle < maxPoolSize) {
logger.log(Level.WARNING, "idleTimeout is less than 10000ms, setting to default ms: " +
poolName + " " + IDLE_TIMEOUT);
idleTimeout = IDLE_TIMEOUT;
} else if (idleTimeout != IDLE_TIMEOUT && idleTimeout != 0 && minIdle == maxPoolSize) {
logger.log(Level.WARNING, "idleTimeout is less than 10s, setting to default ms: " +
poolName + " " + TimeUnit.SECONDS.toMillis(10));
idleTimeout = TimeUnit.SECONDS.toMillis(10);
} else if (idleTimeout != TimeUnit.SECONDS.toMillis(10) && idleTimeout != 0 && minIdle == maxPoolSize) {
logger.log(Level.WARNING, "idleTimeout has been set but has no effect because the pool is operating as a fixed size pool: " + poolName);
}
}

@ -15,9 +15,9 @@ import org.xbib.jdbc.connection.pool.PoolDataSource;
public class ConcurrentCloseConnectionTest
{
@Test
public void testConcurrentClose() throws Exception
{
public void testConcurrentClose() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
try (PoolDataSource ds = new PoolDataSource(config);
final Connection connection = ds.getConnection()) {

@ -31,6 +31,7 @@ public class ConnectionCloseBlockingTest {
@Test
public void testConnectionCloseBlocking() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(1500);

@ -63,6 +63,7 @@ public class ConnectionPoolSizeVsThreadsTest {
LOGGER.info(MessageFormat.format("Starting test (minIdle={0}, maxPoolSize={1}, threadCount={2}, workTimeMs={3}, restTimeMs={4}, connectionAcquisitionTimeMs={5}, iterations={6}, postTestTimeMs={7})",
minIdle, maxPoolSize, threadCount, workTimeMs, restTimeMs, connectionAcquisitionTimeMs, iterations, postTestTimeMs));
final PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(minIdle);
config.setMaximumPoolSize(maxPoolSize);
config.setInitializationFailTimeout(Long.MAX_VALUE);

@ -21,6 +21,7 @@ public class ConnectionRaceConditionTest {
@Test
public void testRaceCondition() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(10);
config.setInitializationFailTimeout(Long.MAX_VALUE);

@ -20,9 +20,9 @@ public class ConnectionStateTest {
Properties properties = new Properties();
properties.put("user", "bar");
properties.put("password", "secret");
properties.put("url", "baf");
properties.put("loginTimeout", "10");
PoolConfig config = new PoolConfig(properties);
config.setUrl("jdbc:stub");
config.setAutoCommit(true);
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
@ -41,6 +41,7 @@ public class ConnectionStateTest {
public void testTransactionIsolation() throws Exception {
Properties properties = new Properties();
PoolConfig config = new PoolConfig(properties);
config.setUrl("jdbc:stub");
config.setTransactionIsolation("TRANSACTION_READ_COMMITTED");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
@ -58,6 +59,7 @@ public class ConnectionStateTest {
@Test
public void testIsolation() {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
config.setTransactionIsolation("TRANSACTION_REPEATABLE_READ");
config.validate();
@ -68,6 +70,7 @@ public class ConnectionStateTest {
@Test
public void testReadOnly() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setCatalog("test");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
@ -85,6 +88,7 @@ public class ConnectionStateTest {
@Test
public void testCatalog() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setCatalog("test");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
@ -95,6 +99,7 @@ public class ConnectionStateTest {
Connection unwrap = connection.unwrap(Connection.class);
connection.setCatalog("other");
connection.close();
// after close, we can access unwrap
assertEquals("test", unwrap.getCatalog());
}
}
@ -103,6 +108,7 @@ public class ConnectionStateTest {
@Test
public void testCommitTracking() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setAutoCommit(false);
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);

@ -34,6 +34,7 @@ public class ConnectionTest {
@Test
public void testCreate() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setConnectionTestQuery("VALUES 1");
@ -69,6 +70,7 @@ public class ConnectionTest {
@Test
public void testMaxLifetime() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(1500);
@ -110,6 +112,7 @@ public class ConnectionTest {
@Test
public void testMaxLifetime2() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(2500);
@ -149,6 +152,7 @@ public class ConnectionTest {
@Test
public void testDoubleClose() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(2500);
@ -167,6 +171,7 @@ public class ConnectionTest {
@Test
public void testEviction() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(5);
config.setConnectionTimeout(2500);
@ -184,11 +189,11 @@ public class ConnectionTest {
@Test
public void testEviction2() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMaximumPoolSize(5);
config.setConnectionTimeout(2500);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
//config.setExceptionOverrideClassName(OverrideHandler.class.getName());
try (PoolDataSource ds = new PoolDataSource(config)) {
Pool pool = ds.getPool();
while (pool.getTotalConnections() < 5) {
@ -214,6 +219,7 @@ public class ConnectionTest {
@Test
public void testEviction3() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMaximumPoolSize(5);
config.setConnectionTimeout(2500);
config.setConnectionTestQuery("VALUES 1");
@ -243,6 +249,7 @@ public class ConnectionTest {
@Test
public void testEvictAllRefill() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(5);
config.setMaximumPoolSize(10);
config.setConnectionTimeout(2500);
@ -268,6 +275,7 @@ public class ConnectionTest {
@Test
public void testBackfill() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(4);
config.setConnectionTimeout(1000);
@ -309,6 +317,7 @@ public class ConnectionTest {
@Test
public void testMaximumPoolLimit() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(4);
config.setConnectionTimeout(20000);
@ -348,6 +357,7 @@ public class ConnectionTest {
@Test
public void testOldDriver() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(2500);
@ -375,6 +385,7 @@ public class ConnectionTest {
StubDataSource stubDataSource = new StubDataSource();
stubDataSource.setThrowException(new SQLException("Connection refused"));
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(2500);
@ -394,6 +405,7 @@ public class ConnectionTest {
StubDataSource stubDataSource = new StubDataSource();
stubDataSource.setThrowException(new SQLException("Connection refused"));
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setConnectionTestQuery("VALUES 1");
config.setDataSource(stubDataSource);
@ -420,6 +432,7 @@ public class ConnectionTest {
}
};
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(3));
@ -448,6 +461,7 @@ public class ConnectionTest {
StubDataSourceWithErrorSwitch stubDataSource = new StubDataSourceWithErrorSwitch();
stubDataSource.setErrorOnConnection(true);
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setConnectionTestQuery("VALUES 1");
config.setDataSource(stubDataSource);
@ -465,6 +479,7 @@ public class ConnectionTest {
public void testDataSourceRaisesErrorAfterInitializationTestQuery() throws Exception {
StubDataSourceWithErrorSwitch stubDataSource = new StubDataSourceWithErrorSwitch();
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(2);
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(3));
@ -486,6 +501,7 @@ public class ConnectionTest {
@Test
public void testPopulationSlowAcquisition() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMaximumPoolSize(20);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
@ -515,6 +531,7 @@ public class ConnectionTest {
@Test
public void testMinimumIdleZero() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(5);
config.setConnectionTimeout(1000L);
@ -545,11 +562,4 @@ public class ConnectionTest {
this.errorOnConnection = errorOnConnection;
}
}
/*public static class OverrideHandler implements SQLExceptionOverride {
@java.lang.Override
public Override adjudicate(SQLException sqlException) {
return (sqlException.getSQLState().equals("08999")) ? Override.DO_NOT_EVICT : Override.CONTINUE_EVICT;
}
}*/
}

@ -22,6 +22,7 @@ public class ConnectionTimeoutRetryTest {
@Test
public void testConnectionRetries() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(2800);
@ -46,6 +47,7 @@ public class ConnectionTimeoutRetryTest {
@Test
public void testConnectionRetries2() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(2800);
@ -76,6 +78,7 @@ public class ConnectionTimeoutRetryTest {
@Test
public void testConnectionRetries3() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(2);
config.setConnectionTimeout(2800);
@ -114,6 +117,7 @@ public class ConnectionTimeoutRetryTest {
@Test
public void testConnectionRetries5() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(2);
config.setConnectionTimeout(1000);
@ -151,6 +155,7 @@ public class ConnectionTimeoutRetryTest {
public void testConnectionIdleFill() throws Exception {
StubConnection.slowCreate = false;
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(5);
config.setMaximumPoolSize(10);
config.setConnectionTimeout(2000);

@ -28,6 +28,7 @@ public class HouseKeeperCleanupTest {
@Test
public void testHouseKeeperCleanupWithCustomExecutor() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(10);
config.setInitializationFailTimeout(Long.MAX_VALUE);

@ -12,6 +12,7 @@ public class IsolationTest {
@Test
public void testIsolation() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setIsolateInternalQueries(true);
@ -31,6 +32,7 @@ public class IsolationTest {
@Test
public void testNonIsolation() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setIsolateInternalQueries(false);

@ -25,10 +25,10 @@ public class JdbcDriverTest {
@Test
public void driverTest1() throws Exception {
Properties properties = new Properties();
properties.put("url", "jdbc:stub");
properties.put("user", "bart");
properties.put("password", "simpson");
PoolConfig config = new PoolConfig(properties);
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setConnectionTestQuery("VALUES 1");
@ -46,8 +46,8 @@ public class JdbcDriverTest {
@Test
public void driverTest2() throws Exception {
Properties properties = new Properties();
properties.put("url", "jdbc:invalid");
PoolConfig config = new PoolConfig(properties);
config.setUrl("jdbc:invalid");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setConnectionTestQuery("VALUES 1");

@ -23,18 +23,17 @@ public class PoolTest {
@BeforeAll
static void setup() throws Exception {
Properties properties = new Properties();
properties.put("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
PoolConfig config = new PoolConfig(properties);
config.setUrl("jdbc:h2:mem:test");
config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
config.setConnectionTestQuery("SELECT 1");
config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
try (PoolDataSource ds = new PoolDataSource(config);
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement()) {
stmt.executeUpdate("DROP TABLE IF EXISTS basic_pool_test");
stmt.executeUpdate("CREATE TABLE basic_pool_test ("
+ "id INTEGER NOT NULL IDENTITY PRIMARY KEY, "
+ "id INTEGER PRIMARY KEY, "
+ "timestamp TIMESTAMP, "
+ "string VARCHAR(128), "
+ "string_from_number NUMERIC "
@ -45,12 +44,11 @@ public class PoolTest {
@Test
public void testIdleTimeout() throws Exception {
Properties properties = new Properties();
properties.put("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
PoolConfig config = new PoolConfig(properties);
config.setUrl("jdbc:h2:mem:test");
config.setMinimumIdle(5);
config.setMaximumPoolSize(10);
config.setConnectionTestQuery("SELECT 1");
config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
System.setProperty("pool.jdbc.housekeeping.periodMs", "1000");
try (PoolDataSource ds = new PoolDataSource(config)) {
System.clearProperty("pool.jdbc.housekeeping.periodMs");
@ -79,11 +77,10 @@ public class PoolTest {
@Test
public void testIdleTimeout2() throws Exception {
Properties properties = new Properties();
properties.put("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
PoolConfig config = new PoolConfig(properties);
config.setUrl("jdbc:h2:mem:test");
config.setMaximumPoolSize(50);
config.setConnectionTestQuery("SELECT 1");
config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
System.setProperty("pool.jdbc.housekeeping.periodMs", "1000");
try (PoolDataSource ds = new PoolDataSource(config)) {
System.clearProperty("pool.jdbc.housekeeping.periodMs");

@ -3,32 +3,12 @@ package org.xbib.io.pool.jdbc;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.util.Locale;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import org.xbib.jdbc.connection.pool.IsolationLevel;
public class PoolTestExtension implements BeforeAllCallback {
@Override
public void beforeAll(ExtensionContext context) {
//Level level = Level.INFO;
Level level = Level.ALL;
System.setProperty("java.util.logging.SimpleFormatter.format",
"%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s %6$s%n");
LogManager.getLogManager().reset();
Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler handler = new ConsoleHandler();
handler.setFormatter(new SimpleFormatter());
rootLogger.addHandler(handler);
rootLogger.setLevel(level);
for (Handler h : rootLogger.getHandlers()) {
handler.setFormatter(new SimpleFormatter());
h.setLevel(level);
}
}
public static void quietlySleep(long millis) {

@ -22,6 +22,7 @@ public class ProxiesTest {
@Test
public void testProxyCreation() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTestQuery("VALUES 1");
@ -55,6 +56,7 @@ public class ProxiesTest {
@Test
public void testStatementProxy() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTestQuery("VALUES 1");
@ -81,6 +83,7 @@ public class ProxiesTest {
@Test
public void testStatementExceptions() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(1));
@ -168,6 +171,7 @@ public class ProxiesTest {
@Test
public void testOtherExceptions() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setConnectionTestQuery("VALUES 1");

@ -14,6 +14,7 @@ public class RampUpDownTest {
@Test
public void rampUpDownTest() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(5);
config.setMaximumPoolSize(60);
config.setInitializationFailTimeout(0);

@ -29,6 +29,7 @@ public class SaturatedPoolTest830 {
@Test
public void saturatedPoolTest() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(5);
config.setMaximumPoolSize(MAX_POOL_SIZE);
config.setInitializationFailTimeout(Long.MAX_VALUE);

@ -117,6 +117,7 @@ public class ShutdownTest {
public void testShutdown4() throws Exception {
StubConnection.slowCreate = true;
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(10);
config.setMaximumPoolSize(10);
config.setInitializationFailTimeout(Long.MAX_VALUE);
@ -137,6 +138,7 @@ public class ShutdownTest {
public void testShutdown5() throws Exception {
assertSame( 0, StubConnection.count.get(), "StubConnection count not as expected");
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(5);
config.setMaximumPoolSize(5);
config.setInitializationFailTimeout(0);
@ -158,6 +160,7 @@ public class ShutdownTest {
@Test
public void testAfterShutdown() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(0);
config.setMaximumPoolSize(5);
config.setInitializationFailTimeout(0);
@ -177,6 +180,7 @@ public class ShutdownTest {
@Test
public void testShutdownDuringInit() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(5);
config.setMaximumPoolSize(5);
config.setConnectionTimeout(1000);
@ -193,6 +197,7 @@ public class ShutdownTest {
@Test
public void testThreadedShutdown() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(5);
config.setMaximumPoolSize(5);
config.setConnectionTimeout(1000);

@ -19,6 +19,7 @@ public class StatementTest {
@BeforeEach
public void setup() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
config.setConnectionTestQuery("VALUES 1");

@ -19,6 +19,7 @@ public class UnwrapTest {
@Test
public void testUnwrapConnection() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setInitializationFailTimeout(0);
@ -37,6 +38,7 @@ public class UnwrapTest {
@Test
public void testUnwrapDataSource() throws Exception {
PoolConfig config = new PoolConfig();
config.setUrl("jdbc:stub");
config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
config.setInitializationFailTimeout(0);

@ -0,0 +1,10 @@
handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level=ALL
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s %6$s%n
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.pattern=build/database.log
jdk.event.security.level=INFO
javax.management.level=INFO

@ -0,0 +1,12 @@
dependencies {
api project(':jdbc-query')
implementation libs.mariadb
testImplementation project(':jdbc-test')
testImplementation libs.testcontainers
testImplementation libs.testcontainers.junit.jupiter
testImplementation libs.testcontainers.mariadb
}
test {
systemProperty 'user.timezone', 'GMT'
}

@ -0,0 +1,10 @@
import org.xbib.jdbc.query.Flavor;
import org.xbib.jdbc.mariadb.MariaDB;
module org.xbib.jdbc.mariadb {
requires org.xbib.jdbc.query;
requires java.sql;
uses Flavor;
exports org.xbib.jdbc.mariadb;
provides Flavor with MariaDB;
}

@ -1,27 +1,33 @@
package org.xbib.jdbc.query.flavor;
package org.xbib.jdbc.mariadb;
import org.xbib.jdbc.query.Flavor;
public class MySQL implements Flavor {
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class MariaDB implements Flavor {
public MariaDB() {
}
@Override
public String getName() {
return "mysql";
return "mariadb";
}
@Override
public boolean supports(String url) {
return url.startsWith("jdbc:mysql:");
return url.startsWith("jdbc:mariadb:");
}
@Override
public String driverClass() {
return "com.mysql.jdbc.Driver";
return "org.mariadb.jdbc.Driver";
}
@Override
public boolean isNormalizedUpperCase() {
return true;
return false;
}
@Override
@ -41,7 +47,12 @@ public class MySQL implements Flavor {
@Override
public String typeFloat() {
return "real";
return "double";
}
@Override
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
preparedStatement.setFloat(i, floatValue);
}
@Override
@ -49,6 +60,11 @@ public class MySQL implements Flavor {
return "double";
}
@Override
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
preparedStatement.setDouble(i, doubleValue);
}
@Override
public String typeBigDecimal(int size, int precision) {
return "numeric(" + size + "," + precision + ")";
@ -56,6 +72,9 @@ public class MySQL implements Flavor {
@Override
public String typeStringVar(int length) {
if (length == 16777215) {
return "mediumtext";
}
return "varchar(" + length + ")";
}
@ -66,17 +85,17 @@ public class MySQL implements Flavor {
@Override
public String typeClob() {
return "clob";
return "mediumtext"; // mediumtext = varchar(16777215), longtext = varchar(0)
}
@Override
public String typeBlob() {
return "blob";
return "mediumblob";
}
@Override
public String typeLocalDateTime() {
return "timestamp";
return "datetime(3)";
}
@Override
@ -86,67 +105,67 @@ public class MySQL implements Flavor {
@Override
public boolean useStringForClob() {
return false;
return true;
}
@Override
public boolean useBytesForBlob() {
return false;
return true;
}
@Override
public String sequenceNextVal(String sequenceName) {
return "next value for " + sequenceName;
return "next value for " + sequenceName + "";
}
@Override
public String sequenceSelectNextVal(String sequenceName) {
return "values next value for " + sequenceName;
return "select " + sequenceNextVal(sequenceName) + fromAny();
}
@Override
public String sequenceDrop(String sequenceName) {
return "drop sequence " + sequenceName + " restrict";
public String sequenceDrop(String dbtestSeq) {
return "drop sequence if exists " + dbtestSeq;
}
@Override
public String tableDrop(String table) {
return "drop table " + table;
return "drop table if exists " + table;
}
@Override
public boolean supportsInsertReturning() {
return false;
public String sequenceOrderClause(boolean order) {
return "";
}
@Override
public String sequenceCacheClause(int nbrValuesToCache) {
public String sequenceCycleClause(boolean cycle) {
return "";
}
@Override
public String sequenceOrderClause(boolean order) {
public String fromAny() {
return "";
}
@Override
public String sequenceCycleClause(boolean cycle) {
return cycle ? " cycle" : " no cycle";
public boolean supportsInsertReturning() {
return false;
}
@Override
public String dbTimeMillis() {
return "current_timestamp";
return "localtimestamp(3)";
}
@Override
public String fromAny() {
return " from sysibm.sysdummy1";
public String sequenceCacheClause(int nbrValuesToCache) {
return " cache " + nbrValuesToCache;
}
@Override
public String sequenceOptions() {
return " as bigint";
return "";
}
@Override
@ -156,22 +175,25 @@ public class MySQL implements Flavor {
@Override
public String writeNextIntoQueue(String table) {
throw new UnsupportedOperationException();
return "insert into " + table
+ " (channel, data, state, delay, modified) "
+ "values (?, ?, null, 0, ?)";
}
@Override
public String readNextFromQueue(String table) {
throw new UnsupportedOperationException();
return "select id, data from " + table +
" where channel = ? and state is NULL and pushed_at <= (CAST (? as TIMESTAMP) - (INTERVAL '1 minute' * delay))" +
" order by id asc limit 1 for update skip lock";
}
@Override
public String succeedInQueue(String table) {
throw new UnsupportedOperationException();
return "update" + table + " set state = 'OK', modified = " + dbTimeMillis() + " where id = ?";
}
@Override
public String failInQueue(String table) {
throw new UnsupportedOperationException();
return "update" + table + " set state = 'FAIL', modified = " + dbTimeMillis() + " where id = ?";
}
}

@ -0,0 +1,108 @@
package org.xbib.jdbc.mariadb.test;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.MariaDBContainer;
import org.xbib.jdbc.query.Config;
import org.xbib.jdbc.query.ConfigSupplier;
import org.xbib.jdbc.query.DatabaseProvider;
import org.xbib.jdbc.query.OptionsOverride;
import org.xbib.jdbc.test.CommonTest;
public class MariaDBTest extends CommonTest {
static MariaDBContainer<?> mariaDBContainer;
static {
mariaDBContainer = new MariaDBContainer<>("mariadb")
.withDatabaseName("testDB")
.withUsername("testUser")
.withPassword("testPassword");
}
@BeforeAll
public static void startContainer() {
mariaDBContainer.start();
}
@AfterAll
public static void stopContainer() {
mariaDBContainer.stop();
}
@Override
protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception {
Config config = ConfigSupplier.of()
.property("database.url", mariaDBContainer.getJdbcUrl())
.property("database.user", "testUser")
.property("database.password", "testPassword")
.get();
return DatabaseProvider.builder(config)
.withSqlParameterLogging()
.withSqlInExceptionMessages()
.withOptions(options)
.build();
}
@Disabled("MariaDB prohibits NaN and Infinity")
@Test
public void argFloatNaN() {
super.argFloatNaN();
}
@Disabled("MariaDB prohibits NaN and Infinity")
@Test
public void argFloatInfinity() {
super.argFloatInfinity();
}
@Disabled("MariaDB prohibits NaN and Infinity")
@Test
public void argDoubleNaN() {
super.argDoubleNaN();
}
@Disabled("MariaDB prohibits NaN and Infinity")
@Test
public void argDoubleInfinity() {
super.argDoubleInfinity();
}
@Disabled("MariaDB prohibits NaN and Infinity")
@Test
public void argFloatNegativeZero() {
super.argFloatNegativeZero();
}
@Disabled("MariaDB prohibits NaN and Infinity")
@Test
public void argDoubleNegativeZero() {
super.argDoubleNegativeZero();
}
@Disabled("MariaDB temporarily disabled")
@Override
public void intervals() {
super.intervals();
}
@Disabled("MariaDB temporarily disabled")
@Override
public void metadataColumnNames() {
super.intervals();
}
@Disabled("MariaDB temporarily disabled")
@Override
public void metadataColumnTypes() {
super.metadataColumnTypes();
}
@Disabled("MariaDB temporarily disabled")
@Override
public void saveResultAsTable() {
super.saveResultAsTable();
}
}

@ -0,0 +1,10 @@
handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level=ALL
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s %6$s%n
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.pattern=build/database.log
jdk.event.security.level=INFO
javax.management.level=INFO

@ -0,0 +1,12 @@
dependencies {
api project(':jdbc-query')
implementation libs.oracle
testImplementation project(':jdbc-test')
testImplementation libs.testcontainers
testImplementation libs.testcontainers.junit.jupiter
testImplementation libs.testcontainers.oracle.xe
}
test {
systemProperty 'user.timezone', 'GMT'
}

@ -0,0 +1,12 @@
import org.xbib.jdbc.oracle.Oracle;
import org.xbib.jdbc.query.Flavor;
module org.xbib.jdbc.oracle {
requires org.xbib.jdbc.query;
requires org.xbib.jdbc.connection.pool;
requires com.oracle.database.jdbc;
requires java.sql;
uses Flavor;
exports org.xbib.jdbc.oracle;
provides Flavor with Oracle;
}

@ -1,9 +1,17 @@
package org.xbib.jdbc.query.flavor;
package org.xbib.jdbc.oracle;
import oracle.jdbc.OraclePreparedStatement;
import org.xbib.jdbc.connection.pool.ProxyPreparedStatement;
import org.xbib.jdbc.query.Flavor;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Oracle implements Flavor {
public Oracle() {
}
@Override
public String getName() {
return "oracle";
@ -29,11 +37,31 @@ public class Oracle implements Flavor {
return "binary_float";
}
@Override
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
if (preparedStatement instanceof ProxyPreparedStatement) {
ProxyPreparedStatement proxyPreparedStatement = (ProxyPreparedStatement) preparedStatement;
((OraclePreparedStatement) proxyPreparedStatement.getDelegate()).setBinaryFloat(i, floatValue);
} else {
((OraclePreparedStatement) preparedStatement).setBinaryFloat(i, floatValue);
}
}
@Override
public String typeDouble() {
return "binary_double";
}
@Override
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
if (preparedStatement instanceof ProxyPreparedStatement) {
ProxyPreparedStatement proxyPreparedStatement = (ProxyPreparedStatement) preparedStatement;