HHH-17103 massively simplify @Index + @UniqueKey handling
There was a whole completely unnecessary second-pass-based lifecycle making everything way more complicated than it needed to be.
This commit is contained in:
parent
5bfe11fd27
commit
367a647412
|
@ -19,7 +19,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.DuplicateMappingException;
|
import org.hibernate.DuplicateMappingException;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
@ -57,9 +56,6 @@ import org.hibernate.boot.model.internal.SetBasicValueTypeSecondPass;
|
||||||
import org.hibernate.boot.model.internal.UniqueConstraintHolder;
|
import org.hibernate.boot.model.internal.UniqueConstraintHolder;
|
||||||
import org.hibernate.boot.model.naming.Identifier;
|
import org.hibernate.boot.model.naming.Identifier;
|
||||||
import org.hibernate.boot.model.naming.ImplicitForeignKeyNameSource;
|
import org.hibernate.boot.model.naming.ImplicitForeignKeyNameSource;
|
||||||
import org.hibernate.boot.model.naming.ImplicitIndexNameSource;
|
|
||||||
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
|
||||||
import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource;
|
|
||||||
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
|
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
|
||||||
import org.hibernate.boot.model.relational.Database;
|
import org.hibernate.boot.model.relational.Database;
|
||||||
import org.hibernate.boot.model.relational.ExportableProducer;
|
import org.hibernate.boot.model.relational.ExportableProducer;
|
||||||
|
@ -92,19 +88,15 @@ import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.DenormalizedTable;
|
import org.hibernate.mapping.DenormalizedTable;
|
||||||
import org.hibernate.mapping.FetchProfile;
|
import org.hibernate.mapping.FetchProfile;
|
||||||
import org.hibernate.mapping.ForeignKey;
|
import org.hibernate.mapping.ForeignKey;
|
||||||
import org.hibernate.mapping.Formula;
|
|
||||||
import org.hibernate.mapping.IdentifierCollection;
|
import org.hibernate.mapping.IdentifierCollection;
|
||||||
import org.hibernate.mapping.Index;
|
|
||||||
import org.hibernate.mapping.Join;
|
import org.hibernate.mapping.Join;
|
||||||
import org.hibernate.mapping.KeyValue;
|
import org.hibernate.mapping.KeyValue;
|
||||||
import org.hibernate.mapping.MappedSuperclass;
|
import org.hibernate.mapping.MappedSuperclass;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.RootClass;
|
import org.hibernate.mapping.RootClass;
|
||||||
import org.hibernate.mapping.Selectable;
|
|
||||||
import org.hibernate.mapping.SimpleValue;
|
import org.hibernate.mapping.SimpleValue;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
import org.hibernate.mapping.UniqueKey;
|
|
||||||
import org.hibernate.metamodel.CollectionClassification;
|
import org.hibernate.metamodel.CollectionClassification;
|
||||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||||
import org.hibernate.query.named.NamedObjectRepository;
|
import org.hibernate.query.named.NamedObjectRepository;
|
||||||
|
@ -122,7 +114,6 @@ import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.MapsId;
|
import jakarta.persistence.MapsId;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,8 +172,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
||||||
private Map<String, String> mappedByResolver;
|
private Map<String, String> mappedByResolver;
|
||||||
private Map<String, String> propertyRefResolver;
|
private Map<String, String> propertyRefResolver;
|
||||||
private Set<DelayedPropertyReferenceHandler> delayedPropertyReferenceHandlers;
|
private Set<DelayedPropertyReferenceHandler> delayedPropertyReferenceHandlers;
|
||||||
private Map<Table, List<UniqueConstraintHolder>> uniqueConstraintHoldersByTable;
|
|
||||||
private Map<Table, List<IndexHolder>> indexHoldersByTable;
|
|
||||||
private List<Function<MetadataBuildingContext, Boolean>> valueResolvers;
|
private List<Function<MetadataBuildingContext, Boolean>> valueResolvers;
|
||||||
|
|
||||||
public InFlightMetadataCollectorImpl(
|
public InFlightMetadataCollectorImpl(
|
||||||
|
@ -1440,59 +1429,16 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
||||||
|
|
||||||
@Override @Deprecated(forRemoval = true)
|
@Override @Deprecated(forRemoval = true)
|
||||||
public void addUniqueConstraints(Table table, List<String[]> uniqueConstraints) {
|
public void addUniqueConstraints(Table table, List<String[]> uniqueConstraints) {
|
||||||
List<UniqueConstraintHolder> constraintHolders = new ArrayList<>( uniqueConstraints.size() );
|
throw new UnsupportedOperationException("addUniqueConstraints() will be removed");
|
||||||
|
|
||||||
int keyNameBase = determineCurrentNumberOfUniqueConstraintHolders( table );
|
|
||||||
for ( String[] columns : uniqueConstraints ) {
|
|
||||||
final String keyName = "key" + keyNameBase++;
|
|
||||||
constraintHolders.add(
|
|
||||||
new UniqueConstraintHolder( keyName, columns )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
addUniqueConstraintHolders( table, constraintHolders );
|
|
||||||
}
|
}
|
||||||
|
@Override @Deprecated(forRemoval = true)
|
||||||
private int determineCurrentNumberOfUniqueConstraintHolders(Table table) {
|
|
||||||
List currentHolders = uniqueConstraintHoldersByTable == null ? null : uniqueConstraintHoldersByTable.get( table );
|
|
||||||
return currentHolders == null ? 0 : currentHolders.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addUniqueConstraintHolders(Table table, List<UniqueConstraintHolder> holders) {
|
public void addUniqueConstraintHolders(Table table, List<UniqueConstraintHolder> holders) {
|
||||||
List<UniqueConstraintHolder> holderList = null;
|
throw new UnsupportedOperationException("addUniqueConstraintHolders() will be removed");
|
||||||
|
|
||||||
if ( uniqueConstraintHoldersByTable == null ) {
|
|
||||||
uniqueConstraintHoldersByTable = new HashMap<>();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
holderList = uniqueConstraintHoldersByTable.get( table );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( holderList == null ) {
|
|
||||||
holderList = new ArrayList<>();
|
|
||||||
uniqueConstraintHoldersByTable.put( table, holderList );
|
|
||||||
}
|
|
||||||
|
|
||||||
holderList.addAll( holders );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override @Deprecated(forRemoval = true)
|
||||||
public void addIndexHolders(Table table, List<IndexHolder> holders) {
|
public void addIndexHolders(Table table, List<IndexHolder> holders) {
|
||||||
List<IndexHolder> holderList = null;
|
throw new UnsupportedOperationException("addIndexHolders() will be removed");
|
||||||
|
|
||||||
if ( indexHoldersByTable == null ) {
|
|
||||||
indexHoldersByTable = new HashMap<>();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
holderList = indexHoldersByTable.get( table );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( holderList == null ) {
|
|
||||||
holderList = new ArrayList<>();
|
|
||||||
indexHoldersByTable.put( table, holderList );
|
|
||||||
}
|
|
||||||
|
|
||||||
holderList.addAll( holders );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<String,EntityTableXrefImpl> entityTableXrefMap = new HashMap<>();
|
private final Map<String,EntityTableXrefImpl> entityTableXrefMap = new HashMap<>();
|
||||||
|
@ -1848,9 +1794,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
||||||
|
|
||||||
secondPassCompileForeignKeys( buildingContext );
|
secondPassCompileForeignKeys( buildingContext );
|
||||||
|
|
||||||
processUniqueConstraintHolders( buildingContext );
|
|
||||||
processIndexHolders( buildingContext );
|
|
||||||
|
|
||||||
processNaturalIdUniqueKeyBinders();
|
processNaturalIdUniqueKeyBinders();
|
||||||
|
|
||||||
processCachingOverrides();
|
processCachingOverrides();
|
||||||
|
@ -2044,18 +1987,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Identifier> toIdentifiers(String[] names) {
|
|
||||||
if ( names == null ) {
|
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Identifier> columnNames = arrayList( names.length );
|
|
||||||
for ( String name : names ) {
|
|
||||||
columnNames.add( getDatabase().toIdentifier( name ) );
|
|
||||||
}
|
|
||||||
return columnNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Identifier> extractColumnNames(List<Column> columns) {
|
private List<Identifier> extractColumnNames(List<Column> columns) {
|
||||||
if ( columns == null || columns.isEmpty() ) {
|
if ( columns == null || columns.isEmpty() ) {
|
||||||
return emptyList();
|
return emptyList();
|
||||||
|
@ -2082,141 +2013,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
||||||
delayedPropertyReferenceHandlers.clear();
|
delayedPropertyReferenceHandlers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processUniqueConstraintHolders(MetadataBuildingContext buildingContext) {
|
|
||||||
if ( uniqueConstraintHoldersByTable == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( Map.Entry<Table, List<UniqueConstraintHolder>> tableListEntry : uniqueConstraintHoldersByTable.entrySet() ) {
|
|
||||||
final Table table = tableListEntry.getKey();
|
|
||||||
final List<UniqueConstraintHolder> uniqueConstraints = tableListEntry.getValue();
|
|
||||||
for ( UniqueConstraintHolder holder : uniqueConstraints ) {
|
|
||||||
buildUniqueKeyFromColumnNames( table, holder.getName(), holder.isNameExplicit(), holder.getColumns(), buildingContext );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uniqueConstraintHoldersByTable.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildUniqueKeyFromColumnNames(
|
|
||||||
Table table,
|
|
||||||
String keyName,
|
|
||||||
boolean nameExplicit,
|
|
||||||
String[] columnNames,
|
|
||||||
MetadataBuildingContext context) {
|
|
||||||
buildUniqueKeyFromColumnNames( table, keyName, nameExplicit, columnNames, null, true, context );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildUniqueKeyFromColumnNames(
|
|
||||||
final Table table,
|
|
||||||
String keyName,
|
|
||||||
boolean nameExplicit,
|
|
||||||
final String[] columnNames,
|
|
||||||
String[] orderings,
|
|
||||||
boolean unique,
|
|
||||||
final MetadataBuildingContext context) {
|
|
||||||
final int size = columnNames.length;
|
|
||||||
if ( size == 0 ) {
|
|
||||||
throw new AnnotationException( ( unique ? "Unique constraint" : "Index" )
|
|
||||||
+ ( isEmpty( keyName ) ? "" : " '" + keyName + "'" )
|
|
||||||
+ " on table '" + table.getName() + "' has no columns" );
|
|
||||||
}
|
|
||||||
final Selectable[] columns = new Selectable[size];
|
|
||||||
for ( int index = 0; index < size; index++ ) {
|
|
||||||
final String columnName = columnNames[index];
|
|
||||||
if ( isEmpty( columnName ) ) {
|
|
||||||
throw new AnnotationException( ( unique ? "Unique constraint" : "Index" )
|
|
||||||
+ ( isEmpty( keyName ) ? "" : " '" + keyName + "'" )
|
|
||||||
+ " on table '" + table.getName() + "' has an empty column name" );
|
|
||||||
}
|
|
||||||
columns[index] = indexColumn( table, context, columnName);
|
|
||||||
}
|
|
||||||
createIndexOrUniqueKey( table, keyName, nameExplicit, columnNames, orderings, unique, context, columns );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Selectable indexColumn(Table table, MetadataBuildingContext buildingContext, String logicalColumnName) {
|
|
||||||
if ( logicalColumnName.startsWith("(") ) {
|
|
||||||
return new Formula( logicalColumnName );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Column column;
|
|
||||||
try {
|
|
||||||
column = table.getColumn( buildingContext.getMetadataCollector(), logicalColumnName );
|
|
||||||
}
|
|
||||||
catch (MappingException me) {
|
|
||||||
column = null;
|
|
||||||
}
|
|
||||||
if ( column != null ) {
|
|
||||||
return column;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// assume it's a SQL formula with missing parens
|
|
||||||
return new Formula( "(" + logicalColumnName + ")" );
|
|
||||||
// throw new AnnotationException(
|
|
||||||
// "Table '" + table.getName() + "' has no column named '" + logicalColumnName
|
|
||||||
// + "' matching the column specified in '@UniqueConstraint'"
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createIndexOrUniqueKey(
|
|
||||||
Table table,
|
|
||||||
String originalKeyName,
|
|
||||||
boolean nameExplicit,
|
|
||||||
String[] columnNames,
|
|
||||||
String[] orderings,
|
|
||||||
boolean unique,
|
|
||||||
MetadataBuildingContext context,
|
|
||||||
Selectable[] columns) {
|
|
||||||
final ImplicitNamingStrategy naming = getMetadataBuildingOptions().getImplicitNamingStrategy();
|
|
||||||
final IndexOrUniqueKeyNameSource source =
|
|
||||||
new IndexOrUniqueKeyNameSource( context, table, columnNames, originalKeyName );
|
|
||||||
final Dialect dialect = getDatabase().getJdbcEnvironment().getDialect();
|
|
||||||
boolean hasFormula = false;
|
|
||||||
for ( Selectable selectable : columns ) {
|
|
||||||
if ( selectable.isFormula() ) {
|
|
||||||
hasFormula = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( unique && !hasFormula ) {
|
|
||||||
final String keyName = naming.determineUniqueKeyName( source ).render( dialect );
|
|
||||||
final UniqueKey uniqueKey = table.getOrCreateUniqueKey( keyName );
|
|
||||||
uniqueKey.setNameExplicit( nameExplicit );
|
|
||||||
for ( int i = 0; i < columns.length; i++ ) {
|
|
||||||
uniqueKey.addColumn( (Column) columns[i], orderings != null ? orderings[i] : null );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final String keyName = naming.determineIndexName( source ).render( dialect );
|
|
||||||
final Index index = table.getOrCreateIndex( keyName );
|
|
||||||
index.setUnique( unique );
|
|
||||||
for ( int i = 0; i < columns.length; i++ ) {
|
|
||||||
index.addColumn( columns[i], orderings != null ? orderings[i] : null );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processIndexHolders(MetadataBuildingContext context) {
|
|
||||||
if ( indexHoldersByTable != null ) {
|
|
||||||
for ( Map.Entry<Table, List<IndexHolder>> entry : indexHoldersByTable.entrySet() ) {
|
|
||||||
final Table table = entry.getKey();
|
|
||||||
final List<IndexHolder> indexHolders = entry.getValue();
|
|
||||||
for ( IndexHolder holder : indexHolders) {
|
|
||||||
buildUniqueKeyFromColumnNames(
|
|
||||||
table,
|
|
||||||
holder.getName(),
|
|
||||||
!holder.getName().isEmpty(),
|
|
||||||
holder.getColumns(),
|
|
||||||
holder.getOrdering(),
|
|
||||||
holder.isUnique(),
|
|
||||||
context
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String,NaturalIdUniqueKeyBinder> naturalIdUniqueKeyBinderMap;
|
private Map<String,NaturalIdUniqueKeyBinder> naturalIdUniqueKeyBinderMap;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2394,46 +2190,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IndexOrUniqueKeyNameSource implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource {
|
|
||||||
private final MetadataBuildingContext buildingContext;
|
|
||||||
private final Table table;
|
|
||||||
private final String[] columnNames;
|
|
||||||
private final String originalKeyName;
|
|
||||||
|
|
||||||
public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, String[] columnNames, String originalKeyName) {
|
|
||||||
this.buildingContext = buildingContext;
|
|
||||||
this.table = table;
|
|
||||||
this.columnNames = columnNames;
|
|
||||||
this.originalKeyName = originalKeyName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MetadataBuildingContext getBuildingContext() {
|
|
||||||
return buildingContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Identifier getTableName() {
|
|
||||||
return table.getNameIdentifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Identifier> columnNameIdentifiers;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Identifier> getColumnNames() {
|
|
||||||
// be lazy about building these
|
|
||||||
if ( columnNameIdentifiers == null ) {
|
|
||||||
columnNameIdentifiers = toIdentifiers(columnNames);
|
|
||||||
}
|
|
||||||
return columnNameIdentifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Identifier getUserProvidedIdentifier() {
|
|
||||||
return originalKeyName != null ? Identifier.toIdentifier(originalKeyName) : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ForeignKeyNameSource implements ImplicitForeignKeyNameSource {
|
private class ForeignKeyNameSource implements ImplicitForeignKeyNameSource {
|
||||||
final List<Identifier> columnNames;
|
final List<Identifier> columnNames;
|
||||||
private final ForeignKey foreignKey;
|
private final ForeignKey foreignKey;
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||||
import org.hibernate.boot.model.relational.Database;
|
import org.hibernate.boot.model.relational.Database;
|
||||||
import org.hibernate.boot.model.source.spi.AttributePath;
|
import org.hibernate.boot.model.source.spi.AttributePath;
|
||||||
|
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.boot.spi.PropertyData;
|
import org.hibernate.boot.spi.PropertyData;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
|
@ -433,17 +434,14 @@ public class AnnotatedColumn {
|
||||||
|
|
||||||
protected void addColumnBinding(SimpleValue value) {
|
protected void addColumnBinding(SimpleValue value) {
|
||||||
final String logicalColumnName;
|
final String logicalColumnName;
|
||||||
|
final MetadataBuildingContext context = getBuildingContext();
|
||||||
|
final InFlightMetadataCollector collector = context.getMetadataCollector();
|
||||||
if ( isNotEmpty( this.logicalColumnName ) ) {
|
if ( isNotEmpty( this.logicalColumnName ) ) {
|
||||||
logicalColumnName = this.logicalColumnName;
|
logicalColumnName = this.logicalColumnName;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final ObjectNameNormalizer normalizer = getBuildingContext().getObjectNameNormalizer();
|
final Identifier implicitName = context.getObjectNameNormalizer().normalizeIdentifierQuoting(
|
||||||
final Database database = getBuildingContext().getMetadataCollector().getDatabase();
|
context.getBuildingOptions().getImplicitNamingStrategy().determineBasicColumnName(
|
||||||
final ImplicitNamingStrategy implicitNamingStrategy = getBuildingContext().getBuildingOptions()
|
|
||||||
.getImplicitNamingStrategy();
|
|
||||||
|
|
||||||
final Identifier implicitName = normalizer.normalizeIdentifierQuoting(
|
|
||||||
implicitNamingStrategy.determineBasicColumnName(
|
|
||||||
new ImplicitBasicColumnNameSource() {
|
new ImplicitBasicColumnNameSource() {
|
||||||
@Override
|
@Override
|
||||||
public AttributePath getAttributePath() {
|
public AttributePath getAttributePath() {
|
||||||
|
@ -457,14 +455,14 @@ public class AnnotatedColumn {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MetadataBuildingContext getBuildingContext() {
|
public MetadataBuildingContext getBuildingContext() {
|
||||||
return AnnotatedColumn.this.getBuildingContext();
|
return context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
logicalColumnName = implicitName.render( database.getDialect() );
|
logicalColumnName = implicitName.render( collector.getDatabase().getDialect() );
|
||||||
}
|
}
|
||||||
getBuildingContext().getMetadataCollector().addColumnNameBinding( value.getTable(), logicalColumnName, getMappingColumn() );
|
collector.addColumnNameBinding( value.getTable(), logicalColumnName, getMappingColumn() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forceNotNull() {
|
public void forceNotNull() {
|
||||||
|
|
|
@ -12,8 +12,6 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
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.relational.Database;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.internal.util.MutableInteger;
|
import org.hibernate.internal.util.MutableInteger;
|
||||||
|
@ -69,26 +67,7 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
||||||
@Override
|
@Override
|
||||||
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
|
||||||
final PersistentClass referencedPersistentClass = persistentClasses.get( referencedEntityName );
|
final PersistentClass referencedPersistentClass = persistentClasses.get( referencedEntityName );
|
||||||
if ( referencedPersistentClass == null ) {
|
final Component referencedComponent = getReferencedComponent( referencedPersistentClass );
|
||||||
// TODO: much better error message if this is something that can really happen!
|
|
||||||
throw new AnnotationException( "Unknown entity name '" + referencedEntityName + "'");
|
|
||||||
}
|
|
||||||
final KeyValue identifier = referencedPersistentClass.getIdentifier();
|
|
||||||
if ( !(identifier instanceof Component) ) {
|
|
||||||
// The entity with the @MapsId annotation has a composite
|
|
||||||
// id type, but the referenced entity has a basic-typed id.
|
|
||||||
// Therefore, the @MapsId annotation should have specified
|
|
||||||
// a property of the composite id that has the foreign key
|
|
||||||
throw new AnnotationException(
|
|
||||||
"Missing 'value' in '@MapsId' annotation of association '" + propertyName
|
|
||||||
+ "' of entity '" + component.getOwner().getEntityName()
|
|
||||||
+ "' with composite identifier type"
|
|
||||||
+ " ('@MapsId' must specify a property of the '@EmbeddedId' class which has the foreign key of '"
|
|
||||||
+ referencedEntityName + "')"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Component referencedComponent = (Component) identifier;
|
|
||||||
|
|
||||||
//prepare column name structure
|
//prepare column name structure
|
||||||
boolean isExplicitReference = true;
|
boolean isExplicitReference = true;
|
||||||
|
@ -113,7 +92,6 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
||||||
final Property property;
|
final Property property;
|
||||||
if ( referencedProperty.isComposite() ) {
|
if ( referencedProperty.isComposite() ) {
|
||||||
property = createComponentProperty(
|
property = createComponentProperty(
|
||||||
referencedPersistentClass,
|
|
||||||
isExplicitReference,
|
isExplicitReference,
|
||||||
columnByReferencedName,
|
columnByReferencedName,
|
||||||
index,
|
index,
|
||||||
|
@ -133,8 +111,29 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Component getReferencedComponent(PersistentClass referencedPersistentClass) {
|
||||||
|
if ( referencedPersistentClass == null ) {
|
||||||
|
// TODO: much better error message if this is something that can really happen!
|
||||||
|
throw new AnnotationException( "Unknown entity name '" + referencedEntityName + "'");
|
||||||
|
}
|
||||||
|
final KeyValue identifier = referencedPersistentClass.getIdentifier();
|
||||||
|
if ( !(identifier instanceof Component) ) {
|
||||||
|
// The entity with the @MapsId annotation has a composite
|
||||||
|
// id type, but the referenced entity has a basic-typed id.
|
||||||
|
// Therefore, the @MapsId annotation should have specified
|
||||||
|
// a property of the composite id that has the foreign key
|
||||||
|
throw new AnnotationException(
|
||||||
|
"Missing 'value' in '@MapsId' annotation of association '" + propertyName
|
||||||
|
+ "' of entity '" + component.getOwner().getEntityName()
|
||||||
|
+ "' with composite identifier type"
|
||||||
|
+ " ('@MapsId' must specify a property of the '@EmbeddedId' class which has the foreign key of '"
|
||||||
|
+ referencedEntityName + "')"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (Component) identifier;
|
||||||
|
}
|
||||||
|
|
||||||
private Property createComponentProperty(
|
private Property createComponentProperty(
|
||||||
PersistentClass referencedPersistentClass,
|
|
||||||
boolean isExplicitReference,
|
boolean isExplicitReference,
|
||||||
Map<String, AnnotatedJoinColumn> columnByReferencedName,
|
Map<String, AnnotatedJoinColumn> columnByReferencedName,
|
||||||
MutableInteger index,
|
MutableInteger index,
|
||||||
|
@ -156,12 +155,21 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
||||||
|
|
||||||
for ( Property referencedComponentProperty : referencedValue.getProperties() ) {
|
for ( Property referencedComponentProperty : referencedValue.getProperties() ) {
|
||||||
if ( referencedComponentProperty.isComposite() ) {
|
if ( referencedComponentProperty.isComposite() ) {
|
||||||
Property componentProperty = createComponentProperty( referencedValue.getOwner(), isExplicitReference, columnByReferencedName, index, referencedComponentProperty );
|
value.addProperty( createComponentProperty(
|
||||||
value.addProperty( componentProperty );
|
isExplicitReference,
|
||||||
|
columnByReferencedName,
|
||||||
|
index,
|
||||||
|
referencedComponentProperty
|
||||||
|
) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Property componentProperty = createSimpleProperty( referencedValue.getOwner(), isExplicitReference, columnByReferencedName, index, referencedComponentProperty );
|
value.addProperty( createSimpleProperty(
|
||||||
value.addProperty( componentProperty );
|
referencedValue.getOwner(),
|
||||||
|
isExplicitReference,
|
||||||
|
columnByReferencedName,
|
||||||
|
index,
|
||||||
|
referencedComponentProperty
|
||||||
|
) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,10 +236,11 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
||||||
: joinColumn.getName();
|
: joinColumn.getName();
|
||||||
|
|
||||||
final Database database = buildingContext.getMetadataCollector().getDatabase();
|
final Database database = buildingContext.getMetadataCollector().getDatabase();
|
||||||
final PhysicalNamingStrategy physicalNamingStrategy = buildingContext.getBuildingOptions().getPhysicalNamingStrategy();
|
final String physicalName =
|
||||||
final Identifier explicitName = database.toIdentifier( columnName );
|
buildingContext.getBuildingOptions().getPhysicalNamingStrategy()
|
||||||
final Identifier physicalName = physicalNamingStrategy.toPhysicalColumnName( explicitName, database.getJdbcEnvironment() );
|
.toPhysicalColumnName( database.toIdentifier( columnName ), database.getJdbcEnvironment() )
|
||||||
value.addColumn( new Column( physicalName.render( database.getDialect() ) ) );
|
.render( database.getDialect() );
|
||||||
|
value.addColumn( new Column( physicalName ) );
|
||||||
if ( joinColumn != null ) {
|
if ( joinColumn != null ) {
|
||||||
applyComponentColumnSizeValueToJoinColumn( column, joinColumn );
|
applyComponentColumnSizeValueToJoinColumn( column, joinColumn );
|
||||||
joinColumn.linkWithValue( value );
|
joinColumn.linkWithValue( value );
|
||||||
|
@ -243,7 +252,7 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyComponentColumnSizeValueToJoinColumn(Column column, AnnotatedJoinColumn joinColumn) {
|
private void applyComponentColumnSizeValueToJoinColumn(Column column, AnnotatedJoinColumn joinColumn) {
|
||||||
Column mappingColumn = joinColumn.getMappingColumn();
|
final Column mappingColumn = joinColumn.getMappingColumn();
|
||||||
mappingColumn.setLength( column.getLength() );
|
mappingColumn.setLength( column.getLength() );
|
||||||
mappingColumn.setPrecision( column.getPrecision() );
|
mappingColumn.setPrecision( column.getPrecision() );
|
||||||
mappingColumn.setScale( column.getScale() );
|
mappingColumn.setScale( column.getScale() );
|
||||||
|
|
|
@ -2051,8 +2051,7 @@ public class EntityBinder {
|
||||||
secondaryTable.uniqueConstraints()
|
secondaryTable.uniqueConstraints()
|
||||||
);
|
);
|
||||||
final Table table = join.getTable();
|
final Table table = join.getTable();
|
||||||
context.getMetadataCollector()
|
new IndexBinder( context ).bindIndexes( table, secondaryTable.indexes() );
|
||||||
.addIndexHolders( table, TableBinder.buildIndexHolders( secondaryTable.indexes() ) );
|
|
||||||
return join;
|
return join;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2239,9 +2238,7 @@ public class EntityBinder {
|
||||||
|
|
||||||
public void processComplementaryTableDefinitions(jakarta.persistence.Table table) {
|
public void processComplementaryTableDefinitions(jakarta.persistence.Table table) {
|
||||||
if ( table != null ) {
|
if ( table != null ) {
|
||||||
final Table classTable = persistentClass.getTable();
|
new IndexBinder( context ).bindIndexes( persistentClass.getTable(), table.indexes() );
|
||||||
context.getMetadataCollector()
|
|
||||||
.addIndexHolders( classTable, TableBinder.buildIndexHolders( table.indexes() ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* 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.internal;
|
||||||
|
|
||||||
|
import jakarta.persistence.UniqueConstraint;
|
||||||
|
import org.hibernate.AnnotationException;
|
||||||
|
import org.hibernate.boot.model.naming.Identifier;
|
||||||
|
import org.hibernate.boot.model.naming.ImplicitIndexNameSource;
|
||||||
|
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||||
|
import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource;
|
||||||
|
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
||||||
|
import org.hibernate.boot.model.relational.Database;
|
||||||
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.mapping.Column;
|
||||||
|
import org.hibernate.mapping.Formula;
|
||||||
|
import org.hibernate.mapping.Index;
|
||||||
|
import org.hibernate.mapping.Selectable;
|
||||||
|
import org.hibernate.mapping.Table;
|
||||||
|
import org.hibernate.mapping.UniqueKey;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||||
|
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for interpreting {@link jakarta.persistence.Index} and
|
||||||
|
* {@link UniqueConstraint} annotations.
|
||||||
|
*
|
||||||
|
* @author Gavin King
|
||||||
|
*/
|
||||||
|
class IndexBinder {
|
||||||
|
|
||||||
|
private final MetadataBuildingContext context;
|
||||||
|
|
||||||
|
IndexBinder(MetadataBuildingContext context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Database getDatabase() {
|
||||||
|
return context.getMetadataCollector().getDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImplicitNamingStrategy getImplicitNamingStrategy() {
|
||||||
|
return context.getBuildingOptions().getImplicitNamingStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PhysicalNamingStrategy getPhysicalNamingStrategy() {
|
||||||
|
return context.getBuildingOptions().getPhysicalNamingStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dialect getDialect() {
|
||||||
|
return getDatabase().getJdbcEnvironment().getDialect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Selectable selectable(Table table, String columnNameOrFormula) {
|
||||||
|
if ( columnNameOrFormula.startsWith("(") ) {
|
||||||
|
return new Formula( columnNameOrFormula );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return createColumn( columnNameOrFormula );
|
||||||
|
// Column column;
|
||||||
|
// try {
|
||||||
|
// column = table.getColumn( context.getMetadataCollector(), columnNameOrFormula );
|
||||||
|
// }
|
||||||
|
// catch (MappingException me) {
|
||||||
|
// column = null;
|
||||||
|
// }
|
||||||
|
// return column == null
|
||||||
|
// // Assume it's actually a formula with missing parens
|
||||||
|
// ? new Formula( "(" + columnNameOrFormula + ")" )
|
||||||
|
// : column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Column column(Table table, String columnName) {
|
||||||
|
return createColumn( columnName );
|
||||||
|
// Column column;
|
||||||
|
// try {
|
||||||
|
// column = table.getColumn( context.getMetadataCollector(), columnName );
|
||||||
|
// }
|
||||||
|
// catch (MappingException me) {
|
||||||
|
// column = null;
|
||||||
|
// }
|
||||||
|
// if ( column != null ) {
|
||||||
|
// return column;
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// throw new AnnotationException(
|
||||||
|
// "Table '" + table.getName() + "' has no column named '" + columnName
|
||||||
|
// + "' matching the column specified in '@UniqueConstraint'"
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Column createColumn(String logicalName) {
|
||||||
|
final Database database = getDatabase();
|
||||||
|
final String physicalName =
|
||||||
|
getPhysicalNamingStrategy()
|
||||||
|
.toPhysicalColumnName( database.toIdentifier( logicalName ), database.getJdbcEnvironment() )
|
||||||
|
.render( getDialect() );
|
||||||
|
return new Column( physicalName );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Selectable[] selectables(Table table, String name, final String[] columnNames) {
|
||||||
|
final int size = columnNames.length;
|
||||||
|
if ( size == 0 ) {
|
||||||
|
throw new AnnotationException( "Index"
|
||||||
|
+ ( isEmpty( name ) ? "" : " '" + name + "'" )
|
||||||
|
+ " on table '" + table.getName() + "' has no columns" );
|
||||||
|
}
|
||||||
|
final Selectable[] columns = new Selectable[size];
|
||||||
|
for ( int index = 0; index < size; index++ ) {
|
||||||
|
final String columnName = columnNames[index];
|
||||||
|
if ( isEmpty( columnName ) ) {
|
||||||
|
throw new AnnotationException( "Index"
|
||||||
|
+ ( isEmpty( name ) ? "" : " '" + name + "'" )
|
||||||
|
+ " on table '" + table.getName() + "' has an empty column name" );
|
||||||
|
}
|
||||||
|
columns[index] = selectable( table, columnName );
|
||||||
|
}
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Column[] columns(Table table, String name, final String[] columnNames) {
|
||||||
|
final int size = columnNames.length;
|
||||||
|
if ( size == 0 ) {
|
||||||
|
throw new AnnotationException( "Unique constraint"
|
||||||
|
+ ( isEmpty( name ) ? "" : " '" + name + "'" )
|
||||||
|
+ " on table '" + table.getName() + "' has no columns" );
|
||||||
|
}
|
||||||
|
final Column[] columns = new Column[size];
|
||||||
|
for ( int index = 0; index < size; index++ ) {
|
||||||
|
final String columnName = columnNames[index];
|
||||||
|
if ( isEmpty( columnName ) ) {
|
||||||
|
throw new AnnotationException( "Unique constraint"
|
||||||
|
+ ( isEmpty( name ) ? "" : " '" + name + "'" )
|
||||||
|
+ " on table '" + table.getName() + "' has an empty column name" );
|
||||||
|
}
|
||||||
|
columns[index] = column( table, columnName );
|
||||||
|
}
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createIndexOrUniqueKey(
|
||||||
|
Table table,
|
||||||
|
String originalKeyName,
|
||||||
|
boolean nameExplicit,
|
||||||
|
String[] columnNames,
|
||||||
|
String[] orderings,
|
||||||
|
boolean unique,
|
||||||
|
Selectable[] columns) {
|
||||||
|
final IndexOrUniqueKeyNameSource source =
|
||||||
|
new IndexOrUniqueKeyNameSource( context, table, columnNames, originalKeyName );
|
||||||
|
boolean hasFormula = false;
|
||||||
|
for ( Selectable selectable : columns ) {
|
||||||
|
if ( selectable.isFormula() ) {
|
||||||
|
hasFormula = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( unique && !hasFormula ) {
|
||||||
|
final String keyName = getImplicitNamingStrategy().determineUniqueKeyName( source ).render( getDialect() );
|
||||||
|
final UniqueKey uniqueKey = table.getOrCreateUniqueKey( keyName );
|
||||||
|
uniqueKey.setNameExplicit( nameExplicit );
|
||||||
|
for ( int i = 0; i < columns.length; i++ ) {
|
||||||
|
uniqueKey.addColumn( (Column) columns[i], orderings != null ? orderings[i] : null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final String keyName = getImplicitNamingStrategy().determineIndexName( source ).render( getDialect() );
|
||||||
|
final Index index = table.getOrCreateIndex( keyName );
|
||||||
|
index.setUnique( unique );
|
||||||
|
for ( int i = 0; i < columns.length; i++ ) {
|
||||||
|
index.addColumn( columns[i], orderings != null ? orderings[i] : null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindIndexes(Table table, jakarta.persistence.Index[] indexes) {
|
||||||
|
for ( jakarta.persistence.Index index : indexes ) {
|
||||||
|
final StringTokenizer tokenizer = new StringTokenizer( index.columnList(), "," );
|
||||||
|
final List<String> parsed = new ArrayList<>();
|
||||||
|
while ( tokenizer.hasMoreElements() ) {
|
||||||
|
final String trimmed = tokenizer.nextToken().trim();
|
||||||
|
if ( !trimmed.isEmpty() ) {
|
||||||
|
parsed.add( trimmed ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String[] columnExpressions = new String[parsed.size()];
|
||||||
|
final String[] ordering = new String[parsed.size()];
|
||||||
|
initializeColumns( columnExpressions, ordering, parsed );
|
||||||
|
final String name = index.name();
|
||||||
|
final boolean unique = index.unique();
|
||||||
|
createIndexOrUniqueKey( table, name, !name.isEmpty(), columnExpressions, ordering, unique,
|
||||||
|
selectables( table, name, columnExpressions ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindUniqueConstraints(Table table, UniqueConstraint[] constraints) {
|
||||||
|
for ( UniqueConstraint constraint : constraints ) {
|
||||||
|
final String name = constraint.name();
|
||||||
|
final String[] columnNames = constraint.columnNames();
|
||||||
|
createIndexOrUniqueKey( table, name, !name.isEmpty(), columnNames, null, true,
|
||||||
|
columns( table, name, columnNames ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeColumns(String[] columns, String[] ordering, List<String> list) {
|
||||||
|
for ( int i = 0, size = list.size(); i < size; i++ ) {
|
||||||
|
final String description = list.get( i );
|
||||||
|
final String tmp = description.toLowerCase(Locale.ROOT);
|
||||||
|
if ( tmp.endsWith( " desc" ) ) {
|
||||||
|
columns[i] = description.substring( 0, description.length() - 5 );
|
||||||
|
ordering[i] = "desc";
|
||||||
|
}
|
||||||
|
else if ( tmp.endsWith( " asc" ) ) {
|
||||||
|
columns[i] = description.substring( 0, description.length() - 4 );
|
||||||
|
ordering[i] = "asc";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
columns[i] = description;
|
||||||
|
ordering[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IndexOrUniqueKeyNameSource implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource {
|
||||||
|
private final MetadataBuildingContext buildingContext;
|
||||||
|
private final Table table;
|
||||||
|
private final String[] columnNames;
|
||||||
|
private final String originalKeyName;
|
||||||
|
|
||||||
|
public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, String[] columnNames, String originalKeyName) {
|
||||||
|
this.buildingContext = buildingContext;
|
||||||
|
this.table = table;
|
||||||
|
this.columnNames = columnNames;
|
||||||
|
this.originalKeyName = originalKeyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetadataBuildingContext getBuildingContext() {
|
||||||
|
return buildingContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier getTableName() {
|
||||||
|
return table.getNameIdentifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Identifier> columnNameIdentifiers;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Identifier> getColumnNames() {
|
||||||
|
// be lazy about building these
|
||||||
|
if ( columnNameIdentifiers == null ) {
|
||||||
|
columnNameIdentifiers = toIdentifiers( columnNames );
|
||||||
|
}
|
||||||
|
return columnNameIdentifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier getUserProvidedIdentifier() {
|
||||||
|
return originalKeyName != null ? Identifier.toIdentifier( originalKeyName ) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Identifier> toIdentifiers(String[] names) {
|
||||||
|
if ( names == null ) {
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Identifier> columnNames = arrayList( names.length );
|
||||||
|
for ( String name : names ) {
|
||||||
|
columnNames.add( getDatabase().toIdentifier( name ) );
|
||||||
|
}
|
||||||
|
return columnNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,7 +15,10 @@ import jakarta.persistence.Index;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Strong Liu
|
* @author Strong Liu
|
||||||
|
*
|
||||||
|
* @deprecated no longer used, will be removed in next release
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.3", forRemoval = true)
|
||||||
public class IndexHolder {
|
public class IndexHolder {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String[] columns;
|
private final String[] columns;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.boot.model.internal;
|
package org.hibernate.boot.model.internal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
import org.hibernate.AnnotationException;
|
||||||
|
@ -43,13 +42,10 @@ import org.jboss.logging.Logger;
|
||||||
import jakarta.persistence.Index;
|
import jakarta.persistence.Index;
|
||||||
import jakarta.persistence.UniqueConstraint;
|
import jakarta.persistence.UniqueConstraint;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||||
import static org.hibernate.internal.util.StringHelper.isQuoted;
|
import static org.hibernate.internal.util.StringHelper.isQuoted;
|
||||||
import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
|
import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
|
||||||
import static org.hibernate.internal.util.StringHelper.unquote;
|
import static org.hibernate.internal.util.StringHelper.unquote;
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stateful binder responsible for producing instances of {@link Table}.
|
* Stateful binder responsible for producing instances of {@link Table}.
|
||||||
|
@ -488,12 +484,12 @@ public class TableBinder {
|
||||||
logicalName, isAbstract, buildingContext, subselect,
|
logicalName, isAbstract, buildingContext, subselect,
|
||||||
denormalizedSuperTableXref, metadataCollector );
|
denormalizedSuperTableXref, metadataCollector );
|
||||||
|
|
||||||
if ( isNotEmpty( uniqueConstraints ) ) {
|
if ( uniqueConstraints != null ) {
|
||||||
metadataCollector.addUniqueConstraintHolders( table, buildUniqueConstraintHolders( uniqueConstraints ) );
|
new IndexBinder( buildingContext ).bindUniqueConstraints( table, uniqueConstraints );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isNotEmpty( indexes ) ) {
|
if ( indexes != null ) {
|
||||||
metadataCollector.addIndexHolders( table, buildIndexHolders( indexes ) );
|
new IndexBinder( buildingContext ).bindIndexes( table, indexes );
|
||||||
}
|
}
|
||||||
|
|
||||||
metadataCollector.addTableNameBinding( logicalName, table );
|
metadataCollector.addTableNameBinding( logicalName, table );
|
||||||
|
@ -815,35 +811,6 @@ public class TableBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a list of {@link IndexHolder} instances given a
|
|
||||||
* list of {@link Index} annotations.
|
|
||||||
*/
|
|
||||||
static List<IndexHolder> buildIndexHolders(Index[] indexes) {
|
|
||||||
List<IndexHolder> holders = new ArrayList<>( indexes.length );
|
|
||||||
for ( Index index : indexes ) {
|
|
||||||
holders.add( new IndexHolder( index ) );
|
|
||||||
}
|
|
||||||
return holders;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a list of {@link UniqueConstraintHolder} instances
|
|
||||||
* given a list of {@link UniqueConstraint} annotations.
|
|
||||||
*/
|
|
||||||
static List<UniqueConstraintHolder> buildUniqueConstraintHolders(UniqueConstraint[] uniqueConstraints) {
|
|
||||||
if ( uniqueConstraints == null || uniqueConstraints.length == 0 ) {
|
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final List<UniqueConstraintHolder> result = arrayList( uniqueConstraints.length );
|
|
||||||
for ( UniqueConstraint uniqueConstraint : uniqueConstraints ) {
|
|
||||||
result.add( new UniqueConstraintHolder( uniqueConstraint ) );
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultName(
|
public void setDefaultName(
|
||||||
String ownerClassName,
|
String ownerClassName,
|
||||||
String ownerEntity,
|
String ownerEntity,
|
||||||
|
|
|
@ -10,14 +10,13 @@ package org.hibernate.boot.model.internal;
|
||||||
import jakarta.persistence.UniqueConstraint;
|
import jakarta.persistence.UniqueConstraint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link jakarta.persistence.UniqueConstraint} annotations are handled via second pass. I do not
|
* {@link jakarta.persistence.UniqueConstraint} annotations are handled via second pass.
|
||||||
* understand the reasons why at this time, so here I use a holder object to hold the information
|
|
||||||
* needed to create the unique constraint. The ability to name it is new, and so the code used to
|
|
||||||
* simply keep this as a String array (the column names).
|
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
*
|
||||||
|
* @deprecated no longer used, will be removed in next release
|
||||||
*/
|
*/
|
||||||
// Isn't this ultimately the same as IndexOrUniqueKeySecondPass?
|
@Deprecated(since = "6.3", forRemoval = true)
|
||||||
public class UniqueConstraintHolder {
|
public class UniqueConstraintHolder {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String[] columns;
|
private final String[] columns;
|
||||||
|
|
|
@ -354,11 +354,19 @@ public interface InFlightMetadataCollector extends MetadataImplementor {
|
||||||
String getFromMappedBy(String ownerEntityName, String propertyName);
|
String getFromMappedBy(String ownerEntityName, String propertyName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated no longer used
|
* @deprecated no longer implemented, will be removed in next release
|
||||||
*/
|
*/
|
||||||
@Deprecated(forRemoval = true)
|
@Deprecated(forRemoval = true)
|
||||||
void addUniqueConstraints(Table table, List<String[]> uniqueConstraints);
|
void addUniqueConstraints(Table table, List<String[]> uniqueConstraints);
|
||||||
|
/**
|
||||||
|
* @deprecated no longer implemented, will be removed in next release
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
void addUniqueConstraintHolders(Table table, List<UniqueConstraintHolder> uniqueConstraints);
|
void addUniqueConstraintHolders(Table table, List<UniqueConstraintHolder> uniqueConstraints);
|
||||||
|
/**
|
||||||
|
* @deprecated no longer implemented, will be removed in next release
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
void addIndexHolders(Table table, List<IndexHolder> indexHolders);
|
void addIndexHolders(Table table, List<IndexHolder> indexHolders);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ import java.util.Map;
|
||||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
|
||||||
|
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapping model object representing a {@linkplain jakarta.persistence.UniqueConstraint unique key}
|
* A mapping model object representing a {@linkplain jakarta.persistence.UniqueConstraint unique key}
|
||||||
* constraint on a relational database table.
|
* constraint on a relational database table.
|
||||||
|
@ -35,7 +37,7 @@ public class UniqueKey extends Constraint {
|
||||||
|
|
||||||
public void addColumn(Column column, String order) {
|
public void addColumn(Column column, String order) {
|
||||||
addColumn( column );
|
addColumn( column );
|
||||||
if ( StringHelper.isNotEmpty( order ) ) {
|
if ( isNotEmpty( order ) ) {
|
||||||
columnOrderMap.put( column, order );
|
columnOrderMap.put( column, order );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +65,8 @@ public class UniqueKey extends Constraint {
|
||||||
|
|
||||||
public boolean hasNullableColumn() {
|
public boolean hasNullableColumn() {
|
||||||
for ( Column column : getColumns() ) {
|
for ( Column column : getColumns() ) {
|
||||||
if ( column.isNullable() ) {
|
final Column tableColumn = getTable().getColumn( column );
|
||||||
|
if ( tableColumn != null && tableColumn.isNullable() ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue