From 7378b91c282eae2548158a6f3aa9b77ad290ada3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=CC=88rg=20Prante?=
Date: Sun, 30 Oct 2022 11:42:00 +0100
Subject: [PATCH] cleaning the code, move sqlserver, table name normalization
in flavor, get rid of properties/file handling in DatabaseProvider
---
NOTICE.txt | 10 +-
...oolTest830.java => SaturatedPoolTest.java} | 4 +-
.../java/org/xbib/jdbc/mariadb/MariaDB.java | 20 +-
.../xbib/jdbc/mariadb/test/MariaDBTest.java | 165 +-
.../java/org/xbib/jdbc/oracle/Oracle.java | 17 +-
.../org/xbib/jdbc/postgresql/Postgresql.java | 18 +-
.../jdbc/postgresql/test/PostgresqlTest.java | 1 +
.../src/test/resources/logging.properties | 1 +
jdbc-query/build.gradle | 8 +-
jdbc-query/src/main/java/module-info.java | 4 +-
.../java/org/xbib/jdbc/query/Database.java | 17 +-
.../org/xbib/jdbc/query/DatabaseImpl.java | 46 +-
.../org/xbib/jdbc/query/DatabaseProvider.java | 620 +-----
.../jdbc/query/DatabaseProviderBuilder.java | 126 ++
.../main/java/org/xbib/jdbc/query/Flavor.java | 8 +-
.../main/java/org/xbib/jdbc/query/Schema.java | 106 +-
.../main/java/org/xbib/jdbc/query/When.java | 45 +-
.../org/xbib/jdbc/query/flavor/Derby.java | 17 +-
.../java/org/xbib/jdbc/query/flavor/H2.java | 17 +-
.../java/org/xbib/jdbc/query/flavor/Hsql.java | 17 +-
.../services/org.xbib.jdbc.query.Flavor | 3 +-
.../org/xbib/jdbc/query/test/CommonTest.java | 1721 -----------------
.../org/xbib/jdbc/query/test/DerbyTest.java | 8 +-
.../org/xbib/jdbc/query/test/HsqldbTest.java | 21 +-
.../jdbc/query/test/example/DerbyExample.java | 5 +-
.../jdbc/query/test/example/HelloAny.java | 47 -
.../jdbc/query/test/example/HelloDerby.java | 9 +-
jdbc-sqlserver/build.gradle | 10 +
jdbc-sqlserver/src/main/java/module-info.java | 10 +
.../org/xbib/jdbc/sqlserver}/SqlServer.java | 22 +-
.../services/org.xbib.jdbc.query.Flavor | 1 +
.../jdbc/sqlserver}/test/SqlServerTest.java | 5 +-
.../src/test/resources/logging.properties | 10 +
.../java/org/xbib/jdbc/test/CommonTest.java | 40 +-
settings.gradle | 1 +
35 files changed, 626 insertions(+), 2554 deletions(-)
rename jdbc-connection-pool/src/test/java/org/xbib/io/pool/jdbc/{SaturatedPoolTest830.java => SaturatedPoolTest.java} (98%)
create mode 100644 jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProviderBuilder.java
delete mode 100644 jdbc-query/src/test/java/org/xbib/jdbc/query/test/CommonTest.java
delete mode 100644 jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/HelloAny.java
create mode 100644 jdbc-sqlserver/build.gradle
create mode 100644 jdbc-sqlserver/src/main/java/module-info.java
rename {jdbc-query/src/main/java/org/xbib/jdbc/query/flavor => jdbc-sqlserver/src/main/java/org/xbib/jdbc/sqlserver}/SqlServer.java (88%)
create mode 100644 jdbc-sqlserver/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor
rename {jdbc-query/src/test/java/org/xbib/jdbc/query => jdbc-sqlserver/src/test/java/org/xbib/jdbc/sqlserver}/test/SqlServerTest.java (97%)
create mode 100644 jdbc-sqlserver/src/test/resources/logging.properties
diff --git a/NOTICE.txt b/NOTICE.txt
index adfaf00..8eb427a 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,4 +1,12 @@
-This work is based upon
+The work in jdbc-connection-pool is base upon
+
+https://github.com/brettwooldridge/HikariCP
+
+as of 28 Dec 2021
+
+License: Apache 2.0
+
+The work in jdbc-query is based upon
https://github.com/susom/database
diff --git a/jdbc-connection-pool/src/test/java/org/xbib/io/pool/jdbc/SaturatedPoolTest830.java b/jdbc-connection-pool/src/test/java/org/xbib/io/pool/jdbc/SaturatedPoolTest.java
similarity index 98%
rename from jdbc-connection-pool/src/test/java/org/xbib/io/pool/jdbc/SaturatedPoolTest830.java
rename to jdbc-connection-pool/src/test/java/org/xbib/io/pool/jdbc/SaturatedPoolTest.java
index 8534919..686e1d6 100644
--- a/jdbc-connection-pool/src/test/java/org/xbib/io/pool/jdbc/SaturatedPoolTest830.java
+++ b/jdbc-connection-pool/src/test/java/org/xbib/io/pool/jdbc/SaturatedPoolTest.java
@@ -20,9 +20,9 @@ import org.xbib.jdbc.connection.pool.PoolConfig;
import org.xbib.jdbc.connection.pool.PoolDataSource;
@ExtendWith(PoolTestExtension.class)
-public class SaturatedPoolTest830 {
+public class SaturatedPoolTest {
- private static final Logger logger = Logger.getLogger(SaturatedPoolTest830.class.getName());
+ private static final Logger logger = Logger.getLogger(SaturatedPoolTest.class.getName());
private static final int MAX_POOL_SIZE = 10;
diff --git a/jdbc-mariadb/src/main/java/org/xbib/jdbc/mariadb/MariaDB.java b/jdbc-mariadb/src/main/java/org/xbib/jdbc/mariadb/MariaDB.java
index 39fbed0..5b6e279 100644
--- a/jdbc-mariadb/src/main/java/org/xbib/jdbc/mariadb/MariaDB.java
+++ b/jdbc-mariadb/src/main/java/org/xbib/jdbc/mariadb/MariaDB.java
@@ -4,6 +4,7 @@ import org.xbib.jdbc.query.Flavor;
import java.sql.PreparedStatement;
import java.sql.SQLException;
+import java.util.Locale;
public class MariaDB implements Flavor {
@@ -26,8 +27,16 @@ public class MariaDB implements Flavor {
}
@Override
- public boolean isNormalizedUpperCase() {
- return false;
+ public String normalizeTableName(String tableName) {
+ if (tableName == null) {
+ return tableName;
+ }
+ if (tableName.length() > 2) {
+ if (tableName.startsWith("\"") && tableName.endsWith("\"")) {
+ return tableName.substring(1, tableName.length() - 1);
+ }
+ }
+ return tableName.toLowerCase(Locale.ROOT);
}
@Override
@@ -52,7 +61,7 @@ public class MariaDB implements Flavor {
@Override
public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException {
- preparedStatement.setFloat(i, floatValue);
+ preparedStatement.setDouble(i, floatValue);
}
@Override
@@ -98,6 +107,11 @@ public class MariaDB implements Flavor {
return "datetime(3)";
}
+ @Override
+ public String columnTypeLocalDateTime() {
+ return "DATETIME";
+ }
+
@Override
public String typeLocalDate() {
return "date";
diff --git a/jdbc-mariadb/src/test/java/org/xbib/jdbc/mariadb/test/MariaDBTest.java b/jdbc-mariadb/src/test/java/org/xbib/jdbc/mariadb/test/MariaDBTest.java
index 122d29f..9681b9b 100644
--- a/jdbc-mariadb/src/test/java/org/xbib/jdbc/mariadb/test/MariaDBTest.java
+++ b/jdbc-mariadb/src/test/java/org/xbib/jdbc/mariadb/test/MariaDBTest.java
@@ -1,6 +1,7 @@
package org.xbib.jdbc.mariadb.test;
import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -9,13 +10,24 @@ 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.query.Sql;
+import org.xbib.jdbc.query.SqlArgs;
import org.xbib.jdbc.test.CommonTest;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
public class MariaDBTest extends CommonTest {
static MariaDBContainer> mariaDBContainer;
static {
+ // mariadb 10.3.6
mariaDBContainer = new MariaDBContainer<>("mariadb")
.withDatabaseName("testDB")
.withUsername("testUser")
@@ -88,21 +100,156 @@ public class MariaDBTest extends CommonTest {
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")
+ /**
+ * MariaDB seems to have different behavior in that is does not convert
+ * column names.
+ * 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
- public void saveResultAsTable() {
- super.saveResultAsTable();
+ @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;
+ });
}
+
+ /**
+ * This one is adjusted in that the float values are passed as double, because
+ * the database stores them both as double and there doesn't appear to be a way
+ * to tell that one was actually declared as a float.
+ *
+ * Also, CLOBs are stored as strings ("mediumtext" is just an alias).
+ */
+ @Test
+ public void saveResultAsTable() {
+ new Schema().addTable("dbtest")
+ .addColumn("nbr_integer").asInteger().primaryKey().table()
+ .addColumn("nbr_long").asLong().table()
+ .addColumn("nbr_float").asFloat().table()
+ .addColumn("nbr_double").asDouble().table()
+ .addColumn("nbr_big_decimal").asBigDecimal(19, 9).table()
+ .addColumn("str_varchar").asString(80).table()
+ .addColumn("str_fixed").asStringFixed(1).table()
+ .addColumn("str_lob").asClob().table()
+ .addColumn("bin_blob").asBlob().table()
+ .addColumn("boolean_flag").asBoolean().table()
+ .addColumn("date_millis").asLocalDateTime().table()
+ .addColumn("local_date").asLocalDate().schema().execute(db);
+ db.toInsert("insert into dbtest (nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar,"
+ + " str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date) values (?,?,?,?,?,?,?,?,?,?,?,?)")
+ .argInteger(Integer.MAX_VALUE)
+ .argLong(Long.MAX_VALUE)
+ .argDouble((double) Float.MAX_VALUE)
+ .argDouble(Double.MAX_VALUE)
+ .argBigDecimal(new BigDecimal("123.456"))
+ .argString("hello")
+ .argString("Z")
+ .argClobString("hello again")
+ .argBlobBytes(new byte[]{'1', '2'})
+ .argBoolean(true)
+ .argLocalDateTime(now)
+ .argLocalDate(localDateNow)
+ .insert(1);
+
+ db.toInsert("insert into dbtest (nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar,"
+ + " str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date) values (?,?,?,?,?,?,?,?,?,?,?,?)")
+ .argInteger(Integer.MIN_VALUE)
+ .argLong(Long.MIN_VALUE)
+ .argDouble((double) Float.MIN_VALUE)
+ .argDouble(Double.MIN_VALUE)
+ .argBigDecimal(new BigDecimal("-123.456"))
+ .argString("goodbye")
+ .argString("A")
+ .argClobString("bye again")
+ .argBlobBytes(new byte[]{'3', '4'})
+ .argBoolean(false)
+ .argLocalDateTime(now)
+ .argLocalDate(localDateNow)
+ .insert(1);
+
+ String expectedSchema = new Schema().addTable("dbtest2")
+ .addColumn("nbr_integer").asInteger().table()
+ .addColumn("nbr_long").asLong().table()
+ .addColumn("nbr_float").asFloat().table()
+ .addColumn("nbr_double").asDouble().table()
+ .addColumn("nbr_big_decimal").asBigDecimal(19, 9).table()
+ .addColumn("str_varchar").asString(80).table()
+ .addColumn("str_fixed").asStringFixed(1).table()
+ .addColumn("str_lob").asClob().table()
+ .addColumn("bin_blob").asBlob().table()
+ .addColumn("boolean_flag").asBoolean().table()
+ .addColumn("date_millis").asLocalDateTime().table()
+ .addColumn("local_date").asLocalDate()
+ .schema()
+ .print(db.flavor());
+
+ List args = db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal,"
+ + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest")
+ .query(rs -> {
+ List result = new ArrayList<>();
+ while (rs.next()) {
+ if (result.size() == 0) {
+ db.dropTableQuietly("dbtest2");
+ Schema schema = new Schema().addTableFromRow("dbtest2", rs).schema();
+ assertEquals(expectedSchema, schema.print(db.flavor()));
+ schema.execute(db);
+ }
+ result.add(SqlArgs.readRow(rs));
+ }
+ return result;
+ });
+
+ db.toInsert(Sql.insert("dbtest2", args)).insertBatch();
+
+ assertEquals(2, db.toSelect("select count(*) from dbtest2").queryIntegerOrZero());
+ assertEquals(db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal,"
+ + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest order by 1")
+ .queryMany(SqlArgs::readRow),
+ db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal,"
+ + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest2 order by 1")
+ .queryMany(SqlArgs::readRow));
+ assertEquals(Arrays.asList(
+ new SqlArgs()
+ .argInteger("nbr_integer", Integer.MIN_VALUE)
+ .argLong("nbr_long", Long.MIN_VALUE)
+ .argDouble("nbr_float", (double) Float.MIN_VALUE)
+ .argDouble("nbr_double", Double.MIN_VALUE)
+ .argBigDecimal("nbr_big_decimal", new BigDecimal("-123.456"))
+ .argString("str_varchar", "goodbye")
+ .argString("str_fixed", "A")
+ .argString("str_lob", "bye again")
+ .argBlobBytes("bin_blob", new byte[]{'3', '4'})
+ .argString("boolean_flag", "N")//.argBoolean("boolean_flag", false)
+ .argLocalDateTime("date_millis", now)
+ .argLocalDate("local_date", localDateNow),
+ new SqlArgs()
+ .argInteger("nbr_integer", Integer.MAX_VALUE)
+ .argLong("nbr_long", Long.MAX_VALUE)
+ .argDouble("nbr_float", (double) Float.MAX_VALUE)
+ .argDouble("nbr_double", Double.MAX_VALUE)
+ .argBigDecimal("nbr_big_decimal", new BigDecimal("123.456"))
+ .argString("str_varchar", "hello")
+ .argString("str_fixed", "Z")
+ .argString("str_lob", "hello again")
+ .argBlobBytes("bin_blob", new byte[]{'1', '2'})
+ .argString("boolean_flag", "Y")//.argBoolean("boolean_flag", true)
+ .argLocalDateTime("date_millis", now)
+ .argLocalDate("local_date", localDateNow)),
+ db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal,"
+ + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest2 order by 1")
+ .queryMany(SqlArgs::readRow));
+ }
+
}
diff --git a/jdbc-oracle/src/main/java/org/xbib/jdbc/oracle/Oracle.java b/jdbc-oracle/src/main/java/org/xbib/jdbc/oracle/Oracle.java
index e431f6e..c714ba5 100644
--- a/jdbc-oracle/src/main/java/org/xbib/jdbc/oracle/Oracle.java
+++ b/jdbc-oracle/src/main/java/org/xbib/jdbc/oracle/Oracle.java
@@ -28,8 +28,16 @@ public class Oracle implements Flavor {
}
@Override
- public boolean isNormalizedUpperCase() {
- return true;
+ public String normalizeTableName(String tableName) {
+ if (tableName == null) {
+ return tableName;
+ }
+ if (tableName.length() > 2) {
+ if (tableName.startsWith("\"") && tableName.endsWith("\"")) {
+ return tableName.substring(1, tableName.length() - 1);
+ }
+ }
+ return tableName.toUpperCase();
}
@Override
@@ -87,6 +95,11 @@ public class Oracle implements Flavor {
return "timestamp(3)";
}
+ @Override
+ public String columnTypeLocalDateTime() {
+ return "TIMESTAMP";
+ }
+
@Override
public String typeLocalDate() {
return "date";
diff --git a/jdbc-postgresql/src/main/java/org/xbib/jdbc/postgresql/Postgresql.java b/jdbc-postgresql/src/main/java/org/xbib/jdbc/postgresql/Postgresql.java
index f82ec5c..33ab4b7 100644
--- a/jdbc-postgresql/src/main/java/org/xbib/jdbc/postgresql/Postgresql.java
+++ b/jdbc-postgresql/src/main/java/org/xbib/jdbc/postgresql/Postgresql.java
@@ -4,6 +4,7 @@ import org.xbib.jdbc.query.Flavor;
import java.sql.PreparedStatement;
import java.sql.SQLException;
+import java.util.Locale;
public class Postgresql implements Flavor {
@@ -26,8 +27,16 @@ public class Postgresql implements Flavor {
}
@Override
- public boolean isNormalizedUpperCase() {
- return false;
+ public String normalizeTableName(String tableName) {
+ if (tableName == null) {
+ return tableName;
+ }
+ if (tableName.length() > 2) {
+ if (tableName.startsWith("\"") && tableName.endsWith("\"")) {
+ return tableName.substring(1, tableName.length() - 1);
+ }
+ }
+ return tableName.toLowerCase(Locale.ROOT);
}
@Override
@@ -95,6 +104,11 @@ public class Postgresql implements Flavor {
return "timestamp(3)";
}
+ @Override
+ public String columnTypeLocalDateTime() {
+ return "timestamp";
+ }
+
@Override
public String typeLocalDate() {
return "date";
diff --git a/jdbc-postgresql/src/test/java/org/xbib/jdbc/postgresql/test/PostgresqlTest.java b/jdbc-postgresql/src/test/java/org/xbib/jdbc/postgresql/test/PostgresqlTest.java
index c62b72c..df0e2f1 100644
--- a/jdbc-postgresql/src/test/java/org/xbib/jdbc/postgresql/test/PostgresqlTest.java
+++ b/jdbc-postgresql/src/test/java/org/xbib/jdbc/postgresql/test/PostgresqlTest.java
@@ -20,6 +20,7 @@ public class PostgresqlTest extends CommonTest {
static PostgreSQLContainer> postgreSQLContainer;
static {
+ // postgresql 9.6.12
postgreSQLContainer = new PostgreSQLContainer<>("postgres")
.withDatabaseName("testDB")
.withUsername("testUser")
diff --git a/jdbc-postgresql/src/test/resources/logging.properties b/jdbc-postgresql/src/test/resources/logging.properties
index 5885e4d..f0ffda7 100644
--- a/jdbc-postgresql/src/test/resources/logging.properties
+++ b/jdbc-postgresql/src/test/resources/logging.properties
@@ -8,3 +8,4 @@ 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
+org.postgresql.level=INFO
diff --git a/jdbc-query/build.gradle b/jdbc-query/build.gradle
index 19de6b8..1f334c1 100644
--- a/jdbc-query/build.gradle
+++ b/jdbc-query/build.gradle
@@ -1,7 +1,13 @@
dependencies {
- api project(":jdbc-connection-pool")
+ api project(':jdbc-connection-pool')
+ testImplementation project(':jdbc-test')
testImplementation libs.derby
testImplementation libs.hsqldb
+ testImplementation libs.h2
testImplementation libs.testcontainers
testImplementation libs.testcontainers.junit.jupiter
}
+
+test {
+ systemProperty 'user.timezone', 'GMT'
+}
diff --git a/jdbc-query/src/main/java/module-info.java b/jdbc-query/src/main/java/module-info.java
index 19df7a3..935bbe0 100644
--- a/jdbc-query/src/main/java/module-info.java
+++ b/jdbc-query/src/main/java/module-info.java
@@ -1,12 +1,12 @@
import org.xbib.jdbc.query.Flavor;
import org.xbib.jdbc.query.flavor.Derby;
+import org.xbib.jdbc.query.flavor.H2;
import org.xbib.jdbc.query.flavor.Hsql;
-import org.xbib.jdbc.query.flavor.SqlServer;
module org.xbib.jdbc.query {
uses Flavor;
requires org.xbib.jdbc.connection.pool;
requires java.sql;
exports org.xbib.jdbc.query;
- provides Flavor with Derby, Hsql, SqlServer;
+ provides Flavor with Derby, Hsql, H2;
}
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/Database.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/Database.java
index 6138778..c3de0f0 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/Database.java
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/Database.java
@@ -11,6 +11,11 @@ import java.util.function.Supplier;
* Primary class for accessing a relational (SQL) database.
*/
public interface Database extends Supplier {
+
+ int jdbcMajorVersion();
+
+ int jdbcMinorVersion();
+
/**
* Create a SQL "insert" statement for further manipulation and execution.
* Note this call does not actually execute the SQL.
@@ -181,18 +186,6 @@ public interface Database extends Supplier {
*/
Map getColumnSizesOfTable(String tableName);
- /**
- * Return the DB table name in the normalized form in which it is stored.
- * Databases like Oracle, Derby, HSQL store their tables in upper case.
- * Databases like postgres and sqlserver use lower case unless configured otherwise.
- * If the caller passes in a quoted string, we will leave the name as is, removing
- * the quotes.
- *
- * @param tableName this should be a name, not a pattern
- * @return table name in appropriate format for DB lookup - original case, uppercase, or lowercase
- */
- String normalizeTableName(String tableName);
-
/**
* Check the JVM time (and timezone) against the database and log a warning
* or throw an error if they are too far apart. It is a good idea to do this
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseImpl.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseImpl.java
index 8c635e1..0173ec8 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseImpl.java
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseImpl.java
@@ -131,16 +131,15 @@ public class DatabaseImpl implements Database {
throw new DatabaseException("Unable to rollback transaction", e);
}
}
-
+
@Override
public Connection underlyingConnection() {
if (!options.allowConnectionAccess()) {
throw new DatabaseException("Calls to underlyingConnection() are not allowed");
}
-
return connection;
}
-
+
@Override
public Options options() {
return options;
@@ -151,7 +150,24 @@ public class DatabaseImpl implements Database {
return options.flavor();
}
-
+ @Override
+ public int jdbcMajorVersion() {
+ try {
+ return connection.getMetaData().getJDBCMajorVersion();
+ } catch (SQLException e) {
+ throw new DatabaseException(e);
+ }
+ }
+
+ @Override
+ public int jdbcMinorVersion() {
+ try {
+ return connection.getMetaData().getJDBCMinorVersion();
+ } catch (SQLException e) {
+ throw new DatabaseException(e);
+ }
+ }
+
@Override
public When when() {
return new When(options.flavor());
@@ -181,7 +197,7 @@ public class DatabaseImpl implements Database {
if (tableName != null && connection != null) {
try {
DatabaseMetaData metadata = connection.getMetaData();
- String normalizedTable = normalizeTableName(tableName);
+ String normalizedTable = flavor().normalizeTableName(tableName);
ResultSet resultSet = metadata.getTables(connection.getCatalog(), schemaName, normalizedTable, new String[]{"TABLE", "VIEW"});
while (resultSet.next()) {
if (normalizedTable.equals(resultSet.getString("TABLE_NAME"))) {
@@ -203,7 +219,7 @@ public class DatabaseImpl implements Database {
if (tableName != null && connection != null) {
try {
DatabaseMetaData metaData = connection.getMetaData();
- String normalizedTable = normalizeTableName(tableName);
+ String normalizedTable = flavor().normalizeTableName(tableName);
ResultSet resultSet = metaData.getColumns(null, null, normalizedTable, "%");
ResultSetMetaData rsmd = resultSet.getMetaData();
int cols = rsmd.getColumnCount();
@@ -229,24 +245,6 @@ public class DatabaseImpl implements Database {
return map;
}
- @Override
- public String normalizeTableName(String tableName) {
- if (tableName == null) {
- return tableName;
- }
- // If user gave us a quoted string, leave it alone for look up
- if (tableName.length() > 2) {
- if (tableName.startsWith("\"") && tableName.endsWith("\"")) {
- // Remove quotes and return as is.
- return tableName.substring(1, tableName.length() - 1);
- }
- }
- if (flavor().isNormalizedUpperCase()) {
- return tableName.toUpperCase();
- }
- return tableName.toLowerCase();
- }
-
@Override
public void assertTimeSynchronized(long millisToWarn, long millisToError) {
toSelect("select ?" + flavor().fromAny())
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProvider.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProvider.java
index 02636a5..d790c4a 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProvider.java
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProvider.java
@@ -6,12 +6,8 @@ import org.xbib.jdbc.query.util.Metric;
import javax.sql.DataSource;
import java.io.Closeable;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
@@ -30,7 +26,7 @@ import java.util.logging.Logger;
*/
public final class DatabaseProvider implements Supplier, Closeable {
- private static final Logger log = Logger.getLogger(DatabaseProvider.class.getName());
+ private static final Logger logger = Logger.getLogger(DatabaseProvider.class.getName());
private static final AtomicInteger poolNameCounter = new AtomicInteger(1);
@@ -63,7 +59,8 @@ public final class DatabaseProvider implements Supplier, Closeable {
*
* A database pool will be created using jdbc-connection-pool.
*/
- public static DatabaseProviderBuilder 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));
}
@@ -85,67 +82,12 @@ public final class DatabaseProvider implements Supplier, Closeable {
* the JDBC standard DriverManager method. The url parameter will be inspected
* to determine the Flavor for this database.
*/
- public static DatabaseProviderBuilder builder(String url) {
- return builder(url, Flavor.fromJdbcUrl(url), null, null, null);
+ public static DatabaseProviderBuilder builder(ClassLoader classLoader, String url) {
+ return builder(classLoader, url, Flavor.fromJdbcUrl(url), null, null, null);
}
- /**
- * Builder method to create and initialize an instance of this class using
- * the JDBC standard DriverManager method.
- *
- * @param flavor use this flavor rather than guessing based on the url
- */
-
- public static DatabaseProviderBuilder builder(String url, Flavor flavor) {
- return builder(url, flavor, null, null, null);
- }
-
- /**
- * Builder method to create and initialize an instance of this class using
- * the JDBC standard DriverManager method. The url parameter will be inspected
- * to determine the Flavor for this database.
- */
-
- public static DatabaseProviderBuilder builder(String url, Properties info) {
- return builder(url, Flavor.fromJdbcUrl(url), info, null, null);
- }
-
- /**
- * Builder method to create and initialize an instance of this class using
- * the JDBC standard DriverManager method.
- *
- * @param flavor use this flavor rather than guessing based on the url
- */
-
- public static DatabaseProviderBuilder builder(String url, Flavor flavor, Properties info) {
- return builder(url, flavor, info, null, null);
- }
-
- /**
- * Builder method to create and initialize an instance of this class using
- * the JDBC standard DriverManager method. The url parameter will be inspected
- * to determine the Flavor for this database.
- */
-
- public static DatabaseProviderBuilder builder(String url, String user, String password) {
- return builder(url, Flavor.fromJdbcUrl(url), null, user, password);
- }
-
- /**
- * Builder method to create and initialize an instance of this class using
- * the JDBC standard DriverManager method.
- *
- * @param flavor use this flavor rather than guessing based on the url
- */
-
- public static DatabaseProviderBuilder builder(String url,
- Flavor flavor,
- String user,
- String password) {
- return builder(url, flavor, null, user, password);
- }
-
- private static DatabaseProviderBuilder builder(String url,
+ private static DatabaseProviderBuilder builder(ClassLoader classLoader,
+ String url,
Flavor flavor,
Properties info,
String user,
@@ -156,7 +98,7 @@ public final class DatabaseProvider implements Supplier, Closeable {
} catch (SQLException e) {
if (flavor.driverClass() != null) {
try {
- Class.forName(flavor.driverClass());
+ Class.forName(flavor.driverClass(), true, classLoader);
} catch (ClassNotFoundException e1) {
throw new DatabaseException("couldn't locate JDBC driver", e1);
}
@@ -176,417 +118,6 @@ public final class DatabaseProvider implements Supplier, Closeable {
}, options);
}
- /**
- * Configure the database from up to five properties read from a file:
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- * This will use the JVM default character encoding to read the property file.
- *
- * @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
- */
- public static DatabaseProviderBuilder fromPropertyFile(String propertyFileName) {
- return fromPropertyFile(propertyFileName, Charset.defaultCharset().newDecoder());
- }
-
- /**
- * Configure the database from up to five properties read from a file:
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- *
- * @param propertyFileName path to the properties file we will attempt to read
- * @param decoder character encoding to use when reading the property file
- * @throws DatabaseException if the property file could not be read for any reason
- */
- public static DatabaseProviderBuilder fromPropertyFile(String propertyFileName, CharsetDecoder decoder) {
- Properties properties = new Properties();
- if (propertyFileName != null && propertyFileName.length() > 0) {
- try (
- FileInputStream fis = new FileInputStream(propertyFileName);
- InputStreamReader reader = new InputStreamReader(fis, decoder)
- ) {
- properties.load(reader);
- } catch (Exception e) {
- throw new DatabaseException("Unable to read properties file: " + propertyFileName, e);
- }
- }
- return fromProperties(properties, "", true);
- }
-
- /**
- * Configure the database from up to five properties read from a file:
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- * This will use the JVM default character encoding to read the property file.
- *
- * @param filename path to the properties file we will attempt to read
- * @param propertyPrefix if this is null or empty the properties above will be read;
- * if a value is provided it will be prefixed to each property
- * (exactly, so if you want to use "my.database.url" you must
- * pass "my." as the prefix)
- * @throws DatabaseException if the property file could not be read for any reason
- */
- public static DatabaseProviderBuilder fromPropertyFile(String filename, String propertyPrefix) {
- return fromPropertyFile(filename, propertyPrefix, Charset.defaultCharset().newDecoder());
- }
-
- /**
- * Configure the database from up to five properties read from a file:
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- *
- * @param filename path to the properties file we will attempt to read
- * @param propertyPrefix if this is null or empty the properties above will be read;
- * if a value is provided it will be prefixed to each property
- * (exactly, so if you want to use "my.database.url" you must
- * pass "my." as the prefix)
- * @param decoder character encoding to use when reading the property file
- * @throws DatabaseException if the property file could not be read for any reason
- */
- public static DatabaseProviderBuilder fromPropertyFile(String filename, String propertyPrefix, CharsetDecoder decoder) {
- Properties properties = new Properties();
- if (filename != null && filename.length() > 0) {
- try (
- FileInputStream fis = new FileInputStream(filename);
- InputStreamReader reader = new InputStreamReader(fis, decoder)
- ) {
- properties.load(reader);
- } catch (Exception e) {
- throw new DatabaseException("Unable to read properties file: " + filename, e);
- }
- }
- return fromProperties(properties, propertyPrefix, true);
- }
-
- /**
- * Configure the database from up to five properties read from the provided properties:
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- *
- * @param properties properties will be read from here
- * @throws DatabaseException if the property file could not be read for any reason
- */
- public static DatabaseProviderBuilder fromProperties(Properties properties) {
- return fromProperties(properties, "", false);
- }
-
- /**
- * Configure the database from up to five properties read from the provided properties:
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- *
- * @param properties properties will be read from here
- * @param propertyPrefix if this is null or empty the properties above will be read;
- * if a value is provided it will be prefixed to each property
- * (exactly, so if you want to use "my.database.url" you must
- * pass "my." as the prefix)
- * @throws DatabaseException if the property file could not be read for any reason
- */
- public static DatabaseProviderBuilder fromProperties(Properties properties, String propertyPrefix) {
- return fromProperties(properties, propertyPrefix, false);
- }
-
- /**
- * Configure the database from up to five properties read from the specified
- * properties file, or from the system properties (system properties will take
- * precedence over the file):
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- * This will use the JVM default character encoding to read the property file.
- *
- * @param filename path to the properties file we will attempt to read; if the file
- * cannot be read for any reason (e.g. does not exist) a debug level
- * log entry will be entered, but it will attempt to proceed using
- * solely the system properties
- */
- public static DatabaseProviderBuilder fromPropertyFileOrSystemProperties(String filename) {
- return fromPropertyFileOrSystemProperties(filename, Charset.defaultCharset().newDecoder());
- }
-
- /**
- * Configure the database from up to five properties read from the specified
- * properties file, or from the system properties (system properties will take
- * precedence over the file):
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- *
- * @param filename path to the properties file we will attempt to read; if the file
- * cannot be read for any reason (e.g. does not exist) a debug level
- * log entry will be entered, but it will attempt to proceed using
- * solely the system properties
- * @param decoder character encoding to use when reading the property file
- */
- public static DatabaseProviderBuilder fromPropertyFileOrSystemProperties(String filename, CharsetDecoder decoder) {
- Properties properties = new Properties();
- if (filename != null && filename.length() > 0) {
- try (
- FileInputStream fis = new FileInputStream(filename);
- InputStreamReader reader = new InputStreamReader(fis, decoder)
- ) {
- properties.load(reader);
- } catch (Exception e) {
- log.fine("Trying system properties - unable to read properties file: " + filename);
- }
- }
- return fromProperties(properties, "", true);
- }
-
- /**
- * Configure the database from up to five properties read from the specified
- * properties file, or from the system properties (system properties will take
- * precedence over the file):
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- * This will use the JVM default character encoding to read the property file.
- *
- * @param filename path to the properties file we will attempt to read; if the file
- * cannot be read for any reason (e.g. does not exist) a debug level
- * log entry will be entered, but it will attempt to proceed using
- * solely the system properties
- * @param propertyPrefix if this is null or empty the properties above will be read;
- * if a value is provided it will be prefixed to each property
- * (exactly, so if you want to use "my.database.url" you must
- * pass "my." as the prefix)
- */
- public static DatabaseProviderBuilder fromPropertyFileOrSystemProperties(String filename, String propertyPrefix) {
- return fromPropertyFileOrSystemProperties(filename, propertyPrefix, Charset.defaultCharset().newDecoder());
- }
-
- /**
- * Configure the database from up to five properties read from the specified
- * properties file, or from the system properties (system properties will take
- * precedence over the file):
- *
- * database.url=... Database connect string (required)
- * database.user=... Authenticate as this user (optional if provided in url)
- * database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- *
- * @param filename path to the properties file we will attempt to read; if the file
- * cannot be read for any reason (e.g. does not exist) a debug level
- * log entry will be entered, but it will attempt to proceed using
- * solely the system properties
- * @param propertyPrefix if this is null or empty the properties above will be read;
- * if a value is provided it will be prefixed to each property
- * (exactly, so if you want to use "my.database.url" you must
- * pass "my." as the prefix)
- * @param decoder character encoding to use when reading the property file
- */
- public static DatabaseProviderBuilder fromPropertyFileOrSystemProperties(String filename, String propertyPrefix,
- CharsetDecoder decoder) {
- Properties properties = new Properties();
- if (filename != null && filename.length() > 0) {
- try (
- FileInputStream fis = new FileInputStream(filename);
- InputStreamReader reader = new InputStreamReader(fis, decoder)
- ) {
- properties.load(reader);
- } catch (Exception e) {
- log.fine("Trying system properties - unable to read properties file: " + filename);
- }
- }
- return fromProperties(properties, propertyPrefix, true);
- }
-
- /**
- * Configure the database from up to five system properties:
- *
- * -Ddatabase.url=... Database connect string (required)
- * -Ddatabase.user=... Authenticate as this user (optional if provided in url)
- * -Ddatabase.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * -Ddatabase.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * -Ddatabase.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- */
-
- public static DatabaseProviderBuilder fromSystemProperties() {
- return fromProperties(null, "", true);
- }
-
- /**
- * Configure the database from up to five system properties:
- *
- * -D{prefix}database.url=... Database connect string (required)
- * -D{prefix}database.user=... Authenticate as this user (optional if provided in url)
- * -D{prefix}database.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * -D{prefix}database.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * -D{prefix}database.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- *
- * @param propertyPrefix a prefix to attach to each system property - be sure to include the
- * dot if desired (e.g. "mydb." for properties like -Dmydb.database.url)
- */
-
- public static DatabaseProviderBuilder fromSystemProperties(String propertyPrefix) {
- return fromProperties(null, propertyPrefix, true);
- }
-
- private static DatabaseProviderBuilder fromProperties(Properties properties, String propertyPrefix, boolean useSystemProperties) {
- if (propertyPrefix == null) {
- propertyPrefix = "";
- }
- String driver;
- String flavorStr;
- String url;
- String user;
- String password;
- if (useSystemProperties) {
- if (properties == null) {
- properties = new Properties();
- }
- driver = System.getProperty(propertyPrefix + "database.driver",
- properties.getProperty(propertyPrefix + "database.driver"));
- flavorStr = System.getProperty(propertyPrefix + "database.flavor",
- properties.getProperty(propertyPrefix + "database.flavor"));
- url = System.getProperty(propertyPrefix + "database.url",
- properties.getProperty(propertyPrefix + "database.url"));
- user = System.getProperty(propertyPrefix + "database.user",
- properties.getProperty(propertyPrefix + "database.user"));
- password = System.getProperty(propertyPrefix + "database.password",
- properties.getProperty(propertyPrefix + "database.password"));
- } else {
- if (properties == null) {
- throw new DatabaseException("No properties were provided");
- }
- driver = properties.getProperty(propertyPrefix + "database.driver");
- flavorStr = properties.getProperty(propertyPrefix + "database.flavor");
- url = properties.getProperty(propertyPrefix + "database.url");
- user = properties.getProperty(propertyPrefix + "database.user");
- password = properties.getProperty(propertyPrefix + "database.password");
- }
- if (url == null) {
- throw new DatabaseException("You must use -D" + propertyPrefix + "database.url=...");
- }
- if (user != null && password == null) {
- System.out.println("Enter database password for user " + user + ":");
- byte[] input = new byte[256];
- try {
- int bytesRead = System.in.read(input);
- password = new String(input, 0, bytesRead - 1, Charset.defaultCharset());
- } catch (IOException e) {
- throw new DatabaseException("Error reading password from standard input", e);
- }
- }
- Flavor flavor;
- if (flavorStr != null) {
- flavor = Flavor.valueOf(flavorStr);
- } else {
- flavor = Flavor.fromJdbcUrl(url);
- }
- if (driver != null) {
- try {
- Class.forName(driver).getDeclaredConstructor().newInstance();
- } catch (Exception e) {
- driver = flavor.driverClass();
- try {
- Class.forName(driver).getDeclaredConstructor().newInstance();
- } catch (Exception ee) {
- throw new DatabaseException("Unable to load JDBC driver: " + driver, ee);
- }
- }
- }
- if (user == null) {
- return builder(url, flavor);
- } else {
- return builder(url, flavor, user, password);
- }
- }
-
private static DataSource createDataSource(Config config)
throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException,
IllegalAccessException {
@@ -749,7 +280,7 @@ public final class DatabaseProvider implements Supplier, Closeable {
if (builder.isClosed()) {
throw new DatabaseException("Called get() on a DatabaseProvider after close()");
}
- Metric metric = new Metric(log.isLoggable(Level.FINE));
+ Metric metric = new Metric(logger.isLoggable(Level.FINE));
try {
connection = builder.connectionProvider.get();
metric.checkpoint("getConn");
@@ -770,10 +301,10 @@ public final class DatabaseProvider implements Supplier, Closeable {
throw e;
} finally {
metric.done();
- if (log.isLoggable(Level.FINE)) {
+ if (logger.isLoggable(Level.FINE)) {
StringBuilder buf = new StringBuilder("Get ").append(builder.options.flavor()).append(" database: ");
metric.printMessage(buf);
- log.fine(buf.toString());
+ logger.fine(buf.toString());
}
}
return database;
@@ -811,7 +342,7 @@ public final class DatabaseProvider implements Supplier, Closeable {
connection.rollback();
}
} catch (Exception e) {
- log.log(Level.SEVERE, "Unable to rollback the transaction", e);
+ logger.log(Level.SEVERE, "Unable to rollback the transaction", e);
}
}
}
@@ -825,7 +356,7 @@ public final class DatabaseProvider implements Supplier, Closeable {
}
close();
} catch (Exception e) {
- log.log(Level.SEVERE, "Unable to rollback the transaction", e);
+ logger.log(Level.SEVERE, "Unable to rollback the transaction", e);
}
}
@@ -835,7 +366,7 @@ public final class DatabaseProvider implements Supplier, Closeable {
try {
connection.close();
} catch (Exception e) {
- log.log(Level.SEVERE, "Unable to close the database connection", e);
+ logger.log(Level.SEVERE, "Unable to close the database connection", e);
}
}
connection = null;
@@ -843,129 +374,6 @@ public final class DatabaseProvider implements Supplier, Closeable {
builder.close();
}
- /**
- * This builder is immutable, so setting various options does not affect
- * the previous instance. This is intended to make it safe to pass builders
- * around without risk someone will reconfigure it.
- */
- public interface DatabaseProviderBuilder {
-
- DatabaseProviderBuilder withOptions(OptionsOverride options);
-
- /**
- * Enable logging of parameter values along with the SQL.
- */
-
- DatabaseProviderBuilder withSqlParameterLogging();
-
- /**
- * Include SQL in exception messages. This will also include parameters in the
- * exception messages if SQL parameter logging is enabled. This is handy for
- * development, but be careful as this is an information disclosure risk,
- * dependent on how the exception are caught and handled.
- */
-
- DatabaseProviderBuilder withSqlInExceptionMessages();
-
- /**
- * Wherever argDateNowPerDb() is specified, use argDateNowPerApp() instead. This is
- * useful for testing purposes as you can use OptionsOverride to provide your
- * own system clock that will be used for time travel.
- */
-
- DatabaseProviderBuilder withDatePerAppOnly();
-
- /**
- * Allow provided Database instances to explicitly control transactions using the
- * commitNow() and rollbackNow() methods. Otherwise calling those methods would
- * throw an exception.
- */
-
- DatabaseProviderBuilder withTransactionControl();
-
- /**
- * 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.
- */
-
- DatabaseProviderBuilder withTransactionControlSilentlyIgnored();
-
- /**
- * Allow direct access to the underlying database connection. Normally this is
- * not allowed, and is a bad idea, but it can be helpful when migrating from
- * legacy code that works with raw JDBC.
- */
-
- DatabaseProviderBuilder withConnectionAccess();
-
- /**
- * WARNING: You should try to avoid using this method. If you use it more
- * that once or twice in your entire codebase you are probably doing
- * something wrong.
- *
- * If you use this method you are responsible for managing
- * the transaction and commit/rollback/close.
- */
-
- DatabaseProvider build();
-
- /**
- * This is a convenience method to eliminate the need for explicitly
- * managing the resources (and error handling) for this class. After
- * the run block is complete the transaction will commit unless the
- * {@link DbCode#run(Supplier) run(Supplier)} method threw a {@link Throwable}.
- *
- * Here is a typical usage:
- *
- * dbp.transact(dbs -> {
- * List r = dbs.get().toSelect("select a from b where c=?").argInteger(1).queryStrings();
- * ... do something with the results ...
- * });
- *
- *
- *
- * @param code the code you want to run as a transaction with a Database
- * @see #transact(DbCodeTx)
- */
- void transact(DbCode code);
-
- /**
- * This method is the same as {@link #transact(DbCode)} but allows a return value.
- *
- * Here is a typical usage:
- *
- * List r = dbp.transact(dbs -> {
- * return dbs.get().toSelect("select a from b where c=?").argInteger(1).queryStrings();
- * });
- *
- *
- */
- T transactReturning(DbCodeTyped code);
-
- /**
- * This is a convenience method to eliminate the need for explicitly
- * managing the resources (and error handling) for this class. After
- * the run block is complete commit() will be called unless either the
- * {@link DbCodeTx#run(Supplier, Transaction)} method threw a {@link Throwable}
- * while {@link Transaction#isRollbackOnError()} returns true, or
- * {@link Transaction#isRollbackOnly()} returns a true value.
- *
- * Here is a typical usage:
- *
- * dbp.transact((dbs, tx) -> {
- * tx.setRollbackOnError(false);
- * dbs.get().toInsert("...").argInteger(1).insert(1);
- * ...some stuff that might fail...
- * });
- *
- *
- *
- * @param code the code you want to run as a transaction with a Database
- */
- void transact(DbCodeTx code);
-
- }
-
private static class DatabaseProviderBuilderImpl implements DatabaseProviderBuilder, Closeable {
private DataSource dataSource;
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProviderBuilder.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProviderBuilder.java
new file mode 100644
index 0000000..9d501bb
--- /dev/null
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProviderBuilder.java
@@ -0,0 +1,126 @@
+package org.xbib.jdbc.query;
+
+import java.util.function.Supplier;
+
+/**
+ * This builder is immutable, so setting various options does not affect
+ * the previous instance. This is intended to make it safe to pass builders
+ * around without risk someone will reconfigure it.
+ */
+public interface DatabaseProviderBuilder {
+
+ DatabaseProviderBuilder withOptions(OptionsOverride options);
+
+ /**
+ * Enable logging of parameter values along with the SQL.
+ */
+
+ DatabaseProviderBuilder withSqlParameterLogging();
+
+ /**
+ * Include SQL in exception messages. This will also include parameters in the
+ * exception messages if SQL parameter logging is enabled. This is handy for
+ * development, but be careful as this is an information disclosure risk,
+ * dependent on how the exception are caught and handled.
+ */
+
+ DatabaseProviderBuilder withSqlInExceptionMessages();
+
+ /**
+ * Wherever argDateNowPerDb() is specified, use argDateNowPerApp() instead. This is
+ * useful for testing purposes as you can use OptionsOverride to provide your
+ * own system clock that will be used for time travel.
+ */
+
+ DatabaseProviderBuilder withDatePerAppOnly();
+
+ /**
+ * Allow provided Database instances to explicitly control transactions using the
+ * commitNow() and rollbackNow() methods. Otherwise calling those methods would
+ * throw an exception.
+ */
+
+ DatabaseProviderBuilder withTransactionControl();
+
+ /**
+ * 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.
+ */
+
+ DatabaseProviderBuilder withTransactionControlSilentlyIgnored();
+
+ /**
+ * Allow direct access to the underlying database connection. Normally this is
+ * not allowed, and is a bad idea, but it can be helpful when migrating from
+ * legacy code that works with raw JDBC.
+ */
+
+ DatabaseProviderBuilder withConnectionAccess();
+
+ /**
+ * WARNING: You should try to avoid using this method. If you use it more
+ * that once or twice in your entire codebase you are probably doing
+ * something wrong.
+ *
+ * If you use this method you are responsible for managing
+ * the transaction and commit/rollback/close.
+ */
+
+ DatabaseProvider build();
+
+ /**
+ * This is a convenience method to eliminate the need for explicitly
+ * managing the resources (and error handling) for this class. After
+ * the run block is complete the transaction will commit unless the
+ * {@link DbCode#run(Supplier) run(Supplier)} method threw a {@link Throwable}.
+ *
+ * Here is a typical usage:
+ *
+ * dbp.transact(dbs -> {
+ * List r = dbs.get().toSelect("select a from b where c=?").argInteger(1).queryStrings();
+ * ... do something with the results ...
+ * });
+ *
+ *
+ *
+ * @param code the code you want to run as a transaction with a Database
+ * @see #transact(DbCodeTx)
+ */
+ void transact(DbCode code);
+
+ /**
+ * This method is the same as {@link #transact(DbCode)} but allows a return value.
+ *
+ * Here is a typical usage:
+ *
+ * List r = dbp.transact(dbs -> {
+ * return dbs.get().toSelect("select a from b where c=?").argInteger(1).queryStrings();
+ * });
+ *
+ *
+ */
+ T transactReturning(DbCodeTyped code);
+
+ /**
+ * This is a convenience method to eliminate the need for explicitly
+ * managing the resources (and error handling) for this class. After
+ * the run block is complete commit() will be called unless either the
+ * {@link DbCodeTx#run(Supplier, Transaction)} method threw a {@link Throwable}
+ * while {@link Transaction#isRollbackOnError()} returns true, or
+ * {@link Transaction#isRollbackOnly()} returns a true value.
+ *
+ * Here is a typical usage:
+ *
+ * dbp.transact((dbs, tx) -> {
+ * tx.setRollbackOnError(false);
+ * dbs.get().toInsert("...").argInteger(1).insert(1);
+ * ...some stuff that might fail...
+ * });
+ *
+ *
+ *
+ * @param code the code you want to run as a transaction with a Database
+ */
+ void transact(DbCodeTx code);
+
+}
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/Flavor.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/Flavor.java
index 175b95e..cf7b3fc 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/Flavor.java
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/Flavor.java
@@ -12,11 +12,7 @@ public interface Flavor {
String driverClass();
- /**
- * Returns true if DB normalizes to upper case names for ids like tables and columns
- * See ();
+ sequences = new ArrayList<>();
+ indexForeignKeys = true;
+ userTableName = "user_principal";
}
public Sequence addSequence(String name) {
@@ -70,10 +74,10 @@ public class Schema {
return table;
}
- public Table addTableFromRow(String tableName, Row r) {
+ public Table addTableFromRow(String tableName, Row row) {
Table table = addTable(tableName);
try {
- ResultSetMetaData metadata = r.getMetadata();
+ ResultSetMetaData metadata = row.getMetadata();
int columnCount = metadata.getColumnCount();
String[] names = new String[columnCount];
for (int i = 0; i < columnCount; i++) {
@@ -464,51 +468,70 @@ public class Schema {
}
public class Table {
+
private final String name;
+
private String comment;
- private final List columns = new ArrayList<>();
+
private PrimaryKey primaryKey;
- private final List foreignKeys = new ArrayList<>();
- private final List indexes = new ArrayList<>();
- private final List checks = new ArrayList<>();
- private final List uniques = new ArrayList<>();
- private final Map customClauses = new HashMap<>();
+
+ private final List columns;
+
+ private final List foreignKeys;
+
+ private final List indexes;
+
+ private final List checks;
+
+ private final List uniques;
+
+ private final Map customClauses;
+
private boolean createTracking;
+
private String createTrackingFkName;
+
private String createTrackingFkTable;
+
private boolean updateTracking;
+
private String updateTrackingFkName;
+
private String updateTrackingFkTable;
+
private boolean updateSequence;
+
private boolean historyTable;
public Table(String name) {
this.name = toName(name);
if (this.name.length() > 27) {
- throw new RuntimeException("Table name should be 27 characters or less");
+ throw new IllegalArgumentException("Table name should be 27 characters or less");
}
+ columns = new ArrayList<>();
+ foreignKeys = new ArrayList<>();
+ indexes = new ArrayList<>();
+ checks = new ArrayList<>();
+ uniques = new ArrayList<>();
+ customClauses = new HashMap<>();
}
public void validate() {
if (columns.size() < 1) {
- throw new RuntimeException("Table " + name + " needs at least one column");
+ throw new IllegalArgumentException("Table " + name + " needs at least one column");
}
for (Column c : columns) {
c.validate();
}
-
if (primaryKey != null) {
primaryKey.validate();
}
-
for (ForeignKey fk : foreignKeys) {
fk.validate();
}
-
for (Check c : checks) {
c.validate();
}
-
for (Index i : indexes) {
i.validate();
}
@@ -629,12 +652,12 @@ public class Schema {
public PrimaryKey addPrimaryKey(String name, String... columnNames) {
if (primaryKey != null) {
- throw new RuntimeException("Only one primary key is allowed. For composite keys use"
+ throw new IllegalArgumentException("Only one primary key is allowed. For composite keys use"
+ " addPrimaryKey(name, c1, c2, ...).");
}
for (Column c : columns) {
if (c.name.equalsIgnoreCase(name)) {
- throw new RuntimeException("For table: " + this.name + " primary key name should not be a column name: " + name);
+ throw new IllegalArgumentException("For table: " + this.name + " primary key name should not be a column name: " + name);
}
}
primaryKey = new PrimaryKey(name, columnNames);
@@ -671,18 +694,20 @@ public class Schema {
}
public class PrimaryKey {
+
private final String name;
- private final List columnNames = new ArrayList<>();
+
+ private final List columnNames;
public PrimaryKey(String name, String[] columnNames) {
this.name = toName(name);
+ this.columnNames = new ArrayList<>();
for (String s : columnNames) {
this.columnNames.add(toName(s));
}
}
public void validate() {
-
}
public Table table() {
@@ -692,18 +717,20 @@ public class Schema {
}
public class Unique {
+
private final String name;
- private final List columnNames = new ArrayList<>();
+
+ private final List columnNames;
public Unique(String name, String[] columnNames) {
this.name = toName(name);
+ this.columnNames = new ArrayList<>();
for (String s : columnNames) {
this.columnNames.add(toName(s));
}
}
public void validate() {
-
}
public Table table() {
@@ -713,13 +740,18 @@ public class Schema {
}
public class ForeignKey {
+
private final String name;
- private final List columnNames = new ArrayList<>();
- public String foreignTable;
- private boolean onDeleteCascade = false;
+
+ private final List columnNames;
+
+ private String foreignTable;
+
+ private boolean onDeleteCascade;
public ForeignKey(String name, String[] columnNames) {
this.name = toName(name);
+ this.columnNames = new ArrayList<>();
for (String s : columnNames) {
this.columnNames.add(toName(s));
}
@@ -737,7 +769,7 @@ public class Schema {
private void validate() {
if (foreignTable == null) {
- throw new RuntimeException("Foreign key " + name + " must reference a table");
+ throw new IllegalArgumentException("Foreign key " + name + " must reference a table");
}
}
@@ -748,7 +780,9 @@ public class Schema {
}
public class Check {
+
private final String name;
+
private final String expression;
public Check(String name, String expression) {
@@ -758,7 +792,7 @@ public class Schema {
private void validate() {
if (expression == null) {
- throw new RuntimeException("Expression needed for check constraint " + name + " on table " + Table.this.name);
+ throw new IllegalArgumentException("Expression needed for check constraint " + name + " on table " + Table.this.name);
}
}
@@ -769,12 +803,16 @@ public class Schema {
}
public class Index {
+
private final String name;
- private final List columnNames = new ArrayList<>();
+
+ private final List columnNames;
+
private boolean unique;
public Index(String name, String[] columnNames) {
this.name = toName(name);
+ this.columnNames = new ArrayList<>();
for (String s : columnNames) {
this.columnNames.add(toName(s));
}
@@ -787,7 +825,7 @@ public class Schema {
private void validate() {
if (columnNames.size() < 1) {
- throw new RuntimeException("Index " + name + " needs at least one column");
+ throw new IllegalArgumentException("Index " + name + " needs at least one column");
}
}
@@ -798,11 +836,17 @@ public class Schema {
}
public class Column {
+
private final String name;
+
private ColumnType type;
+
private int scale;
+
private int precision;
+
private boolean notNull;
+
private String comment;
public Column(String name) {
@@ -886,7 +930,7 @@ public class Schema {
private void validate() {
if (type == null) {
- throw new RuntimeException("Call as*() on column " + name + " table " + Table.this.name);
+ throw new IllegalArgumentException("Call as*() on column " + name + " table " + Table.this.name);
}
}
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/When.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/When.java
index e81ea02..e394295 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/When.java
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/When.java
@@ -1,8 +1,5 @@
package org.xbib.jdbc.query;
-import org.xbib.jdbc.query.flavor.Derby;
-import org.xbib.jdbc.query.flavor.SqlServer;
-
import java.util.Objects;
/**
@@ -17,21 +14,42 @@ public class When {
public When(Flavor actualFlavor) {
this.actualFlavor = actualFlavor;
}
-
+
+ public When derby(String sql) {
+ if ("derby".equals(actualFlavor.getName())) {
+ chosen = sql;
+ }
+ return this;
+ }
+
+ public When h2(String sql) {
+ if ("h2".equals(actualFlavor.getName())) {
+ chosen = sql;
+ }
+ return this;
+ }
+
+ public When hsqldb(String sql) {
+ if ("hsqldb".equals(actualFlavor.getName())) {
+ chosen = sql;
+ }
+ return this;
+ }
+
+ public When mariadb(String sql) {
+ if ("mariadb".equals(actualFlavor.getName())) {
+ chosen = sql;
+ }
+ return this;
+ }
+
public When oracle(String sql) {
if ("oracle".equals(actualFlavor.getName())) {
chosen = sql;
}
return this;
}
-
- public When derby(String sql) {
- if (actualFlavor instanceof Derby) {
- chosen = sql;
- }
- return this;
- }
-
+
public When postgres(String sql) {
if ("postgresql".equals(actualFlavor.getName())) {
chosen = sql;
@@ -40,12 +58,11 @@ public class When {
}
public When sqlserver(String sql) {
- if (actualFlavor instanceof SqlServer) {
+ if ("sqlserver".equals(actualFlavor.getName())) {
chosen = sql;
}
return this;
}
-
public String other(String sql) {
if (chosen == null) {
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Derby.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Derby.java
index 6dffb16..2eb7d4a 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Derby.java
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Derby.java
@@ -23,8 +23,16 @@ public class Derby implements Flavor {
}
@Override
- public boolean isNormalizedUpperCase() {
- return true;
+ public String normalizeTableName(String tableName) {
+ if (tableName == null) {
+ return tableName;
+ }
+ if (tableName.length() > 2) {
+ if (tableName.startsWith("\"") && tableName.endsWith("\"")) {
+ return tableName.substring(1, tableName.length() - 1);
+ }
+ }
+ return tableName.toUpperCase();
}
@Override
@@ -92,6 +100,11 @@ public class Derby implements Flavor {
return "timestamp";
}
+ @Override
+ public String columnTypeLocalDateTime() {
+ return "timestamp";
+ }
+
@Override
public String typeLocalDate() {
return "date";
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/H2.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/H2.java
index 8725875..a615e4d 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/H2.java
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/H2.java
@@ -23,8 +23,16 @@ public class H2 implements Flavor {
}
@Override
- public boolean isNormalizedUpperCase() {
- return true;
+ public String normalizeTableName(String tableName) {
+ if (tableName == null) {
+ return tableName;
+ }
+ if (tableName.length() > 2) {
+ if (tableName.startsWith("\"") && tableName.endsWith("\"")) {
+ return tableName.substring(1, tableName.length() - 1);
+ }
+ }
+ return tableName.toUpperCase();
}
@Override
@@ -92,6 +100,11 @@ public class H2 implements Flavor {
return "timestamp(3)";
}
+ @Override
+ public String columnTypeLocalDateTime() {
+ return "timestamp";
+ }
+
@Override
public String typeLocalDate() {
return "date";
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Hsql.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Hsql.java
index 2ec425b..6c1b452 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Hsql.java
+++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Hsql.java
@@ -23,8 +23,16 @@ public class Hsql implements Flavor {
}
@Override
- public boolean isNormalizedUpperCase() {
- return true;
+ public String normalizeTableName(String tableName) {
+ if (tableName == null) {
+ return tableName;
+ }
+ if (tableName.length() > 2) {
+ if (tableName.startsWith("\"") && tableName.endsWith("\"")) {
+ return tableName.substring(1, tableName.length() - 1);
+ }
+ }
+ return tableName.toUpperCase();
}
@Override
@@ -92,6 +100,11 @@ public class Hsql implements Flavor {
return "timestamp with time zone";
}
+ @Override
+ public String columnTypeLocalDateTime() {
+ return "TIMESTAMP WITH TIME ZONE";
+ }
+
@Override
public String typeLocalDate() {
return "date";
diff --git a/jdbc-query/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor b/jdbc-query/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor
index 0e4363b..017c60c 100644
--- a/jdbc-query/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor
+++ b/jdbc-query/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor
@@ -1,4 +1,3 @@
org.xbib.jdbc.query.flavor.Derby
org.xbib.jdbc.query.flavor.Hsql
-org.xbib.jdbc.query.flavor.H2
-org.xbib.jdbc.query.flavor.SqlServer
\ No newline at end of file
+org.xbib.jdbc.query.flavor.H2
\ No newline at end of file
diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/CommonTest.java b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/CommonTest.java
deleted file mode 100644
index f47ad3d..0000000
--- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/CommonTest.java
+++ /dev/null
@@ -1,1721 +0,0 @@
-package org.xbib.jdbc.query.test;
-
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.xbib.jdbc.query.ConstraintViolationException;
-import org.xbib.jdbc.query.Database;
-import org.xbib.jdbc.query.DatabaseException;
-import org.xbib.jdbc.query.DatabaseProvider;
-import org.xbib.jdbc.query.OptionsDefault;
-import org.xbib.jdbc.query.OptionsOverride;
-import org.xbib.jdbc.query.Row;
-import org.xbib.jdbc.query.RowHandler;
-import org.xbib.jdbc.query.RowsHandler;
-import org.xbib.jdbc.query.Schema;
-import org.xbib.jdbc.query.Sql;
-import org.xbib.jdbc.query.SqlArgs;
-import org.xbib.jdbc.query.StatementAdapter;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.io.StringReader;
-import java.math.BigDecimal;
-import java.sql.ResultSetMetaData;
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.Month;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.TimeZone;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
-/**
- * Exercise Database functionality with a real database.
- */
-public abstract class CommonTest {
-
- private static final Logger logger = Logger.getLogger(CommonTest.class.getName());
-
- final static String TEST_TABLE_NAME = "dbtest";
-
- protected static DatabaseProvider dbp;
-
- protected Database db;
-
- protected LocalDateTime now;
-
- protected LocalDate localDateNow;
-
- protected abstract DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception;
-
- @BeforeEach
- public void setupJdbc() throws Exception {
- now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS);
- localDateNow = LocalDate.now();
- dbp = createDatabaseProvider(new OptionsOverride() {
- });
- db = dbp.get();
- db.dropTableQuietly(TEST_TABLE_NAME);
- }
-
- @AfterEach
- public void closeJdbc() {
- if (dbp != null) {
- dbp.commitAndClose();
- }
- }
-
- @Test
- public void tableExists() {
- // Verify dbtest table does not exist
- String lowercaseTable = TEST_TABLE_NAME.toLowerCase();
- testTableLookup(lowercaseTable);
- db.dropTableQuietly(lowercaseTable);
- // Let's try creating a table with an upper case name and verify it works
- String uppercaseTable = TEST_TABLE_NAME.toUpperCase();
- testTableLookup(uppercaseTable);
- db.dropTableQuietly(uppercaseTable);
- // Verify that null or empty name is handled gracefully
- assertFalse(db.tableExists(null));
- assertFalse(db.tableExists(""));
- }
-
- private void testTableLookup(String tableName) {
- // Verify test table does not exist
- assertFalse(db.tableExists(tableName));
- // Create and verify it exists.
- new Schema().addTable(tableName).addColumn("pk").primaryKey().schema().execute(db);
- assertTrue(db.tableExists(tableName));
- }
-
- @Test
- public void normalizeTableName() {
- // Verify that null and empty cases are handled gracefully
- assertNull(db.normalizeTableName(null));
- assertEquals("", db.normalizeTableName(""));
-
- // Verify a quoted table name is returned in exactly the same case, with quotes removed.
- String camelCaseTableName = "\"DbTest\"";
- assertEquals(camelCaseTableName.substring(1, camelCaseTableName.length() - 1),
- db.normalizeTableName(camelCaseTableName));
-
- // Verify that the database flavor gets the expected normalized case
- boolean isUpperCase = db.flavor().isNormalizedUpperCase();
- if (isUpperCase) {
- assertEquals(TEST_TABLE_NAME.toUpperCase(), db.normalizeTableName(TEST_TABLE_NAME));
- } else {
- assertEquals(TEST_TABLE_NAME.toLowerCase(), db.normalizeTableName(TEST_TABLE_NAME));
- }
- }
-
- @Test
- public void selectNewTable() {
- new Schema()
- .addTable("dbtest")
- .addColumn("nbr_integer").asInteger().primaryKey().table()
- .addColumn("nbr_long").asLong().table()
- .addColumn("nbr_float").asFloat().table()
- .addColumn("nbr_double").asDouble().table()
- .addColumn("nbr_big_decimal").asBigDecimal(19, 9).table()
- .addColumn("str_varchar").asString(80).table()
- .addColumn("str_fixed").asStringFixed(1).table()
- .addColumn("str_lob").asClob().table()
- .addColumn("bin_blob").asBlob().table()
- .addColumn("date_millis").asLocalDateTime().table()
- .addColumn("local_date").asLocalDate().table().schema().execute(db);
-
- BigDecimal bigDecimal = new BigDecimal("5.3");
- db.toInsert("insert into dbtest values (?,?,?,?,?,?,?,?,?,?,?)").argInteger(1).argLong(2L).argFloat(3.2f).argDouble(4.2)
- .argBigDecimal(bigDecimal).argString("Hello").argString("T").argClobString("World")
- .argBlobBytes("More".getBytes()).argLocalDateTime(now).argLocalDate(localDateNow).insert(1);
-
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
- + "bin_blob, date_millis, local_date from dbtest")
- .query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(Integer.valueOf(1), rs.getIntegerOrNull(1));
- assertEquals(Integer.valueOf(1), rs.getIntegerOrNull("nbr_integer"));
- assertEquals(1, rs.getIntegerOrZero(1));
- assertEquals(1, rs.getIntegerOrZero("nbr_integer"));
- assertEquals(Long.valueOf(2), rs.getLongOrNull(2));
- assertEquals(Long.valueOf(2), rs.getLongOrNull("nbr_long"));
- assertEquals(2, rs.getLongOrZero(2));
- assertEquals(2, rs.getLongOrZero("nbr_long"));
- assertEquals(Float.valueOf(3.2f), rs.getFloatOrNull(3));
- assertEquals(Float.valueOf(3.2f), rs.getFloatOrNull("nbr_float"));
- assertEquals(3.2, rs.getFloatOrZero(3), 0.01);
- assertEquals(3.2, rs.getFloatOrZero("nbr_float"), 0.01);
- assertEquals(Double.valueOf(4.2), rs.getDoubleOrNull(4));
- assertEquals(Double.valueOf(4.2), rs.getDoubleOrNull("nbr_double"));
- assertEquals(4.2, rs.getDoubleOrZero(4), 0.01);
- assertEquals(4.2, rs.getDoubleOrZero("nbr_double"), 0.01);
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrNull(5));
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrNull("nbr_big_decimal"));
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrZero(5));
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrZero("nbr_big_decimal"));
- assertEquals("Hello", rs.getStringOrNull(6));
- assertEquals("Hello", rs.getStringOrNull("str_varchar"));
- assertEquals("Hello", rs.getStringOrEmpty(6));
- assertEquals("Hello", rs.getStringOrEmpty("str_varchar"));
- assertEquals("T", rs.getStringOrNull(7));
- assertEquals("T", rs.getStringOrNull("str_fixed"));
- assertEquals("T", rs.getStringOrEmpty(7));
- assertEquals("T", rs.getStringOrEmpty("str_fixed"));
- assertEquals("World", rs.getClobStringOrNull(8));
- assertEquals("World", rs.getClobStringOrNull("str_lob"));
- assertEquals("World", rs.getClobStringOrEmpty(8));
- assertEquals("World", rs.getClobStringOrEmpty("str_lob"));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull(9));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull("bin_blob"));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrZeroLen(9));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrZeroLen("bin_blob"));
- assertEquals(now, rs.getLocalDateTimeOrNull(10));
- assertEquals(now, rs.getLocalDateTimeOrNull("date_millis"));
- assertEquals(localDateNow, rs.getLocalDateOrNull(11));
- assertEquals(localDateNow, rs.getLocalDateOrNull("local_date"));
- return null;
- });
- // Repeat the above query, using the various methods that automatically infer the column
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
- + "bin_blob, date_millis, local_date from dbtest")
- .query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(Integer.valueOf(1), rs.getIntegerOrNull());
- assertEquals(Long.valueOf(2), rs.getLongOrNull());
- assertEquals(Float.valueOf(3.2f), rs.getFloatOrNull());
- assertEquals(Double.valueOf(4.2), rs.getDoubleOrNull());
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrNull());
- assertEquals("Hello", rs.getStringOrNull());
- assertEquals("T", rs.getStringOrNull());
- assertEquals("World", rs.getClobStringOrNull());
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull());
- assertEquals(now, rs.getLocalDateTimeOrNull());
- assertEquals(localDateNow, rs.getLocalDateOrNull());
- return null;
- });
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
- + "bin_blob, date_millis, local_date from dbtest")
- .query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(1, rs.getIntegerOrZero());
- assertEquals(2, rs.getLongOrZero());
- assertEquals(3.2, rs.getFloatOrZero(), 0.01);
- assertEquals(4.2, rs.getDoubleOrZero(), 0.01);
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrZero());
- assertEquals("Hello", rs.getStringOrEmpty());
- assertEquals("T", rs.getStringOrEmpty());
- assertEquals("World", rs.getClobStringOrEmpty());
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrZeroLen());
- return null;
- });
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals("World", readerToString(rs.getClobReaderOrNull(1)));
- assertArrayEquals("More".getBytes(), inputStreamToString(rs.getBlobInputStreamOrNull(2)));
- return null;
- });
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals("World", readerToString(rs.getClobReaderOrEmpty(1)));
- assertArrayEquals("More".getBytes(), inputStreamToString(rs.getBlobInputStreamOrEmpty(2)));
- return null;
- });
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals("World", readerToString(rs.getClobReaderOrNull()));
- assertArrayEquals("More".getBytes(), inputStreamToString(rs.getBlobInputStreamOrNull()));
- return null;
- });
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals("World", readerToString(rs.getClobReaderOrEmpty()));
- assertArrayEquals("More".getBytes(), inputStreamToString(rs.getBlobInputStreamOrEmpty()));
- return null;
- });
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals("World", readerToString(rs.getClobReaderOrNull("str_lob")));
- assertArrayEquals("More".getBytes(), inputStreamToString(rs.getBlobInputStreamOrNull("bin_blob")));
- return null;
- });
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals("World", readerToString(rs.getClobReaderOrEmpty("str_lob")));
- assertArrayEquals("More".getBytes(), inputStreamToString(rs.getBlobInputStreamOrEmpty("bin_blob")));
- return null;
- });
- assertEquals(Long.valueOf(1), db.toSelect("select count(*) from dbtest where nbr_integer=:i and nbr_long=:l and "
- + "abs(nbr_float-:f)<0.01 and abs(nbr_double-:d)<0.01 and nbr_big_decimal=:bd and str_varchar=:s "
- + "and str_fixed=:sf and date_millis=:date and local_date=:local_date")
- .argInteger("i", 1)
- .argLong("l", 2L)
- .argFloat("f", 3.2f)
- .argDouble("d", 4.2)
- .argBigDecimal("bd", bigDecimal)
- .argString("s", "Hello")
- .argString("sf", "T")
- .argLocalDateTime("date", now)
- .argLocalDate("local_date", localDateNow)
- .queryLongOrNull());
- List result = db.toSelect("select count(*) from dbtest where nbr_integer=:i and nbr_long=:l and "
- + "abs(nbr_float-:f)<0.01 and abs(nbr_double-:d)<0.01 and nbr_big_decimal=:bd and str_varchar=:s "
- + "and str_fixed=:sf and date_millis=:date and local_date=:local_date").argInteger("i", 1).argLong("l", 2L).argFloat("f", 3.2f)
- .argDouble("d", 4.2).argBigDecimal("bd", bigDecimal).argString("s", "Hello").argString("sf", "T")
- .argLocalDateTime("date", now).argLocalDate("local_date", localDateNow).queryLongs();
- assertEquals(1, result.size());
- assertEquals(Long.valueOf(1), result.get(0));
- }
-
- @Test
- public void updatePositionalArgs() {
- new Schema()
- .addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("nbr_integer").asInteger().table()
- .addColumn("nbr_long").asLong().table()
- .addColumn("nbr_float").asFloat().table()
- .addColumn("nbr_double").asDouble().table()
- .addColumn("nbr_big_decimal").asBigDecimal(19, 9).table()
- .addColumn("str_varchar").asString(80).table()
- .addColumn("str_fixed").asStringFixed(1).table()
- .addColumn("str_lob").asClob().table()
- .addColumn("bin_blob").asBlob().table()
- .addColumn("date_millis").asLocalDateTime().table()
- .addColumn("local_date").asLocalDate().table().schema().execute(db);
-
- BigDecimal bigDecimal = new BigDecimal("5.3");
- assertEquals(1, db.toInsert("insert into dbtest values (?,?,?,?,?,?,?,?,?,?,?,?)")
- .argLong(1L)
- .argInteger(1)
- .argLong(2L)
- .argFloat(3.2f)
- .argDouble(4.2)
- .argBigDecimal(bigDecimal)
- .argString("Hello")
- .argString("T")
- .argClobString("World")
- .argBlobBytes("More".getBytes())
- .argLocalDateTime(now)
- .argLocalDate(localDateNow).insert());
- db.toUpdate("update dbtest set nbr_integer=?, nbr_long=?, nbr_float=?, nbr_double=?, nbr_big_decimal=?, "
- + "str_varchar=?, str_fixed=?, str_lob=?, bin_blob=?, date_millis=?, local_date=?").argInteger(null).argLong(null)
- .argFloat(null).argDouble(null).argBigDecimal(null).argString(null).argString(null).argClobString(null)
- .argBlobBytes(null).argLocalDateTime(null).argLocalDate(null).update(1);
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
- + "bin_blob, date_millis, local_date from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertNull(rs.getIntegerOrNull(1));
- assertNull(rs.getIntegerOrNull("nbr_integer"));
- assertNull(rs.getLongOrNull(2));
- assertNull(rs.getLongOrNull("nbr_long"));
- assertNull(rs.getFloatOrNull(3));
- assertNull(rs.getFloatOrNull("nbr_float"));
- assertNull(rs.getDoubleOrNull(4));
- assertNull(rs.getDoubleOrNull("nbr_double"));
- assertNull(rs.getBigDecimalOrNull(5));
- assertNull(rs.getBigDecimalOrNull("nbr_big_decimal"));
- assertNull(rs.getStringOrNull(6));
- assertNull(rs.getStringOrNull("str_varchar"));
- assertNull(rs.getStringOrNull(7));
- assertNull(rs.getStringOrNull("str_fixed"));
- assertNull(rs.getClobStringOrNull(8));
- assertNull(rs.getClobStringOrNull("str_lob"));
- assertNull(rs.getBlobBytesOrNull(9));
- assertNull(rs.getBlobBytesOrNull("bin_blob"));
- assertNull(rs.getLocalDateTimeOrNull(10));
- assertNull(rs.getLocalDateTimeOrNull("date_millis"));
- assertNull(rs.getLocalDateOrNull(11));
- assertNull(rs.getLocalDateOrNull("local_date"));
- return null;
- });
- assertEquals(1, db.toUpdate("update dbtest set nbr_integer=?, nbr_long=?, nbr_float=?, nbr_double=?, "
- + "nbr_big_decimal=?, str_varchar=?, str_fixed=?, str_lob=?, bin_blob=?, date_millis=?, local_date=?").argInteger(1)
- .argLong(2L).argFloat(3.2f).argDouble(4.2).argBigDecimal(bigDecimal).argString("Hello").argString("T")
- .argClobString("World").argBlobBytes("More".getBytes()).argLocalDateTime(now).argLocalDate(localDateNow).update());
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
- + "bin_blob, date_millis, local_date from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(Integer.valueOf(1), rs.getIntegerOrNull(1));
- assertEquals(Integer.valueOf(1), rs.getIntegerOrNull("nbr_integer"));
- assertEquals(Long.valueOf(2), rs.getLongOrNull(2));
- assertEquals(Long.valueOf(2), rs.getLongOrNull("nbr_long"));
- assertEquals(Float.valueOf(3.2f), rs.getFloatOrNull(3));
- assertEquals(Float.valueOf(3.2f), rs.getFloatOrNull("nbr_float"));
- assertEquals(Double.valueOf(4.2), rs.getDoubleOrNull(4));
- assertEquals(Double.valueOf(4.2), rs.getDoubleOrNull("nbr_double"));
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrNull(5));
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrNull("nbr_big_decimal"));
- assertEquals("Hello", rs.getStringOrNull(6));
- assertEquals("Hello", rs.getStringOrNull("str_varchar"));
- assertEquals("T", rs.getStringOrNull(7));
- assertEquals("T", rs.getStringOrNull("str_fixed"));
- assertEquals("World", rs.getClobStringOrNull(8));
- assertEquals("World", rs.getClobStringOrNull("str_lob"));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull(9));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull("bin_blob"));
- assertEquals(now, rs.getLocalDateTimeOrNull(10));
- assertEquals(now, rs.getLocalDateTimeOrNull("date_millis"));
- assertEquals(localDateNow, rs.getLocalDateOrNull(11));
- assertEquals(localDateNow, rs.getLocalDateOrNull("local_date"));
- return null;
- });
- db.toUpdate("update dbtest set str_lob=?, bin_blob=?").argClobReader(null).argBlobStream(null).update(1);
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertNull(rs.getClobStringOrNull(1));
- assertNull(rs.getClobStringOrNull("str_lob"));
- assertNull(rs.getBlobBytesOrNull(2));
- assertNull(rs.getBlobBytesOrNull("bin_blob"));
- return null;
- });
- db.toUpdate("update dbtest set str_lob=?, bin_blob=?").argClobReader(new StringReader("World"))
- .argBlobStream(new ByteArrayInputStream("More".getBytes())).update(1);
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals("World", rs.getClobStringOrNull(1));
- assertEquals("World", rs.getClobStringOrNull("str_lob"));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull(2));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull("bin_blob"));
- return null;
- });
- }
-
- @Test
- public void updateNamedArgs() {
- new Schema()
- .addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("nbr_integer").asInteger().table()
- .addColumn("nbr_long").asLong().table()
- .addColumn("nbr_float").asFloat().table()
- .addColumn("nbr_double").asDouble().table()
- .addColumn("nbr_big_decimal").asBigDecimal(19, 9).table()
- .addColumn("str_varchar").asString(80).table()
- .addColumn("str_fixed").asStringFixed(1).table()
- .addColumn("str_lob").asClob().table()
- .addColumn("bin_blob").asBlob().table()
- .addColumn("date_millis").asLocalDateTime().table()
- .addColumn("local_date").asLocalDate().table().schema().execute(db);
- BigDecimal bigDecimal = new BigDecimal("5.3");
- db.toInsert("insert into dbtest values (:pk,:a,:b,:c,:d,:e,:f,:sf,:g,:h,:i,:j)").argLong(":pk", 1L).argInteger(":a", 1)
- .argLong(":b", 2L).argFloat(":c", 3.2f).argDouble(":d", 4.2).argBigDecimal(":e", bigDecimal)
- .argString(":f", "Hello").argString(":sf", "T")
- .argClobString(":g", "World").argBlobBytes(":h", "More".getBytes())
- .argLocalDateTime(":i", now).argLocalDate(":j", localDateNow).insert(1);
- db.toUpdate("update dbtest set nbr_integer=:a, nbr_long=:b, nbr_float=:c, nbr_double=:d, nbr_big_decimal=:e, "
- + "str_varchar=:f, str_fixed=:sf, str_lob=:g, bin_blob=:h, date_millis=:i, local_date=:j").argInteger(":a", null)
- .argLong(":b", null).argFloat(":c", null).argDouble(":d", null).argBigDecimal(":e", null)
- .argString(":f", null).argString(":sf", null)
- .argClobString(":g", null).argBlobBytes(":h", null)
- .argLocalDateTime(":i", null).argLocalDate(":j", null).update(1);
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
- + "bin_blob, date_millis, local_date from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertNull(rs.getIntegerOrNull(1));
- assertNull(rs.getIntegerOrNull("nbr_integer"));
- assertNull(rs.getLongOrNull(2));
- assertNull(rs.getLongOrNull("nbr_long"));
- assertNull(rs.getFloatOrNull(3));
- assertNull(rs.getFloatOrNull("nbr_float"));
- assertNull(rs.getDoubleOrNull(4));
- assertNull(rs.getDoubleOrNull("nbr_double"));
- assertNull(rs.getBigDecimalOrNull(5));
- assertNull(rs.getBigDecimalOrNull("nbr_big_decimal"));
- assertNull(rs.getStringOrNull(6));
- assertNull(rs.getStringOrNull("str_varchar"));
- assertNull(rs.getStringOrNull(7));
- assertNull(rs.getStringOrNull("str_fixed"));
- assertNull(rs.getClobStringOrNull(8));
- assertNull(rs.getClobStringOrNull("str_lob"));
- assertNull(rs.getBlobBytesOrNull(9));
- assertNull(rs.getBlobBytesOrNull("bin_blob"));
- assertNull(rs.getLocalDateTimeOrNull(10));
- assertNull(rs.getLocalDateTimeOrNull("date_millis"));
- assertNull(rs.getLocalDateOrNull(11));
- assertNull(rs.getLocalDateOrNull("local_date"));
- return null;
- });
- db.toUpdate("update dbtest set nbr_integer=:a, nbr_long=:b, nbr_float=:c, nbr_double=:d, nbr_big_decimal=:e, "
- + "str_varchar=:f, str_fixed=:sf, str_lob=:g, bin_blob=:h, date_millis=:i, local_date=:j").argInteger(":a", 1)
- .argLong(":b", 2L).argFloat(":c", 3.2f).argDouble(":d", 4.2).argBigDecimal(":e", bigDecimal)
- .argString(":f", "Hello").argString(":sf", "T")
- .argClobString(":g", "World").argBlobBytes(":h", "More".getBytes())
- .argLocalDateTime(":i", now).argLocalDate(":j", localDateNow).update(1);
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
- + "bin_blob, date_millis, local_date from dbtest")
- .query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(Integer.valueOf(1), rs.getIntegerOrNull(1));
- assertEquals(Integer.valueOf(1), rs.getIntegerOrNull("nbr_integer"));
- assertEquals(Long.valueOf(2), rs.getLongOrNull(2));
- assertEquals(Long.valueOf(2), rs.getLongOrNull("nbr_long"));
- assertEquals(Float.valueOf(3.2f), rs.getFloatOrNull(3));
- assertEquals(Float.valueOf(3.2f), rs.getFloatOrNull("nbr_float"));
- assertEquals(Double.valueOf(4.2), rs.getDoubleOrNull(4));
- assertEquals(Double.valueOf(4.2), rs.getDoubleOrNull("nbr_double"));
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrNull(5));
- assertEquals(new BigDecimal("5.3"), rs.getBigDecimalOrNull("nbr_big_decimal"));
- assertEquals("Hello", rs.getStringOrNull(6));
- assertEquals("Hello", rs.getStringOrNull("str_varchar"));
- assertEquals("T", rs.getStringOrNull(7));
- assertEquals("T", rs.getStringOrNull("str_fixed"));
- assertEquals("World", rs.getClobStringOrNull(8));
- assertEquals("World", rs.getClobStringOrNull("str_lob"));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull(9));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull("bin_blob"));
- assertEquals(now, rs.getLocalDateTimeOrNull(10));
- assertEquals(now, rs.getLocalDateTimeOrNull("date_millis"));
- assertEquals(localDateNow, rs.getLocalDateOrNull(11));
- assertEquals(localDateNow, rs.getLocalDateOrNull("local_date"));
- return null;
- });
-
- db.toUpdate("update dbtest set str_lob=:a, bin_blob=:b").argClobReader(":a", null).argBlobStream(":b", null).update(1);
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertNull(rs.getClobStringOrNull(1));
- assertNull(rs.getClobStringOrNull("str_lob"));
- assertNull(rs.getBlobBytesOrNull(2));
- assertNull(rs.getBlobBytesOrNull("bin_blob"));
- return null;
- });
- db.toUpdate("update dbtest set str_lob=:a, bin_blob=:b").argClobReader(":a", new StringReader("World"))
- .argBlobStream(":b", new ByteArrayInputStream("More".getBytes())).update(1);
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals("World", rs.getClobStringOrNull(1));
- assertEquals("World", rs.getClobStringOrNull("str_lob"));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull(2));
- assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull("bin_blob"));
- return null;
- });
- }
-
- @Test
- public void nullValues() {
- new Schema()
- .addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("nbr_integer").asInteger().table()
- .addColumn("nbr_long").asLong().table()
- .addColumn("nbr_float").asFloat().table()
- .addColumn("nbr_double").asDouble().table()
- .addColumn("nbr_big_decimal").asBigDecimal(19, 9).table()
- .addColumn("str_varchar").asString(80).table()
- .addColumn("str_fixed").asStringFixed(1).table()
- .addColumn("str_lob").asClob().table()
- .addColumn("bin_blob").asBlob().table()
- .addColumn("date_millis").asLocalDateTime().table()
- .addColumn("local_date").asLocalDate().table().schema().execute(db);
- db.toInsert("insert into dbtest values (?,?,?,?,?,?,?,?,?,?,?,?)").argLong(1L).argInteger(null).argLong(null)
- .argFloat(null).argDouble(null).argBigDecimal(null).argString(null).argString(null).argClobString(null)
- .argBlobBytes(null).argLocalDateTime(null).argLocalDate(null).insert(1);
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
- + "bin_blob, date_millis, local_date from dbtest")
- .query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertNull(rs.getIntegerOrNull(1));
- assertNull(rs.getIntegerOrNull("nbr_integer"));
- assertNull(rs.getLongOrNull(2));
- assertNull(rs.getLongOrNull("nbr_long"));
- assertNull(rs.getFloatOrNull(3));
- assertNull(rs.getFloatOrNull("nbr_float"));
- assertNull(rs.getDoubleOrNull(4));
- assertNull(rs.getDoubleOrNull("nbr_double"));
- assertNull(rs.getBigDecimalOrNull(5));
- assertNull(rs.getBigDecimalOrNull("nbr_big_decimal"));
- assertNull(rs.getStringOrNull(6));
- assertNull(rs.getStringOrNull("str_varchar"));
- assertNull(rs.getStringOrNull(7));
- assertNull(rs.getStringOrNull("str_fixed"));
- assertNull(rs.getClobStringOrNull(8));
- assertNull(rs.getClobStringOrNull("str_lob"));
- assertNull(rs.getBlobBytesOrNull(9));
- assertNull(rs.getBlobBytesOrNull("bin_blob"));
- assertNull(rs.getLocalDateTimeOrNull(10));
- assertNull(rs.getLocalDateTimeOrNull("date_millis"));
- assertNull(rs.getLocalDateOrNull(11));
- assertNull(rs.getLocalDateOrNull("local_date"));
- return null;
- });
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertNull(rs.getClobReaderOrNull(1));
- assertNull(rs.getBlobInputStreamOrNull(2));
- return null;
- });
- db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertNull(rs.getClobReaderOrNull("str_lob"));
- assertNull(rs.getBlobInputStreamOrNull("bin_blob"));
- return null;
- });
- }
-
- @Test
- public void fromAny() {
- assertEquals(db.toSelect("select 1" + db.flavor().fromAny()).queryIntegerOrZero(), 1);
- }
-
- @Test
- public void metadataColumnNames() {
- 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;
- });
- }
-
- @Test
- public void metadataColumnTypes() {
- String timestampColumnName = "data_millis";
- String dateColumnName = "local_date";
- new Schema()
- .addTable("dbtest")
- .addColumn(timestampColumnName).asLocalDateTime().table()
- .addColumn(dateColumnName).asLocalDate().table().schema().execute(db);
- db.toSelect("select * from dbtest").query((RowsHandler) rs -> {
- ResultSetMetaData metadata = rs.getMetadata();
- for (int i = 1; i <= metadata.getColumnCount(); i++) {
- String columnName = metadata.getColumnName(i);
- String columnType = metadata.getColumnTypeName(i);
- if (columnName.equalsIgnoreCase(timestampColumnName)) {
- if ("sqlserver".equals(db.flavor().getName())) {
- assertEquals("DATETIME2", columnType.toUpperCase());
- } else if ("hsqldb".equals(db.flavor().getName())) {
- assertEquals("TIMESTAMP WITH TIME ZONE", columnType.toUpperCase());
- } else {
- assertEquals("TIMESTAMP", columnType.toUpperCase());
- }
- } else if (columnName.equalsIgnoreCase(dateColumnName)) {
- assertEquals("DATE", columnType.toUpperCase());
- } else {
- fail("Unexpected column " + columnName + " of type " + columnType);
- }
- }
- return null;
- });
- }
-
- @Test
- public void intervals() {
- new Schema().addTable("dbtest").addColumn("d").asLocalDateTime().schema().execute(db);
- db.toInsert("insert into dbtest (d) values (?)").argLocalDateTime(now).insert(1);
- assertEquals(1, db.toSelect("select count(1) from dbtest where d - interval '1' hour * ? < ?")
- .argInteger(2)
- .argLocalDateTime(now)
- .queryIntegerOrZero());
- }
-
- @Test
- public void saveResultAsTable() {
- new Schema().addTable("dbtest")
- .addColumn("nbr_integer").asInteger().primaryKey().table()
- .addColumn("nbr_long").asLong().table()
- .addColumn("nbr_float").asFloat().table()
- .addColumn("nbr_double").asDouble().table()
- .addColumn("nbr_big_decimal").asBigDecimal(19, 9).table()
- .addColumn("str_varchar").asString(80).table()
- .addColumn("str_fixed").asStringFixed(1).table()
- .addColumn("str_lob").asClob().table()
- .addColumn("bin_blob").asBlob().table()
- .addColumn("boolean_flag").asBoolean().table()
- .addColumn("date_millis").asLocalDateTime().table()
- .addColumn("local_date").asLocalDate().schema().execute(db);
- db.toInsert("insert into dbtest (nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar,"
- + " str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date) values (?,?,?,?,?,?,?,?,?,?,?,?)")
- .argInteger(Integer.MAX_VALUE).argLong(Long.MAX_VALUE).argFloat(Float.MAX_VALUE)
- .argDouble(Double.MAX_VALUE).argBigDecimal(new BigDecimal("123.456"))
- .argString("hello").argString("Z").argClobString("hello again")
- .argBlobBytes(new byte[]{'1', '2'}).argBoolean(true)
- .argLocalDateTime(now)
- .argLocalDate(localDateNow).insert(1);
- db.toInsert("insert into dbtest (nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar,"
- + " str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date) values (?,?,?,?,?,?,?,?,?,?,?,?)")
- .argInteger(Integer.MIN_VALUE).argLong(Long.MIN_VALUE).argFloat(0.000001f)
- .argDouble(Double.MIN_VALUE).argBigDecimal(new BigDecimal("-123.456"))
- .argString("goodbye").argString("A").argClobString("bye again")
- .argBlobBytes(new byte[]{'3', '4'}).argBoolean(false)
- .argLocalDateTime(now)
- .argLocalDate(localDateNow).insert(1);
- String expectedSchema = new Schema().addTable("dbtest2")
- .addColumn("nbr_integer").asInteger().table()
- .addColumn("nbr_long").asLong().table()
- .addColumn("nbr_float").asFloat().table()
- .addColumn("nbr_double").asDouble().table()
- .addColumn("nbr_big_decimal").asBigDecimal(19, 9).table()
- .addColumn("str_varchar").asString(80).table()
- .addColumn("str_fixed").asStringFixed(1).table()
- .addColumn("str_lob").asClob().table()
- .addColumn("bin_blob").asBlob().table()
- .addColumn("boolean_flag").asBoolean().table()
- .addColumn("date_millis").asLocalDateTime().table()
- .addColumn("local_date").asLocalDate().schema().print(db.flavor());
- List args = db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal,"
- + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest")
- .query(rs -> {
- List result = new ArrayList<>();
- while (rs.next()) {
- if (result.size() == 0) {
- db.dropTableQuietly("dbtest2");
- Schema schema = new Schema().addTableFromRow("dbtest2", rs).schema();
- assertEquals(expectedSchema, schema.print(db.flavor()));
- schema.execute(db);
- }
- result.add(SqlArgs.readRow(rs));
- }
- return result;
- });
-
- db.toInsert(Sql.insert("dbtest2", args)).insertBatch();
-
- assertEquals(2, db.toSelect("select count(*) from dbtest2").queryIntegerOrZero());
-
- assertEquals(
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal,"
- + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest order by 1")
- .queryMany(SqlArgs::readRow),
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal,"
- + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest2 order by 1")
- .queryMany(SqlArgs::readRow));
-
- assertEquals(
- Arrays.asList(
- new SqlArgs().argInteger("nbr_integer", Integer.MIN_VALUE)
- .argLong("nbr_long", Long.MIN_VALUE)
- .argFloat("nbr_float", 0.000001f)
- .argDouble("nbr_double", Double.MIN_VALUE)
- .argBigDecimal("nbr_big_decimal", new BigDecimal("-123.456"))
- .argString("str_varchar", "goodbye")
- .argString("str_fixed", "A")
- .argClobString("str_lob", "bye again")
- .argBlobBytes("bin_blob", new byte[]{'3', '4'})
- .argString("boolean_flag", "N")//.argBoolean("boolean_flag", false)
- .argLocalDateTime("date_millis", now)
- .argLocalDate("local_date", localDateNow),
- new SqlArgs().argInteger("nbr_integer", Integer.MAX_VALUE)
- .argLong("nbr_long", Long.MAX_VALUE)
- .argFloat("nbr_float", Float.MAX_VALUE)
- .argDouble("nbr_double", Double.MAX_VALUE)
- .argBigDecimal("nbr_big_decimal", new BigDecimal("123.456"))
- .argString("str_varchar", "hello")
- .argString("str_fixed", "Z")
- .argClobString("str_lob", "hello again")
- .argBlobBytes("bin_blob", new byte[]{'1', '2'})
- .argString("boolean_flag", "Y")//.argBoolean("boolean_flag", true)
- .argLocalDateTime("date_millis", now)
- .argLocalDate("local_date", localDateNow)),
- db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal,"
- + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest2 order by 1")
- .queryMany(SqlArgs::readRow));
- }
-
- @Test
- public void readSqlArgs() {
- new Schema().addTable("dbtest").addColumn("pk").primaryKey().schema().execute(db);
- db.toInsert("insert into dbtest (pk) values (?)").argInteger(1).insert(1);
- SqlArgs args = db.toSelect("select Pk, Pk as Foo, Pk as \"Foo\", pk as \"g arB#G!\","
- + " pk as \"TitleCase\" from dbtest")
- .queryOneOrThrow(SqlArgs::readRow);
-
- assertEquals(Arrays.asList("pk", "foo", "foo_2", "g_ar_b_g", "title_case"), args.names());
- }
-
- @Test
- public void clockSync() {
- db.assertTimeSynchronized();
- }
-
- @Test
- public void booleanColumn() {
- new Schema().addTable("dbtest")
- .addColumn("t").asBoolean().table()
- .addColumn("f").asBoolean().table()
- .addColumn("n").asBoolean().schema().execute(db);
- db.toInsert("insert into dbtest (t,f,n) values (?,:f,?)")
- .argBoolean(true).argBoolean("f", false).argBoolean(null).insert(1);
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertSame(rs.getBooleanOrNull(), Boolean.TRUE);
- assertSame(rs.getBooleanOrNull(), Boolean.FALSE);
- assertNull(rs.getBooleanOrNull());
- return null;
- });
- // Verify use of getBooleanOrNull(int) followed by default getBooleanOrNull() tracks
- // the current column index correctly (picks up where the explicit one left off)
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertSame(rs.getBooleanOrNull(2), Boolean.FALSE);
- assertNull(rs.getBooleanOrNull());
- return null;
- });
- // Verify use of getBooleanOrNull(String) followed by default getBooleanOrNull() tracks
- // the current column index correctly (picks up where the explicit one left off)
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertSame(rs.getBooleanOrNull("f"), Boolean.FALSE);
- assertNull(rs.getBooleanOrNull());
- return null;
- });
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertTrue(rs.getBooleanOrFalse());
- assertFalse(rs.getBooleanOrFalse());
- assertFalse(rs.getBooleanOrFalse());
- return null;
- });
- // Verify use of getBooleanOrFalse(int) followed by default getBooleanOrFalse() tracks
- // the current column index correctly (picks up where the explicit one left off)
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertFalse(rs.getBooleanOrFalse(2));
- assertFalse(rs.getBooleanOrFalse());
- return null;
- });
- // Verify use of getBooleanOrFalse(String) followed by default getBooleanOrFalse() tracks
- // the current column index correctly (picks up where the explicit one left off)
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertFalse(rs.getBooleanOrFalse("f"));
- assertFalse(rs.getBooleanOrFalse());
- return null;
- });
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertTrue(rs.getBooleanOrTrue());
- assertFalse(rs.getBooleanOrTrue());
- assertTrue(rs.getBooleanOrTrue());
- return null;
- });
- // Verify use of getBooleanOrTrue(int) followed by default getBooleanOrTrue() tracks
- // the current column index correctly (picks up where the explicit one left off)
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertFalse(rs.getBooleanOrTrue(2));
- assertTrue(rs.getBooleanOrTrue());
- return null;
- });
- // Verify use of getBooleanOrTrue(String) followed by default getBooleanOrTrue() tracks
- // the current column index correctly (picks up where the explicit one left off)
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertFalse(rs.getBooleanOrTrue("f"));
- assertTrue(rs.getBooleanOrTrue());
- return null;
- });
- db.toDelete("delete from dbtest where t=? and f=?")
- .argBoolean(true).argBoolean(false).update(1);
-
- db.toInsert("insert into dbtest (t,f,n) values (:t,:f,:n)")
- .argBoolean("t", true).argBoolean("f", false).argBoolean("n", null).insert(1);
- db.toSelect("select t,f,n from dbtest")
- .query(rs -> {
- assertTrue(rs.next());
- assertSame(rs.getBooleanOrNull(1), Boolean.TRUE);
- assertSame(rs.getBooleanOrNull(2), Boolean.FALSE);
- assertNull(rs.getBooleanOrNull(3));
- assertEquals(rs.getBooleanOrFalse(1), Boolean.TRUE);
- assertEquals(rs.getBooleanOrFalse(2), Boolean.FALSE);
- assertEquals(rs.getBooleanOrFalse(3), Boolean.FALSE);
- assertEquals(rs.getBooleanOrTrue(1), Boolean.TRUE);
- assertEquals(rs.getBooleanOrTrue(2), Boolean.FALSE);
- assertEquals(rs.getBooleanOrTrue(3), Boolean.TRUE);
- assertSame(rs.getBooleanOrNull("t"), Boolean.TRUE);
- assertSame(rs.getBooleanOrNull("f"), Boolean.FALSE);
- assertNull(rs.getBooleanOrNull("n"));
- assertEquals(rs.getBooleanOrFalse("t"), Boolean.TRUE);
- assertEquals(rs.getBooleanOrFalse("f"), Boolean.FALSE);
- assertEquals(rs.getBooleanOrFalse("n"), Boolean.FALSE);
- assertEquals(rs.getBooleanOrTrue("t"), Boolean.TRUE);
- assertEquals(rs.getBooleanOrTrue("f"), Boolean.FALSE);
- assertEquals(rs.getBooleanOrTrue("n"), Boolean.TRUE);
- return null;
- });
- assertSame(db.toSelect("select t from dbtest").queryBooleanOrNull(), Boolean.TRUE);
- assertTrue(db.toSelect("select t from dbtest").queryBooleanOrFalse());
- assertTrue(db.toSelect("select t from dbtest").queryBooleanOrTrue());
- assertSame(db.toSelect("select f from dbtest").queryBooleanOrNull(), Boolean.FALSE);
- assertFalse(db.toSelect("select f from dbtest").queryBooleanOrFalse());
- assertFalse(db.toSelect("select f from dbtest").queryBooleanOrTrue());
- assertNull(db.toSelect("select n from dbtest").queryBooleanOrNull());
- assertFalse(db.toSelect("select n from dbtest").queryBooleanOrFalse());
- assertTrue(db.toSelect("select n from dbtest").queryBooleanOrTrue());
- }
-
- @Test
- public void batchInsert() {
- new Schema().addTable("dbtest")
- .addColumn("pk").primaryKey().schema().execute(db);
-
- db.toInsert("insert into dbtest (pk) values (?)")
- .argInteger(1).batch()
- .argInteger(2).batch()
- .argInteger(3).batch().insertBatch();
-
- assertEquals(3, db.toSelect("select count(*) from dbtest").queryIntegerOrZero());
- }
-
- @Test
- public void batchInsertPkLong() {
- new Schema().addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("s").asString(10).schema().execute(db);
-
- db.toInsert("insert into dbtest (pk,s) values (?,?)")
- .argPkLong(1L).argString("hi").batch()
- .argPkLong(2L).argString("hello").batch()
- .argPkLong(3L).argString("howdy").batch().insertBatch();
-
- assertEquals(3, db.toSelect("select count(*) from dbtest").queryIntegerOrZero());
-
- try {
- db.toInsert("insert into dbtest (pk,s) values (?,?)")
- .argPkLong(1L).argString("hi").batch()
- // argPkLong in different position ==> error
- .argString("hello").argPkLong(2L).batch().insertBatch();
- fail("Expecting an exception to be thrown");
- } catch (DatabaseException e) {
- assertEquals("The argPkLong() calls must be in the same position across batch records", e.getMessage());
- }
-
- try {
- db.toInsert("insert into dbtest (pk,s) values (?,?)")
- // multiple pk calls ==> error
- .argPkLong(1L).argPkLong(1L).batch()
- .argPkLong(2L).argString("hello").batch().insertBatch();
- fail("Expecting an exception to be thrown");
- } catch (DatabaseException e) {
- assertEquals("Only call one argPk*() method", e.getMessage());
- }
- }
-
- @Test
- public void batchInsertPkLongNamed() {
- new Schema().addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("s").asString(10).schema().execute(db);
-
- db.toInsert("insert into dbtest (pk,s) values (:pk,?)")
- .argPkLong("pk", 1L).argString("hi").batch()
- .argPkLong("pk", 2L).argString("hello").batch()
- .argPkLong("pk", 3L).argString("howdy").batch().insertBatch();
-
- assertEquals(3, db.toSelect("select count(*) from dbtest").queryIntegerOrZero());
-
- db.toInsert("insert into dbtest (pk,s) values (:pk,?)")
- .batch().argPkLong("pk", 4L).argString("hi").batch()
- .argString("hello").argPkLong("pk", 5L).insertBatch();
-
- assertEquals(5, db.toSelect("select count(*) from dbtest").queryIntegerOrZero());
-
- try {
- db.toInsert("insert into dbtest (pk,s) values (:pk,?)")
- // multiple pk calls ==> error
- .argPkLong("pk", 1L).argPkLong(1L).batch().insertBatch();
- fail("Expecting an exception to be thrown");
- } catch (DatabaseException e) {
- assertEquals("Only call one argPk*() method", e.getMessage());
- }
-
- try {
- db.toInsert("insert into dbtest (pk,s) values (?,?)")
- .argPkLong("pk", 1L).argString("howdy").batch()
- // different name for pk on second batch ==> error
- .argPkLong("na", 2L).argString("hello").batch().insertBatch();
- fail("Expecting an exception to be thrown");
- } catch (DatabaseException e) {
- assertEquals("The primary key argument name must match across batch rows", e.getMessage());
- }
- }
-
- @Test
- public void batchInsertPkSeq() {
- db.dropSequenceQuietly("seq");
- new Schema().addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("s").asString(10).schema()
- .addSequence("seq").schema().execute(db);
-
- db.toInsert("insert into dbtest (pk,s) values (?,?)")
- .argPkSeq("seq").argString("hi").batch()
- .argPkSeq("seq").argString("hello").batch()
- .argPkSeq("seq").argString("howdy").batch().insertBatch();
-
- assertEquals(3, db.toSelect("select count(*) from dbtest").queryIntegerOrZero());
-
- try {
- db.toInsert("insert into dbtest (pk,s) values (?,?)")
- .argPkSeq("seq").argString("hi").batch()
- // argPkLong in different position ==> error
- .argString("hello").argPkSeq("seq").batch().insertBatch();
- fail("Expecting an exception to be thrown");
- } catch (DatabaseException e) {
- assertEquals("The argPkSeq() calls must be in the same position across batch records", e.getMessage());
- }
-
- try {
- db.toInsert("insert into dbtest (pk,s) values (?,?)")
- // multiple pk calls ==> error
- .argPkSeq("seq").argPkSeq("seq").batch().insertBatch();
- fail("Expecting an exception to be thrown");
- } catch (DatabaseException e) {
- assertEquals("Only call one argPk*() method", e.getMessage());
- }
- }
-
- @Test
- public void batchInsertPkSeqNamed() {
- db.dropSequenceQuietly("seq");
- new Schema().addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("s").asString(10).schema()
- .addSequence("seq").schema().execute(db);
-
- db.toInsert("insert into dbtest (pk,s) values (:pk,?)")
- .argPkSeq("pk", "seq").argString("hi").batch()
- .argPkSeq("pk", "seq").argString("hello").batch()
- .argPkSeq("pk", "seq").argString("howdy").batch().insertBatch();
-
- assertEquals(3, db.toSelect("select count(*) from dbtest").queryIntegerOrZero());
-
- db.toInsert("insert into dbtest (pk,s) values (:pk,?)")
- .batch().argPkSeq("pk", "seq").argString("hi").batch()
- .argString("hello").argPkSeq("pk", "seq").insertBatch();
-
- assertEquals(5, db.toSelect("select count(*) from dbtest").queryIntegerOrZero());
-
- try {
- db.toInsert("insert into dbtest (pk,s) values (:pk,?)")
- // multiple pk calls ==> error
- .argPkSeq("pk", "seq").argPkSeq("pk", "seq").batch().insertBatch();
- fail("Expecting an exception to be thrown");
- } catch (DatabaseException e) {
- assertEquals("Only call one argPk*() method", e.getMessage());
- }
-
- try {
- db.toInsert("insert into dbtest (pk,s) values (?,?)")
- .argPkSeq("pk", "seq").argString("howdy").batch()
- // different name for pk on second batch ==> error
- .argPkSeq("na", "seq").argString("hello").batch().insertBatch();
- fail("Expecting an exception to be thrown");
- } catch (DatabaseException e) {
- assertEquals("The primary key argument name must match across batch rows", e.getMessage());
- }
- }
-
- @Test
- public void bigClob() {
- new Schema().addTable("dbtest").addColumn("str_lob").asClob().schema().execute(db);
- final String longString = "0123456789".repeat(40000);
- db.toInsert("insert into dbtest values (?)").argClobString(longString).insert(1);
- db.toSelect("select str_lob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(longString, rs.getClobStringOrNull(1));
- assertEquals(longString, rs.getClobStringOrNull("str_lob"));
- assertEquals(longString, readerToString(rs.getClobReaderOrNull(1)));
- return null;
- });
- // Intentional slight variation here to test get()
- db.get().toSelect("select str_lob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(longString, readerToString(rs.getClobReaderOrNull("str_lob")));
- return null;
- });
- db.toDelete("delete from dbtest").update(1);
- db.toInsert("insert into dbtest values (?)").argClobReader(new StringReader(longString)).insert(1);
- db.toSelect("select str_lob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(longString, rs.getClobStringOrNull(1));
- assertEquals(longString, rs.getClobStringOrNull("str_lob"));
- assertEquals(longString, readerToString(rs.getClobReaderOrNull(1)));
- return null;
- });
- db.toSelect("select str_lob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertEquals(longString, readerToString(rs.getClobReaderOrNull("str_lob")));
- return null;
- });
- }
-
- @Test
- public void bigBlob() {
- new Schema().addTable("dbtest").addColumn("bin_blob").asBlob().schema().execute(db);
- final byte[] bigBytes = "0123456789".repeat(40000).getBytes();
- db.toInsert("insert into dbtest values (?)").argBlobBytes(bigBytes).insert(1);
- db.toSelect("select bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertArrayEquals(bigBytes, rs.getBlobBytesOrNull(1));
- assertArrayEquals(bigBytes, rs.getBlobBytesOrNull("bin_blob"));
- assertArrayEquals(bigBytes, inputStreamToString(rs.getBlobInputStreamOrNull(1)));
- return null;
- });
- db.toSelect("select bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertArrayEquals(bigBytes, inputStreamToString(rs.getBlobInputStreamOrNull("bin_blob")));
- return null;
- });
- db.toDelete("delete from dbtest").update(1);
- db.toInsert("insert into dbtest values (?)").argBlobStream(new ByteArrayInputStream(bigBytes)).insert(1);
- db.toSelect("select bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertArrayEquals(bigBytes, rs.getBlobBytesOrNull(1));
- assertArrayEquals(bigBytes, rs.getBlobBytesOrNull("bin_blob"));
- assertArrayEquals(bigBytes, inputStreamToString(rs.getBlobInputStreamOrNull(1)));
- return null;
- });
- db.toSelect("select bin_blob from dbtest").query((RowsHandler) rs -> {
- assertTrue(rs.next());
- assertArrayEquals(bigBytes, inputStreamToString(rs.getBlobInputStreamOrNull("bin_blob")));
- return null;
- });
- }
-
- @Test
- public void argLocalDateTimeZones() {
- LocalDate januaryOne2000 = LocalDate.of(2000, Month.JANUARY, 1);
- // Verify we always get the same LocalDate regardless of time zone and DB across all drivers
- new Schema().addTable("dbtest").addColumn("i").asLocalDate().schema().execute(db);
- db.toInsert("insert into dbtest (i) values (?)").argLocalDate(januaryOne2000).insert(1);
- // Query without specifying a zone
- assertEquals(januaryOne2000,
- db.toSelect("select i from dbtest where i=?").argLocalDate(januaryOne2000).queryLocalDateOrNull());
- TimeZone defaultTZ = TimeZone.getDefault();
- try {
- String[] availableTZs = TimeZone.getAvailableIDs();
- for (String tz : availableTZs) {
- TimeZone.setDefault(TimeZone.getTimeZone(tz));
- LocalDate result =
- db.toSelect("select i from dbtest where i=?").argLocalDate(januaryOne2000).queryLocalDateOrNull();
- assertEquals(januaryOne2000, result);
- }
- } finally {
- TimeZone.setDefault(defaultTZ);
- }
- }
-
- @Test
- public void argLocalDateLeapYear() {
- new Schema().addTable("dbtest").addColumn("testdate").asLocalDate().schema().execute(db);
-
- // Start by adding Febriary 28 and March 1 of 1900. This was not a leap year.
- LocalDate feb1900 = LocalDate.of(1900, Month.FEBRUARY, 28);
- db.toInsert("insert into dbtest (testdate) values (?)").argLocalDate(feb1900).insert(1);
- assertEquals(feb1900,
- db.toSelect("select testdate from dbtest where testdate=?").argLocalDate(feb1900).queryLocalDateOrNull());
-
- LocalDate mar1900 = LocalDate.of(1900, Month.MARCH, 1);
- db.toInsert("insert into dbtest (testdate) values (?)").argLocalDate(mar1900).insert(1);
- assertEquals(mar1900,
- db.toSelect("select testdate from dbtest where testdate=?").argLocalDate(mar1900).queryLocalDateOrNull());
-
- // Now try Feb 28, 29, and March 1 of 2000. This was a leap year
- LocalDate feb2000 = LocalDate.of(2000, Month.FEBRUARY, 28);
- db.toInsert("insert into dbtest (testdate) values (?)").argLocalDate(feb2000).insert(1);
- assertEquals(feb2000,
- db.toSelect("select testdate from dbtest where testdate=?").argLocalDate(feb2000).queryLocalDateOrNull());
-
- LocalDate febLeap2000 = LocalDate.of(2000, Month.FEBRUARY, 29);
- db.toInsert("insert into dbtest (testdate) values (?)").argLocalDate(febLeap2000).insert(1);
- assertEquals(febLeap2000,
- db.toSelect("select testdate from dbtest where testdate=?").argLocalDate(febLeap2000).queryLocalDateOrNull());
-
- LocalDate mar2000 = LocalDate.of(2000, Month.MARCH, 1);
- db.toInsert("insert into dbtest (testdate) values (?)").argLocalDate(mar2000).insert(1);
- assertEquals(mar2000,
- db.toSelect("select testdate from dbtest where testdate=?").argLocalDate(mar2000).queryLocalDateOrNull());
- }
-
- @Test
- public void argIntegerMinMax() {
- new Schema().addTable("dbtest").addColumn("i").asInteger().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argInteger(Integer.MIN_VALUE).insert(1);
- assertEquals(Integer.valueOf(Integer.MIN_VALUE),
- db.toSelect("select i from dbtest where i=?").argInteger(Integer.MIN_VALUE).queryIntegerOrNull());
-
- db.toInsert("insert into dbtest (i) values (?)").argInteger(Integer.MAX_VALUE).insert(1);
- assertEquals(Integer.valueOf(Integer.MAX_VALUE),
- db.toSelect("select i from dbtest where i=?").argInteger(Integer.MAX_VALUE).queryIntegerOrNull());
- }
-
- @Test
- public void argLongMinMax() {
- new Schema().addTable("dbtest").addColumn("i").asLong().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argLong(Long.MIN_VALUE).insert(1);
- assertEquals(Long.valueOf(Long.MIN_VALUE),
- db.toSelect("select i from dbtest where i=?").argLong(Long.MIN_VALUE).queryLongOrNull());
-
- db.toInsert("insert into dbtest (i) values (?)").argLong(Long.MAX_VALUE).insert(1);
- assertEquals(Long.valueOf(Long.MAX_VALUE),
- db.toSelect("select i from dbtest where i=?").argLong(Long.MAX_VALUE).queryLongOrNull());
- }
-
- @Test
- public void argFloatMinMax() {
- new Schema().addTable("dbtest").addColumn("i").asFloat().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argFloat(Float.MIN_VALUE).insert(1);
- assertEquals(Float.valueOf(Float.MIN_VALUE),
- db.toSelect("select i from dbtest where i=?").argFloat(Float.MIN_VALUE).queryFloatOrNull());
-
- db.toInsert("insert into dbtest (i) values (?)").argFloat(Float.MAX_VALUE).insert(1);
- assertEquals(Float.valueOf(Float.MAX_VALUE),
- db.toSelect("select i from dbtest where i=?").argFloat(Float.MAX_VALUE).queryFloatOrNull());
- }
-
- @Test
- public void argFloatNaN() {
- new Schema().addTable("dbtest").addColumn("i").asFloat().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argFloat(Float.NaN).insert(1);
- assertEquals(Float.valueOf(Float.NaN),
- db.toSelect("select i from dbtest where i=?").argFloat(Float.NaN).queryFloatOrNull());
- }
-
- @Test
- public void argFloatInfinity() {
- new Schema().addTable("dbtest").addColumn("i").asFloat().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argFloat(Float.NEGATIVE_INFINITY).insert(1);
- assertEquals(Float.valueOf(Float.NEGATIVE_INFINITY),
- db.toSelect("select i from dbtest where i=?").argFloat(Float.NEGATIVE_INFINITY).queryFloatOrNull());
-
- db.toInsert("insert into dbtest (i) values (?)").argFloat(Float.POSITIVE_INFINITY).insert(1);
- assertEquals(Float.valueOf(Float.POSITIVE_INFINITY),
- db.toSelect("select i from dbtest where i=?").argFloat(Float.POSITIVE_INFINITY).queryFloatOrNull());
- }
-
- @Test
- public void argFloatZero() {
- new Schema().addTable("dbtest").addColumn("i").asFloat().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argFloat(0f).insert(1);
- assertEquals(Float.valueOf(0f),
- db.toSelect("select i from dbtest where i=?").argFloat(0f).queryFloatOrNull());
- }
-
- @Test
- public void argFloatNegativeZero() {
- new Schema().addTable("dbtest").addColumn("i").asFloat().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argFloat(-0f).insert(1);
- assertEquals(Float.valueOf(-0f),
- db.toSelect("select i from dbtest where i=?").argFloat(-0f).queryFloatOrNull());
- }
-
- @Test
- public void argDoubleMinMax() {
- new Schema().addTable("dbtest").addColumn("i").asDouble().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argDouble(Double.MIN_VALUE).insert(1);
- assertEquals(Double.valueOf(Double.MIN_VALUE),
- db.toSelect("select i from dbtest where i=?").argDouble(Double.MIN_VALUE).queryDoubleOrNull());
-
- db.toInsert("insert into dbtest (i) values (?)").argDouble(Double.MAX_VALUE).insert(1);
- assertEquals(Double.valueOf(Double.MAX_VALUE),
- db.toSelect("select i from dbtest where i=?").argDouble(Double.MAX_VALUE).queryDoubleOrNull());
- }
-
- @Test
- public void argDoubleNaN() {
- new Schema().addTable("dbtest").addColumn("i").asDouble().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argDouble(Double.NaN).insert(1);
- assertEquals(Double.valueOf(Double.NaN),
- db.toSelect("select i from dbtest where i=?").argDouble(Double.NaN).queryDoubleOrNull());
- }
-
- @Test
- public void argDoubleInfinity() {
- new Schema().addTable("dbtest").addColumn("i").asDouble().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argDouble(Double.NEGATIVE_INFINITY).insert(1);
- assertEquals(Double.valueOf(Double.NEGATIVE_INFINITY),
- db.toSelect("select i from dbtest where i=?").argDouble(Double.NEGATIVE_INFINITY).queryDoubleOrNull());
-
- db.toInsert("insert into dbtest (i) values (?)").argDouble(Double.POSITIVE_INFINITY).insert(1);
- assertEquals(Double.valueOf(Double.POSITIVE_INFINITY),
- db.toSelect("select i from dbtest where i=?").argDouble(Double.POSITIVE_INFINITY).queryDoubleOrNull());
- }
-
- @Test
- public void argDoubleZero() {
- new Schema().addTable("dbtest").addColumn("i").asDouble().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argDouble(0d).insert(1);
- assertEquals(Double.valueOf(0d),
- db.toSelect("select i from dbtest where i=?").argDouble(0d).queryDoubleOrNull());
- }
-
- @Test
- public void argDoubleNegativeZero() {
- new Schema().addTable("dbtest").addColumn("i").asDouble().schema().execute(db);
-
- db.toInsert("insert into dbtest (i) values (?)").argDouble(-0d).insert(1);
- assertEquals(Double.valueOf(-0d),
- db.toSelect("select i from dbtest where i=?").argDouble(-0d).queryDoubleOrNull());
- }
-
- @Test
- public void argBigDecimal38Precision0() {
- new Schema().addTable("dbtest").addColumn("i").asBigDecimal(38, 0).schema().execute(db);
-
- BigDecimal value = new BigDecimal("99999999999999999999999999999999999999"); // 38 digits
- db.toInsert("insert into dbtest (i) values (?)").argBigDecimal(value).insert(1);
- assertEquals(value,
- db.toSelect("select i from dbtest where i=?").argBigDecimal(value).queryBigDecimalOrNull());
- }
-
- @Test
- public void argBigDecimal38Precision1() {
- new Schema().addTable("dbtest").addColumn("i").asBigDecimal(38, 1).schema().execute(db);
-
- BigDecimal value = new BigDecimal("9999999999999999999999999999999999999.9"); // 38 digits
- db.toInsert("insert into dbtest (i) values (?)").argBigDecimal(value).insert(1);
- assertEquals(value,
- db.toSelect("select i from dbtest where i=?").argBigDecimal(value).queryBigDecimalOrNull());
- }
-
- @Test
- public void argBigDecimal38Precision37() {
- new Schema().addTable("dbtest").addColumn("i").asBigDecimal(38, 37).schema().execute(db);
-
- BigDecimal value = new BigDecimal("9.9999999999999999999999999999999999999"); // 38 digits
- db.toInsert("insert into dbtest (i) values (?)").argBigDecimal(value).insert(1);
- assertEquals(value,
- db.toSelect("select i from dbtest where i=?").argBigDecimal(value).queryBigDecimalOrNull());
- }
-
- @Test
- public void argBigDecimal38Precision38() {
- new Schema().addTable("dbtest").addColumn("i").asBigDecimal(38, 38).schema().execute(db);
- BigDecimal value = new BigDecimal("0.99999999999999999999999999999999999999"); // 38 digits
- db.toInsert("insert into dbtest (i) values (?)").argBigDecimal(value).insert(1);
- logger.info(db.toSelect("select i from dbtest").queryBigDecimalOrNull().toString());
- assertEquals(value,
- db.toSelect("select i from dbtest where i=?").argBigDecimal(value).queryBigDecimalOrNull());
- }
-
- @Test
- public void dropTableQuietly() {
- db.dropTableQuietly("dbtest");
- new Schema().addTable("dbtest").addColumn("pk").primaryKey().schema().execute(db);
- db.dropTableQuietly("dbtest");
- // Verify the quietly part really kicks in, since the table might have existed above
- db.dropTableQuietly("dbtest");
- new Schema().addTable("dbtest").addColumn("pk").primaryKey().schema().execute(db);
- }
-
- @Test
- public void dropSequenceQuietly() {
- db.dropSequenceQuietly("dbtest_seq");
- // Verify the quietly part really kicks in, since the sequence might have existed above
- db.dropSequenceQuietly("dbtest_seq");
- }
-
- @Test
- public void insertReturningPkSeq() {
- db.dropSequenceQuietly("dbtest_seq");
-
- db.ddl("create table dbtest (pk numeric)").execute();
- db.ddl("create sequence dbtest_seq start with 1").execute();
-
- assertEquals(Long.valueOf(1L), db.toInsert("insert into dbtest (pk) values (:seq)")
- .argPkSeq(":seq", "dbtest_seq").insertReturningPkSeq("pk"));
- assertEquals(Long.valueOf(2L), db.toInsert("insert into dbtest (pk) values (:seq)")
- .argPkSeq(":seq", "dbtest_seq").insertReturningPkSeq("pk"));
- }
-
- @Test
- public void insertReturningAppDate() {
- db.dropSequenceQuietly("dbtest_seq");
- new Schema()
- .addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("d")
- .asLocalDateTime()
- .table()
- .schema()
- .addSequence("dbtest_seq").schema()
- .execute(db);
- db.toInsert("insert into dbtest (pk, d) values (:seq, :d)")
- .argPkSeq(":seq", "dbtest_seq")
- .argLocalDateTime(":d", now)
- .insertReturning("dbtest", "pk", rs -> {
- assertTrue(rs.next());
- assertEquals(Long.valueOf(1L), rs.getLongOrNull(1));
- assertThat(rs.getLocalDateTimeOrNull(2, ZoneId.systemDefault()), equalTo(now));
- assertFalse(rs.next());
- return null;
- }, "d");
- assertEquals(Long.valueOf(1L), db.toSelect("select count(*) from dbtest where d=?").argLocalDateTime(now).queryLongOrNull());
- }
-
- @Test
- public void quickQueries() {
- new Schema()
- .addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("d").asLocalDateTime().table()
- .addColumn("d2").asLocalDateTime().table()
- .addColumn("d3").asLocalDate().table()
- .addColumn("d4").asLocalDate().table()
- .addColumn("s").asString(5).table()
- .addColumn("s2").asString(5).table()
- .addColumn("i").asInteger().table().schema()
- .execute(db);
- db.toInsert("insert into dbtest (pk, d, d3, s) values (?,?,?,?)")
- .argLong(1L)
- .argLocalDateTime(now)
- .argLocalDate(localDateNow)
- .argString("foo")
- .insert(1);
- assertEquals(Long.valueOf(1L), db.toSelect("select pk from dbtest").queryLongOrNull());
- assertNull(db.toSelect("select pk from dbtest where 1=0").queryLongOrNull());
- assertNull(db.toSelect("select i from dbtest").queryLongOrNull());
- assertEquals(1L, db.toSelect("select pk from dbtest").queryLongOrZero());
- assertEquals(0L, db.toSelect("select pk from dbtest where 1=0").queryLongOrZero());
- assertEquals(0L, db.toSelect("select i from dbtest").queryLongOrZero());
- assertEquals(1L, (long) db.toSelect("select pk from dbtest").queryLongs().get(0));
- assertTrue(db.toSelect("select pk from dbtest where 1=0").queryLongs().isEmpty());
- assertTrue(db.toSelect("select i from dbtest").queryLongs().isEmpty());
- assertEquals(Integer.valueOf(1), db.toSelect("select pk from dbtest").queryIntegerOrNull());
- assertNull(db.toSelect("select pk from dbtest where 1=0").queryIntegerOrNull());
- assertNull(db.toSelect("select i from dbtest").queryIntegerOrNull());
- assertEquals(1, db.toSelect("select pk from dbtest").queryIntegerOrZero());
- assertEquals(0, db.toSelect("select pk from dbtest where 1=0").queryIntegerOrZero());
- assertEquals(0, db.toSelect("select i from dbtest").queryIntegerOrZero());
- assertEquals(1L, (int) db.toSelect("select pk from dbtest").queryIntegers().get(0));
- assertTrue(db.toSelect("select pk from dbtest where 1=0").queryIntegers().isEmpty());
- assertTrue(db.toSelect("select i from dbtest").queryIntegers().isEmpty());
- assertEquals("foo", db.toSelect("select s from dbtest").queryStringOrNull());
- assertNull(db.toSelect("select s from dbtest where 1=0").queryStringOrNull());
- assertNull(db.toSelect("select s2 from dbtest").queryStringOrNull());
- assertEquals("foo", db.toSelect("select s from dbtest").queryStringOrEmpty());
- assertEquals("", db.toSelect("select s from dbtest where 1=0").queryStringOrEmpty());
- assertEquals("", db.toSelect("select s2 from dbtest").queryStringOrEmpty());
- assertEquals("foo", db.toSelect("select s from dbtest").queryStrings().get(0));
- assertTrue(db.toSelect("select s from dbtest where 1=0").queryStrings().isEmpty());
- assertTrue(db.toSelect("select s2 from dbtest").queryStrings().isEmpty());
- assertEquals(now, db.toSelect("select d from dbtest").queryLocalDateTimeOrNull());
- assertNull(db.toSelect("select d from dbtest where 1=0").queryLocalDateTimeOrNull());
- assertNull(db.toSelect("select d2 from dbtest").queryLocalDateTimeOrNull());
- assertEquals(db.toSelect("select d from dbtest").queryLocalDateTimes().get(0), now);
- assertTrue(db.toSelect("select d from dbtest where 1=0").queryLocalDateTimes().isEmpty());
- assertTrue(db.toSelect("select d2 from dbtest").queryLocalDateTimes().isEmpty());
-
- assertEquals(localDateNow, db.toSelect("select d3 from dbtest").queryLocalDateOrNull());
- assertNull(db.toSelect("select d3 from dbtest where 1=0").queryLocalDateOrNull());
- assertEquals(db.toSelect("select d3 from dbtest").queryLocalDates().get(0), localDateNow);
- assertEquals(Long.valueOf(1L),
- db.toSelect("select count(*) from dbtest where d3=?").argLocalDate(localDateNow).queryLongOrNull());
-
- assertNull(db.toSelect("select d4 from dbtest").queryLocalDateOrNull());
- assertNull(db.toSelect("select d4 from dbtest where 1=0").queryLocalDateOrNull());
- assertTrue(db.toSelect("select d4 from dbtest").queryLocalDates().isEmpty());
- }
-
- @Test
- public void rowHandlerQueries() {
- new Schema()
- .addTable("dbtest")
- .addColumn("pk").primaryKey().schema()
- .execute(db);
-
- db.toInsert("insert into dbtest (pk) values (?)").argLong(1L).insert(1);
- db.toInsert("insert into dbtest (pk) values (?)").argLong(2L).insert(1);
-
- RowHandler rowHandler = Row::getLongOrNull;
-
- List many = db.toSelect("select pk from dbtest").queryMany(rowHandler);
- assertEquals(2, many.size());
-
- assertEquals(Long.valueOf(1), db.toSelect("select pk from dbtest where pk=1").queryOneOrNull(rowHandler));
- assertNull(db.toSelect("select pk from dbtest where pk=9").queryOneOrNull(rowHandler));
- try {
- db.toSelect("select pk from dbtest").queryOneOrNull(rowHandler);
- fail("Should have thrown an exception");
- } catch (ConstraintViolationException e) {
- assertEquals("Expected exactly one row to be returned but found multiple", e.getCause().getMessage());
- }
- try {
- db.toSelect("select pk from dbtest where pk=9").queryOneOrThrow(rowHandler);
- fail("Should have thrown an exception");
- } catch (ConstraintViolationException e) {
- assertEquals("Expected exactly one row to be returned but found none", e.getMessage());
- }
-
- assertEquals(Long.valueOf(1), db.toSelect("select pk from dbtest where pk=1").queryFirstOrNull(rowHandler));
- assertEquals(Long.valueOf(1), db.toSelect("select pk from dbtest order by 1").queryFirstOrNull(rowHandler));
- assertNull(db.toSelect("select pk from dbtest where pk=9").queryFirstOrNull(rowHandler));
- try {
- db.toSelect("select pk from dbtest where pk=9").queryFirstOrThrow(rowHandler);
- fail("Should have thrown an exception");
- } catch (ConstraintViolationException e) {
- assertEquals("Expected one or more rows to be returned but found none", e.getMessage());
- }
- }
-
- @Test
- public void nextSequenceValue() {
- db.dropSequenceQuietly("dbtest_seq");
- new Schema()
- .addSequence("dbtest_seq").schema()
- .execute(db);
-
- assertEquals(Long.valueOf(1L), db.nextSequenceValue("dbtest_seq"));
- }
-
- @Test
- public void insertReturningDbDate() {
- db.dropSequenceQuietly("dbtest_seq");
- new Schema()
- .addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("d").asLocalDateTime().table().schema()
- .addSequence("dbtest_seq").schema()
- .execute(db);
- LocalDateTime dbNow = db.toInsert("insert into dbtest (pk, d) values (:seq, :d)")
- .argPkSeq(":seq", "dbtest_seq")
- .argLocalDateTimeNowPerDb(":d")
- .insertReturning("dbtest", "pk", rs -> {
- assertTrue(rs.next());
- assertEquals(Long.valueOf(1L), rs.getLongOrNull(1));
- LocalDateTime dbDate = rs.getLocalDateTimeOrNull(2);
- assertFalse(rs.next());
- return dbDate;
- }, "d");
- assertEquals(Long.valueOf(1L),
- db.toSelect("select count(*) from dbtest where d = ?").argLocalDateTime(dbNow).queryLongOrNull());
- }
-
- @Test
- public void daylightSavings() {
- LocalDate lastStdDateSpring = LocalDate.of(2019, Month.MARCH, 9);
- LocalDate firstDSTDateSpring = LocalDate.of(2019, Month.MARCH, 10);
- // Verify that the original LocalDate matches the driver SQL LocalDate generated.
- StatementAdapter adaptor = new StatementAdapter(new OptionsDefault(db.flavor()));
- assertEquals(lastStdDateSpring.toString(), adaptor.nullLocalDate(lastStdDateSpring).toString());
- assertEquals(firstDSTDateSpring.toString(), adaptor.nullLocalDate(firstDSTDateSpring).toString());
- }
-
- @Test
- public void insertLocalDate() {
- // Date without time
- new Schema()
- .addTable("dbtest")
- .addColumn("d").asLocalDate().table().schema()
- .execute(db);
- LocalDate dateOfBirth = LocalDate.of(1951, Month.AUGUST, 9);
- db.toInsert("insert into dbtest (d) values (?)")
- .argLocalDate(dateOfBirth)
- .insert(1);
- LocalDate testDate = db.toSelect("select d from dbtest").queryLocalDateOrNull();
- assertEquals(dateOfBirth, testDate);
- }
-
- @Test
- public void localDateRoundTrip() {
- new Schema()
- .addTable("dbtest")
- .addColumn("d1").asLocalDate().table()
- .addColumn("d2").asLocalDate().table().schema()
- .execute(db);
- // Store current time as per the database
- db.toInsert("insert into dbtest (d1) values (?)")
- .argLocalDate(localDateNow)
- .insert(1);
- // Now pull it out, put it back in, and verify it matches in the database
- LocalDate queryRsDate = db.toSelect("select d1 from dbtest").queryLocalDateOrNull();
- db.toUpdate("update dbtest set d2=?")
- .argLocalDate(queryRsDate)
- .update(1);
- assertEquals(Long.valueOf(1L), db.toSelect("select count(*) from dbtest where d1=d2").queryLongOrNull());
- }
-
- /**
- * Make sure database times are inserted with at least millisecond precision.
- * This test is non-deterministic since it is checking the timestamp provided
- * by the database, so we use a retry to give it up to ten attempts.
- */
- @Test
- public void dateMillis() {
- for (int attempts = 1; attempts <= 10; attempts++) {
- new Schema()
- .addTable("dbtest")
- .addColumn("d").asLocalDateTime().table().schema()
- .execute(db);
- db.toInsert("insert into dbtest (d) values (?)")
- .argLocalDateTimeNowPerDb()
- .insert(1);
- LocalDateTime dbNow = db.toSelect("select d from dbtest").queryLocalDateTimeOrNull();
- if (dbNow != null && dbNow.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() % 10 != 0) {
- return;
- }
- logger.info("Zero in least significant digit (attempt " + attempts + ")");
- db.dropTableQuietly(TEST_TABLE_NAME);
- }
- fail("Timestamp had zero in the least significant digit");
- }
-
- @Test
- public void dateRoundTrip() {
- new Schema()
- .addTable("dbtest")
- .addColumn("d1").asLocalDateTime().table()
- .addColumn("d2").asLocalDateTime().table()
- .schema()
- .execute(db);
- db.toInsert("insert into dbtest (d1) values (?)")
- .argLocalDateTimeNowPerDb()
- .insert(1);
- LocalDateTime dbNow = db.toSelect("select d1 from dbtest").queryLocalDateTimeOrNull();
- db.toUpdate("update dbtest set d2 = ?")
- .argLocalDateTime(dbNow)
- .update(1);
- assertEquals(Long.valueOf(1L), db.toSelect("select count(*) from dbtest where d1=d2").queryLongOrNull());
- }
-
- @Test
- public void dateRoundTripTimezones() {
- new Schema()
- .addTable("dbtest")
- .addColumn("d")
- .asLocalDateTime()
- .table()
- .schema()
- .execute(db);
- Instant instant = Instant.ofEpochMilli(166656789L);
- ZoneId dateMinusZone = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(-4));
- LocalDateTime dateMinus = LocalDateTime.ofInstant(instant, dateMinusZone);
- ZoneId datePlusZone = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(+4));
- LocalDateTime datePlus = LocalDateTime.ofInstant(instant,datePlusZone);
- logger.log(Level.INFO, "dateMinus = " + dateMinus);
- db.toInsert("insert into dbtest (d) values (?)")
- .argLocalDateTime(dateMinus)
- .insert(1);
- LocalDateTime localDateTimeMinus = db.toSelect("select d from dbtest")
- .queryLocalDateTimeOrNull();
- assertEquals(dateMinus, localDateTimeMinus);
- assertEquals("1970-01-02 18:17:36.789",
- DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(localDateTimeMinus));
- db.toDelete("delete from dbtest where d = ?").argLocalDateTime(dateMinus).update(1);
- db.toInsert("insert into dbtest (d) values (?)")
- .argLocalDateTime(datePlus)
- .insert(1);
- LocalDateTime localDateTimePlus = db.toSelect("select d from dbtest")
- .queryLocalDateTimeOrNull(datePlusZone);
- assertEquals(datePlus, localDateTimePlus);
- assertEquals("1970-01-03 02:17:36.789",
- DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(localDateTimePlus));
- db.toDelete("delete from dbtest where d = ?").argLocalDateTime(datePlus).update(1);
- }
-
- /**
- * Verify the appropriate database flavor can correctly convert a {@code LocalDateTime}
- * into a SQL function representing a conversion from string to timestamp. This
- * function is used to write debug SQL to the log in a way that could be manually
- * executed if desired.
- */
- @Test
- public void stringLocalDateTimeFunctions() {
- Instant instant = Instant.ofEpochMilli(166656789L);
- ZoneId dateMinusZone = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(-4));
- LocalDateTime dateMinus = LocalDateTime.ofInstant(instant, dateMinusZone);
- ZoneId datePlusZone = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(+4));
- LocalDateTime datePlus = LocalDateTime.ofInstant(instant, datePlusZone);
- logger.info("LocalDateTime: dateMinus=" + dateMinus + " datePlus=" + datePlus);
- new Schema().addTable("dbtest").addColumn("d")
- .asLocalDateTime()
- .schema()
- .execute(db);
- db.toInsert("insert into dbtest (d) values (?)")
- .argLocalDateTime(dateMinus)
- .insert(1);
- LocalDateTime localDateTime = db.toSelect("select d from dbtest")
- .queryLocalDateTimeOrNull();
- assertEquals("1970-01-02 18:17:36.789",
- DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(localDateTime.atZone(dateMinusZone)));
- db.toDelete("delete from dbtest where d = ?")
- .argLocalDateTime(dateMinus)
- .update(1);
- db.toInsert("insert into dbtest (d) values (?)")
- .argLocalDateTime(datePlus)
- .insert(1);
- localDateTime = db.toSelect("select d from dbtest")
- .queryLocalDateTimeOrNull(datePlusZone);
- assertEquals("1970-01-03 02:17:36.789",
- DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(localDateTime.atZone(datePlusZone)));
- db.toDelete("delete from dbtest where d = ?")
- .argLocalDateTime(datePlus)
- .update(1);
- }
-
- @Test
- public void mixPositionalAndNamedParameters() {
- new Schema()
- .addTable("dbtest")
- .addColumn("pk").primaryKey().table()
- .addColumn("d").asLocalDateTime().table()
- .addColumn("a").asInteger().table().schema()
- .execute(db);
-
- db.toSelect("select pk as \"time:: now??\" from dbtest where a=? and d=:now")
- .argInteger(1).argLocalDateTimeNowPerDb("now").query(rs -> {
- assertFalse(rs.next());
- return null;
- });
- }
-
- public String readerToString(Reader reader) throws IOException {
- char[] buffer = new char[1024];
- StringBuilder out = new StringBuilder();
- int byteCount;
- while ((byteCount = reader.read(buffer, 0, buffer.length)) >= 0) {
- out.append(buffer, 0, byteCount);
- }
- return out.toString();
- }
-
- public byte[] inputStreamToString(InputStream inputStream) throws IOException {
- byte[] buffer = new byte[1024];
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- int byteCount;
- while ((byteCount = inputStream.read(buffer, 0, buffer.length)) >= 0) {
- out.write(buffer, 0, byteCount);
- }
- return out.toByteArray();
- }
-}
diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/DerbyTest.java b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/DerbyTest.java
index 1ea67e6..5759110 100644
--- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/DerbyTest.java
+++ b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/DerbyTest.java
@@ -6,6 +6,7 @@ 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 org.xbib.jdbc.test.CommonTest;
import java.math.BigDecimal;
import java.util.logging.Logger;
@@ -15,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Exercise Database functionality with a real database (Derby).
*/
-@Disabled
+@Disabled("Derby 10.16.1.1 does not conform to JDBC 4.2 with getObject(... LocalDatetime.class) https://chariotsolutions.com/blog/post/using-java-time-resultset-preparedstatement/")
public class DerbyTest extends CommonTest {
private static final Logger logger = Logger.getLogger(DerbyTest.class.getName());
@@ -26,12 +27,10 @@ public class DerbyTest extends CommonTest {
@Override
protected DatabaseProvider createDatabaseProvider(OptionsOverride options) {
- return DatabaseProvider.builder("jdbc:derby:build/testdb;create=true")
+ return DatabaseProvider.builder(getClass().getClassLoader(), "jdbc:derby:build/testdb;create=true")
.withSqlParameterLogging().withSqlInExceptionMessages().withOptions(options).build();
}
- // TODO fix this test
- @Disabled("Not sure why this fails on the build servers right now...")
@Test
public void clockSync() {
super.clockSync();
@@ -79,7 +78,6 @@ public class DerbyTest extends CommonTest {
super.intervals();
}
-
@Disabled("Derby limits out at precision 31")
@Test
public void argBigDecimal38Precision0() {
diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/HsqldbTest.java b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/HsqldbTest.java
index 1381be4..73b565e 100644
--- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/HsqldbTest.java
+++ b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/HsqldbTest.java
@@ -10,6 +10,7 @@ import org.xbib.jdbc.query.OptionsOverride;
import org.xbib.jdbc.query.Schema;
import org.xbib.jdbc.query.Sql;
import org.xbib.jdbc.query.SqlArgs;
+import org.xbib.jdbc.test.CommonTest;
import java.math.BigDecimal;
import java.util.ArrayList;
@@ -38,25 +39,6 @@ public class HsqldbTest extends CommonTest {
.build();
}
- @Test
- public void noDatabaseAccess() throws Exception {
- DatabaseProvider provider = createDatabaseProvider(new OptionsOverride());
- provider.transact(dbp -> {
- // Do nothing, just making sure no exception is thrown
- });
- provider.transact((dbp, tx) -> {
- // Do nothing, just making sure no exception is thrown
- });
- provider.transact((dbp, tx) -> {
- tx.setRollbackOnError(true);
- // Do nothing, just making sure no exception is thrown
- });
- provider.transact((dbp, tx) -> {
- tx.setRollbackOnly(true);
- // Do nothing, just making sure no exception is thrown
- });
- }
-
@Disabled("LocalDate implementations should be TimeZone agnostic, but HSQLDB implementation has a bug.")
@Test
public void argLocalDateTimeZones() {
@@ -85,7 +67,6 @@ public class HsqldbTest extends CommonTest {
.addColumn("boolean_flag").asBoolean().table()
.addColumn("date_millis").asLocalDateTime().table()
.addColumn("local_date").asLocalDate().schema().execute(db);
-
db.toInsert("insert into dbtest (nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar,"
+ " str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date) values (?,?,?,?,?,?,?,?,?,?,?,?)")
.argInteger(Integer.MAX_VALUE)
diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/DerbyExample.java b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/DerbyExample.java
index fb09d69..d3bcdd5 100644
--- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/DerbyExample.java
+++ b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/DerbyExample.java
@@ -2,6 +2,7 @@ package org.xbib.jdbc.query.test.example;
import org.xbib.jdbc.query.Database;
import org.xbib.jdbc.query.DatabaseProvider;
+import org.xbib.jdbc.query.DatabaseProviderBuilder;
/**
* Demo of using some com.github.susom.database classes with Derby.
@@ -12,7 +13,7 @@ public abstract class DerbyExample {
// For subclasses to override
}
- void example(DatabaseProvider.DatabaseProviderBuilder dbb, final String[] args) {
+ void example(DatabaseProviderBuilder dbb, final String[] args) {
dbb.transact(db -> {
example(db.get(), args);
});
@@ -26,7 +27,7 @@ public abstract class DerbyExample {
try {
System.setProperty("derby.stream.error.file", "java.lang.System.err");
String url = "jdbc:derby:target/testdb;create=true";
- example(DatabaseProvider.builder(url), args);
+ example(DatabaseProvider.builder(getClass().getClassLoader(), url), args);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/HelloAny.java b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/HelloAny.java
deleted file mode 100644
index b9144df..0000000
--- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/HelloAny.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.xbib.jdbc.query.test.example;
-
-import org.xbib.jdbc.query.Database;
-import org.xbib.jdbc.query.DatabaseProvider;
-
-/**
- * Example with database info provided from command line. To use this, set properties like this:
- *
- *
- * -Ddatabase.url=... Database connect string (required)
- * -Ddatabase.user=... Authenticate as this user (optional if provided in url)
- * -Ddatabase.password=... User password (optional if user and password provided in
- * url; prompted on standard input if user is provided and
- * password is not)
- * -Ddatabase.flavor=... What kind of database it is (optional, will guess based
- * on the url if this is not provided)
- * -Ddatabase.driver=... The Java class of the JDBC driver to load (optional, will
- * guess based on the flavor if this is not provided)
- *
- */
-public class HelloAny {
- public static void main(final String[] args) {
- try {
- new HelloAny().run();
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
-
- public void run() {
- DatabaseProvider.fromSystemProperties().transact(dbp -> {
- Database db = dbp.get();
- db.dropTableQuietly("t");
- db.ddl("create table t (a numeric)").execute();
- db.toInsert("insert into t (a) values (?)")
- .argInteger(32)
- .insert(1);
- db.toUpdate("update t set a=:val")
- .argInteger("val", 23)
- .update(1);
-
- Long rows = db.toSelect("select count(1) from t ").queryLongOrNull();
- System.out.println("Rows: " + rows);
- });
- }
-}
diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/HelloDerby.java b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/HelloDerby.java
index d7bbf90..e547668 100644
--- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/HelloDerby.java
+++ b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/example/HelloDerby.java
@@ -5,9 +5,6 @@ import org.xbib.jdbc.query.DatabaseProvider;
import java.io.File;
-/**
- * Demo of using some com.github.susom.database classes with Derby.
- */
public class HelloDerby {
public static void main(final String[] args) {
try {
@@ -19,14 +16,12 @@ public class HelloDerby {
}
public void run() {
- // Put all Derby related files inside ./build to keep our working copy clean
- File directory = new File("target").getAbsoluteFile();
+ File directory = new File("build").getAbsoluteFile();
if (directory.exists() || directory.mkdirs()) {
System.setProperty("derby.stream.error.file", new File(directory, "derby.log").getAbsolutePath());
}
-
String url = "jdbc:derby:target/testdb;create=true";
- DatabaseProvider.builder(url).transact(dbp -> {
+ DatabaseProvider.builder(getClass().getClassLoader(), url).transact(dbp -> {
Database db = dbp.get();
db.ddl("drop table t").executeQuietly();
db.ddl("create table t (a numeric)").execute();
diff --git a/jdbc-sqlserver/build.gradle b/jdbc-sqlserver/build.gradle
new file mode 100644
index 0000000..4574a9f
--- /dev/null
+++ b/jdbc-sqlserver/build.gradle
@@ -0,0 +1,10 @@
+dependencies {
+ api project(':jdbc-query')
+ testImplementation project(':jdbc-test')
+ testImplementation libs.testcontainers
+ testImplementation libs.testcontainers.junit.jupiter
+}
+
+test {
+ systemProperty 'user.timezone', 'GMT'
+}
diff --git a/jdbc-sqlserver/src/main/java/module-info.java b/jdbc-sqlserver/src/main/java/module-info.java
new file mode 100644
index 0000000..e3555d2
--- /dev/null
+++ b/jdbc-sqlserver/src/main/java/module-info.java
@@ -0,0 +1,10 @@
+import org.xbib.jdbc.query.Flavor;
+import org.xbib.jdbc.sqlserver.SqlServer;
+
+module org.xbib.jdbc.sqlserver {
+ requires org.xbib.jdbc.query;
+ requires java.sql;
+ uses Flavor;
+ exports org.xbib.jdbc.sqlserver;
+ provides Flavor with SqlServer;
+}
diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/SqlServer.java b/jdbc-sqlserver/src/main/java/org/xbib/jdbc/sqlserver/SqlServer.java
similarity index 88%
rename from jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/SqlServer.java
rename to jdbc-sqlserver/src/main/java/org/xbib/jdbc/sqlserver/SqlServer.java
index ff98110..3d555a8 100644
--- a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/SqlServer.java
+++ b/jdbc-sqlserver/src/main/java/org/xbib/jdbc/sqlserver/SqlServer.java
@@ -1,4 +1,4 @@
-package org.xbib.jdbc.query.flavor;
+package org.xbib.jdbc.sqlserver;
import org.xbib.jdbc.query.Flavor;
@@ -7,6 +7,9 @@ import java.sql.SQLException;
public class SqlServer implements Flavor {
+ public SqlServer() {
+ }
+
@Override
public String getName() {
return "sqlServer";
@@ -23,8 +26,16 @@ public class SqlServer implements Flavor {
}
@Override
- public boolean isNormalizedUpperCase() {
- return false;
+ public String normalizeTableName(String tableName) {
+ if (tableName == null) {
+ return tableName;
+ }
+ if (tableName.length() > 2) {
+ if (tableName.startsWith("\"") && tableName.endsWith("\"")) {
+ return tableName.substring(1, tableName.length() - 1);
+ }
+ }
+ return tableName;
}
@Override
@@ -72,6 +83,11 @@ public class SqlServer implements Flavor {
return "datetime2(3)";
}
+ @Override
+ public String columnTypeLocalDateTime() {
+ return "datetime2";
+ }
+
@Override
public String typeLocalDate() {
return "date";
diff --git a/jdbc-sqlserver/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor b/jdbc-sqlserver/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor
new file mode 100644
index 0000000..a1e1dec
--- /dev/null
+++ b/jdbc-sqlserver/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor
@@ -0,0 +1 @@
+org.xbib.jdbc.sqlserver.SqlServer
\ No newline at end of file
diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/SqlServerTest.java b/jdbc-sqlserver/src/test/java/org/xbib/jdbc/sqlserver/test/SqlServerTest.java
similarity index 97%
rename from jdbc-query/src/test/java/org/xbib/jdbc/query/test/SqlServerTest.java
rename to jdbc-sqlserver/src/test/java/org/xbib/jdbc/sqlserver/test/SqlServerTest.java
index a21c163..a8e28d9 100644
--- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/SqlServerTest.java
+++ b/jdbc-sqlserver/src/test/java/org/xbib/jdbc/sqlserver/test/SqlServerTest.java
@@ -1,4 +1,4 @@
-package org.xbib.jdbc.query.test;
+package org.xbib.jdbc.sqlserver.test;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -7,6 +7,7 @@ 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;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@@ -77,9 +78,7 @@ public class SqlServerTest extends CommonTest {
@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;
diff --git a/jdbc-sqlserver/src/test/resources/logging.properties b/jdbc-sqlserver/src/test/resources/logging.properties
new file mode 100644
index 0000000..5885e4d
--- /dev/null
+++ b/jdbc-sqlserver/src/test/resources/logging.properties
@@ -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
diff --git a/jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java b/jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java
index 4748633..4db005d 100644
--- a/jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java
+++ b/jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java
@@ -36,6 +36,7 @@ import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Locale;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -86,6 +87,13 @@ public abstract class CommonTest {
}
}
+ @Test
+ public void testJdbcVersion() {
+ // we want JDBC >= 4.2
+ assertEquals(4, db.jdbcMajorVersion());
+ assertTrue(db.jdbcMinorVersion() >= 2);
+ }
+
@Test
public void tableExists() {
// Verify dbtest table does not exist
@@ -111,22 +119,13 @@ public abstract class CommonTest {
@Test
public void normalizeTableName() {
- // Verify that null and empty cases are handled gracefully
- assertNull(db.normalizeTableName(null));
- assertEquals("", db.normalizeTableName(""));
-
- // Verify a quoted table name is returned in exactly the same case, with quotes removed.
+ assertNull(db.flavor().normalizeTableName(null));
+ assertEquals("", db.flavor().normalizeTableName(""));
String camelCaseTableName = "\"DbTest\"";
assertEquals(camelCaseTableName.substring(1, camelCaseTableName.length() - 1),
- db.normalizeTableName(camelCaseTableName));
-
- // Verify that the database flavor gets the expected normalized case
- boolean isUpperCase = db.flavor().isNormalizedUpperCase();
- if (isUpperCase) {
- assertEquals(TEST_TABLE_NAME.toUpperCase(), db.normalizeTableName(TEST_TABLE_NAME));
- } else {
- assertEquals(TEST_TABLE_NAME.toLowerCase(), db.normalizeTableName(TEST_TABLE_NAME));
- }
+ db.flavor().normalizeTableName(camelCaseTableName));
+ assertEquals(TEST_TABLE_NAME.toUpperCase(Locale.ENGLISH),
+ db.flavor().normalizeTableName(TEST_TABLE_NAME).toUpperCase(Locale.ENGLISH));
}
@Test
@@ -144,12 +143,10 @@ public abstract class CommonTest {
.addColumn("bin_blob").asBlob().table()
.addColumn("date_millis").asLocalDateTime().table()
.addColumn("local_date").asLocalDate().table().schema().execute(db);
-
BigDecimal bigDecimal = new BigDecimal("5.3");
db.toInsert("insert into dbtest values (?,?,?,?,?,?,?,?,?,?,?)").argInteger(1).argLong(2L).argFloat(3.2f).argDouble(4.2)
.argBigDecimal(bigDecimal).argString("Hello").argString("T").argClobString("World")
.argBlobBytes("More".getBytes()).argLocalDateTime(now).argLocalDate(localDateNow).insert(1);
-
db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, "
+ "bin_blob, date_millis, local_date from dbtest")
.query((RowsHandler) rs -> {
@@ -594,20 +591,15 @@ public abstract class CommonTest {
new Schema()
.addTable("dbtest")
.addColumn(timestampColumnName).asLocalDateTime().table()
- .addColumn(dateColumnName).asLocalDate().table().schema().execute(db);
+ .addColumn(dateColumnName).asLocalDate().table()
+ .schema().execute(db);
db.toSelect("select * from dbtest").query((RowsHandler) rs -> {
ResultSetMetaData metadata = rs.getMetadata();
for (int i = 1; i <= metadata.getColumnCount(); i++) {
String columnName = metadata.getColumnName(i);
String columnType = metadata.getColumnTypeName(i);
if (columnName.equalsIgnoreCase(timestampColumnName)) {
- if ("sqlserver".equals(db.flavor().getName())) {
- assertEquals("DATETIME2", columnType.toUpperCase());
- } else if ("hsqldb".equals(db.flavor().getName())) {
- assertEquals("TIMESTAMP WITH TIME ZONE", columnType.toUpperCase());
- } else {
- assertEquals("TIMESTAMP", columnType.toUpperCase());
- }
+ assertEquals(db.flavor().columnTypeLocalDateTime(), columnType);
} else if (columnName.equalsIgnoreCase(dateColumnName)) {
assertEquals("DATE", columnType.toUpperCase());
} else {
diff --git a/settings.gradle b/settings.gradle
index 112d795..613d067 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -31,3 +31,4 @@ include 'jdbc-test'
include 'jdbc-mariadb'
include 'jdbc-oracle'
include 'jdbc-postgresql'
+include 'jdbc-sqlserver'