From e15296c4151fdaf3d807ec7ef784a0bfaf15cc5f Mon Sep 17 00:00:00 2001 From: Maxim Solodovnik Date: Wed, 15 Dec 2021 19:24:19 +0700 Subject: [PATCH] [OPENJPA-2893] latest H2 more or less works (#91) * [OPENJPA-2893] latest H2 more or less works * Tests are green --- .../openjpa/jdbc/sql/DBDictionaryFactory.java | 5 +- .../apache/openjpa/jdbc/sql/H2Dictionary.java | 146 +++++++++++++++++- .../jdbc/sql/DBDictionaryFactoryTest.java | 38 ++--- .../criteria/results/TestTypedResults.java | 4 +- .../jdbc/auto/TestAutoIncrement.java | 4 +- .../mappingApp/EntityWithCompositeId.java | 2 +- .../jpql/literals/TestLiteralInSQL.java | 3 +- .../persistence/query/SimpleEntity.java | 6 +- .../persistence/query/TestJDBCEscapeDate.java | 3 +- .../query/TestResultSetMapping.java | 1 - pom.xml | 29 +++- 11 files changed, 205 insertions(+), 36 deletions(-) diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java index cd248411f..6816b8181 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java @@ -275,10 +275,9 @@ public class DBDictionaryFactory { } // test h2 in a special way, because there's a decent chance the string // h2 could appear in the URL of another database - if (prod.indexOf("jdbc:h2:") != -1) - return dbdictionaryPlugin.unalias("h2"); - if (prod.indexOf("h2 database") != -1) + if (prod.indexOf("jdbc:h2:") != -1 || prod.indexOf("h2 database") != -1) { return dbdictionaryPlugin.unalias("h2"); + } // test db2 last, because there's a decent chance this string could // appear in the URL of another database (like if the db is named // "testdb2" or something) diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java index ae2ac0bf6..8e10535c0 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java @@ -18,6 +18,7 @@ */ package org.apache.openjpa.jdbc.sql; +import java.math.BigDecimal; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; @@ -29,6 +30,7 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.OffsetDateTime; import java.util.Arrays; +import java.util.List; import java.util.Locale; import org.apache.openjpa.jdbc.identifier.DBIdentifier; @@ -47,6 +49,109 @@ import org.apache.openjpa.util.StoreException; * @since 0.9.7 */ public class H2Dictionary extends DBDictionary { + private final static List V2_KEYWORDS = Arrays.asList( + "ALL", + "AND", + "ANY", + "ARRAY", + "AS", + "ASYMMETRIC", + "AUTHORIZATION", + "BETWEEN", + "BOTH", + "CASE", + "CAST", + "CHECK", + "CONSTRAINT", + "CROSS", + "CURRENT_CATALOG", + "CURRENT_DATE", + "CURRENT_PATH", + "CURRENT_ROLE", + "CURRENT_SCHEMA", + "CURRENT_TIME", + "CURRENT_TIMESTAMP", + "CURRENT_USER", + "DAY", + "DEFAULT", + "DISTINCT", + "ELSE", + "END", + "EXCEPT", + "EXISTS", + "FALSE", + "FETCH", + "FILTER", + "FOR", + "FOREIGN", + "FROM", + "FULL", + "GROUP", + "GROUPS", + "HAVING", + "HOUR", + "IF", + "ILIKE", + "IN", + "INNER", + "INTERSECT", + "INTERSECTS", + "INTERVAL", + "IS", + "JOIN", + "KEY", + "LEADING", + "LEFT", + "LIKE", + "LIMIT", + "LOCALTIME", + "LOCALTIMESTAMP", + "MINUS", + "MINUTE", + "MONTH", + "NATURAL", + "NOT", + "NULL", + "OFFSET", + "ON", + "OR", + "ORDER", + "OVER", + "PARTITION", + "PRIMARY", + "QUALIFY", + "RANGE", + "REGEXP", + "RIGHT", + "ROW", + "ROWNUM", + "ROWS", + "SECOND", + "SELECT", + "SESSION_USER", + "SET", + "SOME", + "SYMMETRIC", + "SYSTEM_USER", + "TABLE", + "TO", + "TOP", + "TRAILING", + "TRUE", + "UESCAPE", + "UNION", + "UNIQUE", + "UNKNOWN", + "USER", + "USING", + "VALUE", + "VALUES", + "WHEN", + "WHERE", + "WINDOW", + "WITH", + "YEAR", + "_ROWID_"); public H2Dictionary() { platform = "H2"; @@ -135,6 +240,28 @@ public class H2Dictionary extends DBDictionary { })); } + @Override + public void connectedConfiguration(Connection conn) throws SQLException { + super.connectedConfiguration(conn); + if (versionLaterThan(1)) { + supportsGetGeneratedKeys = true; + supportsNullTableForGetPrimaryKeys = false; + supportsNullTableForGetIndexInfo = false; + autoAssignClause = "GENERATED ALWAYS AS IDENTITY"; + bitTypeName = "BOOLEAN"; + timeTypeName = "TIME(9)"; + timestampTypeName = "TIMESTAMP(9)"; + timeWithZoneTypeName = "TIME(9) WITH TIME ZONE"; + timestampWithZoneTypeName = "TIMESTAMP(9) WITH TIME ZONE"; + booleanRepresentation = BooleanRepresentationFactory.BOOLEAN; + booleanTypeName = "BOOLEAN"; + reservedWordSet.clear(); + reservedWordSet.addAll(V2_KEYWORDS); + invalidColumnWordSet.clear(); + invalidColumnWordSet.addAll(V2_KEYWORDS); + } + } + @Override public int getJDBCType(int metaTypeCode, boolean lob) { int type = super.getJDBCType(metaTypeCode, lob); @@ -207,10 +334,14 @@ public class H2Dictionary extends DBDictionary { @Override protected String getPrimaryKeyConstraintSQL(PrimaryKey pk) { - Column[] cols = pk.getColumns(); - if (cols.length == 1 && cols[0].isAutoAssigned()) - return null; - return super.getPrimaryKeyConstraintSQL(pk); + if (versionLaterThan(1)) { + return super.getPrimaryKeyConstraintSQL(pk); + } else { + Column[] cols = pk.getColumns(); + if (cols.length == 1 && cols[0].isAutoAssigned()) + return null; + return super.getPrimaryKeyConstraintSQL(pk); + } } @Override @@ -300,6 +431,13 @@ public class H2Dictionary extends DBDictionary { stmnt.setObject(idx, val); } + @Override + public int getInt(ResultSet rs, int column) throws SQLException { + //rs.getInt perform rounding `25.5 -> 26` + final BigDecimal decRes = rs.getBigDecimal(column); + return decRes == null ? 0 : decRes.intValue(); + } + /** * h2 does intentionally not support {@code getTimestamp()} for 'TIME WITH TIME ZONE' columns. * See h2 ticket #413. diff --git a/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactoryTest.java b/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactoryTest.java index 29782bf57..9826fdbe1 100644 --- a/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactoryTest.java +++ b/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactoryTest.java @@ -27,25 +27,25 @@ public class DBDictionaryFactoryTest { JDBCConfiguration conf = new JDBCConfigurationImpl(); String[] aliases = new String[]{ - "access", org.apache.openjpa.jdbc.sql.AccessDictionary.class.getName(), - "db2", org.apache.openjpa.jdbc.sql.DB2Dictionary.class.getName(), - "derby", org.apache.openjpa.jdbc.sql.DerbyDictionary.class.getName(), - "empress", org.apache.openjpa.jdbc.sql.EmpressDictionary.class.getName(), - "foxpro", org.apache.openjpa.jdbc.sql.FoxProDictionary.class.getName(), - "h2", org.apache.openjpa.jdbc.sql.H2Dictionary.class.getName(), - "hsql", org.apache.openjpa.jdbc.sql.HSQLDictionary.class.getName(), - "informix", org.apache.openjpa.jdbc.sql.InformixDictionary.class.getName(), - "ingres", org.apache.openjpa.jdbc.sql.IngresDictionary.class.getName(), - "jdatastore", org.apache.openjpa.jdbc.sql.JDataStoreDictionary.class.getName(), - "mariadb", org.apache.openjpa.jdbc.sql.MariaDBDictionary.class.getName(), - "mysql", org.apache.openjpa.jdbc.sql.MySQLDictionary.class.getName(), - "herddb", org.apache.openjpa.jdbc.sql.HerdDBDictionary.class.getName(), - "oracle", org.apache.openjpa.jdbc.sql.OracleDictionary.class.getName(), - "pointbase", org.apache.openjpa.jdbc.sql.PointbaseDictionary.class.getName(), - "postgres", org.apache.openjpa.jdbc.sql.PostgresDictionary.class.getName(), - "soliddb", org.apache.openjpa.jdbc.sql.SolidDBDictionary.class.getName(), - "sqlserver", org.apache.openjpa.jdbc.sql.SQLServerDictionary.class.getName(), - "sybase", org.apache.openjpa.jdbc.sql.SybaseDictionary.class.getName(), + "access", AccessDictionary.class.getName(), + "db2", DB2Dictionary.class.getName(), + "derby", DerbyDictionary.class.getName(), + "empress", EmpressDictionary.class.getName(), + "foxpro", FoxProDictionary.class.getName(), + "h2", H2Dictionary.class.getName(), + "hsql", HSQLDictionary.class.getName(), + "informix", InformixDictionary.class.getName(), + "ingres", IngresDictionary.class.getName(), + "jdatastore", JDataStoreDictionary.class.getName(), + "mariadb", MariaDBDictionary.class.getName(), + "mysql", MySQLDictionary.class.getName(), + "herddb", HerdDBDictionary.class.getName(), + "oracle", OracleDictionary.class.getName(), + "pointbase", PointbaseDictionary.class.getName(), + "postgres", PostgresDictionary.class.getName(), + "soliddb", SolidDBDictionary.class.getName(), + "sqlserver", SQLServerDictionary.class.getName(), + "sybase", SybaseDictionary.class.getName(), "maxdb", MaxDBDictionary.class.getName(), "jdbc:h2:", H2Dictionary.class.getName(), "h2 database", H2Dictionary.class.getName() diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java index 656dad472..866036429 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java @@ -37,6 +37,7 @@ import javax.persistence.criteria.Root; import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.jdbc.sql.H2Dictionary; import org.apache.openjpa.jdbc.sql.PostgresDictionary; import org.apache.openjpa.persistence.test.SingleEMFTestCase; @@ -129,8 +130,9 @@ public class TestTypedResults extends SingleEMFTestCase { DBDictionary dict = ((JDBCConfiguration)emf.getConfiguration()).getDBDictionaryInstance(); String sql = "SELECT * FROM CRIT_RES_ORD o WHERE (o.filled = 1)"; - if (dict instanceof PostgresDictionary) + if (dict instanceof PostgresDictionary || (dict instanceof H2Dictionary && dict.getMajorVersion() > 1)) { sql = "SELECT * FROM CRIT_RES_ORD o WHERE (o.filled = true)"; + } Query nativeQ = em.createNativeQuery(sql, Order.class); // Don't suppress warnings. List typedNativeResults = nativeQ.getResultList(); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/auto/TestAutoIncrement.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/auto/TestAutoIncrement.java index 810d9e593..e18317aa0 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/auto/TestAutoIncrement.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/auto/TestAutoIncrement.java @@ -20,6 +20,7 @@ package org.apache.openjpa.persistence.jdbc.auto; import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.jdbc.sql.H2Dictionary; import org.apache.openjpa.jdbc.sql.OracleDictionary; import org.apache.openjpa.jdbc.sql.SQLServerDictionary; import org.apache.openjpa.jdbc.sql.SybaseDictionary; @@ -35,7 +36,8 @@ public class TestAutoIncrement extends SingleEMTestCase { disabled = true; return; } - if (dic instanceof SQLServerDictionary || dic instanceof OracleDictionary || dic instanceof SybaseDictionary) { + if (dic instanceof SQLServerDictionary || dic instanceof OracleDictionary || dic instanceof SybaseDictionary + || (dic instanceof H2Dictionary && dic.getMajorVersion() > 1)) { disabled = true; return; } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/mappingApp/EntityWithCompositeId.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/mappingApp/EntityWithCompositeId.java index c8e6366d2..26e805687 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/mappingApp/EntityWithCompositeId.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/mappingApp/EntityWithCompositeId.java @@ -50,7 +50,7 @@ public class EntityWithCompositeId { } - @Column(name="VALUE") + @Column(name="OJVALUE") public String getValue () { return value; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/literals/TestLiteralInSQL.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/literals/TestLiteralInSQL.java index 1c0ab465b..956c12c3f 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/literals/TestLiteralInSQL.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/literals/TestLiteralInSQL.java @@ -23,6 +23,7 @@ import javax.persistence.Query; import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.jdbc.sql.H2Dictionary; import org.apache.openjpa.jdbc.sql.PostgresDictionary; import org.apache.openjpa.persistence.simple.AllFieldTypes; import org.apache.openjpa.persistence.test.SQLListenerTestCase; @@ -39,7 +40,7 @@ public class TestLiteralInSQL extends SQLListenerTestCase { em = emf.createEntityManager(); DBDictionary dict = ((JDBCConfiguration)emf.getConfiguration()).getDBDictionaryInstance(); //Disable on Postgres for now.... - if (dict instanceof PostgresDictionary){ + if (dict instanceof PostgresDictionary || (dict instanceof H2Dictionary && dict.getMajorVersion() > 1)) { setTestsDisabled(true); return; } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java index e0e9a111b..1a0c446fd 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java @@ -52,7 +52,7 @@ import javax.persistence.Table; @NamedNativeQueries( { @NamedNativeQuery(name = "findSimpleEntitites", - query = "SELECT ID, NAME, VALUE FROM SIMPLE_ENTITY", + query = "SELECT ID, NAME, OJVALUE FROM SIMPLE_ENTITY", resultSetMapping = "simpleEntitiesResult") }) @SqlResultSetMapping(name = "simpleEntitiesResult", @@ -60,7 +60,7 @@ import javax.persistence.Table; entityClass = org.apache.openjpa.persistence.query.SimpleEntity.class, fields = {@FieldResult(name = "id", column = "ID"), @FieldResult(name = "name", column = "NAME"), - @FieldResult(name = "value", column = "VALUE") })) + @FieldResult(name = "value", column = "OJVALUE") })) @Entity(name = "simple") @Table(name = "SIMPLE_ENTITY") public class SimpleEntity implements Serializable { @@ -79,7 +79,7 @@ public class SimpleEntity implements Serializable { private String name; @Basic - @Column(name = "VALUE") + @Column(name = "OJVALUE") private String value; public SimpleEntity() { diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestJDBCEscapeDate.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestJDBCEscapeDate.java index 370d67111..637503a13 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestJDBCEscapeDate.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestJDBCEscapeDate.java @@ -27,6 +27,7 @@ import javax.persistence.Query; import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.jdbc.sql.H2Dictionary; import org.apache.openjpa.jdbc.sql.HSQLDictionary; import org.apache.openjpa.jdbc.sql.PostgresDictionary; import org.apache.openjpa.jdbc.sql.SQLServerDictionary; @@ -97,7 +98,7 @@ public class TestJDBCEscapeDate extends SingleEMFTestCase { "select a from Employee a where a.hireTimestamp >= {ts '2009-08-25 00:00:00.123456'}", "select {t '00:00:00'}, a.empId from Employee a", }; - } else if (dict instanceof PostgresDictionary) { + } else if (dict instanceof PostgresDictionary || dict instanceof H2Dictionary) { jpql = new String[] { "select a from Employee a where a.hireDate >= {d '2009-08-25'}", "select a from Employee a where a.hireDate >= {d '2009-8-5'}", diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestResultSetMapping.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestResultSetMapping.java index 169eaab79..ada3505d3 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestResultSetMapping.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestResultSetMapping.java @@ -18,7 +18,6 @@ */ package org.apache.openjpa.persistence.query; -import java.util.Iterator; import java.util.List; import javax.persistence.EntityManager; diff --git a/pom.xml b/pom.xml index d80484ee3..95f259bb4 100644 --- a/pom.xml +++ b/pom.xml @@ -448,7 +448,34 @@ - 1.4.196 + 1.4.200 + org.h2.Driver + jdbc:h2:./target/database/openjpa-h2-database + + + + h2mem + + + + + com.h2database + h2 + ${h2.version} + + + + + + + test-h2-2 + + + test-h2-2 + + + + 2.0.202 org.h2.Driver jdbc:h2:./target/database/openjpa-h2-database