factor out subprojects: oracle, postgresql, mariadb, fix pool tests
This commit is contained in:
parent
1409d0e42d
commit
ca784dc6cf
73 changed files with 2546 additions and 755 deletions
|
@ -6,13 +6,13 @@ java {
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
compileTestJava {
|
compileTestJava {
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
@ -35,7 +35,7 @@ artifacts {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
options.compilerArgs << '-Xlint:all,-fallthrough'
|
options.compilerArgs << '-Xlint:all,-fallthrough,-exports,-try'
|
||||||
}
|
}
|
||||||
|
|
||||||
javadoc {
|
javadoc {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module org.xbib.jdbc.connection.pool {
|
module org.xbib.jdbc.connection.pool {
|
||||||
requires java.logging;
|
requires java.logging;
|
||||||
requires transitive java.sql;
|
requires java.sql;
|
||||||
exports org.xbib.jdbc.connection.pool;
|
exports org.xbib.jdbc.connection.pool;
|
||||||
exports org.xbib.jdbc.connection.pool.util;
|
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 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 static final int DEFAULT_POOL_SIZE = 8;
|
||||||
|
|
||||||
private final Properties properties;
|
private final Properties properties;
|
||||||
|
@ -100,20 +92,28 @@ public class PoolConfig {
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
this.minIdle = -1;
|
this.minIdle = -1;
|
||||||
this.maxPoolSize = -1;
|
this.maxPoolSize = -1;
|
||||||
this.maxLifetime = MAX_LIFETIME;
|
this.maxLifetime = TimeUnit.MINUTES.toMillis(30);
|
||||||
this.connectionTimeout = CONNECTION_TIMEOUT;
|
this.connectionTimeout = TimeUnit.SECONDS.toMillis(30);
|
||||||
this.validationTimeout = VALIDATION_TIMEOUT;
|
this.validationTimeout = TimeUnit.SECONDS.toMillis(5);
|
||||||
this.idleTimeout = IDLE_TIMEOUT;
|
this.idleTimeout = TimeUnit.MINUTES.toMillis(1);
|
||||||
this.initializationFailTimeout = -1;
|
this.initializationFailTimeout = -1;
|
||||||
this.isAutoCommit = true;
|
this.isAutoCommit = true; // JDBC convention
|
||||||
this.aliveBypassWindowMs = TimeUnit.MILLISECONDS.toMillis(500);
|
this.aliveBypassWindowMs = TimeUnit.MILLISECONDS.toMillis(500);
|
||||||
this.housekeepingPeriodMs = TimeUnit.SECONDS.toMillis(30);
|
this.housekeepingPeriodMs = TimeUnit.SECONDS.toMillis(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the JDBC URL.
|
||||||
|
* @param url the JDBC url as string
|
||||||
|
*/
|
||||||
public void setUrl(String url) {
|
public void setUrl(String url) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the JDBC URL.
|
||||||
|
* @return the JDBC URL as string
|
||||||
|
*/
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ public class PoolConfig {
|
||||||
* case that a connection cannot be obtained. However, upon start the pool will
|
* case that a connection cannot be obtained. However, upon start the pool will
|
||||||
* attempt to obtain a connection and validate that the {@code connectionTestQuery}
|
* attempt to obtain a connection and validate that the {@code connectionTestQuery}
|
||||||
* and {@code connectionInitSql} are valid. If those validations fail, an exception
|
* 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
|
* 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
|
* background. This can mean that callers to {@code DataSource#getConnection()} may
|
||||||
* encounter exceptions. </li>
|
* 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
|
* 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
|
* @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
|
* 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
|
* @param isolate {@code true} if internal pool queries should be isolated, {@code false} if not
|
||||||
*/
|
*/
|
||||||
|
@ -450,6 +450,15 @@ public class PoolConfig {
|
||||||
this.isIsolateInternalQueries = isolate;
|
this.isIsolateInternalQueries = isolate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the Connections to be added to the pool as read-only Connections.
|
||||||
|
*
|
||||||
|
* @param readOnly {@code true} if the Connections in the pool are read-only, {@code false} if not
|
||||||
|
*/
|
||||||
|
public void setReadOnly(boolean readOnly) {
|
||||||
|
this.isReadOnly = readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the Connections in the pool are in read-only mode.
|
* Determine whether the Connections in the pool are in read-only mode.
|
||||||
*
|
*
|
||||||
|
@ -459,19 +468,6 @@ public class PoolConfig {
|
||||||
return isReadOnly;
|
return isReadOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the Connections to be added to the pool as read-only Connections.
|
|
||||||
*
|
|
||||||
* @param readOnly {@code true} if the Connections in the pool are read-only, {@code false} if not
|
|
||||||
*/
|
|
||||||
public void setReadOnly(boolean readOnly) {
|
|
||||||
this.isReadOnly = readOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPoolName() {
|
|
||||||
return poolName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name of the connection pool. This is primarily used for the MBean
|
* Set the name of the connection pool. This is primarily used for the MBean
|
||||||
* to uniquely identify the pool configuration.
|
* to uniquely identify the pool configuration.
|
||||||
|
@ -482,6 +478,10 @@ public class PoolConfig {
|
||||||
this.poolName = poolName;
|
this.poolName = poolName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPoolName() {
|
||||||
|
return poolName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ScheduledExecutorService used for housekeeping.
|
* Get the ScheduledExecutorService used for housekeeping.
|
||||||
*
|
*
|
||||||
|
@ -628,26 +628,26 @@ public class PoolConfig {
|
||||||
|
|
||||||
private void validateNumerics() {
|
private void validateNumerics() {
|
||||||
if (maxLifetime != 0 && maxLifetime < TimeUnit.SECONDS.toMillis(30)) {
|
if (maxLifetime != 0 && maxLifetime < TimeUnit.SECONDS.toMillis(30)) {
|
||||||
logger.log(Level.WARNING, "maxLifetime is less than 30000ms, setting to default ms: " +
|
logger.log(Level.WARNING, "maxLifetime is less than 30s, setting to default ms: " +
|
||||||
poolName + " " + MAX_LIFETIME);
|
poolName + " " + TimeUnit.SECONDS.toMillis(30));
|
||||||
maxLifetime = MAX_LIFETIME;
|
maxLifetime = TimeUnit.SECONDS.toMillis(30);
|
||||||
}
|
}
|
||||||
if (leakDetectionThreshold > 0) {
|
if (leakDetectionThreshold > 0) {
|
||||||
if (leakDetectionThreshold < TimeUnit.SECONDS.toMillis(2) || (leakDetectionThreshold > maxLifetime && maxLifetime > 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);
|
poolName);
|
||||||
leakDetectionThreshold = 0;
|
leakDetectionThreshold = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (connectionTimeout < 250) {
|
if (connectionTimeout < 250) {
|
||||||
logger.log(Level.WARNING, "connectionTimeout is less than 250ms, setting to ms: " +
|
logger.log(Level.WARNING, "connectionTimeout is less than 250ms, setting to ms: " +
|
||||||
poolName + " " + CONNECTION_TIMEOUT);
|
poolName + " " + TimeUnit.MILLISECONDS.toMillis(250));
|
||||||
connectionTimeout = CONNECTION_TIMEOUT;
|
connectionTimeout = TimeUnit.MILLISECONDS.toMillis(250);
|
||||||
}
|
}
|
||||||
if (validationTimeout < 250) {
|
if (validationTimeout < 250) {
|
||||||
logger.log(Level.WARNING, "validationTimeout is less than 250ms, setting to ms" +
|
logger.log(Level.WARNING, "validationTimeout is less than 250ms, setting to ms" +
|
||||||
poolName + " " + VALIDATION_TIMEOUT);
|
poolName + " " + TimeUnit.MILLISECONDS.toMillis(250));
|
||||||
validationTimeout = VALIDATION_TIMEOUT;
|
validationTimeout = TimeUnit.MILLISECONDS.toMillis(250);
|
||||||
}
|
}
|
||||||
if (maxPoolSize < 1) {
|
if (maxPoolSize < 1) {
|
||||||
maxPoolSize = DEFAULT_POOL_SIZE;
|
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);
|
logger.log(Level.WARNING, "idleTimeout is close to or more than maxLifetime, disabling it:" + poolName);
|
||||||
idleTimeout = 0;
|
idleTimeout = 0;
|
||||||
} else if (idleTimeout != 0 && idleTimeout < TimeUnit.SECONDS.toMillis(10) && minIdle < maxPoolSize) {
|
} else if (idleTimeout != 0 && idleTimeout < TimeUnit.SECONDS.toMillis(10) && minIdle < maxPoolSize) {
|
||||||
logger.log(Level.WARNING, "idleTimeout is less than 10000ms, setting to default ms: " +
|
logger.log(Level.WARNING, "idleTimeout is less than 10s, setting to default ms: " +
|
||||||
poolName + " " + IDLE_TIMEOUT);
|
poolName + " " + TimeUnit.SECONDS.toMillis(10));
|
||||||
idleTimeout = IDLE_TIMEOUT;
|
idleTimeout = TimeUnit.SECONDS.toMillis(10);
|
||||||
} else if (idleTimeout != IDLE_TIMEOUT && idleTimeout != 0 && minIdle == maxPoolSize) {
|
} 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);
|
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
|
public class ConcurrentCloseConnectionTest
|
||||||
{
|
{
|
||||||
@Test
|
@Test
|
||||||
public void testConcurrentClose() throws Exception
|
public void testConcurrentClose() throws Exception {
|
||||||
{
|
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
|
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
|
||||||
try (PoolDataSource ds = new PoolDataSource(config);
|
try (PoolDataSource ds = new PoolDataSource(config);
|
||||||
final Connection connection = ds.getConnection()) {
|
final Connection connection = ds.getConnection()) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class ConnectionCloseBlockingTest {
|
||||||
@Test
|
@Test
|
||||||
public void testConnectionCloseBlocking() throws Exception {
|
public void testConnectionCloseBlocking() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(1500);
|
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})",
|
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));
|
minIdle, maxPoolSize, threadCount, workTimeMs, restTimeMs, connectionAcquisitionTimeMs, iterations, postTestTimeMs));
|
||||||
final PoolConfig config = new PoolConfig();
|
final PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(minIdle);
|
config.setMinimumIdle(minIdle);
|
||||||
config.setMaximumPoolSize(maxPoolSize);
|
config.setMaximumPoolSize(maxPoolSize);
|
||||||
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
||||||
|
|
|
@ -21,6 +21,7 @@ public class ConnectionRaceConditionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRaceCondition() throws Exception {
|
public void testRaceCondition() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(10);
|
config.setMaximumPoolSize(10);
|
||||||
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
||||||
|
|
|
@ -20,9 +20,9 @@ public class ConnectionStateTest {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.put("user", "bar");
|
properties.put("user", "bar");
|
||||||
properties.put("password", "secret");
|
properties.put("password", "secret");
|
||||||
properties.put("url", "baf");
|
|
||||||
properties.put("loginTimeout", "10");
|
properties.put("loginTimeout", "10");
|
||||||
PoolConfig config = new PoolConfig(properties);
|
PoolConfig config = new PoolConfig(properties);
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setAutoCommit(true);
|
config.setAutoCommit(true);
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
|
@ -41,6 +41,7 @@ public class ConnectionStateTest {
|
||||||
public void testTransactionIsolation() throws Exception {
|
public void testTransactionIsolation() throws Exception {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
PoolConfig config = new PoolConfig(properties);
|
PoolConfig config = new PoolConfig(properties);
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setTransactionIsolation("TRANSACTION_READ_COMMITTED");
|
config.setTransactionIsolation("TRANSACTION_READ_COMMITTED");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
|
@ -58,6 +59,7 @@ public class ConnectionStateTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIsolation() {
|
public void testIsolation() {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
|
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
|
||||||
config.setTransactionIsolation("TRANSACTION_REPEATABLE_READ");
|
config.setTransactionIsolation("TRANSACTION_REPEATABLE_READ");
|
||||||
config.validate();
|
config.validate();
|
||||||
|
@ -68,6 +70,7 @@ public class ConnectionStateTest {
|
||||||
@Test
|
@Test
|
||||||
public void testReadOnly() throws Exception {
|
public void testReadOnly() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setCatalog("test");
|
config.setCatalog("test");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
|
@ -85,6 +88,7 @@ public class ConnectionStateTest {
|
||||||
@Test
|
@Test
|
||||||
public void testCatalog() throws Exception {
|
public void testCatalog() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setCatalog("test");
|
config.setCatalog("test");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
|
@ -95,6 +99,7 @@ public class ConnectionStateTest {
|
||||||
Connection unwrap = connection.unwrap(Connection.class);
|
Connection unwrap = connection.unwrap(Connection.class);
|
||||||
connection.setCatalog("other");
|
connection.setCatalog("other");
|
||||||
connection.close();
|
connection.close();
|
||||||
|
// after close, we can access unwrap
|
||||||
assertEquals("test", unwrap.getCatalog());
|
assertEquals("test", unwrap.getCatalog());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +108,7 @@ public class ConnectionStateTest {
|
||||||
@Test
|
@Test
|
||||||
public void testCommitTracking() throws Exception {
|
public void testCommitTracking() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setAutoCommit(false);
|
config.setAutoCommit(false);
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
|
|
|
@ -34,6 +34,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testCreate() throws Exception {
|
public void testCreate() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
|
@ -69,6 +70,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testMaxLifetime() throws Exception {
|
public void testMaxLifetime() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(1500);
|
config.setConnectionTimeout(1500);
|
||||||
|
@ -110,6 +112,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testMaxLifetime2() throws Exception {
|
public void testMaxLifetime2() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(2500);
|
config.setConnectionTimeout(2500);
|
||||||
|
@ -149,6 +152,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDoubleClose() throws Exception {
|
public void testDoubleClose() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(2500);
|
config.setConnectionTimeout(2500);
|
||||||
|
@ -167,6 +171,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testEviction() throws Exception {
|
public void testEviction() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(5);
|
config.setMaximumPoolSize(5);
|
||||||
config.setConnectionTimeout(2500);
|
config.setConnectionTimeout(2500);
|
||||||
|
@ -184,11 +189,11 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testEviction2() throws Exception {
|
public void testEviction2() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMaximumPoolSize(5);
|
config.setMaximumPoolSize(5);
|
||||||
config.setConnectionTimeout(2500);
|
config.setConnectionTimeout(2500);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
|
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
|
||||||
//config.setExceptionOverrideClassName(OverrideHandler.class.getName());
|
|
||||||
try (PoolDataSource ds = new PoolDataSource(config)) {
|
try (PoolDataSource ds = new PoolDataSource(config)) {
|
||||||
Pool pool = ds.getPool();
|
Pool pool = ds.getPool();
|
||||||
while (pool.getTotalConnections() < 5) {
|
while (pool.getTotalConnections() < 5) {
|
||||||
|
@ -214,6 +219,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testEviction3() throws Exception {
|
public void testEviction3() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMaximumPoolSize(5);
|
config.setMaximumPoolSize(5);
|
||||||
config.setConnectionTimeout(2500);
|
config.setConnectionTimeout(2500);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
|
@ -243,6 +249,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testEvictAllRefill() throws Exception {
|
public void testEvictAllRefill() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(5);
|
config.setMinimumIdle(5);
|
||||||
config.setMaximumPoolSize(10);
|
config.setMaximumPoolSize(10);
|
||||||
config.setConnectionTimeout(2500);
|
config.setConnectionTimeout(2500);
|
||||||
|
@ -268,6 +275,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testBackfill() throws Exception {
|
public void testBackfill() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(4);
|
config.setMaximumPoolSize(4);
|
||||||
config.setConnectionTimeout(1000);
|
config.setConnectionTimeout(1000);
|
||||||
|
@ -309,6 +317,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testMaximumPoolLimit() throws Exception {
|
public void testMaximumPoolLimit() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(4);
|
config.setMaximumPoolSize(4);
|
||||||
config.setConnectionTimeout(20000);
|
config.setConnectionTimeout(20000);
|
||||||
|
@ -348,6 +357,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testOldDriver() throws Exception {
|
public void testOldDriver() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(2500);
|
config.setConnectionTimeout(2500);
|
||||||
|
@ -375,6 +385,7 @@ public class ConnectionTest {
|
||||||
StubDataSource stubDataSource = new StubDataSource();
|
StubDataSource stubDataSource = new StubDataSource();
|
||||||
stubDataSource.setThrowException(new SQLException("Connection refused"));
|
stubDataSource.setThrowException(new SQLException("Connection refused"));
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(2500);
|
config.setConnectionTimeout(2500);
|
||||||
|
@ -394,6 +405,7 @@ public class ConnectionTest {
|
||||||
StubDataSource stubDataSource = new StubDataSource();
|
StubDataSource stubDataSource = new StubDataSource();
|
||||||
stubDataSource.setThrowException(new SQLException("Connection refused"));
|
stubDataSource.setThrowException(new SQLException("Connection refused"));
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
config.setDataSource(stubDataSource);
|
config.setDataSource(stubDataSource);
|
||||||
|
@ -420,6 +432,7 @@ public class ConnectionTest {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(2);
|
config.setMaximumPoolSize(2);
|
||||||
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(3));
|
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(3));
|
||||||
|
@ -448,6 +461,7 @@ public class ConnectionTest {
|
||||||
StubDataSourceWithErrorSwitch stubDataSource = new StubDataSourceWithErrorSwitch();
|
StubDataSourceWithErrorSwitch stubDataSource = new StubDataSourceWithErrorSwitch();
|
||||||
stubDataSource.setErrorOnConnection(true);
|
stubDataSource.setErrorOnConnection(true);
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
config.setDataSource(stubDataSource);
|
config.setDataSource(stubDataSource);
|
||||||
|
@ -465,6 +479,7 @@ public class ConnectionTest {
|
||||||
public void testDataSourceRaisesErrorAfterInitializationTestQuery() throws Exception {
|
public void testDataSourceRaisesErrorAfterInitializationTestQuery() throws Exception {
|
||||||
StubDataSourceWithErrorSwitch stubDataSource = new StubDataSourceWithErrorSwitch();
|
StubDataSourceWithErrorSwitch stubDataSource = new StubDataSourceWithErrorSwitch();
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(2);
|
config.setMaximumPoolSize(2);
|
||||||
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(3));
|
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(3));
|
||||||
|
@ -486,6 +501,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testPopulationSlowAcquisition() throws Exception {
|
public void testPopulationSlowAcquisition() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMaximumPoolSize(20);
|
config.setMaximumPoolSize(20);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
|
config.setDataSourceClassName("org.xbib.io.pool.jdbc.mock.StubDataSource");
|
||||||
|
@ -515,6 +531,7 @@ public class ConnectionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testMinimumIdleZero() throws Exception {
|
public void testMinimumIdleZero() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(5);
|
config.setMaximumPoolSize(5);
|
||||||
config.setConnectionTimeout(1000L);
|
config.setConnectionTimeout(1000L);
|
||||||
|
@ -545,11 +562,4 @@ public class ConnectionTest {
|
||||||
this.errorOnConnection = errorOnConnection;
|
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
|
@Test
|
||||||
public void testConnectionRetries() throws Exception {
|
public void testConnectionRetries() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(2800);
|
config.setConnectionTimeout(2800);
|
||||||
|
@ -46,6 +47,7 @@ public class ConnectionTimeoutRetryTest {
|
||||||
@Test
|
@Test
|
||||||
public void testConnectionRetries2() throws Exception {
|
public void testConnectionRetries2() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(2800);
|
config.setConnectionTimeout(2800);
|
||||||
|
@ -76,6 +78,7 @@ public class ConnectionTimeoutRetryTest {
|
||||||
@Test
|
@Test
|
||||||
public void testConnectionRetries3() throws Exception {
|
public void testConnectionRetries3() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(2);
|
config.setMaximumPoolSize(2);
|
||||||
config.setConnectionTimeout(2800);
|
config.setConnectionTimeout(2800);
|
||||||
|
@ -114,6 +117,7 @@ public class ConnectionTimeoutRetryTest {
|
||||||
@Test
|
@Test
|
||||||
public void testConnectionRetries5() throws Exception {
|
public void testConnectionRetries5() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(2);
|
config.setMaximumPoolSize(2);
|
||||||
config.setConnectionTimeout(1000);
|
config.setConnectionTimeout(1000);
|
||||||
|
@ -151,6 +155,7 @@ public class ConnectionTimeoutRetryTest {
|
||||||
public void testConnectionIdleFill() throws Exception {
|
public void testConnectionIdleFill() throws Exception {
|
||||||
StubConnection.slowCreate = false;
|
StubConnection.slowCreate = false;
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(5);
|
config.setMinimumIdle(5);
|
||||||
config.setMaximumPoolSize(10);
|
config.setMaximumPoolSize(10);
|
||||||
config.setConnectionTimeout(2000);
|
config.setConnectionTimeout(2000);
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class HouseKeeperCleanupTest {
|
||||||
@Test
|
@Test
|
||||||
public void testHouseKeeperCleanupWithCustomExecutor() throws Exception {
|
public void testHouseKeeperCleanupWithCustomExecutor() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(10);
|
config.setMaximumPoolSize(10);
|
||||||
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
||||||
|
|
|
@ -12,6 +12,7 @@ public class IsolationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIsolation() throws Exception {
|
public void testIsolation() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setIsolateInternalQueries(true);
|
config.setIsolateInternalQueries(true);
|
||||||
|
@ -31,6 +32,7 @@ public class IsolationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testNonIsolation() throws Exception {
|
public void testNonIsolation() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setIsolateInternalQueries(false);
|
config.setIsolateInternalQueries(false);
|
||||||
|
|
|
@ -25,10 +25,10 @@ public class JdbcDriverTest {
|
||||||
@Test
|
@Test
|
||||||
public void driverTest1() throws Exception {
|
public void driverTest1() throws Exception {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.put("url", "jdbc:stub");
|
|
||||||
properties.put("user", "bart");
|
properties.put("user", "bart");
|
||||||
properties.put("password", "simpson");
|
properties.put("password", "simpson");
|
||||||
PoolConfig config = new PoolConfig(properties);
|
PoolConfig config = new PoolConfig(properties);
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
|
@ -46,8 +46,8 @@ public class JdbcDriverTest {
|
||||||
@Test
|
@Test
|
||||||
public void driverTest2() throws Exception {
|
public void driverTest2() throws Exception {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.put("url", "jdbc:invalid");
|
|
||||||
PoolConfig config = new PoolConfig(properties);
|
PoolConfig config = new PoolConfig(properties);
|
||||||
|
config.setUrl("jdbc:invalid");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
|
|
|
@ -23,18 +23,17 @@ public class PoolTest {
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
static void setup() throws Exception {
|
static void setup() throws Exception {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.put("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
|
|
||||||
PoolConfig config = new PoolConfig(properties);
|
PoolConfig config = new PoolConfig(properties);
|
||||||
|
config.setUrl("jdbc:h2:mem:test");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(2);
|
config.setMaximumPoolSize(2);
|
||||||
config.setConnectionTestQuery("SELECT 1");
|
config.setConnectionTestQuery("SELECT 1");
|
||||||
config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
|
|
||||||
try (PoolDataSource ds = new PoolDataSource(config);
|
try (PoolDataSource ds = new PoolDataSource(config);
|
||||||
Connection conn = ds.getConnection();
|
Connection conn = ds.getConnection();
|
||||||
Statement stmt = conn.createStatement()) {
|
Statement stmt = conn.createStatement()) {
|
||||||
stmt.executeUpdate("DROP TABLE IF EXISTS basic_pool_test");
|
stmt.executeUpdate("DROP TABLE IF EXISTS basic_pool_test");
|
||||||
stmt.executeUpdate("CREATE TABLE basic_pool_test ("
|
stmt.executeUpdate("CREATE TABLE basic_pool_test ("
|
||||||
+ "id INTEGER NOT NULL IDENTITY PRIMARY KEY, "
|
+ "id INTEGER PRIMARY KEY, "
|
||||||
+ "timestamp TIMESTAMP, "
|
+ "timestamp TIMESTAMP, "
|
||||||
+ "string VARCHAR(128), "
|
+ "string VARCHAR(128), "
|
||||||
+ "string_from_number NUMERIC "
|
+ "string_from_number NUMERIC "
|
||||||
|
@ -45,12 +44,11 @@ public class PoolTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIdleTimeout() throws Exception {
|
public void testIdleTimeout() throws Exception {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.put("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
|
|
||||||
PoolConfig config = new PoolConfig(properties);
|
PoolConfig config = new PoolConfig(properties);
|
||||||
|
config.setUrl("jdbc:h2:mem:test");
|
||||||
config.setMinimumIdle(5);
|
config.setMinimumIdle(5);
|
||||||
config.setMaximumPoolSize(10);
|
config.setMaximumPoolSize(10);
|
||||||
config.setConnectionTestQuery("SELECT 1");
|
config.setConnectionTestQuery("SELECT 1");
|
||||||
config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
|
|
||||||
System.setProperty("pool.jdbc.housekeeping.periodMs", "1000");
|
System.setProperty("pool.jdbc.housekeeping.periodMs", "1000");
|
||||||
try (PoolDataSource ds = new PoolDataSource(config)) {
|
try (PoolDataSource ds = new PoolDataSource(config)) {
|
||||||
System.clearProperty("pool.jdbc.housekeeping.periodMs");
|
System.clearProperty("pool.jdbc.housekeeping.periodMs");
|
||||||
|
@ -79,11 +77,10 @@ public class PoolTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIdleTimeout2() throws Exception {
|
public void testIdleTimeout2() throws Exception {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.put("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
|
|
||||||
PoolConfig config = new PoolConfig(properties);
|
PoolConfig config = new PoolConfig(properties);
|
||||||
|
config.setUrl("jdbc:h2:mem:test");
|
||||||
config.setMaximumPoolSize(50);
|
config.setMaximumPoolSize(50);
|
||||||
config.setConnectionTestQuery("SELECT 1");
|
config.setConnectionTestQuery("SELECT 1");
|
||||||
config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
|
|
||||||
System.setProperty("pool.jdbc.housekeeping.periodMs", "1000");
|
System.setProperty("pool.jdbc.housekeeping.periodMs", "1000");
|
||||||
try (PoolDataSource ds = new PoolDataSource(config)) {
|
try (PoolDataSource ds = new PoolDataSource(config)) {
|
||||||
System.clearProperty("pool.jdbc.housekeeping.periodMs");
|
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.BeforeAllCallback;
|
||||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
import java.util.Locale;
|
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;
|
import org.xbib.jdbc.connection.pool.IsolationLevel;
|
||||||
|
|
||||||
public class PoolTestExtension implements BeforeAllCallback {
|
public class PoolTestExtension implements BeforeAllCallback {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeAll(ExtensionContext context) {
|
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) {
|
public static void quietlySleep(long millis) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ public class ProxiesTest {
|
||||||
@Test
|
@Test
|
||||||
public void testProxyCreation() throws Exception {
|
public void testProxyCreation() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
|
@ -55,6 +56,7 @@ public class ProxiesTest {
|
||||||
@Test
|
@Test
|
||||||
public void testStatementProxy() throws Exception {
|
public void testStatementProxy() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
|
@ -81,6 +83,7 @@ public class ProxiesTest {
|
||||||
@Test
|
@Test
|
||||||
public void testStatementExceptions() throws Exception {
|
public void testStatementExceptions() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(1));
|
config.setConnectionTimeout(TimeUnit.SECONDS.toMillis(1));
|
||||||
|
@ -168,6 +171,7 @@ public class ProxiesTest {
|
||||||
@Test
|
@Test
|
||||||
public void testOtherExceptions() throws Exception {
|
public void testOtherExceptions() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
|
|
|
@ -14,6 +14,7 @@ public class RampUpDownTest {
|
||||||
@Test
|
@Test
|
||||||
public void rampUpDownTest() throws Exception {
|
public void rampUpDownTest() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(5);
|
config.setMinimumIdle(5);
|
||||||
config.setMaximumPoolSize(60);
|
config.setMaximumPoolSize(60);
|
||||||
config.setInitializationFailTimeout(0);
|
config.setInitializationFailTimeout(0);
|
||||||
|
|
|
@ -29,6 +29,7 @@ public class SaturatedPoolTest830 {
|
||||||
@Test
|
@Test
|
||||||
public void saturatedPoolTest() throws Exception {
|
public void saturatedPoolTest() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(5);
|
config.setMinimumIdle(5);
|
||||||
config.setMaximumPoolSize(MAX_POOL_SIZE);
|
config.setMaximumPoolSize(MAX_POOL_SIZE);
|
||||||
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
||||||
|
|
|
@ -117,6 +117,7 @@ public class ShutdownTest {
|
||||||
public void testShutdown4() throws Exception {
|
public void testShutdown4() throws Exception {
|
||||||
StubConnection.slowCreate = true;
|
StubConnection.slowCreate = true;
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(10);
|
config.setMinimumIdle(10);
|
||||||
config.setMaximumPoolSize(10);
|
config.setMaximumPoolSize(10);
|
||||||
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
config.setInitializationFailTimeout(Long.MAX_VALUE);
|
||||||
|
@ -137,6 +138,7 @@ public class ShutdownTest {
|
||||||
public void testShutdown5() throws Exception {
|
public void testShutdown5() throws Exception {
|
||||||
assertSame( 0, StubConnection.count.get(), "StubConnection count not as expected");
|
assertSame( 0, StubConnection.count.get(), "StubConnection count not as expected");
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(5);
|
config.setMinimumIdle(5);
|
||||||
config.setMaximumPoolSize(5);
|
config.setMaximumPoolSize(5);
|
||||||
config.setInitializationFailTimeout(0);
|
config.setInitializationFailTimeout(0);
|
||||||
|
@ -158,6 +160,7 @@ public class ShutdownTest {
|
||||||
@Test
|
@Test
|
||||||
public void testAfterShutdown() throws Exception {
|
public void testAfterShutdown() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(0);
|
config.setMinimumIdle(0);
|
||||||
config.setMaximumPoolSize(5);
|
config.setMaximumPoolSize(5);
|
||||||
config.setInitializationFailTimeout(0);
|
config.setInitializationFailTimeout(0);
|
||||||
|
@ -177,6 +180,7 @@ public class ShutdownTest {
|
||||||
@Test
|
@Test
|
||||||
public void testShutdownDuringInit() throws Exception {
|
public void testShutdownDuringInit() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(5);
|
config.setMinimumIdle(5);
|
||||||
config.setMaximumPoolSize(5);
|
config.setMaximumPoolSize(5);
|
||||||
config.setConnectionTimeout(1000);
|
config.setConnectionTimeout(1000);
|
||||||
|
@ -193,6 +197,7 @@ public class ShutdownTest {
|
||||||
@Test
|
@Test
|
||||||
public void testThreadedShutdown() throws Exception {
|
public void testThreadedShutdown() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(5);
|
config.setMinimumIdle(5);
|
||||||
config.setMaximumPoolSize(5);
|
config.setMaximumPoolSize(5);
|
||||||
config.setConnectionTimeout(1000);
|
config.setConnectionTimeout(1000);
|
||||||
|
|
|
@ -19,6 +19,7 @@ public class StatementTest {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(2);
|
config.setMaximumPoolSize(2);
|
||||||
config.setConnectionTestQuery("VALUES 1");
|
config.setConnectionTestQuery("VALUES 1");
|
||||||
|
|
|
@ -19,6 +19,7 @@ public class UnwrapTest {
|
||||||
@Test
|
@Test
|
||||||
public void testUnwrapConnection() throws Exception {
|
public void testUnwrapConnection() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setInitializationFailTimeout(0);
|
config.setInitializationFailTimeout(0);
|
||||||
|
@ -37,6 +38,7 @@ public class UnwrapTest {
|
||||||
@Test
|
@Test
|
||||||
public void testUnwrapDataSource() throws Exception {
|
public void testUnwrapDataSource() throws Exception {
|
||||||
PoolConfig config = new PoolConfig();
|
PoolConfig config = new PoolConfig();
|
||||||
|
config.setUrl("jdbc:stub");
|
||||||
config.setMinimumIdle(1);
|
config.setMinimumIdle(1);
|
||||||
config.setMaximumPoolSize(1);
|
config.setMaximumPoolSize(1);
|
||||||
config.setInitializationFailTimeout(0);
|
config.setInitializationFailTimeout(0);
|
||||||
|
|
10
jdbc-connection-pool/src/test/resources/logging.properties
Normal file
10
jdbc-connection-pool/src/test/resources/logging.properties
Normal file
|
@ -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
|
12
jdbc-mariadb/build.gradle
Normal file
12
jdbc-mariadb/build.gradle
Normal file
|
@ -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'
|
||||||
|
}
|
10
jdbc-mariadb/src/main/java/module-info.java
Normal file
10
jdbc-mariadb/src/main/java/module-info.java
Normal file
|
@ -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;
|
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
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "mysql";
|
return "mariadb";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(String url) {
|
public boolean supports(String url) {
|
||||||
return url.startsWith("jdbc:mysql:");
|
return url.startsWith("jdbc:mariadb:");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String driverClass() {
|
public String driverClass() {
|
||||||
return "com.mysql.jdbc.Driver";
|
return "org.mariadb.jdbc.Driver";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isNormalizedUpperCase() {
|
public boolean isNormalizedUpperCase() {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -41,7 +47,12 @@ public class MySQL implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeFloat() {
|
public String typeFloat() {
|
||||||
return "real";
|
return "double";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
|
||||||
|
preparedStatement.setFloat(i, floatValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -49,6 +60,11 @@ public class MySQL implements Flavor {
|
||||||
return "double";
|
return "double";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
|
||||||
|
preparedStatement.setDouble(i, doubleValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeBigDecimal(int size, int precision) {
|
public String typeBigDecimal(int size, int precision) {
|
||||||
return "numeric(" + size + "," + precision + ")";
|
return "numeric(" + size + "," + precision + ")";
|
||||||
|
@ -56,6 +72,9 @@ public class MySQL implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeStringVar(int length) {
|
public String typeStringVar(int length) {
|
||||||
|
if (length == 16777215) {
|
||||||
|
return "mediumtext";
|
||||||
|
}
|
||||||
return "varchar(" + length + ")";
|
return "varchar(" + length + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,17 +85,17 @@ public class MySQL implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeClob() {
|
public String typeClob() {
|
||||||
return "clob";
|
return "mediumtext"; // mediumtext = varchar(16777215), longtext = varchar(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeBlob() {
|
public String typeBlob() {
|
||||||
return "blob";
|
return "mediumblob";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeLocalDateTime() {
|
public String typeLocalDateTime() {
|
||||||
return "timestamp";
|
return "datetime(3)";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -86,42 +105,32 @@ public class MySQL implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean useStringForClob() {
|
public boolean useStringForClob() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean useBytesForBlob() {
|
public boolean useBytesForBlob() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sequenceNextVal(String sequenceName) {
|
public String sequenceNextVal(String sequenceName) {
|
||||||
return "next value for " + sequenceName;
|
return "next value for " + sequenceName + "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sequenceSelectNextVal(String sequenceName) {
|
public String sequenceSelectNextVal(String sequenceName) {
|
||||||
return "values next value for " + sequenceName;
|
return "select " + sequenceNextVal(sequenceName) + fromAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sequenceDrop(String sequenceName) {
|
public String sequenceDrop(String dbtestSeq) {
|
||||||
return "drop sequence " + sequenceName + " restrict";
|
return "drop sequence if exists " + dbtestSeq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String tableDrop(String table) {
|
public String tableDrop(String table) {
|
||||||
return "drop table " + table;
|
return "drop table if exists " + table;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsInsertReturning() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sequenceCacheClause(int nbrValuesToCache) {
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,22 +140,32 @@ public class MySQL implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sequenceCycleClause(boolean cycle) {
|
public String sequenceCycleClause(boolean cycle) {
|
||||||
return cycle ? " cycle" : " no cycle";
|
return "";
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String dbTimeMillis() {
|
|
||||||
return "current_timestamp";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String fromAny() {
|
public String fromAny() {
|
||||||
return " from sysibm.sysdummy1";
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInsertReturning() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String dbTimeMillis() {
|
||||||
|
return "localtimestamp(3)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sequenceCacheClause(int nbrValuesToCache) {
|
||||||
|
return " cache " + nbrValuesToCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sequenceOptions() {
|
public String sequenceOptions() {
|
||||||
return " as bigint";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -156,22 +175,25 @@ public class MySQL implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String writeNextIntoQueue(String table) {
|
public String writeNextIntoQueue(String table) {
|
||||||
throw new UnsupportedOperationException();
|
return "insert into " + table
|
||||||
|
+ " (channel, data, state, delay, modified) "
|
||||||
|
+ "values (?, ?, null, 0, ?)";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String readNextFromQueue(String table) {
|
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
|
@Override
|
||||||
public String succeedInQueue(String table) {
|
public String succeedInQueue(String table) {
|
||||||
throw new UnsupportedOperationException();
|
return "update" + table + " set state = 'OK', modified = " + dbTimeMillis() + " where id = ?";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String failInQueue(String table) {
|
public String failInQueue(String table) {
|
||||||
throw new UnsupportedOperationException();
|
return "update" + table + " set state = 'FAIL', modified = " + dbTimeMillis() + " where id = ?";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.xbib.jdbc.mariadb.MariaDB
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
10
jdbc-mariadb/src/test/resources/logging.properties
Normal file
10
jdbc-mariadb/src/test/resources/logging.properties
Normal file
|
@ -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
|
12
jdbc-oracle/build.gradle
Normal file
12
jdbc-oracle/build.gradle
Normal file
|
@ -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'
|
||||||
|
}
|
12
jdbc-oracle/src/main/java/module-info.java
Normal file
12
jdbc-oracle/src/main/java/module-info.java
Normal file
|
@ -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 org.xbib.jdbc.query.Flavor;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public class Oracle implements Flavor {
|
public class Oracle implements Flavor {
|
||||||
|
|
||||||
|
public Oracle() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "oracle";
|
return "oracle";
|
||||||
|
@ -29,11 +37,31 @@ public class Oracle implements Flavor {
|
||||||
return "binary_float";
|
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
|
@Override
|
||||||
public String typeDouble() {
|
public String typeDouble() {
|
||||||
return "binary_double";
|
return "binary_double";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
|
||||||
|
if (preparedStatement instanceof ProxyPreparedStatement) {
|
||||||
|
ProxyPreparedStatement proxyPreparedStatement = (ProxyPreparedStatement) preparedStatement;
|
||||||
|
((OraclePreparedStatement) proxyPreparedStatement.getDelegate()).setBinaryDouble(i, doubleValue);
|
||||||
|
} else {
|
||||||
|
((OraclePreparedStatement) preparedStatement).setBinaryDouble(i, doubleValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeBigDecimal(int size, int precision) {
|
public String typeBigDecimal(int size, int precision) {
|
||||||
return "numeric(" + size + "," + precision + ")";
|
return "numeric(" + size + "," + precision + ")";
|
|
@ -0,0 +1 @@
|
||||||
|
org.xbib.jdbc.oracle.Oracle
|
|
@ -0,0 +1,67 @@
|
||||||
|
package org.xbib.jdbc.oracle.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.OracleContainer;
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exercise Database functionality with a real Oracle database.
|
||||||
|
*/
|
||||||
|
@Testcontainers
|
||||||
|
public class OracleTest extends CommonTest {
|
||||||
|
|
||||||
|
static OracleContainer oracleContainer;
|
||||||
|
|
||||||
|
static {
|
||||||
|
oracleContainer = new OracleContainer("gvenzl/oracle-xe:21.3.0-slim")
|
||||||
|
.withDatabaseName("testDB")
|
||||||
|
.withUsername("testUser")
|
||||||
|
.withPassword("testPassword")
|
||||||
|
.withExposedPorts(1521)
|
||||||
|
.withReuse(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void startContainer() {
|
||||||
|
oracleContainer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public static void stopContainer() {
|
||||||
|
oracleContainer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception {
|
||||||
|
Config config = ConfigSupplier.of()
|
||||||
|
.property("database.url", oracleContainer.getJdbcUrl())
|
||||||
|
.property("database.user", "testUser")
|
||||||
|
.property("database.password", "testPassword")
|
||||||
|
.get();
|
||||||
|
return DatabaseProvider.builder(config)
|
||||||
|
.withSqlParameterLogging()
|
||||||
|
.withSqlInExceptionMessages()
|
||||||
|
.withOptions(options)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Disabled("Current Oracle behavior is to convert -0f to 0f")
|
||||||
|
@Test
|
||||||
|
public void argFloatNegativeZero() {
|
||||||
|
super.argFloatNegativeZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Disabled("Current Oracle behavior is to convert -0d to 0d")
|
||||||
|
@Test
|
||||||
|
public void argDoubleNegativeZero() {
|
||||||
|
super.argDoubleNegativeZero();
|
||||||
|
}
|
||||||
|
}
|
10
jdbc-oracle/src/test/resources/logging.properties
Normal file
10
jdbc-oracle/src/test/resources/logging.properties
Normal file
|
@ -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
|
12
jdbc-postgresql/build.gradle
Normal file
12
jdbc-postgresql/build.gradle
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
dependencies {
|
||||||
|
api project(':jdbc-query')
|
||||||
|
implementation libs.postgresql
|
||||||
|
testImplementation project(':jdbc-test')
|
||||||
|
testImplementation libs.testcontainers
|
||||||
|
testImplementation libs.testcontainers.junit.jupiter
|
||||||
|
testImplementation libs.testcontainers.postgresql
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
systemProperty 'user.timezone', 'GMT'
|
||||||
|
}
|
10
jdbc-postgresql/src/main/java/module-info.java
Normal file
10
jdbc-postgresql/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import org.xbib.jdbc.query.Flavor;
|
||||||
|
import org.xbib.jdbc.postgresql.Postgresql;
|
||||||
|
|
||||||
|
module org.xbib.jdbc.postgresql {
|
||||||
|
requires org.xbib.jdbc.query;
|
||||||
|
requires java.sql;
|
||||||
|
uses Flavor;
|
||||||
|
exports org.xbib.jdbc.postgresql;
|
||||||
|
provides Flavor with Postgresql;
|
||||||
|
}
|
|
@ -1,9 +1,15 @@
|
||||||
package org.xbib.jdbc.query.flavor;
|
package org.xbib.jdbc.postgresql;
|
||||||
|
|
||||||
import org.xbib.jdbc.query.Flavor;
|
import org.xbib.jdbc.query.Flavor;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public class Postgresql implements Flavor {
|
public class Postgresql implements Flavor {
|
||||||
|
|
||||||
|
public Postgresql() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "postgresql";
|
return "postgresql";
|
||||||
|
@ -44,11 +50,21 @@ public class Postgresql implements Flavor {
|
||||||
return "real";
|
return "real";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
|
||||||
|
preparedStatement.setFloat(i, floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeDouble() {
|
public String typeDouble() {
|
||||||
return "double precision";
|
return "double precision";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
|
||||||
|
preparedStatement.setDouble(i, doubleValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeBigDecimal(int size, int precision) {
|
public String typeBigDecimal(int size, int precision) {
|
||||||
return "numeric(" + size + "," + precision + ")";
|
return "numeric(" + size + "," + precision + ")";
|
|
@ -0,0 +1 @@
|
||||||
|
org.xbib.jdbc.postgresql.Postgresql
|
|
@ -0,0 +1,71 @@
|
||||||
|
package org.xbib.jdbc.postgresql.test;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.testcontainers.containers.PostgreSQLContainer;
|
||||||
|
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.query.Schema;
|
||||||
|
import org.xbib.jdbc.test.CommonTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exercise Database functionality with a real PostgreSQL database.
|
||||||
|
*/
|
||||||
|
public class PostgresqlTest extends CommonTest {
|
||||||
|
|
||||||
|
static PostgreSQLContainer<?> postgreSQLContainer;
|
||||||
|
|
||||||
|
static {
|
||||||
|
postgreSQLContainer = new PostgreSQLContainer<>("postgres")
|
||||||
|
.withDatabaseName("testDB")
|
||||||
|
.withUsername("testUser")
|
||||||
|
.withPassword("testPassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void startContainer() {
|
||||||
|
postgreSQLContainer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public static void stopContainer() {
|
||||||
|
postgreSQLContainer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception {
|
||||||
|
Config config = ConfigSupplier.of()
|
||||||
|
.property("database.url", postgreSQLContainer.getJdbcUrl())
|
||||||
|
.property("database.user", "testUser")
|
||||||
|
.property("database.password", "testPassword")
|
||||||
|
.get();
|
||||||
|
return DatabaseProvider.builder(config)
|
||||||
|
.withSqlParameterLogging()
|
||||||
|
.withSqlInExceptionMessages()
|
||||||
|
.withOptions(options)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PostgreSQL seems to have different behavior in that is does not convert
|
||||||
|
* column names to uppercase (it actually converts them to lowercase).
|
||||||
|
* I haven't figured out how to smooth over this difference, since all databases
|
||||||
|
* seem to respect the provided case when it is inside quotes, but don't provide
|
||||||
|
* a way to tell whether a particular parameter was quoted.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Test
|
||||||
|
public void metadataColumnNames() {
|
||||||
|
db.dropTableQuietly("dbtest");
|
||||||
|
new Schema().addTable("dbtest").addColumn("pk").primaryKey().schema().execute(db);
|
||||||
|
db.toSelect("select Pk, Pk as Foo, Pk as \"Foo\" from dbtest")
|
||||||
|
.query(rs -> {
|
||||||
|
Assertions.assertArrayEquals(new String[]{"pk", "foo", "Foo"}, rs.getColumnLabels());
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
10
jdbc-postgresql/src/test/resources/logging.properties
Normal file
10
jdbc-postgresql/src/test/resources/logging.properties
Normal file
|
@ -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
|
|
@ -4,5 +4,4 @@ dependencies {
|
||||||
testImplementation libs.hsqldb
|
testImplementation libs.hsqldb
|
||||||
testImplementation libs.testcontainers
|
testImplementation libs.testcontainers
|
||||||
testImplementation libs.testcontainers.junit.jupiter
|
testImplementation libs.testcontainers.junit.jupiter
|
||||||
testImplementation libs.testcontainers.oracle.xe
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import org.xbib.jdbc.query.Flavor;
|
import org.xbib.jdbc.query.Flavor;
|
||||||
import org.xbib.jdbc.query.flavor.Derby;
|
import org.xbib.jdbc.query.flavor.Derby;
|
||||||
import org.xbib.jdbc.query.flavor.Hsql;
|
import org.xbib.jdbc.query.flavor.Hsql;
|
||||||
import org.xbib.jdbc.query.flavor.Oracle;
|
|
||||||
import org.xbib.jdbc.query.flavor.Postgresql;
|
|
||||||
import org.xbib.jdbc.query.flavor.SqlServer;
|
import org.xbib.jdbc.query.flavor.SqlServer;
|
||||||
|
|
||||||
module org.xbib.jdbc.query {
|
module org.xbib.jdbc.query {
|
||||||
uses Flavor;
|
uses Flavor;
|
||||||
requires transitive org.xbib.jdbc.connection.pool;
|
requires org.xbib.jdbc.connection.pool;
|
||||||
|
requires java.sql;
|
||||||
exports org.xbib.jdbc.query;
|
exports org.xbib.jdbc.query;
|
||||||
provides Flavor with Derby, Hsql, Oracle, Postgresql, SqlServer;
|
provides Flavor with Derby, Hsql, SqlServer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,12 @@ public interface ConfigSupplier extends Supplier<Config> {
|
||||||
|
|
||||||
ConfigSupplier custom(Function<String, String> keyValueLookup);
|
ConfigSupplier custom(Function<String, String> keyValueLookup);
|
||||||
|
|
||||||
ConfigSupplier value(String key, String value);
|
ConfigSupplier property(String key, String value);
|
||||||
|
|
||||||
ConfigSupplier systemProperties();
|
|
||||||
|
|
||||||
ConfigSupplier env();
|
ConfigSupplier env();
|
||||||
|
|
||||||
|
ConfigSupplier systemProperties();
|
||||||
|
|
||||||
ConfigSupplier properties(Properties properties);
|
ConfigSupplier properties(Properties properties);
|
||||||
|
|
||||||
ConfigSupplier config(Config config);
|
ConfigSupplier config(Config config);
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class ConfigSupplierImpl implements ConfigSupplier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigSupplier value(String key, String value) {
|
public ConfigSupplier property(String key, String value) {
|
||||||
return custom(k -> k.equals(key) ? value : null, "value(" + key + ")");
|
return custom(k -> k.equals(key) ? value : null, "value(" + key + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -259,17 +259,17 @@ public class DatabaseImpl implements Database {
|
||||||
}
|
}
|
||||||
Duration duration = Duration.between(appDate, dbDate).abs();
|
Duration duration = Duration.between(appDate, dbDate).abs();
|
||||||
if (duration.getSeconds() > 3600) {
|
if (duration.getSeconds() > 3600) {
|
||||||
throw new DatabaseException("App and db time are over an hour apart (check your timezones) app: "
|
throw new DatabaseException("JDBC and database time are over an hour apart (check your timezones) app: "
|
||||||
+ appDate + " db: "
|
+ appDate + " db: "
|
||||||
+ dbDate);
|
+ dbDate);
|
||||||
}
|
}
|
||||||
if (duration.getSeconds() * 1000 > millisToError) {
|
if (duration.getSeconds() * 1000 > millisToError) {
|
||||||
throw new DatabaseException("App and db time over " + millisToError + " millis apart (check your clocks) app: "
|
throw new DatabaseException("JDBC and database time over " + millisToError + " millis apart (check your clocks) app: "
|
||||||
+ appDate + " db: "
|
+ appDate + " db: "
|
||||||
+ dbDate);
|
+ dbDate);
|
||||||
}
|
}
|
||||||
if (duration.getSeconds() * 1000 > millisToWarn) {
|
if (duration.getSeconds() * 1000 > millisToWarn) {
|
||||||
logger.warning("App and db time are over " + millisToWarn + " millis apart (check your clocks) app: "
|
logger.warning("JDBC and database time are over " + millisToWarn + " millis apart (check your clocks) app: "
|
||||||
+ appDate + " db: "
|
+ appDate + " db: "
|
||||||
+ dbDate);
|
+ dbDate);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
@ -27,33 +28,20 @@ import java.util.logging.Logger;
|
||||||
* of this laziness, the underlying resources require explicit cleanup by calling either
|
* of this laziness, the underlying resources require explicit cleanup by calling either
|
||||||
* commitAndClose() or rollbackAndClose().
|
* commitAndClose() or rollbackAndClose().
|
||||||
*/
|
*/
|
||||||
public final class DatabaseProvider implements Supplier<Database> {
|
public final class DatabaseProvider implements Supplier<Database>, Closeable {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(DatabaseProvider.class.getName());
|
private static final Logger log = Logger.getLogger(DatabaseProvider.class.getName());
|
||||||
|
|
||||||
private static final AtomicInteger poolNameCounter = new AtomicInteger(1);
|
private static final AtomicInteger poolNameCounter = new AtomicInteger(1);
|
||||||
|
|
||||||
private final Options options;
|
|
||||||
|
|
||||||
private DatabaseProvider delegateTo = null;
|
|
||||||
|
|
||||||
private Supplier<Connection> connectionProvider;
|
|
||||||
|
|
||||||
private Connection connection = null;
|
|
||||||
|
|
||||||
private Database database = null;
|
|
||||||
|
|
||||||
private DatabaseProvider(Supplier<Connection> connectionProvider, Options options) {
|
private final DatabaseProviderBuilderImpl builder;
|
||||||
if (connectionProvider == null) {
|
|
||||||
throw new IllegalArgumentException("connection provider cannot be null");
|
|
||||||
}
|
|
||||||
this.connectionProvider = connectionProvider;
|
|
||||||
this.options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DatabaseProvider(DatabaseProvider delegateTo) {
|
private Connection connection;
|
||||||
this.delegateTo = delegateTo;
|
|
||||||
this.options = delegateTo.options;
|
private Database database;
|
||||||
|
|
||||||
|
private DatabaseProvider(DatabaseProviderBuilderImpl builder) {
|
||||||
|
this.builder = builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,15 +63,15 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
*
|
*
|
||||||
* <p>A database pool will be created using jdbc-connection-pool.</p>
|
* <p>A database pool will be created using jdbc-connection-pool.</p>
|
||||||
*/
|
*/
|
||||||
public static Builder builder(Config config) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
public static DatabaseProviderBuilder builder(Config config) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
|
||||||
return builder(createDataSource(config), getFlavor(config));
|
return builder(createDataSource(config), getFlavor(config));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use an externally configured DataSource and a Flavor.
|
* Use an externally configured DataSource and a Flavor.
|
||||||
*/
|
*/
|
||||||
public static Builder builder(DataSource ds, Flavor flavor) {
|
public static DatabaseProviderBuilder builder(DataSource ds, Flavor flavor) {
|
||||||
return new BuilderImpl(ds, () -> {
|
return new DatabaseProviderBuilderImpl(ds, () -> {
|
||||||
try {
|
try {
|
||||||
return ds.getConnection();
|
return ds.getConnection();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -97,7 +85,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* the JDBC standard DriverManager method. The url parameter will be inspected
|
* the JDBC standard DriverManager method. The url parameter will be inspected
|
||||||
* to determine the Flavor for this database.
|
* to determine the Flavor for this database.
|
||||||
*/
|
*/
|
||||||
public static Builder builder(String url) {
|
public static DatabaseProviderBuilder builder(String url) {
|
||||||
return builder(url, Flavor.fromJdbcUrl(url), null, null, null);
|
return builder(url, Flavor.fromJdbcUrl(url), null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +96,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* @param flavor use this flavor rather than guessing based on the url
|
* @param flavor use this flavor rather than guessing based on the url
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static Builder builder(String url, Flavor flavor) {
|
public static DatabaseProviderBuilder builder(String url, Flavor flavor) {
|
||||||
return builder(url, flavor, null, null, null);
|
return builder(url, flavor, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +106,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* to determine the Flavor for this database.
|
* to determine the Flavor for this database.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static Builder builder(String url, Properties info) {
|
public static DatabaseProviderBuilder builder(String url, Properties info) {
|
||||||
return builder(url, Flavor.fromJdbcUrl(url), info, null, null);
|
return builder(url, Flavor.fromJdbcUrl(url), info, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +117,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* @param flavor use this flavor rather than guessing based on the url
|
* @param flavor use this flavor rather than guessing based on the url
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static Builder builder(String url, Flavor flavor, Properties info) {
|
public static DatabaseProviderBuilder builder(String url, Flavor flavor, Properties info) {
|
||||||
return builder(url, flavor, info, null, null);
|
return builder(url, flavor, info, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +127,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* to determine the Flavor for this database.
|
* to determine the Flavor for this database.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static Builder builder(String url, String user, String password) {
|
public static DatabaseProviderBuilder builder(String url, String user, String password) {
|
||||||
return builder(url, Flavor.fromJdbcUrl(url), null, user, password);
|
return builder(url, Flavor.fromJdbcUrl(url), null, user, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,18 +138,18 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* @param flavor use this flavor rather than guessing based on the url
|
* @param flavor use this flavor rather than guessing based on the url
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static Builder builder(String url,
|
public static DatabaseProviderBuilder builder(String url,
|
||||||
Flavor flavor,
|
Flavor flavor,
|
||||||
String user,
|
String user,
|
||||||
String password) {
|
String password) {
|
||||||
return builder(url, flavor, null, user, password);
|
return builder(url, flavor, null, user, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Builder builder(String url,
|
private static DatabaseProviderBuilder builder(String url,
|
||||||
Flavor flavor,
|
Flavor flavor,
|
||||||
Properties info,
|
Properties info,
|
||||||
String user,
|
String user,
|
||||||
String password) {
|
String password) {
|
||||||
Options options = new OptionsDefault(flavor);
|
Options options = new OptionsDefault(flavor);
|
||||||
try {
|
try {
|
||||||
DriverManager.getDriver(url);
|
DriverManager.getDriver(url);
|
||||||
|
@ -174,7 +162,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new BuilderImpl(null, () -> {
|
return new DatabaseProviderBuilderImpl(null, () -> {
|
||||||
try {
|
try {
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
return DriverManager.getConnection(url, info);
|
return DriverManager.getConnection(url, info);
|
||||||
|
@ -206,7 +194,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* @param propertyFileName path to the properties file we will attempt to read
|
* @param propertyFileName path to the properties file we will attempt to read
|
||||||
* @throws DatabaseException if the property file could not be read for any reason
|
* @throws DatabaseException if the property file could not be read for any reason
|
||||||
*/
|
*/
|
||||||
public static Builder fromPropertyFile(String propertyFileName) {
|
public static DatabaseProviderBuilder fromPropertyFile(String propertyFileName) {
|
||||||
return fromPropertyFile(propertyFileName, Charset.defaultCharset().newDecoder());
|
return fromPropertyFile(propertyFileName, Charset.defaultCharset().newDecoder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +216,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* @param decoder character encoding to use when reading the property file
|
* @param decoder character encoding to use when reading the property file
|
||||||
* @throws DatabaseException if the property file could not be read for any reason
|
* @throws DatabaseException if the property file could not be read for any reason
|
||||||
*/
|
*/
|
||||||
public static Builder fromPropertyFile(String propertyFileName, CharsetDecoder decoder) {
|
public static DatabaseProviderBuilder fromPropertyFile(String propertyFileName, CharsetDecoder decoder) {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
if (propertyFileName != null && propertyFileName.length() > 0) {
|
if (propertyFileName != null && propertyFileName.length() > 0) {
|
||||||
try (
|
try (
|
||||||
|
@ -265,7 +253,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* pass "my." as the prefix)
|
* pass "my." as the prefix)
|
||||||
* @throws DatabaseException if the property file could not be read for any reason
|
* @throws DatabaseException if the property file could not be read for any reason
|
||||||
*/
|
*/
|
||||||
public static Builder fromPropertyFile(String filename, String propertyPrefix) {
|
public static DatabaseProviderBuilder fromPropertyFile(String filename, String propertyPrefix) {
|
||||||
return fromPropertyFile(filename, propertyPrefix, Charset.defaultCharset().newDecoder());
|
return fromPropertyFile(filename, propertyPrefix, Charset.defaultCharset().newDecoder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +279,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* @param decoder character encoding to use when reading the property file
|
* @param decoder character encoding to use when reading the property file
|
||||||
* @throws DatabaseException if the property file could not be read for any reason
|
* @throws DatabaseException if the property file could not be read for any reason
|
||||||
*/
|
*/
|
||||||
public static Builder fromPropertyFile(String filename, String propertyPrefix, CharsetDecoder decoder) {
|
public static DatabaseProviderBuilder fromPropertyFile(String filename, String propertyPrefix, CharsetDecoder decoder) {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
if (filename != null && filename.length() > 0) {
|
if (filename != null && filename.length() > 0) {
|
||||||
try (
|
try (
|
||||||
|
@ -323,7 +311,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* @param properties properties will be read from here
|
* @param properties properties will be read from here
|
||||||
* @throws DatabaseException if the property file could not be read for any reason
|
* @throws DatabaseException if the property file could not be read for any reason
|
||||||
*/
|
*/
|
||||||
public static Builder fromProperties(Properties properties) {
|
public static DatabaseProviderBuilder fromProperties(Properties properties) {
|
||||||
return fromProperties(properties, "", false);
|
return fromProperties(properties, "", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +336,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* pass "my." as the prefix)
|
* pass "my." as the prefix)
|
||||||
* @throws DatabaseException if the property file could not be read for any reason
|
* @throws DatabaseException if the property file could not be read for any reason
|
||||||
*/
|
*/
|
||||||
public static Builder fromProperties(Properties properties, String propertyPrefix) {
|
public static DatabaseProviderBuilder fromProperties(Properties properties, String propertyPrefix) {
|
||||||
return fromProperties(properties, propertyPrefix, false);
|
return fromProperties(properties, propertyPrefix, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +362,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* log entry will be entered, but it will attempt to proceed using
|
* log entry will be entered, but it will attempt to proceed using
|
||||||
* solely the system properties
|
* solely the system properties
|
||||||
*/
|
*/
|
||||||
public static Builder fromPropertyFileOrSystemProperties(String filename) {
|
public static DatabaseProviderBuilder fromPropertyFileOrSystemProperties(String filename) {
|
||||||
return fromPropertyFileOrSystemProperties(filename, Charset.defaultCharset().newDecoder());
|
return fromPropertyFileOrSystemProperties(filename, Charset.defaultCharset().newDecoder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +388,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* solely the system properties
|
* solely the system properties
|
||||||
* @param decoder character encoding to use when reading the property file
|
* @param decoder character encoding to use when reading the property file
|
||||||
*/
|
*/
|
||||||
public static Builder fromPropertyFileOrSystemProperties(String filename, CharsetDecoder decoder) {
|
public static DatabaseProviderBuilder fromPropertyFileOrSystemProperties(String filename, CharsetDecoder decoder) {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
if (filename != null && filename.length() > 0) {
|
if (filename != null && filename.length() > 0) {
|
||||||
try (
|
try (
|
||||||
|
@ -441,7 +429,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* (exactly, so if you want to use "my.database.url" you must
|
* (exactly, so if you want to use "my.database.url" you must
|
||||||
* pass "my." as the prefix)
|
* pass "my." as the prefix)
|
||||||
*/
|
*/
|
||||||
public static Builder fromPropertyFileOrSystemProperties(String filename, String propertyPrefix) {
|
public static DatabaseProviderBuilder fromPropertyFileOrSystemProperties(String filename, String propertyPrefix) {
|
||||||
return fromPropertyFileOrSystemProperties(filename, propertyPrefix, Charset.defaultCharset().newDecoder());
|
return fromPropertyFileOrSystemProperties(filename, propertyPrefix, Charset.defaultCharset().newDecoder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,8 +459,8 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* pass "my." as the prefix)
|
* pass "my." as the prefix)
|
||||||
* @param decoder character encoding to use when reading the property file
|
* @param decoder character encoding to use when reading the property file
|
||||||
*/
|
*/
|
||||||
public static Builder fromPropertyFileOrSystemProperties(String filename, String propertyPrefix,
|
public static DatabaseProviderBuilder fromPropertyFileOrSystemProperties(String filename, String propertyPrefix,
|
||||||
CharsetDecoder decoder) {
|
CharsetDecoder decoder) {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
if (filename != null && filename.length() > 0) {
|
if (filename != null && filename.length() > 0) {
|
||||||
try (
|
try (
|
||||||
|
@ -502,7 +490,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static Builder fromSystemProperties() {
|
public static DatabaseProviderBuilder fromSystemProperties() {
|
||||||
return fromProperties(null, "", true);
|
return fromProperties(null, "", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,11 +512,11 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* dot if desired (e.g. "mydb." for properties like -Dmydb.database.url)
|
* dot if desired (e.g. "mydb." for properties like -Dmydb.database.url)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static Builder fromSystemProperties(String propertyPrefix) {
|
public static DatabaseProviderBuilder fromSystemProperties(String propertyPrefix) {
|
||||||
return fromProperties(null, propertyPrefix, true);
|
return fromProperties(null, propertyPrefix, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Builder fromProperties(Properties properties, String propertyPrefix, boolean useSystemProperties) {
|
private static DatabaseProviderBuilder fromProperties(Properties properties, String propertyPrefix, boolean useSystemProperties) {
|
||||||
if (propertyPrefix == null) {
|
if (propertyPrefix == null) {
|
||||||
propertyPrefix = "";
|
propertyPrefix = "";
|
||||||
}
|
}
|
||||||
|
@ -599,7 +587,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataSource createDataSource(Config config)
|
private static DataSource createDataSource(Config config)
|
||||||
throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException,
|
throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException,
|
||||||
IllegalAccessException {
|
IllegalAccessException {
|
||||||
String url = config.getString("database.url");
|
String url = config.getString("database.url");
|
||||||
|
@ -621,7 +609,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
return new PoolDataSource(poolConfig);
|
return new PoolDataSource(poolConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Flavor getFlavor(Config config) {
|
private static Flavor getFlavor(Config config) {
|
||||||
String url = config.getString("database.url");
|
String url = config.getString("database.url");
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
throw new DatabaseException("You must provide database.url");
|
throw new DatabaseException("You must provide database.url");
|
||||||
|
@ -755,30 +743,27 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Database get() {
|
public Database get() {
|
||||||
if (delegateTo != null) {
|
|
||||||
return delegateTo.get();
|
|
||||||
}
|
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
return database;
|
return database;
|
||||||
}
|
}
|
||||||
if (connectionProvider == null) {
|
if (builder.isClosed()) {
|
||||||
throw new DatabaseException("Called get() on a DatabaseProvider after close()");
|
throw new DatabaseException("Called get() on a DatabaseProvider after close()");
|
||||||
}
|
}
|
||||||
Metric metric = new Metric(log.isLoggable(Level.FINE));
|
Metric metric = new Metric(log.isLoggable(Level.FINE));
|
||||||
try {
|
try {
|
||||||
connection = connectionProvider.get();
|
connection = builder.connectionProvider.get();
|
||||||
metric.checkpoint("getConn");
|
metric.checkpoint("getConn");
|
||||||
try {
|
try {
|
||||||
// JDBC specifies that autoCommit is the default for all new connections.
|
// JDBC specifies that autoCommit is the default for all new connections.
|
||||||
// Don't try to be clever about clearing it conditionally.
|
// Don't try to be clever about clearing it conditionally.
|
||||||
if (!options.flavor().isAutoCommitOnly()) {
|
if (!builder.options.flavor().isAutoCommitOnly()) {
|
||||||
connection.setAutoCommit(false);
|
connection.setAutoCommit(false);
|
||||||
metric.checkpoint("setAutoCommit");
|
metric.checkpoint("setAutoCommit");
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DatabaseException("Unable to set autoCommit for the connection", e);
|
throw new DatabaseException("Unable to set autoCommit for the connection", e);
|
||||||
}
|
}
|
||||||
database = new DatabaseImpl(connection, options);
|
database = new DatabaseImpl(connection, builder.options);
|
||||||
metric.checkpoint("dbInit");
|
metric.checkpoint("dbInit");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
metric.checkpoint("fail");
|
metric.checkpoint("fail");
|
||||||
|
@ -786,7 +771,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
} finally {
|
} finally {
|
||||||
metric.done();
|
metric.done();
|
||||||
if (log.isLoggable(Level.FINE)) {
|
if (log.isLoggable(Level.FINE)) {
|
||||||
StringBuilder buf = new StringBuilder("Get ").append(options.flavor()).append(" database: ");
|
StringBuilder buf = new StringBuilder("Get ").append(builder.options.flavor()).append(" database: ");
|
||||||
metric.printMessage(buf);
|
metric.printMessage(buf);
|
||||||
log.fine(buf.toString());
|
log.fine(buf.toString());
|
||||||
}
|
}
|
||||||
|
@ -794,78 +779,10 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
return database;
|
return database;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder fakeBuilder() {
|
|
||||||
return new Builder() {
|
|
||||||
@Override
|
|
||||||
public Builder withOptions(OptionsOverride optionsOverride) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Builder withSqlParameterLogging() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Builder withSqlInExceptionMessages() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Builder withDatePerAppOnly() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Builder withTransactionControl() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Builder withTransactionControlSilentlyIgnored() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Builder withConnectionAccess() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DatabaseProvider build() {
|
|
||||||
return new DatabaseProvider(DatabaseProvider.this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void transact(DbCode tx) {
|
|
||||||
build().transact(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T transactReturning(DbCodeTyped<T> tx) {
|
|
||||||
return build().transactReturning(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void transact(DbCodeTx tx) {
|
|
||||||
build().transact(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
log.fine("Ignoring close call on fakeBuilder");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void commit() {
|
public void commit() {
|
||||||
if (delegateTo != null) {
|
|
||||||
log.fine("Ignoring commit() because this is a fake provider");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
try {
|
try {
|
||||||
if (!options.flavor().isAutoCommitOnly()) {
|
if (!builder.options.flavor().isAutoCommitOnly()) {
|
||||||
connection.commit();
|
connection.commit();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -875,31 +792,22 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void commitAndClose() {
|
public void commitAndClose() {
|
||||||
if (delegateTo != null) {
|
try {
|
||||||
log.fine("Ignoring commitAndClose() because this is a fake provider");
|
if (connection != null) {
|
||||||
return;
|
if (!builder.options.flavor().isAutoCommitOnly()) {
|
||||||
}
|
|
||||||
if (connection != null) {
|
|
||||||
try {
|
|
||||||
if (!options.flavor().isAutoCommitOnly()) {
|
|
||||||
connection.commit();
|
connection.commit();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
throw new DatabaseException("Unable to commit the transaction", e);
|
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new DatabaseException("Unable to commit the transaction", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rollback() {
|
public void rollback() {
|
||||||
if (delegateTo != null) {
|
|
||||||
log.fine("Ignoring rollback() because this is a fake provider");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
try {
|
try {
|
||||||
if (!options.flavor().isAutoCommitOnly()) {
|
if (!builder.options.flavor().isAutoCommitOnly()) {
|
||||||
connection.rollback();
|
connection.rollback();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -909,24 +817,20 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rollbackAndClose() {
|
public void rollbackAndClose() {
|
||||||
if (delegateTo != null) {
|
try {
|
||||||
log.fine("Ignoring rollbackAndClose() because this is a fake provider");
|
if (connection != null) {
|
||||||
return;
|
if (!builder.options.flavor().isAutoCommitOnly()) {
|
||||||
}
|
|
||||||
|
|
||||||
if (connection != null) {
|
|
||||||
try {
|
|
||||||
if (!options.flavor().isAutoCommitOnly()) {
|
|
||||||
connection.rollback();
|
connection.rollback();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
log.log(Level.SEVERE, "Unable to rollback the transaction", e);
|
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.log(Level.SEVERE, "Unable to rollback the transaction", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close() {
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
try {
|
try {
|
||||||
connection.close();
|
connection.close();
|
||||||
|
@ -936,7 +840,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
connection = null;
|
connection = null;
|
||||||
database = null;
|
database = null;
|
||||||
connectionProvider = null;
|
builder.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -944,15 +848,15 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* the previous instance. This is intended to make it safe to pass builders
|
* the previous instance. This is intended to make it safe to pass builders
|
||||||
* around without risk someone will reconfigure it.
|
* around without risk someone will reconfigure it.
|
||||||
*/
|
*/
|
||||||
public interface Builder {
|
public interface DatabaseProviderBuilder {
|
||||||
|
|
||||||
Builder withOptions(OptionsOverride options);
|
DatabaseProviderBuilder withOptions(OptionsOverride options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable logging of parameter values along with the SQL.
|
* Enable logging of parameter values along with the SQL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Builder withSqlParameterLogging();
|
DatabaseProviderBuilder withSqlParameterLogging();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Include SQL in exception messages. This will also include parameters in the
|
* Include SQL in exception messages. This will also include parameters in the
|
||||||
|
@ -961,7 +865,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* dependent on how the exception are caught and handled.
|
* dependent on how the exception are caught and handled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Builder withSqlInExceptionMessages();
|
DatabaseProviderBuilder withSqlInExceptionMessages();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wherever argDateNowPerDb() is specified, use argDateNowPerApp() instead. This is
|
* Wherever argDateNowPerDb() is specified, use argDateNowPerApp() instead. This is
|
||||||
|
@ -969,7 +873,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* own system clock that will be used for time travel.
|
* own system clock that will be used for time travel.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Builder withDatePerAppOnly();
|
DatabaseProviderBuilder withDatePerAppOnly();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow provided Database instances to explicitly control transactions using the
|
* Allow provided Database instances to explicitly control transactions using the
|
||||||
|
@ -977,14 +881,14 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* throw an exception.
|
* throw an exception.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Builder withTransactionControl();
|
DatabaseProviderBuilder withTransactionControl();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This can be useful when testing code, as it can pretend to use transactions,
|
* This can be useful when testing code, as it can pretend to use transactions,
|
||||||
* while giving you control over whether it actually commits or rolls back.
|
* while giving you control over whether it actually commits or rolls back.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Builder withTransactionControlSilentlyIgnored();
|
DatabaseProviderBuilder withTransactionControlSilentlyIgnored();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow direct access to the underlying database connection. Normally this is
|
* Allow direct access to the underlying database connection. Normally this is
|
||||||
|
@ -992,7 +896,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
* legacy code that works with raw JDBC.
|
* legacy code that works with raw JDBC.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Builder withConnectionAccess();
|
DatabaseProviderBuilder withConnectionAccess();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WARNING: You should try to avoid using this method. If you use it more
|
* WARNING: You should try to avoid using this method. If you use it more
|
||||||
|
@ -1060,31 +964,35 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
*/
|
*/
|
||||||
void transact(DbCodeTx code);
|
void transact(DbCodeTx code);
|
||||||
|
|
||||||
void close() throws IOException;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BuilderImpl implements Builder {
|
private static class DatabaseProviderBuilderImpl implements DatabaseProviderBuilder, Closeable {
|
||||||
|
|
||||||
private DataSource ds;
|
private DataSource dataSource;
|
||||||
|
|
||||||
private final Supplier<Connection> connectionProvider;
|
private final Supplier<Connection> connectionProvider;
|
||||||
|
|
||||||
private final Options options;
|
private final Options options;
|
||||||
|
|
||||||
private BuilderImpl(DataSource ds, Supplier<Connection> connectionProvider, Options options) {
|
private final AtomicBoolean closed;
|
||||||
this.ds = ds;
|
|
||||||
|
private DatabaseProviderBuilderImpl(DataSource dataSource,
|
||||||
|
Supplier<Connection> connectionProvider,
|
||||||
|
Options options) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
this.connectionProvider = connectionProvider;
|
this.connectionProvider = connectionProvider;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
this.closed = new AtomicBoolean(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder withOptions(OptionsOverride options) {
|
public DatabaseProviderBuilder withOptions(OptionsOverride options) {
|
||||||
return new BuilderImpl(ds, connectionProvider, options.withParent(this.options));
|
return new DatabaseProviderBuilderImpl(dataSource, connectionProvider, options.withParent(this.options));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder withSqlParameterLogging() {
|
public DatabaseProviderBuilder withSqlParameterLogging() {
|
||||||
return new BuilderImpl(ds, connectionProvider, new OptionsOverride() {
|
return new DatabaseProviderBuilderImpl(dataSource, connectionProvider, new OptionsOverride() {
|
||||||
@Override
|
@Override
|
||||||
public boolean isLogParameters() {
|
public boolean isLogParameters() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1093,8 +1001,8 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder withSqlInExceptionMessages() {
|
public DatabaseProviderBuilder withSqlInExceptionMessages() {
|
||||||
return new BuilderImpl(ds, connectionProvider, new OptionsOverride() {
|
return new DatabaseProviderBuilderImpl(dataSource, connectionProvider, new OptionsOverride() {
|
||||||
@Override
|
@Override
|
||||||
public boolean isDetailedExceptions() {
|
public boolean isDetailedExceptions() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1103,8 +1011,8 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder withDatePerAppOnly() {
|
public DatabaseProviderBuilder withDatePerAppOnly() {
|
||||||
return new BuilderImpl(ds, connectionProvider, new OptionsOverride() {
|
return new DatabaseProviderBuilderImpl(dataSource, connectionProvider, new OptionsOverride() {
|
||||||
@Override
|
@Override
|
||||||
public boolean useLocalDateTimeOnly() {
|
public boolean useLocalDateTimeOnly() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1113,8 +1021,8 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder withTransactionControl() {
|
public DatabaseProviderBuilder withTransactionControl() {
|
||||||
return new BuilderImpl(ds, connectionProvider, new OptionsOverride() {
|
return new DatabaseProviderBuilderImpl(dataSource, connectionProvider, new OptionsOverride() {
|
||||||
@Override
|
@Override
|
||||||
public boolean allowTransactionControl() {
|
public boolean allowTransactionControl() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1123,8 +1031,8 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder withTransactionControlSilentlyIgnored() {
|
public DatabaseProviderBuilder withTransactionControlSilentlyIgnored() {
|
||||||
return new BuilderImpl(ds, connectionProvider, new OptionsOverride() {
|
return new DatabaseProviderBuilderImpl(dataSource, connectionProvider, new OptionsOverride() {
|
||||||
@Override
|
@Override
|
||||||
public boolean ignoreTransactionControl() {
|
public boolean ignoreTransactionControl() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1133,8 +1041,8 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder withConnectionAccess() {
|
public DatabaseProviderBuilder withConnectionAccess() {
|
||||||
return new BuilderImpl(ds, connectionProvider, new OptionsOverride() {
|
return new DatabaseProviderBuilderImpl(dataSource, connectionProvider, new OptionsOverride() {
|
||||||
@Override
|
@Override
|
||||||
public boolean allowConnectionAccess() {
|
public boolean allowConnectionAccess() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1144,7 +1052,7 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatabaseProvider build() {
|
public DatabaseProvider build() {
|
||||||
return new DatabaseProvider(connectionProvider, options);
|
return new DatabaseProvider(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1164,12 +1072,18 @@ public final class DatabaseProvider implements Supplier<Database> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (ds != null) {
|
if (closed.compareAndSet(false, true)) {
|
||||||
if (ds instanceof Closeable) {
|
if (dataSource != null) {
|
||||||
((Closeable) ds).close();
|
if (dataSource instanceof Closeable) {
|
||||||
|
((Closeable) dataSource).close();
|
||||||
|
}
|
||||||
|
dataSource = null;
|
||||||
}
|
}
|
||||||
ds = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ package org.xbib.jdbc.query;
|
||||||
import org.xbib.jdbc.query.util.DebugSql;
|
import org.xbib.jdbc.query.util.DebugSql;
|
||||||
import org.xbib.jdbc.query.util.Metric;
|
import org.xbib.jdbc.query.util.Metric;
|
||||||
|
|
||||||
import java.sql.CallableStatement;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
@ -13,8 +13,6 @@ public class DdlImpl implements Ddl {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(Database.class.getName());
|
private static final Logger log = Logger.getLogger(Database.class.getName());
|
||||||
|
|
||||||
private static final Logger logQuiet = Logger.getLogger(Database.class.getName() + ".quiet");
|
|
||||||
|
|
||||||
private final Connection connection;
|
private final Connection connection;
|
||||||
|
|
||||||
private final String sql;
|
private final String sql;
|
||||||
|
@ -28,15 +26,15 @@ public class DdlImpl implements Ddl {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInternal(boolean quiet) {
|
private void updateInternal(boolean quiet) {
|
||||||
CallableStatement ps = null;
|
PreparedStatement preparedStatement = null;
|
||||||
Metric metric = new Metric(log.isLoggable(Level.FINE));
|
Metric metric = new Metric(log.isLoggable(Level.FINE));
|
||||||
boolean isSuccess = false;
|
boolean isSuccess = false;
|
||||||
String errorCode = null;
|
String errorCode = null;
|
||||||
Exception logEx = null;
|
Exception logEx = null;
|
||||||
try {
|
try {
|
||||||
ps = connection.prepareCall(sql);
|
preparedStatement = connection.prepareStatement(sql);
|
||||||
metric.checkpoint("prep");
|
metric.checkpoint("prep");
|
||||||
ps.execute();
|
preparedStatement.execute();
|
||||||
metric.checkpoint("exec");
|
metric.checkpoint("exec");
|
||||||
isSuccess = true;
|
isSuccess = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -44,15 +42,13 @@ public class DdlImpl implements Ddl {
|
||||||
logEx = e;
|
logEx = e;
|
||||||
throw DatabaseException.wrap(DebugSql.exceptionMessage(sql, null, errorCode, options), e);
|
throw DatabaseException.wrap(DebugSql.exceptionMessage(sql, null, errorCode, options), e);
|
||||||
} finally {
|
} finally {
|
||||||
close(ps);
|
close(preparedStatement);
|
||||||
metric.checkpoint("close");
|
metric.checkpoint("close");
|
||||||
// PostgreSQL requires explicit commit since we are running with setAutoCommit(false)
|
// PostgreSQL requires explicit commit since we are running with setAutoCommit(false)
|
||||||
commit(connection);
|
commit(connection);
|
||||||
metric.done("commit");
|
metric.done("commit");
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
DebugSql.logSuccess("DDL", log, metric, sql, null, options);
|
DebugSql.logSuccess("DDL", log, metric, sql, null, options);
|
||||||
} else if (quiet) {
|
|
||||||
DebugSql.logWarning("DDL", logQuiet, metric, errorCode, sql, null, options, logEx);
|
|
||||||
} else {
|
} else {
|
||||||
DebugSql.logError("DDL", log, metric, errorCode, sql, null, options, logEx);
|
DebugSql.logError("DDL", log, metric, errorCode, sql, null, options, logEx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.xbib.jdbc.query;
|
package org.xbib.jdbc.query;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
public interface Flavor {
|
public interface Flavor {
|
||||||
|
@ -24,8 +26,12 @@ public interface Flavor {
|
||||||
|
|
||||||
String typeFloat();
|
String typeFloat();
|
||||||
|
|
||||||
|
void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException;
|
||||||
|
|
||||||
String typeDouble();
|
String typeDouble();
|
||||||
|
|
||||||
|
void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException;
|
||||||
|
|
||||||
String typeBigDecimal(int size, int precision);
|
String typeBigDecimal(int size, int precision);
|
||||||
|
|
||||||
String typeStringVar(int length);
|
String typeStringVar(int length);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.xbib.jdbc.query;
|
package org.xbib.jdbc.query;
|
||||||
|
|
||||||
import org.xbib.jdbc.query.flavor.Postgresql;
|
import org.xbib.jdbc.query.flavor.Derby;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for selectively overriding another Options object.
|
* Base class for selectively overriding another Options object.
|
||||||
|
@ -18,10 +18,10 @@ public class OptionsOverride implements Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defer to OptionsDefault for anything that is not specified, and use postgresql flavor.
|
* Defer to OptionsDefault for anything that is not specified.
|
||||||
*/
|
*/
|
||||||
public OptionsOverride() {
|
public OptionsOverride() {
|
||||||
parent = new OptionsDefault(new Postgresql());
|
parent = new OptionsDefault(new Derby());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,8 +5,6 @@ import org.xbib.jdbc.query.Schema.Table.Column;
|
||||||
import org.xbib.jdbc.query.Schema.Table.ForeignKey;
|
import org.xbib.jdbc.query.Schema.Table.ForeignKey;
|
||||||
import org.xbib.jdbc.query.Schema.Table.Index;
|
import org.xbib.jdbc.query.Schema.Table.Index;
|
||||||
import org.xbib.jdbc.query.Schema.Table.Unique;
|
import org.xbib.jdbc.query.Schema.Table.Unique;
|
||||||
import org.xbib.jdbc.query.flavor.Oracle;
|
|
||||||
import org.xbib.jdbc.query.flavor.Postgresql;
|
|
||||||
|
|
||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
@ -93,13 +91,14 @@ public class Schema {
|
||||||
table.addColumn(names[i]).asLong();
|
table.addColumn(names[i]).asLong();
|
||||||
break;
|
break;
|
||||||
case Types.REAL:
|
case Types.REAL:
|
||||||
case 100: // Oracle proprietary it seems
|
case 100: // Oracle "binary float"
|
||||||
table.addColumn(names[i]).asFloat();
|
table.addColumn(names[i]).asFloat();
|
||||||
break;
|
break;
|
||||||
case Types.DOUBLE:
|
case Types.DOUBLE:
|
||||||
case 101: // Oracle proprietary it seems
|
case 101: // Oracle "binary double"
|
||||||
table.addColumn(names[i]).asDouble();
|
table.addColumn(names[i]).asDouble();
|
||||||
break;
|
break;
|
||||||
|
case Types.DECIMAL:
|
||||||
case Types.NUMERIC:
|
case Types.NUMERIC:
|
||||||
int precision1 = metadata.getPrecision(i + 1);
|
int precision1 = metadata.getPrecision(i + 1);
|
||||||
int scale = metadata.getScale(i + 1);
|
int scale = metadata.getScale(i + 1);
|
||||||
|
@ -121,6 +120,7 @@ public class Schema {
|
||||||
break;
|
break;
|
||||||
case Types.BINARY:
|
case Types.BINARY:
|
||||||
case Types.VARBINARY:
|
case Types.VARBINARY:
|
||||||
|
case Types.LONGVARBINARY:
|
||||||
case Types.BLOB:
|
case Types.BLOB:
|
||||||
table.addColumn(names[i]).asBlob();
|
table.addColumn(names[i]).asBlob();
|
||||||
break;
|
break;
|
||||||
|
@ -128,14 +128,12 @@ public class Schema {
|
||||||
case Types.NCLOB:
|
case Types.NCLOB:
|
||||||
table.addColumn(names[i]).asClob();
|
table.addColumn(names[i]).asClob();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// The date type is used for a true date - no time info.
|
// The date type is used for a true date - no time info.
|
||||||
// It must be checked before TimeStamp because sql dates are also
|
// It must be checked before TimeStamp because sql dates are also
|
||||||
// recognized as sql timestamp.
|
// recognized as sql timestamp.
|
||||||
case Types.DATE:
|
case Types.DATE:
|
||||||
table.addColumn(names[i]).asLocalDate();
|
table.addColumn(names[i]).asLocalDate();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// This is the type dates and times with time and time zone associated.
|
// This is the type dates and times with time and time zone associated.
|
||||||
// Note that Oracle dates are always really Timestamps.
|
// Note that Oracle dates are always really Timestamps.
|
||||||
case Types.TIMESTAMP:
|
case Types.TIMESTAMP:
|
||||||
|
@ -149,9 +147,9 @@ public class Schema {
|
||||||
table.addColumn(names[i]).asLocalDateTime();
|
table.addColumn(names[i]).asLocalDateTime();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.NVARCHAR:
|
case Types.NVARCHAR:
|
||||||
case Types.VARCHAR:
|
case Types.VARCHAR:
|
||||||
|
case Types.LONGVARCHAR:
|
||||||
int precision = metadata.getPrecision(i + 1);
|
int precision = metadata.getPrecision(i + 1);
|
||||||
if (precision >= 2147483647) {
|
if (precision >= 2147483647) {
|
||||||
// Postgres seems to report clobs are varchar(2147483647)
|
// Postgres seems to report clobs are varchar(2147483647)
|
||||||
|
@ -160,8 +158,8 @@ public class Schema {
|
||||||
table.addColumn(names[i]).asString(precision);
|
table.addColumn(names[i]).asString(precision);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Types.CHAR:
|
|
||||||
case Types.NCHAR:
|
case Types.NCHAR:
|
||||||
|
case Types.CHAR:
|
||||||
table.addColumn(names[i]).asStringFixed(metadata.getPrecision(i + 1));
|
table.addColumn(names[i]).asStringFixed(metadata.getPrecision(i + 1));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -184,12 +182,10 @@ public class Schema {
|
||||||
|
|
||||||
private String executeOrPrint(Database db, Flavor flavor) {
|
private String executeOrPrint(Database db, Flavor flavor) {
|
||||||
validate();
|
validate();
|
||||||
|
|
||||||
if (flavor == null) {
|
if (flavor == null) {
|
||||||
flavor = db.flavor();
|
flavor = db.flavor();
|
||||||
}
|
}
|
||||||
StringBuilder script = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
for (Table table : tables) {
|
for (Table table : tables) {
|
||||||
Sql sql = new Sql();
|
Sql sql = new Sql();
|
||||||
sql.append("create table ").append(table.name).append(" (\n");
|
sql.append("create table ").append(table.name).append(" (\n");
|
||||||
|
@ -228,10 +224,10 @@ public class Schema {
|
||||||
sql.append(flavor.typeStringFixed(column.scale));
|
sql.append(flavor.typeStringFixed(column.scale));
|
||||||
break;
|
break;
|
||||||
case LocalDateTime:
|
case LocalDateTime:
|
||||||
sql.append(flavor.typeLocalDateTime()); // Append a date with time
|
sql.append(flavor.typeLocalDateTime());
|
||||||
break;
|
break;
|
||||||
case LocalDate:
|
case LocalDate:
|
||||||
sql.append(flavor.typeLocalDate()); // Append a true date - no time
|
sql.append(flavor.typeLocalDate());
|
||||||
break;
|
break;
|
||||||
case Clob:
|
case Clob:
|
||||||
sql.append(flavor.typeClob());
|
sql.append(flavor.typeClob());
|
||||||
|
@ -244,7 +240,6 @@ public class Schema {
|
||||||
sql.append(" not null");
|
sql.append(" not null");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (table.primaryKey != null) {
|
if (table.primaryKey != null) {
|
||||||
sql.append(",\n constraint ");
|
sql.append(",\n constraint ");
|
||||||
sql.append(rpad(table.primaryKey.name, 30));
|
sql.append(rpad(table.primaryKey.name, 30));
|
||||||
|
@ -278,16 +273,16 @@ public class Schema {
|
||||||
if (table.customClauses.containsKey(flavor)) {
|
if (table.customClauses.containsKey(flavor)) {
|
||||||
sql.append(" ").append(table.customClauses.get(flavor));
|
sql.append(" ").append(table.customClauses.get(flavor));
|
||||||
}
|
}
|
||||||
executeOrPrint(sql, db, script);
|
executeOrPrint(sql, db, stringBuilder);
|
||||||
sql = new Sql();
|
sql = new Sql();
|
||||||
if (flavor instanceof Oracle || flavor instanceof Postgresql) {
|
if ("oracle".equals(flavor.getName()) || "postgresql".equals(flavor.getName())) {
|
||||||
if (table.comment != null) {
|
if (table.comment != null) {
|
||||||
sql.append("comment on table ");
|
sql.append("comment on table ");
|
||||||
sql.append(table.name);
|
sql.append(table.name);
|
||||||
sql.append(" is \n'");
|
sql.append(" is \n'");
|
||||||
sql.append(table.comment.replace("'", "''"));
|
sql.append(table.comment.replace("'", "''"));
|
||||||
sql.append("'");
|
sql.append("'");
|
||||||
executeOrPrint(sql, db, script);
|
executeOrPrint(sql, db, stringBuilder);
|
||||||
sql = new Sql();
|
sql = new Sql();
|
||||||
}
|
}
|
||||||
for (Column c : table.columns) {
|
for (Column c : table.columns) {
|
||||||
|
@ -299,7 +294,7 @@ public class Schema {
|
||||||
sql.append(" is \n'");
|
sql.append(" is \n'");
|
||||||
sql.append(c.comment.replace("'", "''"));
|
sql.append(c.comment.replace("'", "''"));
|
||||||
sql.append("'");
|
sql.append("'");
|
||||||
executeOrPrint(sql, db, script);
|
executeOrPrint(sql, db, stringBuilder);
|
||||||
sql = new Sql();
|
sql = new Sql();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,7 +317,7 @@ public class Schema {
|
||||||
if (fk.onDeleteCascade) {
|
if (fk.onDeleteCascade) {
|
||||||
sql.append(" on delete cascade");
|
sql.append(" on delete cascade");
|
||||||
}
|
}
|
||||||
executeOrPrint(sql, db, script);
|
executeOrPrint(sql, db, stringBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Table table : tables) {
|
for (Table table : tables) {
|
||||||
|
@ -342,10 +337,9 @@ public class Schema {
|
||||||
sql.append(name);
|
sql.append(name);
|
||||||
}
|
}
|
||||||
sql.listEnd(")");
|
sql.listEnd(")");
|
||||||
executeOrPrint(sql, db, script);
|
executeOrPrint(sql, db, stringBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Sequence sequence : sequences) {
|
for (Sequence sequence : sequences) {
|
||||||
Sql sql = new Sql();
|
Sql sql = new Sql();
|
||||||
sql.append("create sequence ");
|
sql.append("create sequence ");
|
||||||
|
@ -362,11 +356,10 @@ public class Schema {
|
||||||
sql.append(flavor.sequenceCacheClause(sequence.cache));
|
sql.append(flavor.sequenceCacheClause(sequence.cache));
|
||||||
sql.append(flavor.sequenceOrderClause(sequence.order));
|
sql.append(flavor.sequenceOrderClause(sequence.order));
|
||||||
sql.append(flavor.sequenceCycleClause(sequence.cycle));
|
sql.append(flavor.sequenceCycleClause(sequence.cycle));
|
||||||
executeOrPrint(sql, db, script);
|
executeOrPrint(sql, db, stringBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (db == null) {
|
if (db == null) {
|
||||||
return script.toString();
|
return stringBuilder.toString();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -865,12 +858,10 @@ public class Schema {
|
||||||
return asType(ColumnType.StringFixed);
|
return asType(ColumnType.StringFixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This type is for dates that have time associated
|
|
||||||
public Column asLocalDateTime() {
|
public Column asLocalDateTime() {
|
||||||
return asType(ColumnType.LocalDateTime);
|
return asType(ColumnType.LocalDateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This type is for true dates with no time associated
|
|
||||||
public Column asLocalDate() {
|
public Column asLocalDate() {
|
||||||
return asType(ColumnType.LocalDate);
|
return asType(ColumnType.LocalDate);
|
||||||
}
|
}
|
||||||
|
|
|
@ -668,6 +668,7 @@ public class SqlArgs implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Appl
|
||||||
case 101: // Oracle binary double
|
case 101: // Oracle binary double
|
||||||
args.argDouble(names[i], r.getDoubleOrNull());
|
args.argDouble(names[i], r.getDoubleOrNull());
|
||||||
break;
|
break;
|
||||||
|
case Types.DECIMAL:
|
||||||
case Types.NUMERIC:
|
case Types.NUMERIC:
|
||||||
if (precision[i] <= 10 && scale[i] == 0) {
|
if (precision[i] <= 10 && scale[i] == 0) {
|
||||||
args.argInteger(names[i], r.getIntegerOrNull());
|
args.argInteger(names[i], r.getIntegerOrNull());
|
||||||
|
@ -703,6 +704,8 @@ public class SqlArgs implements SqlInsert.Apply, SqlUpdate.Apply, SqlSelect.Appl
|
||||||
case Types.VARCHAR:
|
case Types.VARCHAR:
|
||||||
case Types.CHAR:
|
case Types.CHAR:
|
||||||
case Types.NCHAR:
|
case Types.NCHAR:
|
||||||
|
case Types.LONGVARCHAR:
|
||||||
|
case Types.LONGNVARCHAR:
|
||||||
if (precision[i] >= 2147483647) {
|
if (precision[i] >= 2147483647) {
|
||||||
// Postgres seems to report clobs are varchar(2147483647)
|
// Postgres seems to report clobs are varchar(2147483647)
|
||||||
args.argClobString(names[i], r.getClobStringOrNull());
|
args.argClobString(names[i], r.getClobStringOrNull());
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class SqlInsertImpl implements SqlInsert {
|
||||||
|
|
||||||
private final Connection connection;
|
private final Connection connection;
|
||||||
|
|
||||||
private final StatementAdaptor adaptor;
|
private final StatementAdapter adaptor;
|
||||||
|
|
||||||
private final String sql;
|
private final String sql;
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ public class SqlInsertImpl implements SqlInsert {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.sql = sql;
|
this.sql = sql;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
adaptor = new StatementAdaptor(options);
|
adaptor = new StatementAdapter(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class SqlSelectImpl implements SqlSelect {
|
||||||
|
|
||||||
private final Connection connection;
|
private final Connection connection;
|
||||||
|
|
||||||
private final StatementAdaptor adaptor;
|
private final StatementAdapter adaptor;
|
||||||
|
|
||||||
private final Object cancelLock = new Object();
|
private final Object cancelLock = new Object();
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ public class SqlSelectImpl implements SqlSelect {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.sql = sql;
|
this.sql = sql;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
adaptor = new StatementAdaptor(options);
|
adaptor = new StatementAdapter(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
|
|
||||||
private final Connection connection;
|
private final Connection connection;
|
||||||
|
|
||||||
private final StatementAdaptor adaptor;
|
private final StatementAdapter adaptor;
|
||||||
|
|
||||||
private final String sql;
|
private final String sql;
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ public class SqlUpdateImpl implements SqlUpdate {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.sql = sql;
|
this.sql = sql;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
adaptor = new StatementAdaptor(options);
|
adaptor = new StatementAdapter(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,13 +22,13 @@ import java.util.stream.Collectors;
|
||||||
/**
|
/**
|
||||||
* Deal with mapping parameters into prepared statements.
|
* Deal with mapping parameters into prepared statements.
|
||||||
*/
|
*/
|
||||||
public class StatementAdaptor {
|
public class StatementAdapter {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(StatementAdaptor.class.getName());
|
private static final Logger logger = Logger.getLogger(StatementAdapter.class.getName());
|
||||||
|
|
||||||
private final Options options;
|
private final Options options;
|
||||||
|
|
||||||
public StatementAdaptor(Options options) {
|
public StatementAdapter(Options options) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,9 +90,9 @@ public class StatementAdaptor {
|
||||||
ps.setBinaryStream(i + 1, (InputStream) parameter);
|
ps.setBinaryStream(i + 1, (InputStream) parameter);
|
||||||
}
|
}
|
||||||
} else if (parameter instanceof Float) {
|
} else if (parameter instanceof Float) {
|
||||||
ps.setFloat(i + 1, (Float) parameter);
|
options.flavor().setFloat(ps, i + 1, (Float) parameter);
|
||||||
} else if (parameter instanceof Double) {
|
} else if (parameter instanceof Double) {
|
||||||
ps.setDouble(i + 1, (Double) parameter);
|
options.flavor().setDouble(ps, i + 1, (Double) parameter);
|
||||||
} else {
|
} else {
|
||||||
ps.setObject(i + 1, parameter);
|
ps.setObject(i + 1, parameter);
|
||||||
}
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
package org.xbib.jdbc.query;
|
package org.xbib.jdbc.query;
|
||||||
|
|
||||||
import org.xbib.jdbc.query.flavor.Derby;
|
import org.xbib.jdbc.query.flavor.Derby;
|
||||||
import org.xbib.jdbc.query.flavor.Oracle;
|
|
||||||
import org.xbib.jdbc.query.flavor.Postgresql;
|
|
||||||
import org.xbib.jdbc.query.flavor.SqlServer;
|
import org.xbib.jdbc.query.flavor.SqlServer;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -21,7 +19,7 @@ public class When {
|
||||||
}
|
}
|
||||||
|
|
||||||
public When oracle(String sql) {
|
public When oracle(String sql) {
|
||||||
if (actualFlavor instanceof Oracle) {
|
if ("oracle".equals(actualFlavor.getName())) {
|
||||||
chosen = sql;
|
chosen = sql;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -35,7 +33,7 @@ public class When {
|
||||||
}
|
}
|
||||||
|
|
||||||
public When postgres(String sql) {
|
public When postgres(String sql) {
|
||||||
if (actualFlavor instanceof Postgresql) {
|
if ("postgresql".equals(actualFlavor.getName())) {
|
||||||
chosen = sql;
|
chosen = sql;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -1,177 +0,0 @@
|
||||||
package org.xbib.jdbc.query.flavor;
|
|
||||||
|
|
||||||
import org.xbib.jdbc.query.Flavor;
|
|
||||||
|
|
||||||
public class BigQuery implements Flavor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "bigQuery";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(String url) {
|
|
||||||
return url.startsWith("jdbc:bigquery:");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String driverClass() {
|
|
||||||
return "com.simba.googlebigquery.jdbc42.Driver";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNormalizedUpperCase() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeInteger() {
|
|
||||||
return "int64";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeBoolean() {
|
|
||||||
// BigQuery has a native boolean type, but we're not trying to use it
|
|
||||||
return "string";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeLong() {
|
|
||||||
return "int64";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeFloat() {
|
|
||||||
return "float64";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeDouble() {
|
|
||||||
return "float64";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeBigDecimal(int size, int precision) {
|
|
||||||
return "numeric";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeStringVar(int length) {
|
|
||||||
return "string";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeStringFixed(int length) {
|
|
||||||
return "string";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeClob() {
|
|
||||||
return "string";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeBlob() {
|
|
||||||
return "bytes";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeLocalDateTime() {
|
|
||||||
return "datetime";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String typeLocalDate() {
|
|
||||||
return "date";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean useStringForClob() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean useBytesForBlob() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sequenceNextVal(String sequenceName) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sequenceSelectNextVal(String sequenceName) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sequenceDrop(String dbtestSeq) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String tableDrop(String table) {
|
|
||||||
return "drop table " + table;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsInsertReturning() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String dbTimeMillis() {
|
|
||||||
return "current_timestamp()";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sequenceCacheClause(int nbrValuesToCache) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sequenceOrderClause(boolean order) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sequenceCycleClause(boolean cycle) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String fromAny() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sequenceOptions() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAutoCommitOnly() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String writeNextIntoQueue(String table) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String readNextFromQueue(String table) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String succeedInQueue(String table) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String failInQueue(String table) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,6 +2,9 @@ package org.xbib.jdbc.query.flavor;
|
||||||
|
|
||||||
import org.xbib.jdbc.query.Flavor;
|
import org.xbib.jdbc.query.Flavor;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public class Derby implements Flavor {
|
public class Derby implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,11 +47,21 @@ public class Derby implements Flavor {
|
||||||
return "real";
|
return "real";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
|
||||||
|
preparedStatement.setFloat(i, floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeDouble() {
|
public String typeDouble() {
|
||||||
return "double";
|
return "double";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
|
||||||
|
preparedStatement.setDouble(i, doubleValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeBigDecimal(int size, int precision) {
|
public String typeBigDecimal(int size, int precision) {
|
||||||
return "numeric(" + size + "," + precision + ")";
|
return "numeric(" + size + "," + precision + ")";
|
||||||
|
|
|
@ -2,6 +2,9 @@ package org.xbib.jdbc.query.flavor;
|
||||||
|
|
||||||
import org.xbib.jdbc.query.Flavor;
|
import org.xbib.jdbc.query.Flavor;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public class H2 implements Flavor {
|
public class H2 implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,11 +47,21 @@ public class H2 implements Flavor {
|
||||||
return "double";
|
return "double";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
|
||||||
|
preparedStatement.setFloat(i, floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeDouble() {
|
public String typeDouble() {
|
||||||
return "double";
|
return "double";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
|
||||||
|
preparedStatement.setDouble(i, doubleValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeBigDecimal(int size, int precision) {
|
public String typeBigDecimal(int size, int precision) {
|
||||||
return "numeric(" + size + "," + precision + ")";
|
return "numeric(" + size + "," + precision + ")";
|
||||||
|
|
|
@ -2,6 +2,9 @@ package org.xbib.jdbc.query.flavor;
|
||||||
|
|
||||||
import org.xbib.jdbc.query.Flavor;
|
import org.xbib.jdbc.query.Flavor;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public class Hsql implements Flavor {
|
public class Hsql implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,11 +47,21 @@ public class Hsql implements Flavor {
|
||||||
return "double";
|
return "double";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
|
||||||
|
preparedStatement.setFloat(i, floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeDouble() {
|
public String typeDouble() {
|
||||||
return "double";
|
return "double";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
|
||||||
|
preparedStatement.setDouble(i, doubleValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeBigDecimal(int size, int precision) {
|
public String typeBigDecimal(int size, int precision) {
|
||||||
return "numeric(" + size + "," + precision + ")";
|
return "numeric(" + size + "," + precision + ")";
|
||||||
|
|
|
@ -2,6 +2,9 @@ package org.xbib.jdbc.query.flavor;
|
||||||
|
|
||||||
import org.xbib.jdbc.query.Flavor;
|
import org.xbib.jdbc.query.Flavor;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public class SqlServer implements Flavor {
|
public class SqlServer implements Flavor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,11 +32,21 @@ public class SqlServer implements Flavor {
|
||||||
return "float(24)";
|
return "float(24)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
|
||||||
|
preparedStatement.setFloat(i, floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeDouble() {
|
public String typeDouble() {
|
||||||
return "float(53)";
|
return "float(53)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException {
|
||||||
|
preparedStatement.setDouble(i, doubleValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String typeBigDecimal(int size, int precision) {
|
public String typeBigDecimal(int size, int precision) {
|
||||||
return "numeric(" + size + "," + precision + ")";
|
return "numeric(" + size + "," + precision + ")";
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
org.xbib.jdbc.query.flavor.BigQuery
|
|
||||||
org.xbib.jdbc.query.flavor.Derby
|
org.xbib.jdbc.query.flavor.Derby
|
||||||
org.xbib.jdbc.query.flavor.Hsql
|
org.xbib.jdbc.query.flavor.Hsql
|
||||||
org.xbib.jdbc.query.flavor.H2
|
org.xbib.jdbc.query.flavor.H2
|
||||||
org.xbib.jdbc.query.flavor.MySQL
|
|
||||||
org.xbib.jdbc.query.flavor.Oracle
|
|
||||||
org.xbib.jdbc.query.flavor.Postgresql
|
|
||||||
org.xbib.jdbc.query.flavor.SqlServer
|
org.xbib.jdbc.query.flavor.SqlServer
|
|
@ -15,7 +15,7 @@ import org.xbib.jdbc.query.RowsHandler;
|
||||||
import org.xbib.jdbc.query.Schema;
|
import org.xbib.jdbc.query.Schema;
|
||||||
import org.xbib.jdbc.query.Sql;
|
import org.xbib.jdbc.query.Sql;
|
||||||
import org.xbib.jdbc.query.SqlArgs;
|
import org.xbib.jdbc.query.SqlArgs;
|
||||||
import org.xbib.jdbc.query.StatementAdaptor;
|
import org.xbib.jdbc.query.StatementAdapter;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
@ -59,7 +59,7 @@ public abstract class CommonTest {
|
||||||
|
|
||||||
final static String TEST_TABLE_NAME = "dbtest";
|
final static String TEST_TABLE_NAME = "dbtest";
|
||||||
|
|
||||||
protected DatabaseProvider dbp;
|
protected static DatabaseProvider dbp;
|
||||||
|
|
||||||
protected Database db;
|
protected Database db;
|
||||||
|
|
||||||
|
@ -67,6 +67,8 @@ public abstract class CommonTest {
|
||||||
|
|
||||||
protected LocalDate localDateNow;
|
protected LocalDate localDateNow;
|
||||||
|
|
||||||
|
protected abstract DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setupJdbc() throws Exception {
|
public void setupJdbc() throws Exception {
|
||||||
now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS);
|
now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS);
|
||||||
|
@ -77,8 +79,6 @@ public abstract class CommonTest {
|
||||||
db.dropTableQuietly(TEST_TABLE_NAME);
|
db.dropTableQuietly(TEST_TABLE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception;
|
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void closeJdbc() {
|
public void closeJdbc() {
|
||||||
if (dbp != null) {
|
if (dbp != null) {
|
||||||
|
@ -92,12 +92,10 @@ public abstract class CommonTest {
|
||||||
String lowercaseTable = TEST_TABLE_NAME.toLowerCase();
|
String lowercaseTable = TEST_TABLE_NAME.toLowerCase();
|
||||||
testTableLookup(lowercaseTable);
|
testTableLookup(lowercaseTable);
|
||||||
db.dropTableQuietly(lowercaseTable);
|
db.dropTableQuietly(lowercaseTable);
|
||||||
|
|
||||||
// Let's try creating a table with an upper case name and verify it works
|
// Let's try creating a table with an upper case name and verify it works
|
||||||
String uppercaseTable = TEST_TABLE_NAME.toUpperCase();
|
String uppercaseTable = TEST_TABLE_NAME.toUpperCase();
|
||||||
testTableLookup(uppercaseTable);
|
testTableLookup(uppercaseTable);
|
||||||
db.dropTableQuietly(uppercaseTable);
|
db.dropTableQuietly(uppercaseTable);
|
||||||
|
|
||||||
// Verify that null or empty name is handled gracefully
|
// Verify that null or empty name is handled gracefully
|
||||||
assertFalse(db.tableExists(null));
|
assertFalse(db.tableExists(null));
|
||||||
assertFalse(db.tableExists(""));
|
assertFalse(db.tableExists(""));
|
||||||
|
@ -106,7 +104,6 @@ public abstract class CommonTest {
|
||||||
private void testTableLookup(String tableName) {
|
private void testTableLookup(String tableName) {
|
||||||
// Verify test table does not exist
|
// Verify test table does not exist
|
||||||
assertFalse(db.tableExists(tableName));
|
assertFalse(db.tableExists(tableName));
|
||||||
|
|
||||||
// Create and verify it exists.
|
// Create and verify it exists.
|
||||||
new Schema().addTable(tableName).addColumn("pk").primaryKey().schema().execute(db);
|
new Schema().addTable(tableName).addColumn("pk").primaryKey().schema().execute(db);
|
||||||
assertTrue(db.tableExists(tableName));
|
assertTrue(db.tableExists(tableName));
|
||||||
|
@ -1529,7 +1526,7 @@ public abstract class CommonTest {
|
||||||
LocalDate lastStdDateSpring = LocalDate.of(2019, Month.MARCH, 9);
|
LocalDate lastStdDateSpring = LocalDate.of(2019, Month.MARCH, 9);
|
||||||
LocalDate firstDSTDateSpring = LocalDate.of(2019, Month.MARCH, 10);
|
LocalDate firstDSTDateSpring = LocalDate.of(2019, Month.MARCH, 10);
|
||||||
// Verify that the original LocalDate matches the driver SQL LocalDate generated.
|
// Verify that the original LocalDate matches the driver SQL LocalDate generated.
|
||||||
StatementAdaptor adaptor = new StatementAdaptor(new OptionsDefault(db.flavor()));
|
StatementAdapter adaptor = new StatementAdapter(new OptionsDefault(db.flavor()));
|
||||||
assertEquals(lastStdDateSpring.toString(), adaptor.nullLocalDate(lastStdDateSpring).toString());
|
assertEquals(lastStdDateSpring.toString(), adaptor.nullLocalDate(lastStdDateSpring).toString());
|
||||||
assertEquals(firstDSTDateSpring.toString(), adaptor.nullLocalDate(firstDSTDateSpring).toString());
|
assertEquals(firstDSTDateSpring.toString(), adaptor.nullLocalDate(firstDSTDateSpring).toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ public class ConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStripPrefixConflict() {
|
public void testStripPrefixConflict() {
|
||||||
Config config = ConfigSupplier.of().value("a.foo", "a").value("foo", "bar").removePrefix("a.").get();
|
Config config = ConfigSupplier.of().property("a.foo", "a").property("foo", "bar").removePrefix("a.").get();
|
||||||
|
|
||||||
assertEquals("bar", config.getString("foo"));
|
assertEquals("bar", config.getString("foo"));
|
||||||
}
|
}
|
||||||
|
@ -138,12 +138,12 @@ public class ConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTidyValues() {
|
public void testTidyValues() {
|
||||||
Config config = ConfigSupplier.of().value("foo", " a ").get();
|
Config config = ConfigSupplier.of().property("foo", " a ").get();
|
||||||
|
|
||||||
// Strip whitespace
|
// Strip whitespace
|
||||||
assertEquals("a", config.getString("foo"));
|
assertEquals("a", config.getString("foo"));
|
||||||
|
|
||||||
config = ConfigSupplier.of().value("foo", " ").value("foo", "").value("foo", null).value("foo", "a").get();
|
config = ConfigSupplier.of().property("foo", " ").property("foo", "").property("foo", null).property("foo", "a").get();
|
||||||
|
|
||||||
// Skip over the garbage ones
|
// Skip over the garbage ones
|
||||||
assertEquals("a", config.getString("foo"));
|
assertEquals("a", config.getString("foo"));
|
||||||
|
@ -152,35 +152,35 @@ public class ConfigTest {
|
||||||
@Test
|
@Test
|
||||||
public void testBoolean() {
|
public void testBoolean() {
|
||||||
// Case insensitive, allow either true/false or yes/no
|
// Case insensitive, allow either true/false or yes/no
|
||||||
Config config = ConfigSupplier.of().value("foo", "tRuE").get();
|
Config config = ConfigSupplier.of().property("foo", "tRuE").get();
|
||||||
|
|
||||||
assertTrue(config.getBooleanOrFalse("foo"));
|
assertTrue(config.getBooleanOrFalse("foo"));
|
||||||
assertTrue(config.getBooleanOrTrue("foo"));
|
assertTrue(config.getBooleanOrTrue("foo"));
|
||||||
assertFalse(config.getBooleanOrFalse("unknown"));
|
assertFalse(config.getBooleanOrFalse("unknown"));
|
||||||
assertTrue(config.getBooleanOrTrue("unknown"));
|
assertTrue(config.getBooleanOrTrue("unknown"));
|
||||||
|
|
||||||
config = ConfigSupplier.of().value("foo", "yEs").get();
|
config = ConfigSupplier.of().property("foo", "yEs").get();
|
||||||
|
|
||||||
assertTrue(config.getBooleanOrFalse("foo"));
|
assertTrue(config.getBooleanOrFalse("foo"));
|
||||||
assertTrue(config.getBooleanOrTrue("foo"));
|
assertTrue(config.getBooleanOrTrue("foo"));
|
||||||
assertFalse(config.getBooleanOrFalse("unknown"));
|
assertFalse(config.getBooleanOrFalse("unknown"));
|
||||||
assertTrue(config.getBooleanOrTrue("unknown"));
|
assertTrue(config.getBooleanOrTrue("unknown"));
|
||||||
|
|
||||||
config = ConfigSupplier.of().value("foo", "fAlSe").get();
|
config = ConfigSupplier.of().property("foo", "fAlSe").get();
|
||||||
|
|
||||||
assertFalse(config.getBooleanOrFalse("foo"));
|
assertFalse(config.getBooleanOrFalse("foo"));
|
||||||
assertFalse(config.getBooleanOrTrue("foo"));
|
assertFalse(config.getBooleanOrTrue("foo"));
|
||||||
assertFalse(config.getBooleanOrFalse("unknown"));
|
assertFalse(config.getBooleanOrFalse("unknown"));
|
||||||
assertTrue(config.getBooleanOrTrue("unknown"));
|
assertTrue(config.getBooleanOrTrue("unknown"));
|
||||||
|
|
||||||
config = ConfigSupplier.of().value("foo", "nO").get();
|
config = ConfigSupplier.of().property("foo", "nO").get();
|
||||||
|
|
||||||
assertFalse(config.getBooleanOrFalse("foo"));
|
assertFalse(config.getBooleanOrFalse("foo"));
|
||||||
assertFalse(config.getBooleanOrTrue("foo"));
|
assertFalse(config.getBooleanOrTrue("foo"));
|
||||||
assertFalse(config.getBooleanOrFalse("unknown"));
|
assertFalse(config.getBooleanOrFalse("unknown"));
|
||||||
assertTrue(config.getBooleanOrTrue("unknown"));
|
assertTrue(config.getBooleanOrTrue("unknown"));
|
||||||
|
|
||||||
config = ConfigSupplier.of().value("foo", "bad value").get();
|
config = ConfigSupplier.of().property("foo", "bad value").get();
|
||||||
|
|
||||||
assertFalse(config.getBooleanOrFalse("foo"));
|
assertFalse(config.getBooleanOrFalse("foo"));
|
||||||
assertTrue(config.getBooleanOrTrue("foo"));
|
assertTrue(config.getBooleanOrTrue("foo"));
|
||||||
|
@ -190,7 +190,7 @@ public class ConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInteger() {
|
public void testInteger() {
|
||||||
Config config = ConfigSupplier.of().value("good", "123").value("bad", "hi").get();
|
Config config = ConfigSupplier.of().property("good", "123").property("bad", "hi").get();
|
||||||
assertEquals(Integer.valueOf(123), config.getInteger("good"));
|
assertEquals(Integer.valueOf(123), config.getInteger("good"));
|
||||||
assertNull(config.getInteger("bad"));
|
assertNull(config.getInteger("bad"));
|
||||||
assertNull(config.getInteger("missing"));
|
assertNull(config.getInteger("missing"));
|
||||||
|
@ -201,7 +201,7 @@ public class ConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLong() {
|
public void testLong() {
|
||||||
Config config = ConfigSupplier.of().value("good", "123").value("bad", "hi").get();
|
Config config = ConfigSupplier.of().property("good", "123").property("bad", "hi").get();
|
||||||
|
|
||||||
assertEquals(Long.valueOf(123), config.getLong("good"));
|
assertEquals(Long.valueOf(123), config.getLong("good"));
|
||||||
assertNull(config.getLong("bad"));
|
assertNull(config.getLong("bad"));
|
||||||
|
@ -213,7 +213,7 @@ public class ConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFloat() {
|
public void testFloat() {
|
||||||
Config config = ConfigSupplier.of().value("good", "123.45").value("bad", "hi").get();
|
Config config = ConfigSupplier.of().property("good", "123.45").property("bad", "hi").get();
|
||||||
|
|
||||||
assertEquals(Float.valueOf(123.45f), config.getFloat("good"));
|
assertEquals(Float.valueOf(123.45f), config.getFloat("good"));
|
||||||
assertNull(config.getFloat("bad"));
|
assertNull(config.getFloat("bad"));
|
||||||
|
@ -225,7 +225,7 @@ public class ConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDouble() {
|
public void testDouble() {
|
||||||
Config config = ConfigSupplier.of().value("good", "123.45").value("bad", "hi").get();
|
Config config = ConfigSupplier.of().property("good", "123.45").property("bad", "hi").get();
|
||||||
|
|
||||||
assertEquals(Double.valueOf(123.45), config.getDouble("good"));
|
assertEquals(Double.valueOf(123.45), config.getDouble("good"));
|
||||||
assertNull(config.getDouble("bad"));
|
assertNull(config.getDouble("bad"));
|
||||||
|
@ -237,7 +237,7 @@ public class ConfigTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBigDecimal() {
|
public void testBigDecimal() {
|
||||||
Config config = ConfigSupplier.of().value("good", "123.45").value("bad", "hi").get();
|
Config config = ConfigSupplier.of().property("good", "123.45").property("bad", "hi").get();
|
||||||
|
|
||||||
assertEquals(new BigDecimal("123.45"), config.getBigDecimal("good"));
|
assertEquals(new BigDecimal("123.45"), config.getBigDecimal("good"));
|
||||||
assertNull(config.getBigDecimal("bad"));
|
assertNull(config.getBigDecimal("bad"));
|
||||||
|
|
|
@ -15,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
/**
|
/**
|
||||||
* Exercise Database functionality with a real database (Derby).
|
* Exercise Database functionality with a real database (Derby).
|
||||||
*/
|
*/
|
||||||
|
@Disabled
|
||||||
public class DerbyTest extends CommonTest {
|
public class DerbyTest extends CommonTest {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DerbyTest.class.getName());
|
private static final Logger logger = Logger.getLogger(DerbyTest.class.getName());
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
package org.xbib.jdbc.query.test;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.testcontainers.containers.OracleContainer;
|
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
|
||||||
import org.xbib.jdbc.query.DatabaseProvider;
|
|
||||||
import org.xbib.jdbc.query.OptionsOverride;
|
|
||||||
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exercise Database functionality with a real Oracle database.
|
|
||||||
*/
|
|
||||||
@Disabled
|
|
||||||
public class OracleTest extends CommonTest {
|
|
||||||
|
|
||||||
@Container
|
|
||||||
public OracleContainer oracleContainer = new OracleContainer("");
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception {
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.load(new FileReader(System.getProperty("local.properties", "local.properties")));
|
|
||||||
return DatabaseProvider.builder(
|
|
||||||
properties.getProperty("database.url"),
|
|
||||||
properties.getProperty("database.user"),
|
|
||||||
properties.getProperty("database.password")
|
|
||||||
).withSqlParameterLogging().withSqlInExceptionMessages().withOptions(options).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Disabled("Current Oracle behavior is to convert -0f to 0f")
|
|
||||||
@Test
|
|
||||||
public void argFloatNegativeZero() {
|
|
||||||
super.argFloatNegativeZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Disabled("Current Oracle behavior is to convert -0d to 0d")
|
|
||||||
@Test
|
|
||||||
public void argDoubleNegativeZero() {
|
|
||||||
super.argDoubleNegativeZero();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package org.xbib.jdbc.query.test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.xbib.jdbc.query.DatabaseProvider;
|
|
||||||
import org.xbib.jdbc.query.OptionsOverride;
|
|
||||||
import org.xbib.jdbc.query.Schema;
|
|
||||||
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exercise Database functionality with a real PostgreSQL database.
|
|
||||||
*/
|
|
||||||
@Disabled
|
|
||||||
public class PostgreSqlTest extends CommonTest {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws IOException {
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.load(new FileReader(System.getProperty("local.properties", "local.properties")));
|
|
||||||
return DatabaseProvider.builder(
|
|
||||||
properties.getProperty("postgres.database.url"),
|
|
||||||
properties.getProperty("postgres.database.user"),
|
|
||||||
properties.getProperty("postgres.database.password")
|
|
||||||
).withOptions(options).withSqlParameterLogging().withSqlInExceptionMessages().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PostgreSQL seems to have different behavior in that is does not convert
|
|
||||||
* column names to uppercase (it actually converts them to lowercase).
|
|
||||||
* I haven't figured out how to smooth over this difference, since all databases
|
|
||||||
* seem to respect the provided case when it is inside quotes, but don't provide
|
|
||||||
* a way to tell whether a particular parameter was quoted.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Test
|
|
||||||
public void metadataColumnNames() {
|
|
||||||
db.dropTableQuietly("dbtest");
|
|
||||||
|
|
||||||
new Schema().addTable("dbtest").addColumn("pk").primaryKey().schema().execute(db);
|
|
||||||
|
|
||||||
db.toSelect("select Pk, Pk as Foo, Pk as \"Foo\" from dbtest")
|
|
||||||
.query(rs -> {
|
|
||||||
assertArrayEquals(new String[]{"pk", "foo", "Foo"}, rs.getColumnLabels());
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,7 +12,7 @@ public abstract class DerbyExample {
|
||||||
// For subclasses to override
|
// For subclasses to override
|
||||||
}
|
}
|
||||||
|
|
||||||
void example(DatabaseProvider.Builder dbb, final String[] args) {
|
void example(DatabaseProvider.DatabaseProviderBuilder dbb, final String[] args) {
|
||||||
dbb.transact(db -> {
|
dbb.transact(db -> {
|
||||||
example(db.get(), args);
|
example(db.get(), args);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
package org.xbib.jdbc.query.test.example;
|
|
||||||
|
|
||||||
import org.xbib.jdbc.query.DatabaseException;
|
|
||||||
import org.xbib.jdbc.query.DatabaseProvider;
|
|
||||||
import org.xbib.jdbc.query.Schema;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Demo of how to use the {@code DatabaseProvider.fakeBuilder()} to control
|
|
||||||
* transactions for testing purposes.
|
|
||||||
*/
|
|
||||||
public class FakeBuilder extends DerbyExample {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
new FakeBuilder().launch(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void example(DatabaseProvider.Builder dbb, String[] args) {
|
|
||||||
DatabaseProvider realDbp = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
realDbp = dbb.build();
|
|
||||||
|
|
||||||
dbb.transact(db -> {
|
|
||||||
// Drops in case we are running this multiple times
|
|
||||||
db.get().dropTableQuietly("t");
|
|
||||||
|
|
||||||
// Create and populate a simple table
|
|
||||||
new Schema().addTable("t").addColumn("pk").primaryKey().schema().execute(db.get());
|
|
||||||
});
|
|
||||||
|
|
||||||
DatabaseProvider.Builder fakeBuilder = realDbp.fakeBuilder();
|
|
||||||
|
|
||||||
// Trying all three transact methods, just for completeness
|
|
||||||
fakeBuilder.transact(db -> {
|
|
||||||
db.get().toInsert("insert into t (pk) values (?)").argLong(1L).insert(1);
|
|
||||||
});
|
|
||||||
fakeBuilder.transact((db, tx) -> {
|
|
||||||
db.get().toInsert("insert into t (pk) values (?)").argLong(2L).insert(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
fakeBuilder.transact(db -> {
|
|
||||||
println("Rows before rollback: " + db.get().toSelect("select count(*) from t").queryLongOrZero());
|
|
||||||
});
|
|
||||||
|
|
||||||
realDbp.rollbackAndClose();
|
|
||||||
|
|
||||||
// Can't use fakeBuilder after close
|
|
||||||
try {
|
|
||||||
fakeBuilder.transact(db -> {
|
|
||||||
db.get().tableExists("foo");
|
|
||||||
println("Eeek...shouldn't get here!");
|
|
||||||
});
|
|
||||||
} catch (DatabaseException e) {
|
|
||||||
println("Correctly threw exception: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
dbb.transact(db -> {
|
|
||||||
println("Rows after rollback: " + db.get().toSelect("select count(*) from t").queryLongOrZero());
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
if (realDbp != null) {
|
|
||||||
realDbp.rollbackAndClose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,5 +5,6 @@ java.util.logging.ConsoleHandler.level=ALL
|
||||||
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
||||||
java.util.logging.FileHandler.level=ALL
|
java.util.logging.FileHandler.level=ALL
|
||||||
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
||||||
java.util.logging.FileHandler.pattern=build/marc.log
|
java.util.logging.FileHandler.pattern=build/database.log
|
||||||
jdk.event.security.level=INFO
|
jdk.event.security.level=INFO
|
||||||
|
javax.management.level=INFO
|
||||||
|
|
5
jdbc-test/build.gradle
Normal file
5
jdbc-test/build.gradle
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
dependencies {
|
||||||
|
api project(":jdbc-query")
|
||||||
|
implementation libs.junit.jupiter.api
|
||||||
|
implementation libs.hamcrest
|
||||||
|
}
|
1721
jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java
Normal file
1721
jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -2,23 +2,32 @@ dependencyResolutionManagement {
|
||||||
versionCatalogs {
|
versionCatalogs {
|
||||||
libs {
|
libs {
|
||||||
version('gradle', '7.5.1')
|
version('gradle', '7.5.1')
|
||||||
version('junit', '5.8.2')
|
version('junit', '5.9.1')
|
||||||
version('testcontainers', '1.17.3')
|
version('testcontainers', '1.17.5')
|
||||||
library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit')
|
library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit')
|
||||||
library('junit-jupiter-params', 'org.junit.jupiter', 'junit-jupiter-params').versionRef('junit')
|
library('junit-jupiter-params', 'org.junit.jupiter', 'junit-jupiter-params').versionRef('junit')
|
||||||
library('junit-jupiter-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit')
|
library('junit-jupiter-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit')
|
||||||
library('hamcrest', 'org.hamcrest', 'hamcrest-library').version('2.2')
|
library('hamcrest', 'org.hamcrest', 'hamcrest-library').version('2.2')
|
||||||
library('junit4', 'junit', 'junit').version('4.13.2')
|
library('junit4', 'junit', 'junit').version('4.13.2')
|
||||||
library('derby', 'org.apache.derby', 'derby').version('10.15.2.0')
|
library('derby', 'org.apache.derby', 'derby').version('10.16.1.1')
|
||||||
library('hsqldb', 'org.hsqldb', 'hsqldb').version('2.7.1')
|
library('hsqldb', 'org.hsqldb', 'hsqldb').version('2.7.1')
|
||||||
library('h2', 'com.h2database', 'h2').version('1.4.200')
|
library('h2', 'com.h2database', 'h2').version('2.1.214')
|
||||||
|
library('mariadb', 'org.mariadb.jdbc', 'mariadb-java-client').version('3.0.8')
|
||||||
|
library('oracle', 'com.oracle.database.jdbc','ojdbc11').version('21.7.0.0')
|
||||||
|
library('postgresql', 'org.postgresql', 'postgresql').version('42.5.0')
|
||||||
|
library('mockito-core', 'org.mockito', 'mockito-core').version('4.8.1')
|
||||||
library('testcontainers', 'org.testcontainers', 'testcontainers').versionRef('testcontainers')
|
library('testcontainers', 'org.testcontainers', 'testcontainers').versionRef('testcontainers')
|
||||||
library('testcontainers-junit-jupiter', 'org.testcontainers', 'junit-jupiter').versionRef('testcontainers')
|
library('testcontainers-junit-jupiter', 'org.testcontainers', 'junit-jupiter').versionRef('testcontainers')
|
||||||
|
library('testcontainers-mariadb', 'org.testcontainers', 'mariadb').versionRef('testcontainers')
|
||||||
library('testcontainers-oracle-xe', 'org.testcontainers', 'oracle-xe').versionRef('testcontainers')
|
library('testcontainers-oracle-xe', 'org.testcontainers', 'oracle-xe').versionRef('testcontainers')
|
||||||
library('mockito-core', 'org.mockito', 'mockito-core').version('4.6.1')
|
library('testcontainers-postgresql', 'org.testcontainers', 'postgresql').versionRef('testcontainers')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
include 'jdbc-connection-pool'
|
include 'jdbc-connection-pool'
|
||||||
include 'jdbc-query'
|
include 'jdbc-query'
|
||||||
|
include 'jdbc-test'
|
||||||
|
include 'jdbc-mariadb'
|
||||||
|
include 'jdbc-oracle'
|
||||||
|
include 'jdbc-postgresql'
|
||||||
|
|
Loading…
Reference in a new issue