mirror of https://github.com/apache/openjpa.git
OPENJPA-735: OpenJPA support for SolidDB
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@987013 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
63a24dc7bb
commit
07d599a02d
|
@ -558,7 +558,7 @@ public class SchemaTool {
|
|||
if (dbTable != null) {
|
||||
idx = findIndex(dbTable, idxs[k]);
|
||||
if (idx == null) {
|
||||
if (createIndex(idxs[k], dbTable))
|
||||
if (createIndex(idxs[k], dbTable, tabs[j].getUniques()))
|
||||
dbTable.importIndex(idxs[k]);
|
||||
else
|
||||
_log.warn(_loc.get("add-index", idxs[k],
|
||||
|
@ -953,7 +953,7 @@ public class SchemaTool {
|
|||
*/
|
||||
public boolean createTable(Table table)
|
||||
throws SQLException {
|
||||
return executeSQL(_dict.getCreateTableSQL(table));
|
||||
return executeSQL(_dict.getCreateTableSQL(table, _db));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -992,11 +992,16 @@ public class SchemaTool {
|
|||
* @return true if the operation was successful, false otherwise
|
||||
*/
|
||||
public boolean createIndex(Index idx, Table table)
|
||||
throws SQLException {
|
||||
return createIndex(idx, table, null);
|
||||
}
|
||||
|
||||
public boolean createIndex(Index idx, Table table, Unique[] uniques)
|
||||
throws SQLException {
|
||||
// Informix will automatically create a unique index for the
|
||||
// primary key, so don't create another index again
|
||||
|
||||
if (!_dict.needsToCreateIndex(idx,table))
|
||||
if (!_dict.needsToCreateIndex(idx,table,uniques))
|
||||
return false;
|
||||
|
||||
int max = _dict.maxIndexesPerTable;
|
||||
|
|
|
@ -87,6 +87,7 @@ import org.apache.openjpa.jdbc.schema.Index;
|
|||
import org.apache.openjpa.jdbc.schema.NameSet;
|
||||
import org.apache.openjpa.jdbc.schema.PrimaryKey;
|
||||
import org.apache.openjpa.jdbc.schema.Schema;
|
||||
import org.apache.openjpa.jdbc.schema.SchemaGroup;
|
||||
import org.apache.openjpa.jdbc.schema.Sequence;
|
||||
import org.apache.openjpa.jdbc.schema.Table;
|
||||
import org.apache.openjpa.jdbc.schema.Unique;
|
||||
|
@ -3298,6 +3299,14 @@ public class DBDictionary
|
|||
maxLen, checkForUniqueness);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a series of SQL statements to create the given table, complete
|
||||
* with columns. Indexes and constraints will be created separately.
|
||||
*/
|
||||
public String[] getCreateTableSQL(Table table, SchemaGroup group) {
|
||||
return getCreateTableSQL(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a series of SQL statements to create the given table, complete
|
||||
* with columns. Indexes and constraints will be created separately.
|
||||
|
@ -4525,10 +4534,7 @@ public class DBDictionary
|
|||
String query = lastGeneratedKeyQuery;
|
||||
if (query.indexOf('{') != -1) // only if the token is in the string
|
||||
{
|
||||
query = MessageFormat.format(query, new Object[]{
|
||||
toDBName(col.getIdentifier()), getFullName(col.getTable(), false),
|
||||
getGeneratedKeySequenceName(col),
|
||||
});
|
||||
query = getGenKeySeqName(query, col);
|
||||
}
|
||||
|
||||
PreparedStatement stmnt = prepareStatement(conn, query);
|
||||
|
@ -4545,6 +4551,13 @@ public class DBDictionary
|
|||
}
|
||||
}
|
||||
|
||||
protected String getGenKeySeqName(String query, Column col) {
|
||||
return MessageFormat.format(query, new Object[]{
|
||||
toDBName(col.getIdentifier()), getFullName(col.getTable(), false),
|
||||
getGeneratedKeySequenceName(col),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sequence name used by databases for the given autoassigned
|
||||
* column. This is only used by databases that require an explicit name
|
||||
|
@ -5206,6 +5219,10 @@ public class DBDictionary
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean needsToCreateIndex(Index idx, Table table, Unique[] uniques) {
|
||||
return needsToCreateIndex(idx, table);
|
||||
}
|
||||
|
||||
public boolean needsToCreateIndex(Index idx, Table table) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.openjpa.jdbc.sql;
|
|||
import java.math.BigDecimal;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -28,13 +29,19 @@ import java.util.List;
|
|||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.openjpa.jdbc.identifier.DBIdentifier;
|
||||
import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
|
||||
import org.apache.openjpa.jdbc.kernel.exps.Lit;
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
import org.apache.openjpa.jdbc.schema.Index;
|
||||
import org.apache.openjpa.jdbc.schema.PrimaryKey;
|
||||
import org.apache.openjpa.jdbc.schema.Schema;
|
||||
import org.apache.openjpa.jdbc.schema.SchemaGroup;
|
||||
import org.apache.openjpa.jdbc.schema.Sequence;
|
||||
import org.apache.openjpa.jdbc.schema.Table;
|
||||
import org.apache.openjpa.jdbc.schema.Unique;
|
||||
import org.apache.openjpa.kernel.exps.Literal;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.meta.JavaTypes;
|
||||
import org.apache.openjpa.util.UserException;
|
||||
|
||||
/**
|
||||
* Dictionary for SolidDB database.
|
||||
|
@ -75,7 +82,7 @@ public class SolidDBDictionary
|
|||
public boolean useTriggersForAutoAssign = true;
|
||||
|
||||
/**
|
||||
* The global sequence name to use for autoassign simulation.
|
||||
* The global sequence name to use for auto-assign simulation.
|
||||
*/
|
||||
public String autoAssignSequenceName = null;
|
||||
|
||||
|
@ -84,6 +91,11 @@ public class SolidDBDictionary
|
|||
* trigger name for backwards compatibility.
|
||||
*/
|
||||
public boolean openjpa3GeneratedKeyNames = false;
|
||||
|
||||
/**
|
||||
* Possible values for LockingMode are "PESSIMISTIC" and "OPTIMISTIC"
|
||||
*/
|
||||
public String lockingMode = null;
|
||||
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
|
@ -111,6 +123,10 @@ public class SolidDBDictionary
|
|||
currentDateFunction = "CURDATE()";
|
||||
currentTimeFunction = "CURTIME()";
|
||||
currentTimestampFunction = "NOW()";
|
||||
lastGeneratedKeyQuery = "SELECT {0}.CURRENT";
|
||||
sequenceSQL = "SELECT SEQUENCE_SCHEMA, SEQUENCE_NAME FROM SYS_SEQUENCES";
|
||||
sequenceSchemaSQL = "SEQSCHEMA = ?";
|
||||
sequenceNameSQL = "SEQNAME = ?";
|
||||
|
||||
reservedWordSet.addAll(Arrays.asList(new String[]{
|
||||
"BIGINT", "BINARY", "DATE", "TIME",
|
||||
|
@ -119,7 +135,15 @@ public class SolidDBDictionary
|
|||
}
|
||||
|
||||
@Override
|
||||
public String[] getCreateTableSQL(Table table) {
|
||||
public void endConfiguration() {
|
||||
super.endConfiguration();
|
||||
if (useTriggersForAutoAssign) {
|
||||
supportsAutoAssign = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getCreateTableSQL(Table table, SchemaGroup group) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("CREATE TABLE ").append(getFullName(table, false)).append(" (");
|
||||
Column[] cols = table.getColumns();
|
||||
|
@ -151,7 +175,26 @@ public class SolidDBDictionary
|
|||
else
|
||||
buf.append("DISK");
|
||||
|
||||
String[] create = new String[]{ buf.toString() };
|
||||
String[] create = null;
|
||||
if (lockingMode != null) {
|
||||
StringBuilder buf1 = new StringBuilder();
|
||||
if (lockingMode.equalsIgnoreCase("PESSIMISTIC")) {
|
||||
buf1.append("ALTER TABLE ").append(getFullName(table, false)).
|
||||
append(" SET PESSIMISTIC");
|
||||
} else if (lockingMode.equalsIgnoreCase("OPTIMISTIC")){
|
||||
buf1.append("ALTER TABLE ").append(getFullName(table, false)).
|
||||
append(" SET OPTIMISTIC");
|
||||
} else
|
||||
throw new UserException(_loc.get("invalid-locking-mode", lockingMode));
|
||||
|
||||
create = new String[2];
|
||||
create[0] = buf.toString();
|
||||
create[1] = buf1.toString();
|
||||
} else {
|
||||
create = new String[1];
|
||||
create[0] = buf.toString();
|
||||
}
|
||||
|
||||
if (!useTriggersForAutoAssign)
|
||||
return create;
|
||||
|
||||
|
@ -163,14 +206,11 @@ public class SolidDBDictionary
|
|||
if (seqs == null)
|
||||
seqs = new ArrayList(4);
|
||||
|
||||
seq = autoAssignSequenceName;
|
||||
if (seq == null) {
|
||||
if (openjpa3GeneratedKeyNames)
|
||||
seq = getOpenJPA3GeneratedKeySequenceName(cols[i]);
|
||||
else
|
||||
seq = getGeneratedKeySequenceName(cols[i]);
|
||||
seqs.add("CREATE SEQUENCE " + seq);
|
||||
}
|
||||
seq = getAutoGenSeqName(cols[i]);
|
||||
if (sequenecExists(table.getSchemaIdentifier().getName(), seq, group))
|
||||
seqs.add("DROP SEQUENCE " + seq);
|
||||
seqs.add("CREATE SEQUENCE " + seq);
|
||||
|
||||
if (openjpa3GeneratedKeyNames)
|
||||
trig = getOpenJPA3GeneratedKeyTriggerName(cols[i]);
|
||||
else
|
||||
|
@ -189,6 +229,7 @@ public class SolidDBDictionary
|
|||
+ " ON " + toDBName(table.getIdentifier())
|
||||
+ " BEFORE INSERT REFERENCING NEW " + toDBName(cols[i].getIdentifier())
|
||||
+ " AS NEW_COL1 BEGIN EXEC SEQUENCE " + seq + " NEXT INTO NEW_COL1; END");
|
||||
|
||||
}
|
||||
if (seqs == null)
|
||||
return create;
|
||||
|
@ -201,6 +242,23 @@ public class SolidDBDictionary
|
|||
return sql;
|
||||
}
|
||||
|
||||
protected boolean sequenecExists(String schemaName, String seqName, SchemaGroup group) {
|
||||
Schema[] schemas = group.getSchemas();
|
||||
for (int i = 0; i < schemas.length; i++) {
|
||||
String dbSchemaName = schemas[i].getIdentifier().getName();
|
||||
if (schemaName != null && !schemaName.equalsIgnoreCase(dbSchemaName))
|
||||
continue;
|
||||
|
||||
Sequence[] seqs = schemas[i].getSequences();
|
||||
for (int j = 0; j < seqs.length; j++) {
|
||||
String dbSeqName = seqs[j].getName();
|
||||
if (dbSeqName != null && dbSeqName.equalsIgnoreCase(seqName))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger name for simulating auto-assign values on the given column.
|
||||
*/
|
||||
|
@ -230,6 +288,22 @@ public class SolidDBDictionary
|
|||
getSchemaGroup(), maxTableNameLength, true));
|
||||
}
|
||||
|
||||
protected String getAutoGenSeqName(Column col) {
|
||||
String seqName = autoAssignSequenceName;
|
||||
if (seqName == null) {
|
||||
if (openjpa3GeneratedKeyNames)
|
||||
seqName = getOpenJPA3GeneratedKeySequenceName(col);
|
||||
else
|
||||
seqName = getGeneratedKeySequenceName(col);
|
||||
}
|
||||
return seqName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getGenKeySeqName(String query, Column col) {
|
||||
return MessageFormat.format(query, new Object[]{getAutoGenSeqName(col)});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertSchemaCase(DBIdentifier objectName) {
|
||||
if (objectName != null && objectName.getName() == null)
|
||||
|
@ -302,6 +376,23 @@ public class SolidDBDictionary
|
|||
return super.isSystemIndex(name, table) || startsWith$$;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSystemSequence(DBIdentifier name, DBIdentifier schema,
|
||||
boolean targetSchema) {
|
||||
if (super.isSystemSequence(name, schema, targetSchema))
|
||||
return true;
|
||||
String schemaName = DBIdentifier.isNull(schema) ? null : schema.getName();
|
||||
boolean startsWith_SYSTEM = schema.isDelimited() ? schemaName.startsWith("\"_SYSTEM") :
|
||||
schemaName.startsWith("_SYSTEM");
|
||||
|
||||
String seqName = DBIdentifier.isNull(name) ? null : name.getName();
|
||||
boolean startsWithSYS_SEQ_ = name.isDelimited() ? seqName.startsWith("\"SYS_SEQ_") :
|
||||
seqName.startsWith("SYS_SEQ_");
|
||||
if (startsWith_SYSTEM && startsWithSYS_SEQ_)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBigDecimal(PreparedStatement stmnt, int idx, BigDecimal val,
|
||||
Column col) throws SQLException {
|
||||
|
@ -347,13 +438,90 @@ public class SolidDBDictionary
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean needsToCreateIndex(Index idx, Table table) {
|
||||
public boolean needsToCreateIndex(Index idx, Table table, Unique[] uniques) {
|
||||
// SolidDB will automatically create a unique index for the
|
||||
// constraint, so don't create another index again
|
||||
PrimaryKey pk = table.getPrimaryKey();
|
||||
if (pk != null && idx.columnsMatch(pk.getColumns()))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
// If table1 has constraints on column (a, b), an explicit index on (a)
|
||||
// will cause duplicate index error from SolidDB
|
||||
Column[] icols = idx.getColumns();
|
||||
boolean isDuplicate = false;
|
||||
boolean mayBeDuplicate = false;
|
||||
for (int i = 0; i < uniques.length; i++) {
|
||||
Column[] ucols = uniques[i].getColumns();
|
||||
if (ucols.length < icols.length)
|
||||
continue;
|
||||
for (int j = 0, k = 0; j < ucols.length && k < icols.length; j++, k++) {
|
||||
if (mayBeDuplicate && ucols[j].getQualifiedPath().equals(icols[k].getQualifiedPath())) {
|
||||
if (k == icols.length - 1) {
|
||||
isDuplicate = true;
|
||||
} else {
|
||||
mayBeDuplicate = true;
|
||||
}
|
||||
} else
|
||||
mayBeDuplicate = false;
|
||||
}
|
||||
if (isDuplicate)
|
||||
break;
|
||||
}
|
||||
return isDuplicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSequencesSQL(String schemaName, String sequenceName) {
|
||||
return getSequencesSQL(DBIdentifier.newSchema(schemaName),
|
||||
DBIdentifier.newSequence(sequenceName));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSequencesSQL(DBIdentifier schemaName, DBIdentifier sequenceName) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(sequenceSQL);
|
||||
if (!DBIdentifier.isNull(schemaName) || !DBIdentifier.isNull(sequenceName))
|
||||
buf.append(" WHERE ");
|
||||
if (!DBIdentifier.isNull(schemaName)) {
|
||||
buf.append(sequenceSchemaSQL);
|
||||
if (!DBIdentifier.isNull(sequenceName))
|
||||
buf.append(" AND ");
|
||||
}
|
||||
if (!DBIdentifier.isNull(sequenceName))
|
||||
buf.append(sequenceNameSQL);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendSelect(SQLBuffer selectSQL, Object alias, Select sel,
|
||||
int idx) {
|
||||
// if this is a literal value, add a cast...
|
||||
Object val = sel.getSelects().get(idx);
|
||||
boolean toCast = (val instanceof Lit) &&
|
||||
((Lit)val).getParseType() != Literal.TYPE_DATE &&
|
||||
((Lit)val).getParseType() != Literal.TYPE_TIME &&
|
||||
((Lit)val).getParseType() != Literal.TYPE_TIMESTAMP;
|
||||
|
||||
if (toCast)
|
||||
selectSQL.append("CAST(");
|
||||
|
||||
// ... and add the select per super's behavior...
|
||||
super.appendSelect(selectSQL, alias, sel, idx);
|
||||
|
||||
// ... and finish the cast
|
||||
if (toCast) {
|
||||
Class c = ((Lit) val).getType();
|
||||
int javaTypeCode = JavaTypes.getTypeCode(c);
|
||||
int jdbcTypeCode = getJDBCType(javaTypeCode, false);
|
||||
String typeName = getTypeName(jdbcTypeCode);
|
||||
selectSQL.append(" AS " + typeName);
|
||||
|
||||
// if the literal is a string, use the default char col size
|
||||
// in the cast statement.
|
||||
if (String.class.equals(c))
|
||||
selectSQL.append("(" + characterColumnSize + ")");
|
||||
|
||||
selectSQL.append(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,4 +220,4 @@ sequencesql-override: Going to override the DB2 specific default for the \
|
|||
the property. This will allow openJPA to detect a difference between the DB2 default \
|
||||
string and the string set in the property and will further allow openJPA to use the \
|
||||
string defined by the property rather than the default string for DB2.
|
||||
|
||||
invalid-locking-mode: Invalid locking mode for SolidDB: "{0}"
|
||||
|
|
|
@ -26,6 +26,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.DerbyDictionary;
|
||||
import org.apache.openjpa.jdbc.sql.SolidDBDictionary;
|
||||
import org.apache.openjpa.persistence.test.SingleEMTestCase;
|
||||
import org.apache.openjpa.persistence.simple.AllFieldTypes;
|
||||
import org.apache.openjpa.persistence.ArgumentException;
|
||||
|
@ -186,6 +187,10 @@ public abstract class GroupingTestCase
|
|||
}
|
||||
|
||||
public void testSubstringInGroupBy() {
|
||||
DBDictionary dict = ((JDBCConfiguration)emf.getConfiguration()).getDBDictionaryInstance();
|
||||
if (dict instanceof SolidDBDictionary)
|
||||
return;
|
||||
|
||||
// this is an extension of JPQL
|
||||
Query q = em.createQuery("select substring(o.stringField, 1, 1), " +
|
||||
"count(o) from AllFieldTypes o " +
|
||||
|
|
Loading…
Reference in New Issue