HHH-10208 - Index and unique-key constraints not properly handled with implicit columns in hbm.xml binding
This commit is contained in:
parent
9128b84b54
commit
ec8794bbd0
|
@ -19,7 +19,6 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MapsId;
|
||||
|
@ -45,11 +44,9 @@ import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
|
|||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.relational.ExportableProducer;
|
||||
import org.hibernate.boot.model.relational.Namespace;
|
||||
import org.hibernate.boot.model.source.internal.ConstraintSecondPass;
|
||||
import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass;
|
||||
import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.AttributeConverterAutoApplyHandler;
|
||||
import org.hibernate.boot.spi.AttributeConverterDescriptor;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.MetadataBuildingOptions;
|
||||
|
@ -1452,7 +1449,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
private ArrayList<CreateKeySecondPass> createKeySecondPasList;
|
||||
private ArrayList<SecondaryTableSecondPass> secondaryTableSecondPassList;
|
||||
private ArrayList<QuerySecondPass> querySecondPassList;
|
||||
private ArrayList<ConstraintSecondPass> constraintSecondPassList;
|
||||
private ArrayList<ImplicitColumnNamingSecondPass> implicitColumnNamingSecondPassList;
|
||||
|
||||
private ArrayList<SecondPass> generalSecondPassList;
|
||||
|
@ -1485,9 +1481,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
else if ( secondPass instanceof QuerySecondPass ) {
|
||||
addQuerySecondPass( (QuerySecondPass) secondPass, onTopOfTheQueue );
|
||||
}
|
||||
else if ( secondPass instanceof ConstraintSecondPass ) {
|
||||
addConstraintSecondPass( ( ConstraintSecondPass) secondPass, onTopOfTheQueue );
|
||||
}
|
||||
else if ( secondPass instanceof ImplicitColumnNamingSecondPass ) {
|
||||
addImplicitColumnNamingSecondPass( (ImplicitColumnNamingSecondPass) secondPass );
|
||||
}
|
||||
|
@ -1562,13 +1555,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
addSecondPass( secondPass, querySecondPassList, onTopOfTheQueue );
|
||||
}
|
||||
|
||||
private void addConstraintSecondPass(ConstraintSecondPass secondPass, boolean onTopOfTheQueue) {
|
||||
if ( constraintSecondPassList == null ) {
|
||||
constraintSecondPassList = new ArrayList<ConstraintSecondPass>();
|
||||
}
|
||||
addSecondPass( secondPass, constraintSecondPassList, onTopOfTheQueue );
|
||||
}
|
||||
|
||||
private void addImplicitColumnNamingSecondPass(ImplicitColumnNamingSecondPass secondPass) {
|
||||
if ( implicitColumnNamingSecondPassList == null ) {
|
||||
implicitColumnNamingSecondPassList = new ArrayList<ImplicitColumnNamingSecondPass>();
|
||||
|
@ -1605,7 +1591,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
|
||||
secondPassCompileForeignKeys( buildingContext );
|
||||
|
||||
processSecondPasses( constraintSecondPassList );
|
||||
processUniqueConstraintHolders( buildingContext );
|
||||
processJPAIndexHolders( buildingContext );
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.boot.model.source.internal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.model.source.internal.hbm.MappingDocument;
|
||||
import org.hibernate.boot.model.source.spi.ConstraintSource;
|
||||
import org.hibernate.boot.model.source.spi.IndexConstraintSource;
|
||||
import org.hibernate.boot.model.source.spi.UniqueKeyConstraintSource;
|
||||
import org.hibernate.cfg.SecondPass;
|
||||
import org.hibernate.mapping.Index;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ConstraintSecondPass implements SecondPass {
|
||||
private final MappingDocument sourceDocument;
|
||||
|
||||
private final Table table;
|
||||
private final ConstraintSource constraintSource;
|
||||
|
||||
public ConstraintSecondPass(
|
||||
MappingDocument sourceDocument,
|
||||
Table table,
|
||||
ConstraintSource constraintSource) {
|
||||
this.sourceDocument = sourceDocument;
|
||||
this.table = table;
|
||||
this.constraintSource = constraintSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSecondPass(Map persistentClasses) throws MappingException {
|
||||
if ( IndexConstraintSource.class.isInstance( constraintSource ) ) {
|
||||
bindIndexConstraint();
|
||||
}
|
||||
else if ( UniqueKeyConstraintSource.class.isInstance( constraintSource ) ) {
|
||||
bindUniqueKeyConstraint();
|
||||
}
|
||||
}
|
||||
|
||||
private void bindIndexConstraint() {
|
||||
// todo : implicit naming via strategy
|
||||
final Index index = table.getOrCreateIndex( constraintSource.name() );
|
||||
|
||||
for ( String columnName : constraintSource.columnNames() ) {
|
||||
final Identifier physicalName = sourceDocument.getMetadataCollector().getDatabase().toIdentifier(
|
||||
sourceDocument.getMetadataCollector().getPhysicalColumnName( table, columnName )
|
||||
);
|
||||
index.addColumn( table.getColumn( physicalName ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void bindUniqueKeyConstraint() {
|
||||
// todo : implicit naming via strategy
|
||||
final UniqueKey index = table.getOrCreateUniqueKey( constraintSource.name() );
|
||||
|
||||
for ( String columnName : constraintSource.columnNames() ) {
|
||||
final Identifier physicalName = sourceDocument.getMetadataCollector().getDatabase().toIdentifier(
|
||||
sourceDocument.getMetadataCollector().getPhysicalColumnName( table, columnName )
|
||||
);
|
||||
index.addColumn( table.getColumn( physicalName ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.boot.model.source.spi.ConstraintSource;
|
||||
import org.hibernate.internal.util.compare.EqualsHelper;
|
||||
|
||||
/**
|
||||
* Support for index and unique-key constraint sources.
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class AbstractConstraintSource implements ConstraintSource {
|
||||
protected final String name;
|
||||
protected final String tableName;
|
||||
protected final ArrayList<String> columnNames = new ArrayList<String>();
|
||||
|
||||
protected AbstractConstraintSource(String name, String tableName) {
|
||||
assert name != null : "Constraint name was null";
|
||||
this.name = name;
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> columnNames() {
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
public void addColumnName( String columnName ) {
|
||||
columnNames.add( columnName );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("RedundantIfStatement")
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractConstraintSource that = (AbstractConstraintSource) o;
|
||||
return EqualsHelper.equals( name, that.name )
|
||||
&& EqualsHelper.equals( tableName, that.tableName )
|
||||
&& columnNames.equals( that.columnNames );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + ( tableName == null ? 0 : tableName.hashCode() );
|
||||
result = 31 * result + ( columnNames.hashCode() );
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -33,7 +33,6 @@ import org.hibernate.boot.model.source.spi.AttributePath;
|
|||
import org.hibernate.boot.model.source.spi.AttributeRole;
|
||||
import org.hibernate.boot.model.source.spi.AttributeSource;
|
||||
import org.hibernate.boot.model.source.spi.AttributeSourceContainer;
|
||||
import org.hibernate.boot.model.source.spi.ConstraintSource;
|
||||
import org.hibernate.boot.model.source.spi.EntityHierarchySource;
|
||||
import org.hibernate.boot.model.source.spi.EntityNamingSource;
|
||||
import org.hibernate.boot.model.source.spi.EntitySource;
|
||||
|
@ -79,9 +78,6 @@ public abstract class AbstractEntitySourceImpl
|
|||
|
||||
private final ToolingHintContext toolingHintContext;
|
||||
|
||||
private Map<String, ConstraintSource> constraintMap = new HashMap<String, ConstraintSource>();
|
||||
|
||||
|
||||
protected AbstractEntitySourceImpl(MappingDocument sourceMappingDocument, JaxbHbmEntityBaseDefinition jaxbEntityMapping) {
|
||||
super( sourceMappingDocument );
|
||||
this.jaxbEntityMapping = jaxbEntityMapping;
|
||||
|
@ -223,86 +219,12 @@ public abstract class AbstractEntitySourceImpl
|
|||
public void addAttributeSource(AttributeSource attributeSource) {
|
||||
attributeSources.add( attributeSource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexColumn(String constraintName, String logicalTableName, String columnName) {
|
||||
registerIndexConstraintColumn( constraintName, logicalTableName, columnName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyColumn(String constraintName, String logicalTableName, String columnName) {
|
||||
registerUniqueKeyConstraintColumn( constraintName, logicalTableName, columnName );
|
||||
}
|
||||
};
|
||||
buildAttributeSources( attributeBuildingCallback );
|
||||
|
||||
return attributeSources;
|
||||
}
|
||||
|
||||
private void registerIndexConstraintColumn(String constraintName, String logicalTableName, String columnName) {
|
||||
getOrCreateIndexConstraintSource( constraintName, logicalTableName ).addColumnName( columnName );
|
||||
}
|
||||
|
||||
private IndexConstraintSourceImpl getOrCreateIndexConstraintSource(String constraintName, String logicalTableName) {
|
||||
IndexConstraintSourceImpl constraintSource = (IndexConstraintSourceImpl) constraintMap.get( constraintName );
|
||||
if ( constraintSource == null ) {
|
||||
constraintSource = new IndexConstraintSourceImpl( constraintName, logicalTableName );
|
||||
constraintMap.put( constraintName, constraintSource );
|
||||
}
|
||||
else {
|
||||
// make sure we have the same table name...
|
||||
if ( !EqualsHelper.equals( constraintSource.getTableName(), logicalTableName ) ) {
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Named relational index [%s] referenced more than one table [%s, %s]",
|
||||
constraintName,
|
||||
constraintSource.getTableName() == null
|
||||
? "null(implicit)"
|
||||
: constraintSource.getTableName(),
|
||||
logicalTableName == null
|
||||
? "null(implicit)"
|
||||
: logicalTableName
|
||||
),
|
||||
origin()
|
||||
);
|
||||
}
|
||||
}
|
||||
return constraintSource;
|
||||
}
|
||||
|
||||
private void registerUniqueKeyConstraintColumn(String constraintName, String logicalTableName, String columnName) {
|
||||
getOrCreateUniqueKeyConstraintSource( constraintName, logicalTableName ).addColumnName( columnName );
|
||||
}
|
||||
|
||||
private UniqueKeyConstraintSourceImpl getOrCreateUniqueKeyConstraintSource(String constraintName, String logicalTableName) {
|
||||
UniqueKeyConstraintSourceImpl constraintSource = (UniqueKeyConstraintSourceImpl) constraintMap.get( constraintName );
|
||||
if ( constraintSource == null ) {
|
||||
constraintSource = new UniqueKeyConstraintSourceImpl( constraintName, logicalTableName );
|
||||
constraintMap.put( constraintName, constraintSource );
|
||||
}
|
||||
else {
|
||||
// make sure we have the same table name...
|
||||
if ( !EqualsHelper.equals( constraintSource.getTableName(), logicalTableName ) ) {
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Named relational unique-key [%s] referenced more than one table [%s, %s]",
|
||||
constraintName,
|
||||
constraintSource.getTableName() == null
|
||||
? "null(implicit)"
|
||||
: constraintSource.getTableName(),
|
||||
logicalTableName == null
|
||||
? "null(implicit)"
|
||||
: logicalTableName
|
||||
),
|
||||
origin()
|
||||
);
|
||||
}
|
||||
}
|
||||
return constraintSource;
|
||||
}
|
||||
|
||||
protected void buildAttributeSources(AttributesHelper.Callback attributeBuildingCallback) {
|
||||
AttributesHelper.processAttributes(
|
||||
sourceMappingDocument(),
|
||||
|
@ -344,22 +266,6 @@ public abstract class AbstractEntitySourceImpl
|
|||
public void addAttributeSource(AttributeSource attributeSource) {
|
||||
attributeSources.add( attributeSource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
registerIndexConstraintColumn( constraintName, logicalTableName, columnName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
registerUniqueKeyConstraintColumn( constraintName, logicalTableName, columnName );
|
||||
}
|
||||
},
|
||||
joinElement.getAttributes(),
|
||||
logicalTableName,
|
||||
|
@ -501,11 +407,6 @@ public abstract class AbstractEntitySourceImpl
|
|||
subclassEntitySources.add( subclassEntitySource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ConstraintSource> getConstraints() {
|
||||
return constraintMap.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,SecondaryTableSource> getSecondaryTableMap() {
|
||||
return secondaryTableMap;
|
||||
|
|
|
@ -72,20 +72,6 @@ public abstract class AbstractSingularAttributeSourceEmbeddedImpl
|
|||
public ToolingHintContext getToolingHintContextBaselineForEmbeddable() {
|
||||
return toolingHintContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyConstraintColumn(
|
||||
String constraintName, String logicalTableName, String columnName) {
|
||||
|
||||
}
|
||||
},
|
||||
embeddedAttributeMapping.getEmbeddableMapping(),
|
||||
nestedAttributeMappings,
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
|
||||
import org.hibernate.boot.MappingException;
|
||||
|
@ -18,7 +15,6 @@ import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmAnyAssociationType;
|
|||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmArrayType;
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmBagCollectionType;
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmBasicAttributeType;
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmColumnType;
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmCompositeAttributeType;
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmCompositeKeyBasicAttributeType;
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmCompositeKeyManyToOneType;
|
||||
|
@ -43,20 +39,14 @@ import org.hibernate.boot.model.source.spi.EmbeddedAttributeMapping;
|
|||
import org.hibernate.boot.model.source.spi.NaturalIdMutability;
|
||||
import org.hibernate.boot.model.source.spi.SingularAttributeSourceEmbedded;
|
||||
import org.hibernate.boot.model.source.spi.ToolingHintContext;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AttributesHelper {
|
||||
public static interface Callback {
|
||||
public interface Callback {
|
||||
AttributeSourceContainer getAttributeSourceContainer();
|
||||
void addAttributeSource(AttributeSource attributeSource);
|
||||
|
||||
void registerIndexColumn(String constraintName, String logicalTableName, String columnName);
|
||||
void registerUniqueKeyColumn(String constraintName, String logicalTableName, String columnName);
|
||||
}
|
||||
|
||||
public static void processAttributes(
|
||||
|
@ -303,22 +293,6 @@ public class AttributesHelper {
|
|||
public ToolingHintContext getToolingHintContextBaselineForEmbeddable() {
|
||||
return callback.getAttributeSourceContainer().getToolingHintContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
callback.registerIndexColumn( constraintName, logicalTableName, columnName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
callback.registerUniqueKeyColumn( constraintName, logicalTableName, columnName );
|
||||
}
|
||||
},
|
||||
propertiesGroupJaxbMapping.getAttributes(),
|
||||
logicalTableName,
|
||||
|
@ -447,89 +421,6 @@ public class AttributesHelper {
|
|||
naturalIdMutability
|
||||
)
|
||||
);
|
||||
|
||||
processConstraints(
|
||||
mappingDocument,
|
||||
callback,
|
||||
logicalTableName,
|
||||
basicAttributeJaxbMapping.getColumnAttribute(),
|
||||
basicAttributeJaxbMapping.getColumnOrFormula(),
|
||||
basicAttributeJaxbMapping.getIndex(),
|
||||
basicAttributeJaxbMapping.getUniqueKey()
|
||||
);
|
||||
}
|
||||
|
||||
private static void processConstraints(
|
||||
MappingDocument mappingDocument,
|
||||
Callback callback,
|
||||
String logicalTableName,
|
||||
String columnAttribute,
|
||||
List columns,
|
||||
String groupedIndexNames,
|
||||
String groupedUniqueKeyNames) {
|
||||
|
||||
final Set<String> groupedIndexNameSet = splitNames( groupedIndexNames );
|
||||
final boolean hasGroupedIndexes = !groupedIndexNameSet.isEmpty();
|
||||
|
||||
final Set<String> groupedUniqueKeyNameSet = splitNames( groupedUniqueKeyNames );
|
||||
final boolean hasGroupedUniqueKeys = !groupedUniqueKeyNameSet.isEmpty();
|
||||
|
||||
if ( hasGroupedIndexes ) {
|
||||
if ( isNotEmpty( columnAttribute ) ) {
|
||||
for ( String name : groupedIndexNameSet ) {
|
||||
callback.registerIndexColumn( name, logicalTableName, columnAttribute );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( hasGroupedIndexes && isNotEmpty( columnAttribute ) ) {
|
||||
for ( String name : groupedIndexNameSet ) {
|
||||
callback.registerIndexColumn( name, logicalTableName, columnAttribute );
|
||||
}
|
||||
}
|
||||
|
||||
if ( hasGroupedUniqueKeys && isNotEmpty( columnAttribute ) ) {
|
||||
for ( String name : groupedUniqueKeyNameSet ) {
|
||||
callback.registerUniqueKeyColumn( name, logicalTableName, columnAttribute );
|
||||
}
|
||||
}
|
||||
|
||||
for ( Object oColumn : columns ) {
|
||||
if ( !JaxbHbmColumnType.class.isInstance( oColumn ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final JaxbHbmColumnType column = (JaxbHbmColumnType) oColumn;
|
||||
if ( isNotEmpty( column.getIndex() ) ) {
|
||||
callback.registerIndexColumn( column.getIndex(), logicalTableName, column.getName() );
|
||||
}
|
||||
if ( hasGroupedIndexes ) {
|
||||
for ( String name : groupedIndexNameSet ) {
|
||||
callback.registerIndexColumn( name, logicalTableName, column.getName() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isNotEmpty( column.getUniqueKey() ) ) {
|
||||
callback.registerUniqueKeyColumn( column.getUniqueKey(), logicalTableName, column.getName() );
|
||||
}
|
||||
if ( hasGroupedUniqueKeys ) {
|
||||
for ( String name : groupedUniqueKeyNameSet ) {
|
||||
callback.registerUniqueKeyColumn( name, logicalTableName, column.getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<String> splitNames(String groupedNames) {
|
||||
if ( StringHelper.isEmpty( groupedNames ) ) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
final HashSet<String> splitNames = new HashSet<String>();
|
||||
final StringTokenizer tokens = new StringTokenizer( groupedNames, ", " );
|
||||
while ( tokens.hasMoreTokens() ) {
|
||||
splitNames.add( tokens.nextToken() );
|
||||
}
|
||||
return splitNames;
|
||||
}
|
||||
|
||||
public static void processEmbeddedAttribute(
|
||||
|
@ -598,16 +489,6 @@ public class AttributesHelper {
|
|||
naturalIdMutability
|
||||
)
|
||||
);
|
||||
|
||||
processConstraints(
|
||||
mappingDocument,
|
||||
callback,
|
||||
logicalTableName,
|
||||
manyToOneAttributeJaxbMapping.getColumnAttribute(),
|
||||
manyToOneAttributeJaxbMapping.getColumnOrFormula(),
|
||||
manyToOneAttributeJaxbMapping.getIndex(),
|
||||
manyToOneAttributeJaxbMapping.getUniqueKey()
|
||||
);
|
||||
}
|
||||
|
||||
public static void processOneToOneAttribute(
|
||||
|
@ -642,17 +523,6 @@ public class AttributesHelper {
|
|||
naturalIdMutability
|
||||
)
|
||||
);
|
||||
|
||||
processConstraints(
|
||||
mappingDocument,
|
||||
callback,
|
||||
logicalTableName,
|
||||
null,
|
||||
// todo : should we skip the discriminator column?
|
||||
anyAttributeJaxbMapping.getColumn(),
|
||||
anyAttributeJaxbMapping.getIndex(),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public static void processMapAttribute(
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmBasicAttributeType;
|
||||
import org.hibernate.boot.model.source.spi.SizeSource;
|
||||
|
@ -67,8 +68,8 @@ public class BasicAttributeColumnsAndFormulasSource
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getIndex() {
|
||||
return basicAttributeMapping.getIndex();
|
||||
public Set<String> getIndexConstraintNames() {
|
||||
return CommaSeparatedStringHelper.split( basicAttributeMapping.getIndex() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,7 +78,7 @@ public class BasicAttributeColumnsAndFormulasSource
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueKey() {
|
||||
return basicAttributeMapping.getUniqueKey();
|
||||
public Set<String> getUniqueKeyConstraintNames() {
|
||||
return CommaSeparatedStringHelper.split( basicAttributeMapping.getUniqueKey() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.boot.model.TruthValue;
|
||||
import org.hibernate.boot.model.source.spi.ColumnSource;
|
||||
import org.hibernate.boot.model.source.spi.JdbcDataType;
|
||||
|
@ -26,6 +28,8 @@ class ColumnAttributeSourceImpl
|
|||
private final SizeSource sizeSource;
|
||||
private final TruthValue nullable;
|
||||
private final TruthValue unique;
|
||||
private final Set<String> indexConstraintNames;
|
||||
private final Set<String> ukConstraintNames;
|
||||
|
||||
ColumnAttributeSourceImpl(
|
||||
MappingDocument mappingDocument,
|
||||
|
@ -33,13 +37,17 @@ class ColumnAttributeSourceImpl
|
|||
String columnName,
|
||||
SizeSource sizeSource,
|
||||
TruthValue nullable,
|
||||
TruthValue unique) {
|
||||
TruthValue unique,
|
||||
Set<String> indexConstraintNames,
|
||||
Set<String> ukConstraintNames) {
|
||||
super( mappingDocument );
|
||||
this.tableName = tableName;
|
||||
this.columnName = columnName;
|
||||
this.sizeSource = sizeSource;
|
||||
this.nullable = nullable;
|
||||
this.unique = unique;
|
||||
this.indexConstraintNames = indexConstraintNames;
|
||||
this.ukConstraintNames = ukConstraintNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -106,4 +114,14 @@ class ColumnAttributeSourceImpl
|
|||
public String getComment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getIndexConstraintNames() {
|
||||
return indexConstraintNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getUniqueKeyConstraintNames() {
|
||||
return ukConstraintNames;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmColumnType;
|
||||
import org.hibernate.boot.model.TruthValue;
|
||||
import org.hibernate.boot.model.source.spi.ColumnSource;
|
||||
|
@ -22,16 +24,22 @@ class ColumnSourceImpl
|
|||
private final String tableName;
|
||||
private final JaxbHbmColumnType columnElement;
|
||||
private final TruthValue nullable;
|
||||
private final Set<String> indexConstraintNames;
|
||||
private final Set<String> ukConstraintNames;
|
||||
|
||||
ColumnSourceImpl(
|
||||
MappingDocument mappingDocument,
|
||||
String tableName,
|
||||
JaxbHbmColumnType columnElement) {
|
||||
JaxbHbmColumnType columnElement,
|
||||
Set<String> indexConstraintNames,
|
||||
Set<String> ukConstraintNames) {
|
||||
this(
|
||||
mappingDocument,
|
||||
tableName,
|
||||
columnElement,
|
||||
interpretNotNullToNullability( columnElement.isNotNull() )
|
||||
interpretNotNullToNullability( columnElement.isNotNull() ),
|
||||
indexConstraintNames,
|
||||
ukConstraintNames
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -49,11 +57,22 @@ class ColumnSourceImpl
|
|||
MappingDocument mappingDocument,
|
||||
String tableName,
|
||||
JaxbHbmColumnType columnElement,
|
||||
TruthValue nullable) {
|
||||
TruthValue nullable,
|
||||
Set<String> indexConstraintNames,
|
||||
Set<String> ukConstraintNames) {
|
||||
super( mappingDocument );
|
||||
this.tableName = tableName;
|
||||
this.columnElement = columnElement;
|
||||
this.nullable = nullable;
|
||||
|
||||
this.indexConstraintNames = CommaSeparatedStringHelper.splitAndCombine(
|
||||
indexConstraintNames,
|
||||
columnElement.getIndex()
|
||||
);
|
||||
this.ukConstraintNames = CommaSeparatedStringHelper.splitAndCombine(
|
||||
ukConstraintNames,
|
||||
columnElement.getUniqueKey()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -125,4 +144,14 @@ class ColumnSourceImpl
|
|||
public String getContainingTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getIndexConstraintNames() {
|
||||
return indexConstraintNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getUniqueKeyConstraintNames() {
|
||||
return ukConstraintNames;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CommaSeparatedStringHelper {
|
||||
private CommaSeparatedStringHelper() {
|
||||
}
|
||||
|
||||
public static Set<String> split(String values) {
|
||||
if ( values == null || values.isEmpty() ) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
HashSet<String> set = new HashSet<String>();
|
||||
Collections.addAll( set, values.split( "\\s*,\\s*" ) );
|
||||
return set;
|
||||
}
|
||||
|
||||
public static Set<String> splitAndCombine(Set<String> x, String values) {
|
||||
if ( x.isEmpty() && (values == null || values.isEmpty()) ) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
HashSet<String> set = new HashSet<String>();
|
||||
set.addAll( x );
|
||||
if ( values != null && !values.isEmpty() ) {
|
||||
Collections.addAll( set, values.split( "\\s*,\\s*" ) );
|
||||
}
|
||||
return set;
|
||||
}
|
||||
}
|
|
@ -17,10 +17,7 @@ import org.hibernate.boot.model.source.spi.ToolingHintContext;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EmbeddableSourceContainer {
|
||||
public AttributeRole getAttributeRoleBase();
|
||||
public AttributePath getAttributePathBase();
|
||||
public ToolingHintContext getToolingHintContextBaselineForEmbeddable();
|
||||
|
||||
public void registerIndexConstraintColumn(String constraintName, String logicalTableName, String columnName);
|
||||
public void registerUniqueKeyConstraintColumn(String constraintName, String logicalTableName, String columnName);
|
||||
AttributeRole getAttributeRoleBase();
|
||||
AttributePath getAttributePathBase();
|
||||
ToolingHintContext getToolingHintContextBaselineForEmbeddable();
|
||||
}
|
||||
|
|
|
@ -111,19 +111,6 @@ public class EmbeddableSourceImpl extends AbstractHbmSourceNode implements Embed
|
|||
public void addAttributeSource(AttributeSource attributeSource) {
|
||||
attributeSources.add( attributeSource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexColumn(String constraintName, String logicalTableName, String columnName) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
|
||||
}
|
||||
},
|
||||
attributeMappings,
|
||||
logicalTableName,
|
||||
|
|
|
@ -70,22 +70,6 @@ public class EmbeddableSourceVirtualImpl extends AbstractHbmSourceNode implement
|
|||
public void addAttributeSource(AttributeSource attributeSource) {
|
||||
attributeSources.add( attributeSource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
containingCallback.registerIndexColumn( constraintName, logicalTableName, columnName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
containingCallback.registerUniqueKeyColumn( constraintName, logicalTableName, columnName );
|
||||
}
|
||||
},
|
||||
attributeJaxbMappings,
|
||||
logicalTableName,
|
||||
|
|
|
@ -231,24 +231,6 @@ class IdentifierSourceAggregatedCompositeImpl implements IdentifierSourceAggrega
|
|||
return toolingHintContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
// todo : determine the best option here...
|
||||
// probably (here) delegate back to root entity, but need a general strategy
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
// todo : determine the best option here...
|
||||
// probably (here) delegate back to root entity, but need a general strategy
|
||||
}
|
||||
|
||||
public List getAttributes() {
|
||||
return jaxbCompositeIdMapping.getKeyPropertyOrKeyManyToOne();
|
||||
}
|
||||
|
|
|
@ -72,24 +72,6 @@ class IdentifierSourceNonAggregatedCompositeImpl implements IdentifierSourceNonA
|
|||
public void addAttributeSource(AttributeSource attributeSource) {
|
||||
attributeSources.add( attributeSource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
// todo : determine the best option here...
|
||||
// probably (here) delegate back to root entity, but need a general strategy
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
// todo : determine the best option here...
|
||||
// probably (here) delegate back to root entity, but need a general strategy
|
||||
}
|
||||
},
|
||||
rootEntitySource.jaxbEntityMapping().getCompositeId().getKeyPropertyOrKeyManyToOne()
|
||||
);
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.boot.model.source.spi.IndexConstraintSource;
|
||||
|
||||
/**
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
class IndexConstraintSourceImpl extends AbstractConstraintSource implements IndexConstraintSource {
|
||||
|
||||
public IndexConstraintSourceImpl(String name, String tableName) {
|
||||
super( name, tableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
Locale.ENGLISH,
|
||||
"IndexConstraintSource{name='%s', tableName='%s', columnNames='%s', orderings=<not-implemented>}",
|
||||
name,
|
||||
tableName,
|
||||
columnNames
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnique() {
|
||||
// TODO: Is it possible to have a unique index in HBM?
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmManyToOneType;
|
||||
|
||||
|
@ -55,8 +56,8 @@ public class ManyToOneAttributeColumnsAndFormulasSource extends RelationalValueS
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getIndex() {
|
||||
return manyToOneMapping.getIndex();
|
||||
public Set<String> getIndexConstraintNames() {
|
||||
return CommaSeparatedStringHelper.split( manyToOneMapping.getIndex() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,7 +66,7 @@ public class ManyToOneAttributeColumnsAndFormulasSource extends RelationalValueS
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueKey() {
|
||||
return manyToOneMapping.getUniqueKey();
|
||||
public Set<String> getUniqueKeyConstraintNames() {
|
||||
return CommaSeparatedStringHelper.split( manyToOneMapping.getUniqueKey() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource;
|
|||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.relational.Namespace;
|
||||
import org.hibernate.boot.model.source.internal.ConstraintSecondPass;
|
||||
import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass;
|
||||
import org.hibernate.boot.model.source.spi.AnyMappingSource;
|
||||
import org.hibernate.boot.model.source.spi.AttributePath;
|
||||
|
@ -49,7 +48,6 @@ import org.hibernate.boot.model.source.spi.CascadeStyleSource;
|
|||
import org.hibernate.boot.model.source.spi.CollectionIdSource;
|
||||
import org.hibernate.boot.model.source.spi.ColumnSource;
|
||||
import org.hibernate.boot.model.source.spi.CompositeIdentifierSource;
|
||||
import org.hibernate.boot.model.source.spi.ConstraintSource;
|
||||
import org.hibernate.boot.model.source.spi.EmbeddableSource;
|
||||
import org.hibernate.boot.model.source.spi.EntitySource;
|
||||
import org.hibernate.boot.model.source.spi.FilterSource;
|
||||
|
@ -1291,8 +1289,6 @@ public class ModelBinder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerConstraintSecondPasses( mappingDocument, entitySource, entityTableXref );
|
||||
}
|
||||
|
||||
private void handleNaturalIdBinding(
|
||||
|
@ -1325,28 +1321,6 @@ public class ModelBinder {
|
|||
ukBinder.addAttributeBinding( attributeBinding );
|
||||
}
|
||||
|
||||
private void registerConstraintSecondPasses(
|
||||
MappingDocument mappingDocument,
|
||||
EntitySource entitySource,
|
||||
final EntityTableXref entityTableXref) {
|
||||
if ( entitySource.getConstraints() == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( ConstraintSource constraintSource : entitySource.getConstraints() ) {
|
||||
final String logicalTableName = constraintSource.getTableName();
|
||||
final Table table = entityTableXref.resolveTable( database.toIdentifier( logicalTableName ) );
|
||||
|
||||
mappingDocument.getMetadataCollector().addSecondPass(
|
||||
new ConstraintSecondPass(
|
||||
mappingDocument,
|
||||
table,
|
||||
constraintSource
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private Property createPluralAttribute(
|
||||
MappingDocument sourceDocument,
|
||||
PluralAttributeSource attributeSource,
|
||||
|
|
|
@ -58,22 +58,6 @@ public class PluralAttributeElementSourceEmbeddedImpl
|
|||
public ToolingHintContext getToolingHintContextBaselineForEmbeddable() {
|
||||
return toolingHintContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
// todo : how should this be handled?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
// todo : how should this be handled?
|
||||
}
|
||||
},
|
||||
new EmbeddableMapping() {
|
||||
@Override
|
||||
|
|
|
@ -108,22 +108,6 @@ public class PluralAttributeMapKeySourceEmbeddedImpl
|
|||
public ToolingHintContext getToolingHintContextBaselineForEmbeddable() {
|
||||
return pluralAttributeSource.getToolingHintContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIndexConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
// todo : how should this be handled?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerUniqueKeyConstraintColumn(
|
||||
String constraintName,
|
||||
String logicalTableName,
|
||||
String columnName) {
|
||||
// todo : how should this be handled?
|
||||
}
|
||||
},
|
||||
jaxbEmbeddable,
|
||||
attributeMappings,
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -15,22 +14,16 @@ import org.hibernate.boot.model.naming.Identifier;
|
|||
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.source.spi.ColumnSource;
|
||||
import org.hibernate.boot.model.source.spi.ConstraintSource;
|
||||
import org.hibernate.boot.model.source.spi.DerivedValueSource;
|
||||
import org.hibernate.boot.model.source.spi.IndexConstraintSource;
|
||||
import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext;
|
||||
import org.hibernate.boot.model.source.spi.RelationalValueSource;
|
||||
import org.hibernate.boot.model.source.spi.UniqueKeyConstraintSource;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Formula;
|
||||
import org.hibernate.mapping.Index;
|
||||
import org.hibernate.mapping.OneToOne;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
|
||||
/**
|
||||
* Centralized binding of columns and formulas.
|
||||
|
@ -41,10 +34,8 @@ public class RelationalObjectBinder {
|
|||
private final Database database;
|
||||
private final PhysicalNamingStrategy physicalNamingStrategy;
|
||||
|
||||
public static interface ColumnNamingDelegate {
|
||||
// todo : use ImplicitNamingStrategy / PhysicalNamingStrategy
|
||||
// todo : leverage Identifier class
|
||||
public Identifier determineImplicitName(LocalMetadataBuildingContext context);
|
||||
public interface ColumnNamingDelegate {
|
||||
Identifier determineImplicitName(LocalMetadataBuildingContext context);
|
||||
}
|
||||
|
||||
public RelationalObjectBinder(MetadataBuildingContext buildingContext) {
|
||||
|
@ -185,6 +176,16 @@ public class RelationalObjectBinder {
|
|||
column.setCustomWrite( columnSource.getWriteFragment() );
|
||||
|
||||
simpleValue.addColumn( column );
|
||||
|
||||
if ( table != null ) {
|
||||
for ( String name : columnSource.getIndexConstraintNames() ) {
|
||||
table.getOrCreateIndex( name ).addColumn( column );
|
||||
}
|
||||
|
||||
for ( String name : columnSource.getUniqueKeyConstraintNames() ) {
|
||||
table.getOrCreateUniqueKey( name ).addColumn( column );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean interpretNullability(TruthValue nullable, boolean areColumnsNullableByDefault) {
|
||||
|
@ -204,95 +205,4 @@ public class RelationalObjectBinder {
|
|||
oneToOneBinding.addFormula( new Formula( formulaSource.getExpression() ) );
|
||||
}
|
||||
}
|
||||
|
||||
public static interface RelationalObjectResolutionContext {
|
||||
/**
|
||||
* Resolve a Table, given its logical name.
|
||||
* <p/>
|
||||
* NOTE : not sure yet how to best implement this. One option is to simply
|
||||
* construct the proper key needed to resolve the reference from the
|
||||
* "metadataCollector". Another option is to have this context provide a
|
||||
* "scoped table resolution", local to the point where the table reference
|
||||
* occurred; for example, an entity might act as such a scope and resolution of
|
||||
* table references would occur locally scoped to just tables defined for the
|
||||
* entity.
|
||||
* <p/>
|
||||
* todo : does "logical name" include catalog/schema?
|
||||
*
|
||||
* @param metadataCollector
|
||||
* @param logicalName
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Table resolveTable(InFlightMetadataCollector metadataCollector, String logicalName);
|
||||
|
||||
Column resolveColumn(InFlightMetadataCollector metadataCollector, Table table, String logicalName);
|
||||
}
|
||||
|
||||
public static void bindConstraints(
|
||||
MappingDocument mappingDocument,
|
||||
RelationalObjectResolutionContext resolutionContext,
|
||||
Collection<ConstraintSource> constraintSources) {
|
||||
for ( ConstraintSource constraintSource : constraintSources ) {
|
||||
if ( IndexConstraintSource.class.isInstance( constraintSource ) ) {
|
||||
bindIndexConstraint(
|
||||
mappingDocument,
|
||||
resolutionContext,
|
||||
(IndexConstraintSource) constraintSource
|
||||
);
|
||||
}
|
||||
else if ( UniqueKeyConstraintSource.class.isInstance( constraintSource )) {
|
||||
bindUniqueKeyConstraint(
|
||||
mappingDocument,
|
||||
resolutionContext,
|
||||
(UniqueKeyConstraintSource) constraintSource
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void bindIndexConstraint(
|
||||
MappingDocument mappingDocument,
|
||||
RelationalObjectResolutionContext resolutionContext,
|
||||
IndexConstraintSource constraintSource) {
|
||||
// 1) resolve table
|
||||
final Table table = resolutionContext.resolveTable(
|
||||
mappingDocument.getMetadataCollector(),
|
||||
constraintSource.getTableName()
|
||||
);
|
||||
|
||||
// 2) resolve Index
|
||||
final Index index = table.getOrCreateIndex( constraintSource.name() );
|
||||
|
||||
// 3) add columns
|
||||
for ( String columnName : constraintSource.columnNames() ) {
|
||||
// 3.a) resolve Column reference
|
||||
final Column column = resolutionContext.resolveColumn( mappingDocument.getMetadataCollector(), table, columnName );
|
||||
// 3.b) add it to the Index
|
||||
index.addColumn( column );
|
||||
}
|
||||
}
|
||||
|
||||
private static void bindUniqueKeyConstraint(
|
||||
MappingDocument mappingDocument,
|
||||
RelationalObjectResolutionContext resolutionContext,
|
||||
UniqueKeyConstraintSource constraintSource) {
|
||||
// 1) resolve table
|
||||
final Table table = resolutionContext.resolveTable(
|
||||
mappingDocument.getMetadataCollector(),
|
||||
constraintSource.getTableName()
|
||||
);
|
||||
|
||||
// 2) resolve UniqueKey
|
||||
final UniqueKey uniqueKey = table.getOrCreateUniqueKey( constraintSource.name() );
|
||||
|
||||
// 3) add columns
|
||||
for ( String columnName : constraintSource.columnNames() ) {
|
||||
// 3.a) resolve Column reference
|
||||
final Column column = resolutionContext.resolveColumn( mappingDocument.getMetadataCollector(), table, columnName );
|
||||
// 3.b) add it to the UniqueKey
|
||||
uniqueKey.addColumn( column );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.boot.MappingException;
|
||||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmColumnType;
|
||||
|
@ -40,7 +41,7 @@ public class RelationalValueSourceHelper {
|
|||
* <li>a {@code column} XML attribute</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static interface ColumnsAndFormulasSource {
|
||||
public interface ColumnsAndFormulasSource {
|
||||
/**
|
||||
* What kind of XML element does this information come from?
|
||||
*
|
||||
|
@ -83,14 +84,11 @@ public class RelationalValueSourceHelper {
|
|||
Boolean isNullable();
|
||||
boolean isUnique();
|
||||
|
||||
String getIndex();
|
||||
Set<String> getIndexConstraintNames();
|
||||
|
||||
String getUniqueKey();
|
||||
Set<String> getUniqueKeyConstraintNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract static class AbstractColumnsAndFormulasSource implements ColumnsAndFormulasSource {
|
||||
@Override
|
||||
public String getFormulaAttribute() {
|
||||
|
@ -118,8 +116,8 @@ public class RelationalValueSourceHelper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getIndex() {
|
||||
return null;
|
||||
public Set<String> getIndexConstraintNames() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -128,8 +126,8 @@ public class RelationalValueSourceHelper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueKey() {
|
||||
return null;
|
||||
public Set<String> getUniqueKeyConstraintNames() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,7 +331,9 @@ public class RelationalValueSourceHelper {
|
|||
new ColumnSourceImpl(
|
||||
mappingDocument,
|
||||
containingTableName,
|
||||
columnElement
|
||||
columnElement,
|
||||
columnsAndFormulasSource.getIndexConstraintNames(),
|
||||
columnsAndFormulasSource.getUniqueKeyConstraintNames()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -362,7 +362,9 @@ public class RelationalValueSourceHelper {
|
|||
columnsAndFormulasSource.getColumnAttribute(),
|
||||
columnsAndFormulasSource.getSizeSource(),
|
||||
interpretNullabilityToTruthValue( columnsAndFormulasSource.isNullable() ),
|
||||
columnsAndFormulasSource.isUnique() ? TruthValue.TRUE : TruthValue.FALSE
|
||||
columnsAndFormulasSource.isUnique() ? TruthValue.TRUE : TruthValue.FALSE,
|
||||
columnsAndFormulasSource.getIndexConstraintNames(),
|
||||
columnsAndFormulasSource.getUniqueKeyConstraintNames()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.boot.model.source.internal.hbm;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.boot.model.source.spi.UniqueKeyConstraintSource;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class UniqueKeyConstraintSourceImpl extends AbstractConstraintSource implements UniqueKeyConstraintSource {
|
||||
UniqueKeyConstraintSourceImpl(String name, String tableName) {
|
||||
super( name, tableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
Locale.ENGLISH,
|
||||
"UniqueKeyConstraintSource{name='%s', tableName='%s', columnNames='%s', orderings=<not-implemented>}",
|
||||
name,
|
||||
tableName,
|
||||
columnNames
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,15 +6,16 @@
|
|||
*/
|
||||
package org.hibernate.boot.model.source.spi;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.boot.model.TruthValue;
|
||||
|
||||
/**
|
||||
* Contract for source information pertaining to a physical column definition specific to a particular attribute
|
||||
* context.
|
||||
* <p/>
|
||||
* Conceptual note: this really describes a column from the perspective of its binding to an attribute.
|
||||
* This is especially important for {@link #isIncludedInInsert} and {@link #isIncludedInUpdate}. There it is
|
||||
* not the column itself being described.
|
||||
* Conceptual note: this really describes a column from the perspective of its binding to an attribute, not
|
||||
* necessarily the column itself.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -24,75 +25,79 @@ public interface ColumnSource extends RelationalValueSource {
|
|||
*
|
||||
* @return The name of the column. Can be {@code null}, in which case a naming strategy is applied.
|
||||
*/
|
||||
public String getName();
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* A SQL fragment to apply to the column value on read.
|
||||
*
|
||||
* @return The SQL read fragment
|
||||
*/
|
||||
public String getReadFragment();
|
||||
String getReadFragment();
|
||||
|
||||
/**
|
||||
* A SQL fragment to apply to the column value on write.
|
||||
*
|
||||
* @return The SQL write fragment
|
||||
*/
|
||||
public String getWriteFragment();
|
||||
String getWriteFragment();
|
||||
|
||||
/**
|
||||
* Is this column nullable?
|
||||
*
|
||||
* @return {@code true} indicates it is nullable; {@code false} non-nullable.
|
||||
*/
|
||||
public TruthValue isNullable();
|
||||
TruthValue isNullable();
|
||||
|
||||
/**
|
||||
* Obtain a specified default value for the column
|
||||
*
|
||||
* @return THe column default
|
||||
*/
|
||||
public String getDefaultValue();
|
||||
String getDefaultValue();
|
||||
|
||||
/**
|
||||
* Obtain the free-hand definition of the column's type.
|
||||
*
|
||||
* @return The free-hand column type
|
||||
*/
|
||||
public String getSqlType();
|
||||
String getSqlType();
|
||||
|
||||
/**
|
||||
* The deduced (and dialect convertible) type for this column
|
||||
*
|
||||
* @return The column's SQL data type.
|
||||
*/
|
||||
public JdbcDataType getDatatype();
|
||||
JdbcDataType getDatatype();
|
||||
|
||||
/**
|
||||
* Obtain the source for the specified column size.
|
||||
*
|
||||
* @return The source for the column size.
|
||||
*/
|
||||
public SizeSource getSizeSource();
|
||||
SizeSource getSizeSource();
|
||||
|
||||
/**
|
||||
* Is this column unique?
|
||||
*
|
||||
* @return {@code true} indicates it is unique; {@code false} non-unique.
|
||||
*/
|
||||
public boolean isUnique();
|
||||
boolean isUnique();
|
||||
|
||||
/**
|
||||
* Obtain the specified check constraint condition
|
||||
*
|
||||
* @return Check constraint condition
|
||||
*/
|
||||
public String getCheckCondition();
|
||||
String getCheckCondition();
|
||||
|
||||
/**
|
||||
* Obtain the specified SQL comment
|
||||
*
|
||||
* @return SQL comment
|
||||
*/
|
||||
public String getComment();
|
||||
String getComment();
|
||||
|
||||
Set<String> getIndexConstraintNames();
|
||||
|
||||
Set<String> getUniqueKeyConstraintNames();
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.boot.model.source.spi;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Contract describing source of table constraints
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ConstraintSource {
|
||||
/**
|
||||
* @return returns the name of the constraint or {@code null} in case a generated name should be used
|
||||
*/
|
||||
public String name();
|
||||
|
||||
/**
|
||||
* Obtain the logical name of the table for this constraint.
|
||||
*
|
||||
* @return The logical table name. Can be {@code null} in the case of the "primary table".
|
||||
*/
|
||||
public String getTableName();
|
||||
|
||||
public List<String> columnNames();
|
||||
}
|
|
@ -27,51 +27,51 @@ public interface EntitySource extends IdentifiableTypeSource, ToolingHintContext
|
|||
*
|
||||
* @return The primary table.
|
||||
*/
|
||||
public TableSpecificationSource getPrimaryTable();
|
||||
TableSpecificationSource getPrimaryTable();
|
||||
|
||||
/**
|
||||
* Obtain the secondary tables for this entity
|
||||
*
|
||||
* @return returns an iterator over the secondary tables for this entity
|
||||
*/
|
||||
public Map<String,SecondaryTableSource> getSecondaryTableMap();
|
||||
Map<String,SecondaryTableSource> getSecondaryTableMap();
|
||||
|
||||
public String getXmlNodeName();
|
||||
String getXmlNodeName();
|
||||
|
||||
/**
|
||||
* Obtain the named custom tuplizer classes to be used.
|
||||
*
|
||||
* @return The custom tuplizer class names
|
||||
*/
|
||||
public Map<EntityMode,String> getTuplizerClassMap();
|
||||
Map<EntityMode,String> getTuplizerClassMap();
|
||||
|
||||
/**
|
||||
* Obtain the name of a custom persister class to be used.
|
||||
*
|
||||
* @return The custom persister class name
|
||||
*/
|
||||
public String getCustomPersisterClassName();
|
||||
String getCustomPersisterClassName();
|
||||
|
||||
/**
|
||||
* Is this entity lazy (proxyable)?
|
||||
*
|
||||
* @return {@code true} indicates the entity is lazy; {@code false} non-lazy.
|
||||
*/
|
||||
public boolean isLazy();
|
||||
boolean isLazy();
|
||||
|
||||
/**
|
||||
* For {@link #isLazy() lazy} entities, obtain the interface to use in constructing its proxies.
|
||||
*
|
||||
* @return The proxy interface name
|
||||
*/
|
||||
public String getProxy();
|
||||
String getProxy();
|
||||
|
||||
/**
|
||||
* Obtain the batch-size to be applied when initializing proxies of this entity.
|
||||
*
|
||||
* @return returns the the batch-size.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
int getBatchSize();
|
||||
|
||||
/**
|
||||
* Is the entity abstract?
|
||||
|
@ -81,63 +81,63 @@ public interface EntitySource extends IdentifiableTypeSource, ToolingHintContext
|
|||
* @return {@code true} indicates the entity is abstract; {@code false} non-abstract; {@code null}
|
||||
* indicates that a reflection check should be done when building the persister.
|
||||
*/
|
||||
public Boolean isAbstract();
|
||||
Boolean isAbstract();
|
||||
|
||||
/**
|
||||
* Did the source specify dynamic inserts?
|
||||
*
|
||||
* @return {@code true} indicates dynamic inserts will be used; {@code false} otherwise.
|
||||
*/
|
||||
public boolean isDynamicInsert();
|
||||
boolean isDynamicInsert();
|
||||
|
||||
/**
|
||||
* Did the source specify dynamic updates?
|
||||
*
|
||||
* @return {@code true} indicates dynamic updates will be used; {@code false} otherwise.
|
||||
*/
|
||||
public boolean isDynamicUpdate();
|
||||
boolean isDynamicUpdate();
|
||||
|
||||
/**
|
||||
* Did the source specify to perform selects to decide whether to perform (detached) updates?
|
||||
*
|
||||
* @return {@code true} indicates selects will be done; {@code false} otherwise.
|
||||
*/
|
||||
public boolean isSelectBeforeUpdate();
|
||||
boolean isSelectBeforeUpdate();
|
||||
|
||||
/**
|
||||
* Obtain the name of a named-query that will be used for loading this entity
|
||||
*
|
||||
* @return THe custom loader query name
|
||||
*/
|
||||
public String getCustomLoaderName();
|
||||
String getCustomLoaderName();
|
||||
|
||||
/**
|
||||
* Obtain the custom SQL to be used for inserts for this entity
|
||||
*
|
||||
* @return The custom insert SQL
|
||||
*/
|
||||
public CustomSql getCustomSqlInsert();
|
||||
CustomSql getCustomSqlInsert();
|
||||
|
||||
/**
|
||||
* Obtain the custom SQL to be used for updates for this entity
|
||||
*
|
||||
* @return The custom update SQL
|
||||
*/
|
||||
public CustomSql getCustomSqlUpdate();
|
||||
CustomSql getCustomSqlUpdate();
|
||||
|
||||
/**
|
||||
* Obtain the custom SQL to be used for deletes for this entity
|
||||
*
|
||||
* @return The custom delete SQL
|
||||
*/
|
||||
public CustomSql getCustomSqlDelete();
|
||||
CustomSql getCustomSqlDelete();
|
||||
|
||||
/**
|
||||
* Obtain any additional table names on which to synchronize (auto flushing) this entity.
|
||||
*
|
||||
* @return Additional synchronized table names or 0 sized String array, never return null.
|
||||
*/
|
||||
public String[] getSynchronizedTableNames();
|
||||
String[] getSynchronizedTableNames();
|
||||
|
||||
/**
|
||||
* Get the actual discriminator value in case of a single table inheritance
|
||||
|
@ -145,24 +145,19 @@ public interface EntitySource extends IdentifiableTypeSource, ToolingHintContext
|
|||
* @return the actual discriminator value in case of a single table inheritance or {@code null} in case there is no
|
||||
* explicit value or a different inheritance scheme
|
||||
*/
|
||||
public String getDiscriminatorMatchValue();
|
||||
|
||||
/**
|
||||
* @return returns the source information for constraints defined on the table
|
||||
*/
|
||||
public Collection<ConstraintSource> getConstraints();
|
||||
String getDiscriminatorMatchValue();
|
||||
|
||||
/**
|
||||
* Obtain the filters for this entity.
|
||||
*
|
||||
* @return returns an array of the filters for this entity.
|
||||
*/
|
||||
public FilterSource[] getFilterSources();
|
||||
FilterSource[] getFilterSources();
|
||||
|
||||
public List<JaxbHbmNamedQueryType> getNamedQueries();
|
||||
List<JaxbHbmNamedQueryType> getNamedQueries();
|
||||
|
||||
public List<JaxbHbmNamedNativeQueryType> getNamedNativeQueries();
|
||||
List<JaxbHbmNamedNativeQueryType> getNamedNativeQueries();
|
||||
|
||||
public TruthValue quoteIdentifiersLocalToEntity();
|
||||
TruthValue quoteIdentifiersLocalToEntity();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.boot.model.source.spi;
|
||||
|
||||
/**
|
||||
* Defining a index constraint source
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public interface IndexConstraintSource extends ConstraintSource {
|
||||
public boolean isUnique();
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.boot.model.source.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface UniqueKeyConstraintSource extends ConstraintSource {
|
||||
}
|
|
@ -44,7 +44,7 @@ public class IndexTest extends BaseUnitTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-10208" )
|
||||
// @FailureExpected( jiraKey = "HHH-10208" )
|
||||
public void testOneToMany() throws Exception {
|
||||
verifyIndexCreated(
|
||||
"org/hibernate/test/hbm/index/person_manytoone.hbm.xml",
|
||||
|
@ -68,7 +68,7 @@ public class IndexTest extends BaseUnitTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-10208" )
|
||||
// @FailureExpected( jiraKey = "HHH-10208" )
|
||||
public void testProperty() throws Exception {
|
||||
verifyIndexCreated(
|
||||
"org/hibernate/test/hbm/index/person_property.hbm.xml",
|
||||
|
|
Loading…
Reference in New Issue