diff --git a/pom.xml b/pom.xml
index 204189c8..a359aad6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,9 +64,11 @@
11
11
- 2.5.0
4.0.5
+ 2.7.1
+ debug
+
2.0.9
5.10.0
@@ -98,6 +100,7 @@
org.hsqldb
hsqldb
${dep.hsqldb.version}
+ ${dep.hsqldb.classifier}
com.healthmarketscience.jackcess
diff --git a/src/main/java/net/ucanaccess/jdbc/UcanaccessDriver.java b/src/main/java/net/ucanaccess/jdbc/UcanaccessDriver.java
index 412baab0..f6d3fcd5 100644
--- a/src/main/java/net/ucanaccess/jdbc/UcanaccessDriver.java
+++ b/src/main/java/net/ucanaccess/jdbc/UcanaccessDriver.java
@@ -24,11 +24,15 @@ public final class UcanaccessDriver implements Driver {
DriverManager.registerDriver(new UcanaccessDriver());
Class.forName("org.hsqldb.jdbc.JDBCDriver");
- } catch (ClassNotFoundException e) {
+ // Set property with semicolon-separated list (including wildcards) of Java classes
+ // that can be used for routines based on Java static methods
+ System.setProperty("hsqldb.method_class_names", "net.ucanaccess.converters.*");
+
+ } catch (ClassNotFoundException _ex) {
Logger.logWarning(LoggerMessageEnum.HSQLDB_DRIVER_NOT_FOUND);
- throw new RuntimeException(e.getMessage());
- } catch (SQLException e) {
- throw new RuntimeException(e.getMessage());
+ throw new RuntimeException(_ex.getMessage());
+ } catch (SQLException _ex) {
+ throw new RuntimeException(_ex.getMessage());
}
}
@@ -173,7 +177,11 @@ public Connection connect(String _url, Properties _props) throws SQLException {
SQLWarning sqlw = null;
if (!alreadyLoaded) {
boolean toBeLoaded = !dbRef.loadedFromKeptMirror(session);
- LoadJet la = new LoadJet(dbRef.getHSQLDBConnection(session), dbRef.getDbIO());
+ Connection conn = dbRef.getHSQLDBConnection(session);
+ // from version 2.7 hsqldb translates timestamps stored without timezone in the database
+ // into the default timezone. MS Access however does not know timezones, therefore assume timestamps are UTC
+ conn.createStatement().executeQuery("SET TIME ZONE 'UTC'");
+ LoadJet la = new LoadJet(conn, dbRef.getDbIO());
Logger.turnOffJackcessLog();
if (_props.containsKey("sysschema")) {
boolean sysSchema = Boolean.parseBoolean(_props.getProperty("sysschema"));
diff --git a/src/test/java/net/ucanaccess/converters/AddFunctions.java b/src/test/java/net/ucanaccess/converters/AddFunctions.java
new file mode 100644
index 00000000..f590013a
--- /dev/null
+++ b/src/test/java/net/ucanaccess/converters/AddFunctions.java
@@ -0,0 +1,23 @@
+package net.ucanaccess.converters;
+
+import net.ucanaccess.converters.TypesMap.AccessType;
+import net.ucanaccess.ext.FunctionType;
+
+import java.sql.Timestamp;
+
+public final class AddFunctions {
+
+ private AddFunctions() {
+ }
+
+ @FunctionType(functionName = "pluto", argumentTypes = {AccessType.TEXT, AccessType.TEXT, AccessType.DATETIME}, returnType = AccessType.TEXT)
+ public static String example(String s1, String s2, Timestamp dt) {
+ return s1 + s2 + dt;
+ }
+
+ @FunctionType(functionName = "concat", argumentTypes = {AccessType.TEXT, AccessType.TEXT}, returnType = AccessType.TEXT)
+ public static String concat(String s1, String s2) {
+ return s1 + s2;
+ }
+
+}
diff --git a/src/test/java/net/ucanaccess/test/integration/AddFunctionTest.java b/src/test/java/net/ucanaccess/test/integration/AddFunctionTest.java
index b59cea33..8c5f8819 100644
--- a/src/test/java/net/ucanaccess/test/integration/AddFunctionTest.java
+++ b/src/test/java/net/ucanaccess/test/integration/AddFunctionTest.java
@@ -1,7 +1,7 @@
package net.ucanaccess.test.integration;
+import net.ucanaccess.converters.AddFunctions;
import net.ucanaccess.test.util.AccessVersion;
-import net.ucanaccess.test.util.AddFunctionClass;
import net.ucanaccess.test.util.UcanaccessBaseTest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
@@ -31,9 +31,9 @@ void testAddFunction(AccessVersion _accessVersion) throws Exception {
st.execute("INSERT INTO t_add_function (id) VALUES(1)");
}
- ucanaccess.addFunctions(AddFunctionClass.class);
- dumpQueryResult("SELECT pluto('hello',' world ', NOW()) FROM t_add_function");
- checkQuery("SELECT CONCAT('Hello World, ','Ucanaccess') FROM t_add_function", "Hello World, Ucanaccess");
+ ucanaccess.addFunctions(AddFunctions.class);
+ dumpQueryResult("SELECT pluto('hello', ' world ', NOW()) FROM t_add_function");
+ checkQuery("SELECT CONCAT('Hello World, ', 'Ucanaccess') FROM t_add_function", "Hello World, Ucanaccess");
dropTable("t_add_function");
}
diff --git a/src/test/java/net/ucanaccess/test/integration/CorruptedTest.java b/src/test/java/net/ucanaccess/test/integration/CorruptedTest.java
index 50ae56b9..0e57fe2d 100644
--- a/src/test/java/net/ucanaccess/test/integration/CorruptedTest.java
+++ b/src/test/java/net/ucanaccess/test/integration/CorruptedTest.java
@@ -17,12 +17,12 @@ class CorruptedTest extends UcanaccessBaseTest {
private static final ByteArrayOutputStream ERR_CONTENT = new ByteArrayOutputStream();
@BeforeAll
- static void setUpStreams() {
+ static void setStdErr() {
System.setErr(new PrintStream(ERR_CONTENT));
}
@AfterAll
- static void cleanUpStreams() {
+ static void resetStdErr() {
System.setErr(System.err);
}
@@ -39,10 +39,10 @@ void testCorrupted(AccessVersion _accessVersion) throws SQLException {
getLogger().info("UcanaccessConnection: {}", ucanaccess);
String nl = System.lineSeparator();
String err =
- "WARNING: integrity constraint violation: foreign key no parent; BABY_DADDYBABY table: BABY value: 34" + nl
+ "WARNING: integrity constraint violation: foreign key no parent ; BABY_DADDYBABY table: BABY value: 34" + nl
+ "WARNING: Detected Foreign Key constraint breach, table Baby, record Row[162:1][{ID=2,fk1=34}]: making the table Baby read-only" + nl
+ "WARNING: Detected Not Null constraint breach, table NotNull, record Row[140:0][{ID=1,notnull=,vvv=gg,fk1=34}]: making the table NotNull read-only" + nl
- + "WARNING: integrity constraint violation: foreign key no parent; NOTNULL_DADDYNOTNULL table: NOTNULL value: 34" + nl
+ + "WARNING: integrity constraint violation: foreign key no parent ; NOTNULL_DADDYNOTNULL table: NOTNULL value: 34" + nl
+ "WARNING: Detected Foreign Key constraint breach, table NotNull, record Row[140:3][{ID=4,notnull=t,vvv=t,fk1=2}]: making the table NotNull read-only" + nl
+ "WARNING: Detected Unique constraint breach, table UK, record Row[181:1][{ID=2,uk=1}]: making the table UK read-only";
assertEquals(err, ERR_CONTENT.toString().trim());
diff --git a/src/test/java/net/ucanaccess/test/integration/SummerTimeLostHourTest.java b/src/test/java/net/ucanaccess/test/integration/UtcTimezoneTest.java
similarity index 84%
rename from src/test/java/net/ucanaccess/test/integration/SummerTimeLostHourTest.java
rename to src/test/java/net/ucanaccess/test/integration/UtcTimezoneTest.java
index 1f094049..ca68cac0 100644
--- a/src/test/java/net/ucanaccess/test/integration/SummerTimeLostHourTest.java
+++ b/src/test/java/net/ucanaccess/test/integration/UtcTimezoneTest.java
@@ -18,31 +18,26 @@
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDateTime;
-import java.util.Locale;
import java.util.TimeZone;
-class SummerTimeLostHourTest extends UcanaccessBaseTest {
+class UtcTimezoneTest extends UcanaccessBaseTest {
- private static Locale prevLocale;
private static TimeZone prevTimeZone;
@BeforeAll
static void setLocalAndTimezone() {
- prevLocale = Locale.getDefault();
prevTimeZone = TimeZone.getDefault();
- Locale.setDefault(Locale.ITALY);
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Rome"));
}
@AfterAll
static void resetLocalAndTimezone() {
- Locale.setDefault(prevLocale);
TimeZone.setDefault(prevTimeZone);
}
@Override
protected String getAccessPath() {
- return TEST_DB_DIR + "summerTimeLostHour.accdb"; // Access 2007
+ return TEST_DB_DIR + "utcTimezoneTest.accdb"; // Access 2007
}
@ParameterizedTest(name = "[{index}] {0}")
@@ -56,9 +51,10 @@ void testForLostHour(AccessVersion _accessVersion) throws SQLException, IOExcept
*/
Connection hsqldbConn = ucanaccess.getHSQLDBConnection();
Statement hsqldbStmt = hsqldbConn.createStatement();
- ResultSet rs = hsqldbStmt.executeQuery("SELECT CAST(f_datetime AS VARCHAR(26)) AS str FROM t_datetime WHERE id=1");
+ ResultSet rs = hsqldbStmt.executeQuery("SELECT f_datetime, CAST(f_datetime AS VARCHAR(26)) AS str FROM t_datetime WHERE id=1");
rs.next();
- assertEquals("2017-03-26 02:00:00.000000", rs.getString(1));
+ assertEquals("2017-03-26 02:00:00.000000", rs.getString("f_datetime"));
+ assertEquals("2017-03-26 02:00:00.000000", rs.getString("str"));
/*
* also ensure that 02:00:00 -> 01:00:00 doesn't happen when writing back to Access
diff --git a/src/test/java/net/ucanaccess/test/util/AddFunctionClass.java b/src/test/java/net/ucanaccess/test/util/AddFunctionClass.java
deleted file mode 100644
index 9ad3015c..00000000
--- a/src/test/java/net/ucanaccess/test/util/AddFunctionClass.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.ucanaccess.test.util;
-
-import net.ucanaccess.converters.TypesMap.AccessType;
-import net.ucanaccess.ext.FunctionType;
-
-import java.sql.Timestamp;
-
-public final class AddFunctionClass {
-
- private AddFunctionClass() {
- }
-
- @FunctionType(functionName = "pluto", argumentTypes = { AccessType.TEXT, AccessType.TEXT,
- AccessType.DATETIME }, returnType = AccessType.TEXT)
- public static String example(String s1, String s2, Timestamp dt) {
- return s1 + s2 + dt;
- }
-
- @FunctionType(functionName = "concat", argumentTypes = { AccessType.TEXT,
- AccessType.TEXT }, returnType = AccessType.TEXT)
- public static String concat(String s1, String s2) {
- return s1 + s2;
- }
-
-}
diff --git a/src/test/java/net/ucanaccess/test/util/UcanaccessBaseTest.java b/src/test/java/net/ucanaccess/test/util/UcanaccessBaseTest.java
index f62720d4..542843d9 100644
--- a/src/test/java/net/ucanaccess/test/util/UcanaccessBaseTest.java
+++ b/src/test/java/net/ucanaccess/test/util/UcanaccessBaseTest.java
@@ -22,26 +22,26 @@
public abstract class UcanaccessBaseTest extends AbstractBaseTest {
protected static final String TEST_DB_DIR = "testdbs/";
- private static final File TEST_TEMP_DIR = createTempDir("ucanaccess-test");
+ private static final File TEST_TEMP_DIR = createTempDir("ucanaccess-test");
static {
Main.setBatchMode(true);
}
- private File fileAccDb;
- private String password = "";
- private AccessVersion accessVersion;
+ private File fileAccDb;
+ private String password = "";
+ private AccessVersion accessVersion;
// CHECKSTYLE:OFF
protected UcanaccessConnection ucanaccess;
// CHECKSTYLE:ON
- private String user = "ucanaccess";
- private Connection verifyConnection;
- private Boolean ignoreCase;
+ private String user = "ucanaccess";
+ private Connection verifyConnection;
+ private Boolean ignoreCase;
- private long inactivityTimeout = -1;
- private String columnOrder;
- private String append2JdbcURL = "";
- private Boolean showSchema;
+ private long inactivityTimeout = -1;
+ private String columnOrder;
+ private String append2JdbcURL = "";
+ private Boolean showSchema;
protected UcanaccessBaseTest() {
}
@@ -378,10 +378,8 @@ protected UcanaccessConnection getUcanaccessConnection(String _dbPath) throws SQ
}
private UcanaccessConnection getUcanaccessConnection(String _urlPrefix, String _dbPath) throws SQLException {
- if (_dbPath == null) {
- _dbPath = getAccessTempPath();
- }
- String url = _urlPrefix + _dbPath;
+ String dbPath = Optional.ofNullable(_dbPath).orElseGet(this::getAccessTempPath);
+ String url = _urlPrefix + dbPath;
if (ignoreCase != null) {
url += ";ignoreCase=" + ignoreCase;
}
diff --git a/src/test/resources/testdbs/summerTimeLostHour.accdb b/src/test/resources/testdbs/utcTimezoneTest.accdb
similarity index 100%
rename from src/test/resources/testdbs/summerTimeLostHour.accdb
rename to src/test/resources/testdbs/utcTimezoneTest.accdb