mirror of https://github.com/apache/openjpa.git
OPENJPA-340: Support for @UniqueConstraints on @TableGenerator, @SecondaryTable and @JoinTable.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@672038 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2b3f7ec90c
commit
ff4a96e707
|
@ -28,6 +28,7 @@ import java.util.HashMap;
|
||||||
|
|
||||||
import javax.transaction.NotSupportedException;
|
import javax.transaction.NotSupportedException;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
|
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
|
||||||
import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
|
import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
|
||||||
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
|
@ -38,6 +39,7 @@ import org.apache.openjpa.jdbc.schema.SchemaGroup;
|
||||||
import org.apache.openjpa.jdbc.schema.SchemaTool;
|
import org.apache.openjpa.jdbc.schema.SchemaTool;
|
||||||
import org.apache.openjpa.jdbc.schema.Schemas;
|
import org.apache.openjpa.jdbc.schema.Schemas;
|
||||||
import org.apache.openjpa.jdbc.schema.Table;
|
import org.apache.openjpa.jdbc.schema.Table;
|
||||||
|
import org.apache.openjpa.jdbc.schema.Unique;
|
||||||
import org.apache.openjpa.jdbc.sql.DBDictionary;
|
import org.apache.openjpa.jdbc.sql.DBDictionary;
|
||||||
import org.apache.openjpa.jdbc.sql.RowImpl;
|
import org.apache.openjpa.jdbc.sql.RowImpl;
|
||||||
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
||||||
|
@ -49,6 +51,8 @@ import org.apache.openjpa.lib.util.Localizer;
|
||||||
import org.apache.openjpa.lib.util.Options;
|
import org.apache.openjpa.lib.util.Options;
|
||||||
import org.apache.openjpa.meta.JavaTypes;
|
import org.apache.openjpa.meta.JavaTypes;
|
||||||
import org.apache.openjpa.util.InvalidStateException;
|
import org.apache.openjpa.util.InvalidStateException;
|
||||||
|
import org.apache.openjpa.util.UserException;
|
||||||
|
|
||||||
import serp.util.Numbers;
|
import serp.util.Numbers;
|
||||||
import serp.util.Strings;
|
import serp.util.Strings;
|
||||||
|
|
||||||
|
@ -86,6 +90,7 @@ public class TableJDBCSeq
|
||||||
private String _table = "OPENJPA_SEQUENCE_TABLE";
|
private String _table = "OPENJPA_SEQUENCE_TABLE";
|
||||||
private String _seqColumnName = "SEQUENCE_VALUE";
|
private String _seqColumnName = "SEQUENCE_VALUE";
|
||||||
private String _pkColumnName = "ID";
|
private String _pkColumnName = "ID";
|
||||||
|
private String[] _uniqueColumnNames;
|
||||||
|
|
||||||
private Column _seqColumn = null;
|
private Column _seqColumn = null;
|
||||||
private Column _pkColumn = null;
|
private Column _pkColumn = null;
|
||||||
|
@ -191,6 +196,20 @@ public class TableJDBCSeq
|
||||||
public void setInitialValue(int intValue) {
|
public void setInitialValue(int intValue) {
|
||||||
_intValue = intValue;
|
_intValue = intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the names of the columns on which a unique constraint is set.
|
||||||
|
* @param columnsNames are passed as a single String concatenated with
|
||||||
|
* a '|' character. This method parses it back to array of Strings.
|
||||||
|
*/
|
||||||
|
public void setUniqueColumns(String columnNames) {
|
||||||
|
_uniqueColumnNames = (StringUtils.isEmpty(columnNames))
|
||||||
|
? null : StringUtils.split(columnNames, '|');
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUniqueColumns() {
|
||||||
|
return StringUtils.join(_uniqueColumnNames, '|');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #setAllocate}. Retained for backwards
|
* @deprecated Use {@link #setAllocate}. Retained for backwards
|
||||||
|
@ -235,7 +254,12 @@ public class TableJDBCSeq
|
||||||
if (schema == null)
|
if (schema == null)
|
||||||
schema = group.addSchema(schemaName);
|
schema = group.addSchema(schemaName);
|
||||||
|
|
||||||
schema.importTable(_pkColumn.getTable());
|
Table copy = schema.importTable(_pkColumn.getTable());
|
||||||
|
// importTable() does not import unique constraints
|
||||||
|
Unique[] uniques = _pkColumn.getTable().getUniques();
|
||||||
|
for (Unique u : uniques) {
|
||||||
|
copy.importUnique(u);
|
||||||
|
}
|
||||||
// we need to reset the table name in the column with the
|
// we need to reset the table name in the column with the
|
||||||
// fully qualified name for matching the table name from the
|
// fully qualified name for matching the table name from the
|
||||||
// Column.
|
// Column.
|
||||||
|
@ -244,7 +268,6 @@ public class TableJDBCSeq
|
||||||
// some databases require to create an index for the sequence table
|
// some databases require to create an index for the sequence table
|
||||||
_conf.getDBDictionaryInstance().createIndexIfNecessary(schema,
|
_conf.getDBDictionaryInstance().createIndexIfNecessary(schema,
|
||||||
_table, _pkColumn);
|
_table, _pkColumn);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,6 +384,19 @@ public class TableJDBCSeq
|
||||||
(_seqColumnName, table));
|
(_seqColumnName, table));
|
||||||
_seqColumn.setType(dict.getPreferredType(Types.BIGINT));
|
_seqColumn.setType(dict.getPreferredType(Types.BIGINT));
|
||||||
_seqColumn.setJavaType(JavaTypes.LONG);
|
_seqColumn.setJavaType(JavaTypes.LONG);
|
||||||
|
|
||||||
|
if (_uniqueColumnNames != null) {
|
||||||
|
String uniqueName = dict.getValidUniqueName("UNQ", table);
|
||||||
|
Unique u = table.addUnique(uniqueName);
|
||||||
|
for (String columnName : _uniqueColumnNames) {
|
||||||
|
if (!table.containsColumn(columnName))
|
||||||
|
throw new UserException(_loc.get("unique-missing-column",
|
||||||
|
columnName, table.getName(), table.getColumnNames()));
|
||||||
|
Column col = table.getColumn(columnName);
|
||||||
|
u.addColumn(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
package org.apache.openjpa.jdbc.meta;
|
package org.apache.openjpa.jdbc.meta;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Collection;
|
import java.util.Map.Entry;
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
|
import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
|
||||||
|
@ -38,6 +38,7 @@ import org.apache.openjpa.jdbc.schema.Unique;
|
||||||
import org.apache.openjpa.lib.meta.SourceTracker;
|
import org.apache.openjpa.lib.meta.SourceTracker;
|
||||||
import org.apache.openjpa.lib.util.Localizer;
|
import org.apache.openjpa.lib.util.Localizer;
|
||||||
import org.apache.openjpa.lib.xml.Commentable;
|
import org.apache.openjpa.lib.xml.Commentable;
|
||||||
|
import org.apache.openjpa.meta.MetaDataContext;
|
||||||
import org.apache.openjpa.util.UserException;
|
import org.apache.openjpa.util.UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,7 +65,8 @@ public class ClassMappingInfo
|
||||||
private File _file = null;
|
private File _file = null;
|
||||||
private int _srcType = SRC_OTHER;
|
private int _srcType = SRC_OTHER;
|
||||||
private String[] _comments = null;
|
private String[] _comments = null;
|
||||||
private Collection _uniques = null;//Unique
|
// Unique constraints indexed by primary or secondary table name
|
||||||
|
private Map<String,List<Unique>> _uniques;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The described class name.
|
* The described class name.
|
||||||
|
@ -221,11 +223,12 @@ public class ClassMappingInfo
|
||||||
_seconds = new HashMap();
|
_seconds = new HashMap();
|
||||||
_seconds.put(tableName, cols);
|
_seconds.put(tableName, cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the table for the given class.
|
* Return the named table for the given class.
|
||||||
*/
|
*/
|
||||||
public Table getTable(final ClassMapping cls, boolean adapt) {
|
public Table getTable(final ClassMapping cls, String tableName,
|
||||||
|
boolean adapt) {
|
||||||
Table t = createTable(cls, new TableDefaults() {
|
Table t = createTable(cls, new TableDefaults() {
|
||||||
public String get(Schema schema) {
|
public String get(Schema schema) {
|
||||||
// delay this so that we don't do schema reflection for unique
|
// delay this so that we don't do schema reflection for unique
|
||||||
|
@ -233,13 +236,20 @@ public class ClassMappingInfo
|
||||||
return cls.getMappingRepository().getMappingDefaults().
|
return cls.getMappingRepository().getMappingDefaults().
|
||||||
getTableName(cls, schema);
|
getTableName(cls, schema);
|
||||||
}
|
}
|
||||||
}, _schemaName, _tableName, adapt);
|
}, _schemaName, tableName, adapt);
|
||||||
t.setComment(cls.getTypeAlias() == null
|
t.setComment(cls.getTypeAlias() == null
|
||||||
? cls.getDescribedType().getName()
|
? cls.getDescribedType().getName()
|
||||||
: cls.getTypeAlias());
|
: cls.getTypeAlias());
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the primary table for the given class.
|
||||||
|
*/
|
||||||
|
public Table getTable(final ClassMapping cls, boolean adapt) {
|
||||||
|
return getTable(cls, _tableName, adapt);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the datastore identity columns for the given class, based on the
|
* Return the datastore identity columns for the given class, based on the
|
||||||
* given templates.
|
* given templates.
|
||||||
|
@ -340,51 +350,87 @@ public class ClassMappingInfo
|
||||||
_seconds.put(key, cinfo._seconds.get(key));
|
_seconds.put(key, cinfo._seconds.get(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cinfo._uniques != null)
|
if (cinfo._uniques != null) {
|
||||||
_uniques = new ArrayList(cinfo._uniques);
|
if (_uniques == null)
|
||||||
}
|
_uniques = new HashMap<String, List<Unique>>();
|
||||||
|
for (Entry<String, List<Unique>> entry : cinfo._uniques.entrySet())
|
||||||
|
if (!_uniques.containsKey(entry.getKey()))
|
||||||
|
_uniques.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
public void addUnique(Unique unique) {
|
}
|
||||||
if (unique == null)
|
|
||||||
return;
|
/**
|
||||||
|
* Add a unique constraint for the given table.
|
||||||
|
* @param table must be primary table or secondary table name added a
|
||||||
|
* priori to this receiver.
|
||||||
|
* @param unique the unique constraint. null means no-op.
|
||||||
|
*/
|
||||||
|
public void addUnique(String table, Unique unique) {
|
||||||
|
if (!StringUtils.equals(_tableName, table) &&
|
||||||
|
(_seconds == null || !_seconds.containsKey(table))) {
|
||||||
|
throw new UserException(_loc.get("unique-no-table",
|
||||||
|
new Object[]{table, _className, _tableName,
|
||||||
|
((_seconds == null) ? "" : _seconds.keySet())}));
|
||||||
|
}
|
||||||
|
if (unique == null)
|
||||||
|
return;
|
||||||
if (_uniques == null)
|
if (_uniques == null)
|
||||||
_uniques = new ArrayList();
|
_uniques = new HashMap<String,List<Unique>>();
|
||||||
_uniques.add(unique);
|
unique.setTableName(table);
|
||||||
|
List<Unique> uniques = _uniques.get(table);
|
||||||
|
if (uniques == null) {
|
||||||
|
uniques = new ArrayList<Unique>();
|
||||||
|
uniques.add(unique);
|
||||||
|
_uniques.put(table, uniques);
|
||||||
|
} else {
|
||||||
|
uniques.add(unique);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unique[] getUniques() {
|
/**
|
||||||
return (_uniques == null) ? new Unique[0] :
|
* Get the unique constraints of the given primary or secondary table.
|
||||||
(Unique[])_uniques.toArray(new Unique[_uniques.size()]);
|
*/
|
||||||
|
public Unique[] getUniques(String table) {
|
||||||
|
if (_uniques == null || _uniques.isEmpty()
|
||||||
|
|| _uniques.containsKey(table))
|
||||||
|
return new Unique[0];
|
||||||
|
List<Unique> uniques = _uniques.get(table);
|
||||||
|
return uniques.toArray(new Unique[uniques.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unique[] getUniques(ClassMapping cm, boolean adapt) {
|
/**
|
||||||
|
* Get all the unique constraints associated with both the primary and/or
|
||||||
|
* secondary tables.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public Unique[] getUniques(MetaDataContext cm, boolean adapt) {
|
||||||
if (_uniques == null || _uniques.isEmpty())
|
if (_uniques == null || _uniques.isEmpty())
|
||||||
return new Unique[0];
|
return new Unique[0];
|
||||||
|
List<Unique> result = new ArrayList<Unique>();
|
||||||
Iterator uniqueConstraints = _uniques.iterator();
|
for (String tableName : _uniques.keySet()) {
|
||||||
Table table = cm.getTable();
|
List<Unique> uniqueConstraints = _uniques.get(tableName);
|
||||||
Collection result = new ArrayList();
|
for (Unique template : uniqueConstraints) {
|
||||||
while (uniqueConstraints.hasNext()) {
|
Column[] templateColumns = template.getColumns();
|
||||||
Unique template = (Unique) uniqueConstraints.next();
|
Column[] uniqueColumns = new Column[templateColumns.length];
|
||||||
Column[] templateColumns = template.getColumns();
|
Table table = getTable((ClassMapping)cm, tableName, adapt);
|
||||||
Column[] uniqueColumns = new Column[templateColumns.length];
|
for (int i=0; i<uniqueColumns.length; i++) {
|
||||||
boolean missingColumn = true;
|
String columnName = templateColumns[i].getName();
|
||||||
for (int i=0; i<uniqueColumns.length; i++) {
|
if (!table.containsColumn(columnName)) {
|
||||||
String columnName = templateColumns[i].getName();
|
throw new UserException(_loc.get("unique-missing-column",
|
||||||
Column uniqueColumn = table.getColumn(columnName);
|
new Object[]{cm, columnName, tableName,
|
||||||
missingColumn = (uniqueColumn == null);
|
table.getColumnNames()}));
|
||||||
if (missingColumn) {
|
}
|
||||||
throw new UserException(_loc.get("missing-unique-column",
|
Column uniqueColumn = table.getColumn(columnName);
|
||||||
cm, table, columnName));
|
uniqueColumns[i] = uniqueColumn;
|
||||||
}
|
}
|
||||||
uniqueColumns[i] = uniqueColumn;
|
Unique unique = createUnique(cm, "unique", template,
|
||||||
}
|
uniqueColumns, adapt);
|
||||||
Unique unique = super.createUnique(cm, "unique", template,
|
if (unique != null)
|
||||||
uniqueColumns, adapt);
|
result.add(unique);
|
||||||
if (unique != null)
|
}
|
||||||
result.add(unique);
|
|
||||||
}
|
}
|
||||||
return (Unique[]) result.toArray(new Unique[result.size()]);
|
return result.toArray(new Unique[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getSourceFile() {
|
public File getSourceFile() {
|
||||||
|
|
|
@ -70,7 +70,8 @@ public class FieldMapping
|
||||||
private Index _idx = null;
|
private Index _idx = null;
|
||||||
private boolean _outer = false;
|
private boolean _outer = false;
|
||||||
private int _fetchMode = Integer.MAX_VALUE;
|
private int _fetchMode = Integer.MAX_VALUE;
|
||||||
|
private Unique[] _joinTableUniques; // Unique constraints on JoinTable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
|
@ -183,6 +184,14 @@ public class FieldMapping
|
||||||
_unq = unq;
|
_unq = unq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Unique[] getJoinTableUniques() {
|
||||||
|
return _joinTableUniques;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJoinTableUniques(Unique[] unqs) {
|
||||||
|
_joinTableUniques = unqs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index on join foreign key columns.
|
* Index on join foreign key columns.
|
||||||
*/
|
*/
|
||||||
|
@ -252,6 +261,13 @@ public class FieldMapping
|
||||||
_val.refSchemaComponents();
|
_val.refSchemaComponents();
|
||||||
_key.refSchemaComponents();
|
_key.refSchemaComponents();
|
||||||
_elem.refSchemaComponents();
|
_elem.refSchemaComponents();
|
||||||
|
if (_joinTableUniques != null) {
|
||||||
|
for (Unique joinUnique : _joinTableUniques) {
|
||||||
|
for (Column col : joinUnique.getColumns()) {
|
||||||
|
col.ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -538,6 +554,7 @@ public class FieldMapping
|
||||||
_io = _info.getColumnIO();
|
_io = _info.getColumnIO();
|
||||||
_outer = _info.isJoinOuter();
|
_outer = _info.isJoinOuter();
|
||||||
_unq = _info.getJoinUnique(this, false, adapt);
|
_unq = _info.getJoinUnique(this, false, adapt);
|
||||||
|
_joinTableUniques = _info.getJoinTableUniques(this, false, adapt);
|
||||||
_idx = _info.getJoinIndex(this, adapt);
|
_idx = _info.getJoinIndex(this, adapt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.openjpa.jdbc.meta;
|
package org.apache.openjpa.jdbc.meta;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.openjpa.jdbc.schema.Column;
|
import org.apache.openjpa.jdbc.schema.Column;
|
||||||
|
@ -31,7 +33,9 @@ import org.apache.openjpa.jdbc.schema.Unique;
|
||||||
import org.apache.openjpa.lib.util.Localizer;
|
import org.apache.openjpa.lib.util.Localizer;
|
||||||
import org.apache.openjpa.lib.xml.Commentable;
|
import org.apache.openjpa.lib.xml.Commentable;
|
||||||
import org.apache.openjpa.meta.JavaTypes;
|
import org.apache.openjpa.meta.JavaTypes;
|
||||||
|
import org.apache.openjpa.meta.MetaDataContext;
|
||||||
import org.apache.openjpa.util.MetaDataException;
|
import org.apache.openjpa.util.MetaDataException;
|
||||||
|
import org.apache.openjpa.util.UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the mapping from a field to the schema, in raw form.
|
* Information about the mapping from a field to the schema, in raw form.
|
||||||
|
@ -40,6 +44,7 @@ import org.apache.openjpa.util.MetaDataException;
|
||||||
* with the relevant pieces of information filled in.
|
* with the relevant pieces of information filled in.
|
||||||
*
|
*
|
||||||
* @author Abe White
|
* @author Abe White
|
||||||
|
* @author Pinaki Poddar
|
||||||
*/
|
*/
|
||||||
public class FieldMappingInfo
|
public class FieldMappingInfo
|
||||||
extends MappingInfo
|
extends MappingInfo
|
||||||
|
@ -53,6 +58,7 @@ public class FieldMappingInfo
|
||||||
private Column _orderCol = null;
|
private Column _orderCol = null;
|
||||||
private boolean _canOrderCol = true;
|
private boolean _canOrderCol = true;
|
||||||
private String[] _comments = null;
|
private String[] _comments = null;
|
||||||
|
private List<Unique> _joinTableUniques; // Unique constraints on the JoinTable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The user-supplied name of the table for this field.
|
* The user-supplied name of the table for this field.
|
||||||
|
@ -185,8 +191,47 @@ public class FieldMappingInfo
|
||||||
getJoinUnique(field, fk.getTable(), fk.getColumns());
|
getJoinUnique(field, fk.getTable(), fk.getColumns());
|
||||||
return createUnique(field, "join", unq, fk.getColumns(), adapt);
|
return createUnique(field, "join", unq, fk.getColumns(), adapt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Add Unique Constraint to the Join Table.
|
||||||
|
*/
|
||||||
|
public void addJoinTableUnique(Unique u) {
|
||||||
|
if (_joinTableUniques == null)
|
||||||
|
_joinTableUniques = new ArrayList<Unique>();
|
||||||
|
_joinTableUniques.add(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the unique constraints associated with the Sequence table.
|
||||||
|
*/
|
||||||
|
public Unique[] getJoinTableUniques(FieldMapping field, boolean def,
|
||||||
|
boolean adapt) {
|
||||||
|
return getUniques(field, _joinTableUniques, def, adapt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Unique[] getUniques(FieldMapping field, List<Unique> uniques,
|
||||||
|
boolean def, boolean adapt) {
|
||||||
|
if (uniques == null || uniques.isEmpty())
|
||||||
|
return new Unique[0];
|
||||||
|
Collection<Unique> result = new ArrayList<Unique>();
|
||||||
|
for (Unique template : uniques) {
|
||||||
|
Column[] templateColumns = template.getColumns();
|
||||||
|
Column[] uniqueColumns = new Column[templateColumns.length];
|
||||||
|
Table table = getTable(field, true, adapt);
|
||||||
|
for (int i=0; i<uniqueColumns.length; i++) {
|
||||||
|
String columnName = templateColumns[i].getName();
|
||||||
|
Column uniqueColumn = table.getColumn(columnName);
|
||||||
|
uniqueColumns[i] = uniqueColumn;
|
||||||
|
}
|
||||||
|
Unique unique = createUnique(field, "unique", template,
|
||||||
|
uniqueColumns, adapt);
|
||||||
|
if (unique != null)
|
||||||
|
result.add(unique);
|
||||||
|
}
|
||||||
|
return result.toArray(new Unique[result.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* Index on the field join.
|
* Index on the field join.
|
||||||
*/
|
*/
|
||||||
public Index getJoinIndex(FieldMapping field, boolean adapt) {
|
public Index getJoinIndex(FieldMapping field, boolean adapt) {
|
||||||
|
@ -261,6 +306,7 @@ public class FieldMappingInfo
|
||||||
|
|
||||||
syncIndex(field, field.getJoinIndex());
|
syncIndex(field, field.getJoinIndex());
|
||||||
syncUnique(field, field.getJoinUnique());
|
syncUnique(field, field.getJoinUnique());
|
||||||
|
syncJoinTableUniques(field, field.getJoinTableUniques());
|
||||||
syncOrderColumn(field);
|
syncOrderColumn(field);
|
||||||
syncStrategy(field);
|
syncStrategy(field);
|
||||||
}
|
}
|
||||||
|
@ -290,6 +336,24 @@ public class FieldMappingInfo
|
||||||
else
|
else
|
||||||
_orderCol = null;
|
_orderCol = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets internal constraint information to match given mapped constraint.
|
||||||
|
*/
|
||||||
|
protected void syncJoinTableUniques(MetaDataContext context, Unique[] unqs) {
|
||||||
|
if (unqs == null) {
|
||||||
|
_joinTableUniques = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_joinTableUniques = new ArrayList<Unique>();
|
||||||
|
for (Unique unique:unqs) {
|
||||||
|
Unique copy = new Unique();
|
||||||
|
copy.setName(unique.getName());
|
||||||
|
copy.setDeferred(unique.isDeferred());
|
||||||
|
_joinTableUniques.add(unique);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean hasSchemaComponents() {
|
public boolean hasSchemaComponents() {
|
||||||
return super.hasSchemaComponents() || _tableName != null
|
return super.hasSchemaComponents() || _tableName != null
|
||||||
|
|
|
@ -927,7 +927,7 @@ public abstract class MappingInfo
|
||||||
context, dict.platform));
|
context, dict.platform));
|
||||||
deferred = false;
|
deferred = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Unique unq = table.addUnique(name);
|
Unique unq = table.addUnique(name);
|
||||||
unq.setDeferred(deferred);
|
unq.setDeferred(deferred);
|
||||||
unq.setColumns(cols);
|
unq.setColumns(cols);
|
||||||
|
@ -1534,7 +1534,7 @@ public abstract class MappingInfo
|
||||||
_unq.setName(unq.getName());
|
_unq.setName(unq.getName());
|
||||||
_unq.setDeferred(unq.isDeferred());
|
_unq.setDeferred(unq.isDeferred());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets internal constraint and column information to match given mapped
|
* Sets internal constraint and column information to match given mapped
|
||||||
* constraint.
|
* constraint.
|
||||||
|
|
|
@ -19,11 +19,16 @@
|
||||||
package org.apache.openjpa.jdbc.meta;
|
package org.apache.openjpa.jdbc.meta;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.openjpa.jdbc.conf.JDBCSeqValue;
|
import org.apache.openjpa.jdbc.conf.JDBCSeqValue;
|
||||||
import org.apache.openjpa.jdbc.kernel.ClassTableJDBCSeq;
|
import org.apache.openjpa.jdbc.kernel.ClassTableJDBCSeq;
|
||||||
import org.apache.openjpa.jdbc.kernel.TableJDBCSeq;
|
import org.apache.openjpa.jdbc.kernel.TableJDBCSeq;
|
||||||
import org.apache.openjpa.jdbc.kernel.ValueTableJDBCSeq;
|
import org.apache.openjpa.jdbc.kernel.ValueTableJDBCSeq;
|
||||||
|
import org.apache.openjpa.jdbc.schema.Unique;
|
||||||
import org.apache.openjpa.lib.conf.PluginValue;
|
import org.apache.openjpa.lib.conf.PluginValue;
|
||||||
import org.apache.openjpa.meta.SequenceMetaData;
|
import org.apache.openjpa.meta.SequenceMetaData;
|
||||||
|
|
||||||
|
@ -55,13 +60,15 @@ public class SequenceMapping
|
||||||
private static final String PROP_SEQUENCE_COL = "SequenceColumn";
|
private static final String PROP_SEQUENCE_COL = "SequenceColumn";
|
||||||
private static final String PROP_PK_COL = "PrimaryKeyColumn";
|
private static final String PROP_PK_COL = "PrimaryKeyColumn";
|
||||||
private static final String PROP_PK_VALUE = "PrimaryKeyValue";
|
private static final String PROP_PK_VALUE = "PrimaryKeyValue";
|
||||||
|
private static final String PROP_UNIQUE = "UniqueColumns";
|
||||||
|
|
||||||
private File _mapFile = null;
|
private File _mapFile = null;
|
||||||
private String _table = null;
|
private String _table = null;
|
||||||
private String _sequenceColumn = null;
|
private String _sequenceColumn = null;
|
||||||
private String _primaryKeyColumn = null;
|
private String _primaryKeyColumn = null;
|
||||||
private String _primaryKeyValue = null;
|
private String _primaryKeyValue = null;
|
||||||
|
private String[] _uniqueColumns = null;
|
||||||
|
|
||||||
public SequenceMapping(String name, MappingRepository repos) {
|
public SequenceMapping(String name, MappingRepository repos) {
|
||||||
super(name, repos);
|
super(name, repos);
|
||||||
}
|
}
|
||||||
|
@ -138,6 +145,14 @@ public class SequenceMapping
|
||||||
_primaryKeyValue = primaryKeyValue;
|
_primaryKeyValue = primaryKeyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUniqueColumns(String[] cols) {
|
||||||
|
_uniqueColumns = cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getUniqueColumns() {
|
||||||
|
return _uniqueColumns;
|
||||||
|
}
|
||||||
|
|
||||||
protected PluginValue newPluginValue(String property) {
|
protected PluginValue newPluginValue(String property) {
|
||||||
return new JDBCSeqValue(property);
|
return new JDBCSeqValue(property);
|
||||||
}
|
}
|
||||||
|
@ -148,5 +163,11 @@ public class SequenceMapping
|
||||||
appendProperty(props, PROP_SEQUENCE_COL, _sequenceColumn);
|
appendProperty(props, PROP_SEQUENCE_COL, _sequenceColumn);
|
||||||
appendProperty(props, PROP_PK_COL, _primaryKeyColumn);
|
appendProperty(props, PROP_PK_COL, _primaryKeyColumn);
|
||||||
appendProperty(props, PROP_PK_VALUE, _primaryKeyValue);
|
appendProperty(props, PROP_PK_VALUE, _primaryKeyValue);
|
||||||
|
// Array of unique column names are passed to configuration
|
||||||
|
// as a single string "x|y|z". The configurable (TableJDBCSeq) must
|
||||||
|
// parse it back.
|
||||||
|
if (_uniqueColumns != null && _uniqueColumns.length > 0)
|
||||||
|
appendProperty(props, PROP_UNIQUE,
|
||||||
|
StringUtils.join(_uniqueColumns,'|'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,6 +252,11 @@ public class Table
|
||||||
return _rels;
|
return _rels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getColumnNames() {
|
||||||
|
return _colMap == null ? new String[0] :
|
||||||
|
(String[])_colMap.keySet().toArray(new String[_colMap.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the column with the given name, or null if none.
|
* Return the column with the given name, or null if none.
|
||||||
*/
|
*/
|
||||||
|
@ -260,6 +265,17 @@ public class Table
|
||||||
return null;
|
return null;
|
||||||
return (Column) _colMap.get(name.toUpperCase());
|
return (Column) _colMap.get(name.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Affirms if this table contains the column of the given name without any
|
||||||
|
* side-effect.
|
||||||
|
* @see Table#getColumn(String) can have side-effect of creating a column
|
||||||
|
* for dynamic table implementation.
|
||||||
|
*/
|
||||||
|
public boolean containsColumn(String name) {
|
||||||
|
return name != null && _colMap != null
|
||||||
|
&& _colMap.containsKey(name.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a column to the table.
|
* Add a column to the table.
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.openjpa.jdbc.schema;
|
package org.apache.openjpa.jdbc.schema;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a unique constraint. It can also represent a partial constraint.
|
* Represents a unique constraint. It can also represent a partial constraint.
|
||||||
*
|
*
|
||||||
|
@ -25,11 +27,12 @@ package org.apache.openjpa.jdbc.schema;
|
||||||
*/
|
*/
|
||||||
public class Unique
|
public class Unique
|
||||||
extends LocalConstraint {
|
extends LocalConstraint {
|
||||||
|
private boolean _isAutoSetName = false;
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
public Unique() {
|
public Unique() {
|
||||||
|
_isAutoSetName = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,6 +48,26 @@ public class Unique
|
||||||
public boolean isLogical() {
|
public boolean isLogical() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addColumn(Column col) {
|
||||||
|
super.addColumn(col);
|
||||||
|
col.setNotNull(true);
|
||||||
|
if (_isAutoSetName && getTable() == null) {
|
||||||
|
String pre = StringUtils.isEmpty(getName()) ? "UNQ" : getName();
|
||||||
|
setName(pre + "_" + col.getName());
|
||||||
|
_isAutoSetName = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the name of the constraint. This method cannot be called if the
|
||||||
|
* constraint already belongs to a table.
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
super.setName(name);
|
||||||
|
_isAutoSetName = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the structure of this primary key matches that of
|
* Return true if the structure of this primary key matches that of
|
||||||
|
|
|
@ -410,6 +410,8 @@ untraversable-path: Result path "{2}" in result type "{1}" of mapping "{0}" \
|
||||||
attempts to traverse through a non-relation field.
|
attempts to traverse through a non-relation field.
|
||||||
num-cols-path: Result path "{2}" in result type "{1}" of mapping "{0}" \
|
num-cols-path: Result path "{2}" in result type "{1}" of mapping "{0}" \
|
||||||
attempts to map a field that does not have exactly 1 column.
|
attempts to map a field that does not have exactly 1 column.
|
||||||
missing-unique-column: A unique constraint specified in mapping of class "{0}" \
|
unique-missing-column: The column "{1}" in a unique constraint in "{0}" on \
|
||||||
to table "{1}" includes a column "{2}". However, the column does not \
|
table "{2}" can not be found in the list of available columns "{3}".
|
||||||
exist in "{1}" table.
|
unique-no-table: A unique constraint on table "{0}" can not be added to \
|
||||||
|
mapping of class "{1}" because the table does neither match its primary \
|
||||||
|
table "{2}" nor any of its secondary table(s) "{3}".
|
|
@ -61,6 +61,7 @@ import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
import org.apache.openjpa.jdbc.meta.ClassMappingInfo;
|
import org.apache.openjpa.jdbc.meta.ClassMappingInfo;
|
||||||
import org.apache.openjpa.jdbc.meta.Discriminator;
|
import org.apache.openjpa.jdbc.meta.Discriminator;
|
||||||
import org.apache.openjpa.jdbc.meta.FieldMapping;
|
import org.apache.openjpa.jdbc.meta.FieldMapping;
|
||||||
|
import org.apache.openjpa.jdbc.meta.FieldMappingInfo;
|
||||||
import org.apache.openjpa.jdbc.meta.MappingInfo;
|
import org.apache.openjpa.jdbc.meta.MappingInfo;
|
||||||
import org.apache.openjpa.jdbc.meta.MappingRepository;
|
import org.apache.openjpa.jdbc.meta.MappingRepository;
|
||||||
import org.apache.openjpa.jdbc.meta.QueryResultMapping;
|
import org.apache.openjpa.jdbc.meta.QueryResultMapping;
|
||||||
|
@ -80,6 +81,7 @@ import org.apache.openjpa.lib.util.Localizer;
|
||||||
import org.apache.openjpa.meta.ClassMetaData;
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
import org.apache.openjpa.meta.FieldMetaData;
|
import org.apache.openjpa.meta.FieldMetaData;
|
||||||
import org.apache.openjpa.meta.JavaTypes;
|
import org.apache.openjpa.meta.JavaTypes;
|
||||||
|
import org.apache.openjpa.meta.MetaDataContext;
|
||||||
import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser;
|
import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser;
|
||||||
import static org.apache.openjpa.persistence.jdbc.MappingTag.*;
|
import static org.apache.openjpa.persistence.jdbc.MappingTag.*;
|
||||||
import org.apache.openjpa.util.InternalException;
|
import org.apache.openjpa.util.InternalException;
|
||||||
|
@ -244,10 +246,16 @@ public class AnnotationPersistenceMappingParser
|
||||||
meta.setAllocate(gen.allocationSize());
|
meta.setAllocate(gen.allocationSize());
|
||||||
meta.setSource(getSourceFile(), (el instanceof Class) ? el : null,
|
meta.setSource(getSourceFile(), (el instanceof Class) ? el : null,
|
||||||
meta.SRC_ANNOTATIONS);
|
meta.SRC_ANNOTATIONS);
|
||||||
|
|
||||||
//### EJB3
|
switch (gen.uniqueConstraints().length) {
|
||||||
if (gen.uniqueConstraints().length > 0 && log.isWarnEnabled())
|
case 0:
|
||||||
log.warn(_loc.get("unique-constraints", name));
|
break; // nothing to do
|
||||||
|
case 1:
|
||||||
|
meta.setUniqueColumns(gen.uniqueConstraints()[0].columnNames());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.warn(_loc.get("unique-many-on-seq-unsupported", el, name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -464,8 +472,7 @@ public class AnnotationPersistenceMappingParser
|
||||||
Log log = getLog();
|
Log log = getLog();
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
List<Column> joins;
|
List<Column> joins = null;
|
||||||
boolean warnUnique = false;
|
|
||||||
for (SecondaryTable table : tables) {
|
for (SecondaryTable table : tables) {
|
||||||
name = table.name();
|
name = table.name();
|
||||||
if (StringUtils.isEmpty(name))
|
if (StringUtils.isEmpty(name))
|
||||||
|
@ -476,14 +483,10 @@ public class AnnotationPersistenceMappingParser
|
||||||
joins = new ArrayList<Column>(table.pkJoinColumns().length);
|
joins = new ArrayList<Column>(table.pkJoinColumns().length);
|
||||||
for (PrimaryKeyJoinColumn join : table.pkJoinColumns())
|
for (PrimaryKeyJoinColumn join : table.pkJoinColumns())
|
||||||
joins.add(newColumn(join));
|
joins.add(newColumn(join));
|
||||||
info.setSecondaryTableJoinColumns(name, joins);
|
}
|
||||||
}
|
info.setSecondaryTableJoinColumns(name, joins);
|
||||||
warnUnique |= table.uniqueConstraints().length > 0;
|
addUniqueConstraints(name, cm, info, table.uniqueConstraints());
|
||||||
}
|
}
|
||||||
|
|
||||||
//### EJB3
|
|
||||||
if (warnUnique && log.isWarnEnabled())
|
|
||||||
log.warn(_loc.get("unique-constraints", cm));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -494,10 +497,38 @@ public class AnnotationPersistenceMappingParser
|
||||||
if (tableName != null)
|
if (tableName != null)
|
||||||
cm.getMappingInfo().setTableName(tableName);
|
cm.getMappingInfo().setTableName(tableName);
|
||||||
|
|
||||||
for (UniqueConstraint uniqueConstraint:table.uniqueConstraints()) {
|
addUniqueConstraints(tableName, cm, cm.getMappingInfo(),
|
||||||
Unique unique = newUnique(cm, null, uniqueConstraint.columnNames());
|
table.uniqueConstraints());
|
||||||
cm.getMappingInfo().addUnique(unique);
|
}
|
||||||
}
|
|
||||||
|
Unique createUniqueConstraint(MetaDataContext ctx, UniqueConstraint anno) {
|
||||||
|
String[] columnNames = anno.columnNames();
|
||||||
|
if (columnNames == null || columnNames.length == 0)
|
||||||
|
throw new UserException(_loc.get("unique-no-column", ctx));
|
||||||
|
Unique uniqueConstraint = new Unique();
|
||||||
|
for (int i=0; i<columnNames.length; i++) {
|
||||||
|
if (StringUtils.isEmpty(columnNames[i]))
|
||||||
|
throw new UserException(_loc.get("unique-empty-column",
|
||||||
|
Arrays.toString(columnNames), ctx));
|
||||||
|
Column column = new Column();
|
||||||
|
column.setName(columnNames[i]);
|
||||||
|
uniqueConstraint.addColumn(column);
|
||||||
|
}
|
||||||
|
return uniqueConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addUniqueConstraints(String table, MetaDataContext ctx,
|
||||||
|
MappingInfo info, UniqueConstraint...uniqueConstraints) {
|
||||||
|
for (UniqueConstraint anno : uniqueConstraints) {
|
||||||
|
Unique unique = createUniqueConstraint(ctx, anno);
|
||||||
|
unique.setTableName(table);
|
||||||
|
if (info instanceof ClassMappingInfo)
|
||||||
|
((ClassMappingInfo)info).addUnique(table, unique);
|
||||||
|
else if (info instanceof FieldMappingInfo)
|
||||||
|
((FieldMappingInfo)info).addJoinTableUnique(unique);
|
||||||
|
else
|
||||||
|
throw new InternalException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1261,8 +1292,7 @@ public class AnnotationPersistenceMappingParser
|
||||||
}
|
}
|
||||||
|
|
||||||
unique |= (pcols[i].unique()) ? TRUE : FALSE;
|
unique |= (pcols[i].unique()) ? TRUE : FALSE;
|
||||||
secondary = trackSecondaryTable(fm, secondary,
|
secondary = trackSecondaryTable(fm, secondary, pcols[i].table(), i);
|
||||||
pcols[i].table(), i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setColumns(fm, fm.getValueInfo(), cols, unique);
|
setColumns(fm, fm.getValueInfo(), cols, unique);
|
||||||
|
@ -1337,11 +1367,13 @@ public class AnnotationPersistenceMappingParser
|
||||||
* Parse @JoinTable.
|
* Parse @JoinTable.
|
||||||
*/
|
*/
|
||||||
private void parseJoinTable(FieldMapping fm, JoinTable join) {
|
private void parseJoinTable(FieldMapping fm, JoinTable join) {
|
||||||
fm.getMappingInfo().setTableName(toTableName(join.schema(),
|
FieldMappingInfo info = fm.getMappingInfo();
|
||||||
join.name()));
|
info.setTableName(toTableName(join.schema(), join.name()));
|
||||||
parseJoinColumns(fm, fm.getMappingInfo(), false, join.joinColumns());
|
parseJoinColumns(fm, info, false, join.joinColumns());
|
||||||
parseJoinColumns(fm, fm.getElementMapping().getValueInfo(), false,
|
parseJoinColumns(fm, fm.getElementMapping().getValueInfo(), false,
|
||||||
join.inverseJoinColumns());
|
join.inverseJoinColumns());
|
||||||
|
addUniqueConstraints(info.getTableName(), fm, info,
|
||||||
|
join.uniqueConstraints());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1617,21 +1649,4 @@ public class AnnotationPersistenceMappingParser
|
||||||
col.setFlag (Column.FLAG_UNUPDATABLE, !join.updatable ());
|
col.setFlag (Column.FLAG_UNUPDATABLE, !join.updatable ());
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Unique newUnique(ClassMapping cm, String name,
|
|
||||||
String[] columnNames) {
|
|
||||||
if (columnNames == null || columnNames.length == 0)
|
|
||||||
return null;
|
|
||||||
Unique uniqueConstraint = new Unique();
|
|
||||||
uniqueConstraint.setName(name);
|
|
||||||
for (int i=0; i<columnNames.length; i++) {
|
|
||||||
if (StringUtils.isEmpty(columnNames[i]))
|
|
||||||
throw new UserException(_loc.get("empty-unique-column",
|
|
||||||
Arrays.toString(columnNames), cm));
|
|
||||||
Column column = new Column();
|
|
||||||
column.setName(columnNames[i]);
|
|
||||||
uniqueConstraint.addColumn(column);
|
|
||||||
}
|
|
||||||
return uniqueConstraint;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,12 +221,12 @@ public class AnnotationPersistenceMappingSerializer
|
||||||
AnnotationBuilder abTable = addAnnotation(Table.class, mapping);
|
AnnotationBuilder abTable = addAnnotation(Table.class, mapping);
|
||||||
serializeTable(info.getTableName(), Strings
|
serializeTable(info.getTableName(), Strings
|
||||||
.getClassName(mapping.getDescribedType()), null,
|
.getClassName(mapping.getDescribedType()), null,
|
||||||
info.getUniques(), abTable);
|
info.getUniques(info.getTableName()), abTable);
|
||||||
serializeColumns(info, ColType.PK_JOIN, null, abTable, cls);
|
serializeColumns(info, ColType.PK_JOIN, null, abTable, cls);
|
||||||
for (String second : info.getSecondaryTableNames()) {
|
for (String second : info.getSecondaryTableNames()) {
|
||||||
AnnotationBuilder abSecTable =
|
AnnotationBuilder abSecTable =
|
||||||
addAnnotation(SecondaryTable.class, mapping);
|
addAnnotation(SecondaryTable.class, mapping);
|
||||||
serializeTable(second, null, info, null, abSecTable);
|
serializeTable(second, null, info, info.getUniques(second), abSecTable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
import org.apache.openjpa.jdbc.meta.ClassMappingInfo;
|
import org.apache.openjpa.jdbc.meta.ClassMappingInfo;
|
||||||
import org.apache.openjpa.jdbc.meta.DiscriminatorMappingInfo;
|
import org.apache.openjpa.jdbc.meta.DiscriminatorMappingInfo;
|
||||||
import org.apache.openjpa.jdbc.meta.FieldMapping;
|
import org.apache.openjpa.jdbc.meta.FieldMapping;
|
||||||
|
import org.apache.openjpa.jdbc.meta.MappingInfo;
|
||||||
import org.apache.openjpa.jdbc.meta.MappingRepository;
|
import org.apache.openjpa.jdbc.meta.MappingRepository;
|
||||||
import org.apache.openjpa.jdbc.meta.QueryResultMapping;
|
import org.apache.openjpa.jdbc.meta.QueryResultMapping;
|
||||||
import org.apache.openjpa.jdbc.meta.SequenceMapping;
|
import org.apache.openjpa.jdbc.meta.SequenceMapping;
|
||||||
|
@ -56,6 +57,8 @@ import org.apache.openjpa.meta.FieldMetaData;
|
||||||
import org.apache.openjpa.meta.JavaTypes;
|
import org.apache.openjpa.meta.JavaTypes;
|
||||||
import org.apache.openjpa.meta.MetaDataRepository;
|
import org.apache.openjpa.meta.MetaDataRepository;
|
||||||
import org.apache.openjpa.persistence.XMLPersistenceMetaDataParser;
|
import org.apache.openjpa.persistence.XMLPersistenceMetaDataParser;
|
||||||
|
import org.apache.openjpa.util.InternalException;
|
||||||
|
|
||||||
import static org.apache.openjpa.persistence.jdbc.MappingTag.*;
|
import static org.apache.openjpa.persistence.jdbc.MappingTag.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -293,6 +296,9 @@ public class XMLPersistenceMappingParser
|
||||||
case COLUMN_NAME:
|
case COLUMN_NAME:
|
||||||
endColumnName();
|
endColumnName();
|
||||||
break;
|
break;
|
||||||
|
case TABLE_GEN:
|
||||||
|
endTableGenerator();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,8 +411,13 @@ public class XMLPersistenceMappingParser
|
||||||
Object scope = (cur instanceof ClassMetaData)
|
Object scope = (cur instanceof ClassMetaData)
|
||||||
? ((ClassMetaData) cur).getDescribedType() : null;
|
? ((ClassMetaData) cur).getDescribedType() : null;
|
||||||
seq.setSource(getSourceFile(), scope, seq.SRC_XML);
|
seq.setSource(getSourceFile(), scope, seq.SRC_XML);
|
||||||
|
pushElement(seq);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void endTableGenerator() {
|
||||||
|
popElement();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse inheritance.
|
* Parse inheritance.
|
||||||
|
@ -880,13 +891,9 @@ public class XMLPersistenceMappingParser
|
||||||
*/
|
*/
|
||||||
private boolean startUniqueConstraint(Attributes attrs)
|
private boolean startUniqueConstraint(Attributes attrs)
|
||||||
throws SAXException {
|
throws SAXException {
|
||||||
Object current = currentElement();
|
Unique unique = new Unique();
|
||||||
if (current instanceof ClassMapping && _secondaryTable == null) {
|
pushElement(unique);
|
||||||
Unique unique = new Unique();
|
return true;
|
||||||
pushElement(unique);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -897,9 +904,23 @@ public class XMLPersistenceMappingParser
|
||||||
*/
|
*/
|
||||||
private void endUniqueConstraint() {
|
private void endUniqueConstraint() {
|
||||||
Unique unique = (Unique) popElement();
|
Unique unique = (Unique) popElement();
|
||||||
Object current = currentElement();
|
Object ctx = currentElement();
|
||||||
if (current instanceof ClassMapping && _secondaryTable == null)
|
String tableName = "?";
|
||||||
((ClassMapping) current).getMappingInfo().addUnique(unique);
|
ClassMappingInfo info = null;
|
||||||
|
if (ctx instanceof ClassMapping) {
|
||||||
|
info = ((ClassMapping) ctx).getMappingInfo();
|
||||||
|
tableName = (_secondaryTable != null) ? info.getTableName() : _secondaryTable;
|
||||||
|
info.addUnique(tableName, unique);
|
||||||
|
} else if (ctx instanceof FieldMapping) {// JoinTable
|
||||||
|
info = ((FieldMapping)ctx).getDeclaringMapping().getMappingInfo();
|
||||||
|
tableName = info.getTableName();
|
||||||
|
info.addUnique(tableName, unique);
|
||||||
|
} else if (ctx instanceof SequenceMapping) {
|
||||||
|
tableName = ((SequenceMapping)ctx).getTable();
|
||||||
|
unique.setTableName(tableName);
|
||||||
|
} else {
|
||||||
|
throw new InternalException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -186,9 +186,9 @@ public class XMLPersistenceMappingSerializer
|
||||||
ClassMappingInfo info = cls.getMappingInfo();
|
ClassMappingInfo info = cls.getMappingInfo();
|
||||||
serializeTable(info.getTableName(), "table", Strings
|
serializeTable(info.getTableName(), "table", Strings
|
||||||
.getClassName(mapping.getDescribedType()), null,
|
.getClassName(mapping.getDescribedType()), null,
|
||||||
info.getUniques());
|
info.getUniques(info.getTableName()));
|
||||||
for (String second : info.getSecondaryTableNames())
|
for (String second : info.getSecondaryTableNames())
|
||||||
serializeTable(second, "secondary-table", null, info, null);
|
serializeTable(second, "secondary-table", null, info, info.getUniques(second));
|
||||||
serializeColumns(info, ColType.PK_JOIN, null);
|
serializeColumns(info, ColType.PK_JOIN, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,13 @@ second-version: Version property "{0}" cannot map to a secondary table column. \
|
||||||
Version columns must always be in the primary table of the class.
|
Version columns must always be in the primary table of the class.
|
||||||
not-embedded: Attempt to declare mapping overrides on non-embedded field "{0}".
|
not-embedded: Attempt to declare mapping overrides on non-embedded field "{0}".
|
||||||
no-gen-table: No generated table found at "{0}".
|
no-gen-table: No generated table found at "{0}".
|
||||||
empty-unique-column: A unique constraint "{0}" specified in mapping of class \
|
unique-no-column: A unique constraint specified in mapping of "{0}" specified \
|
||||||
|
no column.
|
||||||
|
unique-empty-column: A unique constraint "{0}" specified in mapping of class \
|
||||||
"{1}" includes an empty column.
|
"{1}" includes an empty column.
|
||||||
|
unique-many-on-seq-unsupported: More than one unique constraints is specified \
|
||||||
|
on sequence generator "{1}" in "{0}". But multiple unique constraint on \
|
||||||
|
sequence generator is currently not supported.
|
||||||
discriminator-on-abstract-class: A discriminator value has been specified for \
|
discriminator-on-abstract-class: A discriminator value has been specified for \
|
||||||
the abstract class "{0}". The discriminator will never be used and may be \
|
the abstract class "{0}". The discriminator will never be used and may be \
|
||||||
safely removed.
|
safely removed.
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.persistence.jdbc.unique;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.apache.openjpa.persistence.test.SQLListenerTestCase;
|
||||||
|
|
||||||
|
public class TestUnique extends SQLListenerTestCase {
|
||||||
|
@Override
|
||||||
|
public void setUp(Object... props) {
|
||||||
|
super.setUp(UniqueA.class, UniqueB.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapping() {
|
||||||
|
EntityManager em = emf.createEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
// The above should trigger schema definition
|
||||||
|
|
||||||
|
List<String> sqls = super.sql;
|
||||||
|
|
||||||
|
assertSQLFragnment(sqls, "CREATE TABLE UNIQUE_A",
|
||||||
|
"UNIQUE (a1, a2)",
|
||||||
|
"UNIQUE (a3, a4)");
|
||||||
|
assertSQLFragnment(sqls, "CREATE TABLE UNIQUE_B",
|
||||||
|
"UNIQUE (b1, b2)");
|
||||||
|
assertSQLFragnment(sqls, "CREATE TABLE UNIQUE_SECONDARY",
|
||||||
|
"UNIQUE (sa1)");
|
||||||
|
assertSQLFragnment(sqls, "CREATE TABLE UNIQUE_GENERATOR",
|
||||||
|
"UNIQUE (GEN1, GEN2)");
|
||||||
|
assertSQLFragnment(sqls, "CREATE TABLE UNIQUE_JOINTABLE",
|
||||||
|
"UNIQUE (UNIQUEA_AID, BS_BID)");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void assertSQLFragnment(List<String> list, String...keys) {
|
||||||
|
for (String sql : list) {
|
||||||
|
String SQL = sql.toUpperCase();
|
||||||
|
boolean matched = true;
|
||||||
|
for (String key : keys) {
|
||||||
|
String KEY = key.toUpperCase();
|
||||||
|
if (SQL.indexOf(KEY) == -1) {
|
||||||
|
matched = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matched)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
for (String sql : list) {
|
||||||
|
i++;
|
||||||
|
System.out.println(""+i+":"+sql);
|
||||||
|
}
|
||||||
|
fail("None of the above SQL contains all keys " + Arrays.toString(keys));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.persistence.jdbc.unique;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinTable;
|
||||||
|
import javax.persistence.ManyToMany;
|
||||||
|
import javax.persistence.SecondaryTable;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structures for testing unique constraint settings
|
||||||
|
* on ORM Annotatations.
|
||||||
|
*
|
||||||
|
* Unique columns must be non-nullable.
|
||||||
|
*
|
||||||
|
* @author Pinaki Poddar
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name="UNIQUE_A",
|
||||||
|
uniqueConstraints={@UniqueConstraint(columnNames={"a1","a2"}),
|
||||||
|
@UniqueConstraint(columnNames={"a3","a4"})})
|
||||||
|
@SecondaryTable(name="UNIQUE_SECONDARY",
|
||||||
|
uniqueConstraints=@UniqueConstraint(columnNames={"sa1"}))
|
||||||
|
|
||||||
|
public class UniqueA {
|
||||||
|
@Id
|
||||||
|
private int aid;
|
||||||
|
|
||||||
|
@Column(unique=true, nullable=false)
|
||||||
|
private int a1;
|
||||||
|
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int a2;
|
||||||
|
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int a3;
|
||||||
|
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int a4;
|
||||||
|
|
||||||
|
|
||||||
|
private int a5;
|
||||||
|
private int a6;
|
||||||
|
|
||||||
|
@Column(table="UNIQUE_SECONDARY", nullable=false)
|
||||||
|
private short sa1;
|
||||||
|
@Column(table="UNIQUE_SECONDARY")
|
||||||
|
private short sa2;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(name="UNIQUE_JOINTABLE",
|
||||||
|
uniqueConstraints=@UniqueConstraint(columnNames={"UNIQUEA_AID","BS_BID"}))
|
||||||
|
private Collection<UniqueB> bs;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.persistence.jdbc.unique;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name="UNIQUE_B",
|
||||||
|
uniqueConstraints={@UniqueConstraint(columnNames={"b1","b2"})})
|
||||||
|
public class UniqueB {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy=GenerationType.TABLE, generator="testGenerator")
|
||||||
|
@TableGenerator(name="testGenerator", table="UNIQUE_GENERATOR",
|
||||||
|
pkColumnName="GEN1", valueColumnName="GEN2",
|
||||||
|
uniqueConstraints={@UniqueConstraint(columnNames={"GEN1","GEN2"})})
|
||||||
|
private int bid;
|
||||||
|
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int b1;
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int b2;
|
||||||
|
}
|
Loading…
Reference in New Issue