From a255da6f654abbe8e70783a0b492bf64656cc2a1 Mon Sep 17 00:00:00 2001 From: Patrick Linskey Date: Sat, 30 Dec 2006 01:38:33 +0000 Subject: [PATCH] submitting patches for OPENJPA-92. I have not tested them aside from compiling and running the regression tests (against Derby). git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@491148 13f79535-47bb-0310-9956-ffa450edef68 --- .../openjpa/jdbc/sql/DBDictionaryFactory.java | 6 + .../apache/openjpa/jdbc/sql/H2Dictionary.java | 230 ++++++++++++++++++ .../openjpa/jdbc/conf/localizer.properties | 3 +- .../src/doc/manual/supported_databases.xml | 40 +++ 4 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java 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 fe8fba121..155bf907c 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 @@ -201,6 +201,12 @@ public class DBDictionaryFactory { return CacheDictionary.class.getName(); if (prod.indexOf("derby") != -1) return DerbyDictionary.class.getName(); + // 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 H2Dictionary.class.getName(); + if (prod.indexOf("h2 database") != -1) + return H2Dictionary.class.getName(); // 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 new file mode 100644 index 000000000..6b88b785c --- /dev/null +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/H2Dictionary.java @@ -0,0 +1,230 @@ +package org.apache.openjpa.jdbc.sql; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Arrays; +import java.util.Locale; + +import org.apache.commons.lang.StringUtils; +import org.apache.openjpa.jdbc.kernel.exps.FilterValue; +import org.apache.openjpa.jdbc.schema.Column; +import org.apache.openjpa.jdbc.schema.PrimaryKey; +import org.apache.openjpa.jdbc.schema.Table; +import org.apache.openjpa.jdbc.schema.Unique; +import org.apache.openjpa.meta.JavaTypes; + +/** + * Support for the H2 database ({@link http://www.h2database.com}). + * + * @since 0.9.7 + */ +public class H2Dictionary extends DBDictionary { + + public H2Dictionary() { + platform = "H2"; + validationSQL = "CALL 1"; + closePoolSQL = "SHUTDOWN"; + + supportsAutoAssign = true; + lastGeneratedKeyQuery = "CALL IDENTITY()"; + autoAssignClause = "IDENTITY"; + autoAssignTypeName = "INTEGER"; + nextSequenceQuery = "CALL NEXT VALUE FOR {0}"; + + // CROSS JOIN is currently not supported + crossJoinClause = "JOIN"; + requiresConditionForCrossJoin = true; + stringLengthFunction = "LENGTH({0})"; + trimLeadingFunction = "LTRIM({0})"; + trimTrailingFunction = "RTRIM({0})"; + trimBothFunction = "TRIM({0})"; + + useSchemaName = true; + supportsSelectForUpdate = true; + supportsSelectStartIndex = true; + supportsSelectEndIndex = true; + rangePosition = RANGE_POST_LOCK; + supportsDeferredConstraints = false; + + useGetObjectForBlobs = true; + blobTypeName = "BLOB"; + doubleTypeName = "DOUBLE"; + + supportsNullTableForGetPrimaryKeys = true; + supportsNullTableForGetIndexInfo = true; + + requiresCastForMathFunctions = false; + requiresCastForComparisons = false; + + reservedWordSet.addAll(Arrays.asList(new String[] { + "CURRENT_TIMESTAMP", "CURRENT_TIME", "CURRENT_DATE", "CROSS", + "DISTINCT", "EXCEPT", "EXISTS", "FROM", "FOR", "FALSE", "FULL", + "GROUP", "HAVING", "INNER", "INTERSECT", "IS", "JOIN", "LIKE", + "MINUS", "NATURAL", "NOT", "NULL", "ON", "ORDER", "PRIMARY", + "ROWNUM", "SELECT", "SYSDATE", "SYSTIME", "SYSTIMESTAMP", "TODAY", + "TRUE", "UNION", "WHERE" + })); + } + + public int getJDBCType(int metaTypeCode, boolean lob) { + int type = super.getJDBCType(metaTypeCode, lob); + switch (type) { + case Types.BIGINT: + if (metaTypeCode == JavaTypes.BIGINTEGER) + return Types.NUMERIC; + break; + } + return type; + } + + public int getPreferredType(int type) { + return super.getPreferredType(type); + } + + public String[] getAddPrimaryKeySQL(PrimaryKey pk) { + return new String[0]; + } + + public String[] getDropPrimaryKeySQL(PrimaryKey pk) { + return new String[0]; + } + + public String[] getAddColumnSQL(Column column) { + return new String[] { + "ALTER TABLE " + getFullName(column.getTable(), false) + + " ADD COLUMN " + getDeclareColumnSQL(column, true) + }; + } + + public String[] getCreateTableSQL(Table table) { + StringBuffer buf = new StringBuffer(); + buf.append("CREATE TABLE ").append(getFullName(table, false)) + .append(" ("); + + Column[] cols = table.getColumns(); + for (int i = 0; i < cols.length; i++) { + if (i > 0) + buf.append(", "); + buf.append(getDeclareColumnSQL(cols[i], false)); + } + + PrimaryKey pk = table.getPrimaryKey(); + String pkStr; + if (pk != null) { + pkStr = getPrimaryKeyConstraintSQL(pk); + if (!StringUtils.isEmpty(pkStr)) + buf.append(", ").append(pkStr); + } + + Unique[] unqs = table.getUniques(); + String unqStr; + for (int i = 0; i < unqs.length; i++) { + unqStr = getUniqueConstraintSQL(unqs[i]); + if (unqStr != null) + buf.append(", ").append(unqStr); + } + + buf.append(")"); + return new String[] { buf.toString() }; + } + + protected String getPrimaryKeyConstraintSQL(PrimaryKey pk) { + Column[] cols = pk.getColumns(); + if (cols.length == 1 && cols[0].isAutoAssigned()) + return null; + return super.getPrimaryKeyConstraintSQL(pk); + } + + public boolean isSystemIndex(String name, Table table) { + return name.toUpperCase(Locale.ENGLISH).startsWith("SYSTEM_"); + } + + protected String getSequencesSQL(String schemaName, String sequenceName) { + StringBuffer buf = new StringBuffer(); + buf.append("SELECT SEQUENCE_SCHEMA, SEQUENCE_NAME FROM ") + .append("INFORMATION_SCHEMA.SEQUENCES"); + if (schemaName != null || sequenceName != null) + buf.append(" WHERE "); + if (schemaName != null) { + buf.append("SEQUENCE_SCHEMA = ?"); + if (sequenceName != null) + buf.append(" AND "); + } + if (sequenceName != null) + buf.append("SEQUENCE_NAME = ?"); + return buf.toString(); + } + + protected SQLBuffer toOperation(String op, SQLBuffer selects, + SQLBuffer from, SQLBuffer where, SQLBuffer group, SQLBuffer having, + SQLBuffer order, boolean distinct, boolean forUpdate, long start, + long end) { + return super.toOperation(op, selects, from, where, group, having, + order, distinct, forUpdate, start, end); + } + + public Column[] getColumns(DatabaseMetaData meta, String catalog, + String schemaName, String tableName, String columnName, Connection conn) + throws SQLException { + Column[] cols = super.getColumns(meta, catalog, schemaName, tableName, + columnName, conn); + return cols; + } + + public void setDouble(PreparedStatement stmnt, int idx, double val, + Column col) + throws SQLException { + super.setDouble(stmnt, idx, val, col); + } + + public void setBigDecimal(PreparedStatement stmnt, int idx, BigDecimal val, + Column col) + throws SQLException { + super.setBigDecimal(stmnt, idx, val, col); + } + + protected void appendSelectRange(SQLBuffer buf, long start, long end) { + if (end != Long.MAX_VALUE) + buf.append(" LIMIT ").appendValue(end - start); + if (start != 0) + buf.append(" OFFSET ").appendValue(start); + } + + public void substring(SQLBuffer buf, FilterValue str, FilterValue start, + FilterValue end) { + buf.append("SUBSTR("); + str.appendTo(buf); + buf.append(", ("); + start.appendTo(buf); + buf.append(" + 1)"); + if (end != null) { + buf.append(", ("); + end.appendTo(buf); + buf.append(" - "); + start.appendTo(buf); + buf.append(")"); + } + buf.append(")"); + } + + public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find, + FilterValue start) { + buf.append("(POSITION("); + find.appendTo(buf); + buf.append(" IN "); + if (start != null) + substring(buf, str, start, null); + else + str.appendTo(buf); + buf.append(") - 1"); + if (start != null) { + buf.append(" + "); + start.appendTo(buf); + } + buf.append(")"); + } +} \ No newline at end of file diff --git a/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/conf/localizer.properties b/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/conf/localizer.properties index 30047d841..300083215 100644 --- a/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/conf/localizer.properties +++ b/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/conf/localizer.properties @@ -179,6 +179,7 @@ MappingDefaults-displayorder: 50 MappingDefaults-interface: org.apache.openjpa.jdbc.meta.MappingDefaults ConnectionDriverName-values: org.hsqldb.jdbcDriver,org.hsql.jdbcDriver,\ + org.h2.Driver,\ COM.cloudscape.core.JDBCDriver,in.co.daffodil.db.jdbc.DaffodilDBDriver,\ com.ddtek.jdbc.db2.DB2Driver,interbase.interclient.Driver,\ com.mysql.jdbc.Driver,com.ddtek.jdbc.oracle.OracleDriver,\ @@ -213,7 +214,7 @@ ConnectionURL-values: jdbc:JSQLConnect:///database=,\ MaxPooledStatements=0,\ jdbc:datadirect:sqlserver://:1433;SelectMethod=cursor;\ DatabaseName=,jdbc:datadirect:sybase://:5000,\ - jdbc:db2:///,jdbc:hsqldb:,\ + jdbc:db2:///,jdbc:hsqldb:,jdbc:h2:,\ jdbc:idb:.properties,\ jdbc:informix-sqli://:1526/:INFORMIXSERVER=,\ jdbc:interbase:////.gdb,\ diff --git a/openjpa-project/src/doc/manual/supported_databases.xml b/openjpa-project/src/doc/manual/supported_databases.xml index 97fd39aaa..625904154 100644 --- a/openjpa-project/src/doc/manual/supported_databases.xml +++ b/openjpa-project/src/doc/manual/supported_databases.xml @@ -132,6 +132,20 @@ by OpenJPA. 1.0.1 + + + H2 Database Engine + + + 1.0 + + + H2 + + + 1.0 + + Hypersonic Database Engine @@ -448,6 +462,32 @@ Only the category 2 non-local driver is supported. +
+ + H2 Database Engine + + + + Example properties for H2 Database Engine + + +openjpa.ConnectionDriverName: org.h2.Driver +openjpa.ConnectionURL: jdbc:h2:DB_NAME + + +
+ + Known issues with H2 Database Engine + + + + +H2 does not support cross joins + + + +
+
Hypersonic