[OPENJPA-2893] latest H2 more or less works (#91)

* [OPENJPA-2893] latest H2 more or less works

* Tests are green
This commit is contained in:
Maxim Solodovnik 2021-12-15 19:24:19 +07:00 committed by GitHub
parent 720869a4e0
commit e15296c415
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 205 additions and 36 deletions

View File

@ -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)

View File

@ -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<String> 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.

View File

@ -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()

View File

@ -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<Order> typedNativeResults = nativeQ.getResultList();

View File

@ -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;
}

View File

@ -50,7 +50,7 @@ public class EntityWithCompositeId {
}
@Column(name="VALUE")
@Column(name="OJVALUE")
public String getValue ()
{
return value;

View File

@ -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;
}

View File

@ -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() {

View File

@ -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'}",

View File

@ -18,7 +18,6 @@
*/
package org.apache.openjpa.persistence.query;
import java.util.Iterator;
import java.util.List;
import javax.persistence.EntityManager;

29
pom.xml
View File

@ -448,7 +448,34 @@
</property>
</activation>
<properties>
<h2.version>1.4.196</h2.version>
<h2.version>1.4.200</h2.version>
<connection.driver.name>org.h2.Driver</connection.driver.name>
<connection.url>jdbc:h2:./target/database/openjpa-h2-database</connection.url>
<connection.username />
<connection.password />
<!-- TCK specific properties -->
<tck.db.name>h2mem</tck.db.name>
</properties>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
</profile>
<!-- profile for testing with an embedded h2 2.x DB -->
<profile>
<id>test-h2-2</id>
<activation>
<property>
<name>test-h2-2</name>
</property>
</activation>
<properties>
<h2.version>2.0.202</h2.version>
<connection.driver.name>org.h2.Driver</connection.driver.name>
<connection.url>jdbc:h2:./target/database/openjpa-h2-database</connection.url>
<connection.username />