HHH-18619 add support for @ForeignKey(options), @UniqueConstraint(options), @Index(options)

This commit is contained in:
Gavin King 2024-09-14 15:21:50 +02:00
parent 9f2beca226
commit 5f8bf125fc
29 changed files with 196 additions and 104 deletions

View File

@ -2075,6 +2075,7 @@ public abstract class CollectionBinder {
else {
key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
key.setForeignKeyOptions( foreignKey.options() );
if ( key.getForeignKeyName() == null
&& key.getForeignKeyDefinition() == null
&& collectionTableAnn.joinColumns().length == 1 ) {
@ -2082,6 +2083,7 @@ public abstract class CollectionBinder {
final ForeignKey nestedForeignKey = joinColumn.foreignKey();
key.setForeignKeyName( nullIfEmpty( nestedForeignKey.name() ) );
key.setForeignKeyDefinition( nullIfEmpty( nestedForeignKey.foreignKeyDefinition() ) );
key.setForeignKeyOptions( nestedForeignKey.options() );
}
}
}
@ -2091,6 +2093,7 @@ public abstract class CollectionBinder {
final ForeignKey foreignKey = joinTableAnn.foreignKey();
String foreignKeyName = foreignKey.name();
String foreignKeyDefinition = foreignKey.foreignKeyDefinition();
String foreignKeyOptions = foreignKey.options();
ConstraintMode foreignKeyValue = foreignKey.value();
final JoinColumn[] joinColumnAnnotations = joinTableAnn.joinColumns();
if ( !ArrayHelper.isEmpty( joinColumnAnnotations ) ) {
@ -2099,6 +2102,7 @@ public abstract class CollectionBinder {
if ( foreignKeyName.isEmpty() ) {
foreignKeyName = joinColumnForeignKey.name();
foreignKeyDefinition = joinColumnForeignKey.foreignKeyDefinition();
foreignKeyOptions = joinColumnForeignKey.options();
}
if ( foreignKeyValue != NO_CONSTRAINT ) {
foreignKeyValue = joinColumnForeignKey.value();
@ -2111,6 +2115,7 @@ public abstract class CollectionBinder {
else {
key.setForeignKeyName( nullIfEmpty( foreignKeyName ) );
key.setForeignKeyDefinition( nullIfEmpty( foreignKeyDefinition ) );
key.setForeignKeyOptions( foreignKeyOptions );
}
}
else {
@ -2155,6 +2160,7 @@ public abstract class CollectionBinder {
else {
key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
key.setForeignKeyOptions( foreignKey.options() );
}
}
@ -2425,6 +2431,7 @@ public abstract class CollectionBinder {
final ForeignKey inverseForeignKey = joinTableAnn.inverseForeignKey();
String foreignKeyName = inverseForeignKey.name();
String foreignKeyDefinition = inverseForeignKey.foreignKeyDefinition();
String foreignKeyOptions = inverseForeignKey.options();
final JoinColumn[] inverseJoinColumns = joinTableAnn.inverseJoinColumns();
if ( !ArrayHelper.isEmpty( inverseJoinColumns ) ) {
@ -2433,6 +2440,7 @@ public abstract class CollectionBinder {
final ForeignKey inverseJoinColumnForeignKey = joinColumnAnn.foreignKey();
foreignKeyName = inverseJoinColumnForeignKey.name();
foreignKeyDefinition = inverseJoinColumnForeignKey.foreignKeyDefinition();
foreignKeyOptions = inverseJoinColumnForeignKey.options();
}
}
@ -2445,6 +2453,7 @@ public abstract class CollectionBinder {
else {
element.setForeignKeyName( nullIfEmpty( foreignKeyName ) );
element.setForeignKeyDefinition( nullIfEmpty( foreignKeyDefinition ) );
element.setForeignKeyOptions( foreignKeyOptions );
}
}
return element;

View File

@ -54,7 +54,6 @@ import org.hibernate.annotations.Synchronize;
import org.hibernate.annotations.TypeBinderType;
import org.hibernate.annotations.View;
import org.hibernate.binder.TypeBinder;
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
import org.hibernate.boot.model.NamedEntityGraphDefinition;
import org.hibernate.boot.model.internal.InheritanceState.ElementsToProcess;
import org.hibernate.boot.model.naming.EntityNaming;
@ -896,6 +895,7 @@ public class EntityBinder {
else if ( foreignKey != null ) {
key.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
key.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
key.setForeignKeyOptions( foreignKey.options() );
}
else if ( noConstraintByDefault ) {
key.disableForeignKey();
@ -904,11 +904,13 @@ public class EntityBinder {
final ForeignKey nestedFk = pkJoinColumns.foreignKey();
key.setForeignKeyName( nullIfEmpty( nestedFk.name() ) );
key.setForeignKeyDefinition( nullIfEmpty( nestedFk.foreignKeyDefinition() ) );
key.setForeignKeyOptions( nestedFk.options() );
}
else if ( pkJoinColumn != null ) {
final ForeignKey nestedFk = pkJoinColumn.foreignKey();
key.setForeignKeyName( nullIfEmpty( nestedFk.name() ) );
key.setForeignKeyDefinition( nullIfEmpty( nestedFk.foreignKeyDefinition() ) );
key.setForeignKeyOptions( nestedFk.options() );
}
}
}
@ -1987,6 +1989,7 @@ public class EntityBinder {
else {
key.setForeignKeyName( nullIfEmpty( jpaSecondaryTable.foreignKey().name() ) );
key.setForeignKeyDefinition( nullIfEmpty( jpaSecondaryTable.foreignKey().foreignKeyDefinition() ) );
key.setForeignKeyOptions( jpaSecondaryTable.foreignKey().options() );
}
}
}

View File

@ -160,6 +160,7 @@ class IndexBinder {
String[] columnNames,
String[] orderings,
boolean unique,
String options,
Selectable[] columns) {
final IndexOrUniqueKeyNameSource source =
new IndexOrUniqueKeyNameSource( context, table, columnNames, originalKeyName );
@ -174,6 +175,7 @@ class IndexBinder {
final UniqueKey uniqueKey = table.getOrCreateUniqueKey( keyName );
uniqueKey.setExplicit( true );
uniqueKey.setNameExplicit( nameExplicit );
uniqueKey.setOptions( options );
for ( int i = 0; i < columns.length; i++ ) {
uniqueKey.addColumn( (Column) columns[i], orderings != null ? orderings[i] : null );
}
@ -182,6 +184,7 @@ class IndexBinder {
final String keyName = getImplicitNamingStrategy().determineIndexName( source ).render( getDialect() );
final Index index = table.getOrCreateIndex( keyName );
index.setUnique( unique );
index.setOptions( options );
for ( int i = 0; i < columns.length; i++ ) {
index.addColumn( columns[i], orderings != null ? orderings[i] : null );
}
@ -203,6 +206,7 @@ class IndexBinder {
initializeColumns( columnExpressions, ordering, parsed );
final String name = index.name();
final boolean unique = index.unique();
final String options = index.options();
createIndexOrUniqueKey(
table,
name,
@ -210,6 +214,7 @@ class IndexBinder {
columnExpressions,
ordering,
unique,
options,
selectables( table, name, columnExpressions )
);
}
@ -219,6 +224,7 @@ class IndexBinder {
for ( UniqueConstraint constraint : constraints ) {
final String name = constraint.name();
final String[] columnNames = constraint.columnNames();
final String options = constraint.options();
createIndexOrUniqueKey(
table,
name,
@ -226,6 +232,7 @@ class IndexBinder {
columnNames,
null,
true,
options,
columns( table, name, columnNames )
);
}

View File

@ -319,6 +319,7 @@ public class MapBinder extends CollectionBinder {
else {
element.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
element.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
element.setForeignKeyOptions( foreignKey.options() );
}
}
}
@ -495,8 +496,7 @@ public class MapBinder extends CollectionBinder {
private SimpleValue createTargetValue(Table mapKeyTable, SimpleValue sourceValue) {
final SimpleValue targetValue;
if ( sourceValue instanceof ManyToOne ) {
final ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
if ( sourceValue instanceof ManyToOne sourceManyToOne ) {
final ManyToOne targetManyToOne = new ManyToOne( getBuildingContext(), mapKeyTable);
targetManyToOne.setFetchMode( FetchMode.DEFAULT );
targetManyToOne.setLazy( true );

View File

@ -609,6 +609,7 @@ public class ToOneBinder {
else if ( foreignKey != null ) {
value.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
value.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
value.setForeignKeyOptions( foreignKey.options() );
}
else if ( noConstraintByDefault ) {
value.disableForeignKey();
@ -617,11 +618,13 @@ public class ToOneBinder {
final ForeignKey joinColumnsForeignKey = joinColumns.foreignKey();
value.setForeignKeyName( nullIfEmpty( joinColumnsForeignKey.name() ) );
value.setForeignKeyDefinition( nullIfEmpty( joinColumnsForeignKey.foreignKeyDefinition() ) );
value.setForeignKeyOptions( joinColumnsForeignKey.options() );
}
else if ( joinColumn != null ) {
final ForeignKey joinColumnForeignKey = joinColumn.foreignKey();
value.setForeignKeyName( nullIfEmpty( joinColumnForeignKey.name() ) );
value.setForeignKeyDefinition( nullIfEmpty( joinColumnForeignKey.foreignKeyDefinition() ) );
value.setForeignKeyOptions( joinColumnForeignKey.options() );
}
}
}

View File

@ -112,10 +112,10 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.ast.spi.MultiKeyLoadSizingStrategy;
import org.hibernate.mapping.CheckConstraint;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.Index;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
@ -3274,7 +3274,7 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
}
/**
* Get an {@link Exporter} for {@link UserDefinedType}s,
* Get an {@link Exporter} for {@link UserDefinedType user defined types},
* usually {@link StandardUserDefinedTypeExporter}.
*/
public Exporter<UserDefinedType> getUserDefinedTypeExporter() {
@ -3282,7 +3282,7 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
}
/**
* Get an {@link Exporter} for {@link Sequence}s,
* Get an {@link Exporter} for {@linkplain Sequence sequences},
* usually {@link StandardSequenceExporter}.
*/
public Exporter<Sequence> getSequenceExporter() {
@ -3290,7 +3290,7 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
}
/**
* Get an {@link Exporter} for {@link Index}es,
* Get an {@link Exporter} for {@linkplain Index indexes},
* usually {@link StandardIndexExporter}.
*/
public Exporter<Index> getIndexExporter() {
@ -3298,7 +3298,7 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
}
/**
* Get an {@link Exporter} for {@link ForeignKey}s,
* Get an {@link Exporter} for {@linkplain ForeignKey foreign key} constraints,
* usually {@link StandardForeignKeyExporter}.
*/
public Exporter<ForeignKey> getForeignKeyExporter() {
@ -3306,10 +3306,10 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
}
/**
* Get an {@link Exporter} for unique key {@link Constraint}s,
* Get an {@link Exporter} for {@linkplain UniqueKey unique key} constraints,
* usually {@link StandardUniqueKeyExporter}.
*/
public Exporter<Constraint> getUniqueKeyExporter() {
public Exporter<UniqueKey> getUniqueKeyExporter() {
return uniqueKeyExporter;
}

View File

@ -49,10 +49,10 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.loader.ast.spi.MultiKeyLoadSizingStrategy;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.Index;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
@ -866,7 +866,7 @@ public class DialectDelegateWrapper extends Dialect {
}
@Override
public Exporter<Constraint> getUniqueKeyExporter() {
public Exporter<UniqueKey> getUniqueKeyExporter() {
return wrapped.getUniqueKeyExporter();
}

View File

@ -30,7 +30,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
@ -802,7 +801,7 @@ public class SpannerDialect extends Dialect {
}
@Override
public Exporter<Constraint> getUniqueKeyExporter() {
public Exporter<UniqueKey> getUniqueKeyExporter() {
return NOOP_EXPORTER;
}

View File

@ -13,6 +13,8 @@ import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
/**
* A {@link UniqueDelegate} which uses {@code alter table} commands to create and drop
* the unique constraint. When possible, prefer {@link CreateTableUniqueDelegate}.
@ -68,7 +70,11 @@ public class AlterTableUniqueDelegate implements UniqueDelegate {
fragment.append( " " ).append( uniqueKey.getColumnOrderMap().get( column ) );
}
}
return fragment.append( ')' ).toString();
fragment.append( ')' );
if ( isNotEmpty( uniqueKey.getOptions() ) ) {
fragment.append( " " ).append( uniqueKey.getOptions() );
}
return fragment.toString();
}
@Override

View File

@ -351,8 +351,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
}
private static Type getUnderlyingType(Mapping mapping, Type type, int typeIndex) {
if ( type instanceof ComponentType ) {
final ComponentType componentType = (ComponentType) type;
if ( type instanceof ComponentType componentType ) {
int cols = 0;
for ( Type subtype : componentType.getSubtypes() ) {
int columnSpan = subtype.getColumnSpan( mapping );
@ -363,8 +362,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
}
throw new IndexOutOfBoundsException();
}
else if ( type instanceof EntityType ) {
final EntityType entityType = (EntityType) type;
else if ( type instanceof EntityType entityType ) {
final Type idType = entityType.getIdentifierOrUniqueKeyType( mapping );
return getUnderlyingType( mapping, idType, typeIndex );
}
@ -454,8 +452,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
if ( type instanceof ComponentType ) {
type = getTypeForComponentValue( mapping, type, getTypeIndex() );
}
if ( type instanceof BasicType ) {
final BasicType<?> basicType = (BasicType<?>) type;
if ( type instanceof BasicType<?> basicType ) {
if ( isTemporal( basicType.getExpressibleJavaType() ) ) {
precisionToUse = getTemporalPrecision();
lengthToUse = null;
@ -510,12 +507,11 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
private Type getTypeForEntityValue(Mapping mapping, Type type, int typeIndex) {
int index = 0;
if ( type instanceof EntityType ) {
final EntityType entityType = (EntityType) type;
if ( type instanceof EntityType entityType ) {
return getTypeForEntityValue( mapping, entityType.getIdentifierOrUniqueKeyType( mapping ), typeIndex );
}
else if ( type instanceof ComponentType ) {
for ( Type subtype : ((ComponentType) type).getSubtypes() ) {
else if ( type instanceof ComponentType componentType ) {
for ( Type subtype : componentType.getSubtypes() ) {
final Type result = getTypeForEntityValue( mapping, subtype, typeIndex - index );
if ( result != null ) {
return result;
@ -672,7 +668,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
@Override
public String getWriteExpr() {
return customWrite != null && customWrite.length() > 0 ? customWrite : "?";
return customWrite != null && !customWrite.isEmpty() ? customWrite : "?";
}
@Override

View File

@ -24,6 +24,7 @@ public abstract class Constraint implements Exportable, Serializable {
private String name;
private final ArrayList<Column> columns = new ArrayList<>();
private Table table;
private String options = "";
public String getName() {
return name;
@ -33,6 +34,14 @@ public abstract class Constraint implements Exportable, Serializable {
this.name = name;
}
public String getOptions() {
return options;
}
public void setOptions(String options) {
this.options = options;
}
public void addColumn(Column column) {
if ( !columns.contains( column ) ) {
columns.add( column );

View File

@ -79,6 +79,7 @@ public class DenormalizedTable extends Table {
foreignKey.getColumns(),
foreignKey.getReferencedEntityName(),
foreignKey.getKeyDefinition(),
foreignKey.getOptions(),
foreignKey.getReferencedColumns()
);
}
@ -88,6 +89,7 @@ public class DenormalizedTable extends Table {
final ForeignKey denormalizedForeignKey = new ForeignKey(this);
denormalizedForeignKey.setReferencedEntityName( includedTableFk.getReferencedEntityName() );
denormalizedForeignKey.setKeyDefinition( includedTableFk.getKeyDefinition() );
denormalizedForeignKey.setOptions( includedTableFk.getOptions() );
denormalizedForeignKey.setReferencedTable( includedTableFk.getReferencedTable() );
denormalizedForeignKey.addReferencedColumns( includedTableFk.getReferencedColumns() );
for ( Column keyColumn : includedTableFk.getColumns() ) {

View File

@ -18,7 +18,6 @@ import org.hibernate.dialect.Dialect;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
import static java.util.stream.Collectors.toUnmodifiableList;
import static java.util.stream.Collectors.toUnmodifiableMap;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.StringHelper.qualify;
@ -35,6 +34,7 @@ public class Index implements Exportable, Serializable {
private Identifier name;
private Table table;
private boolean unique;
private String options = "";
private final java.util.List<Selectable> selectables = new ArrayList<>();
private final java.util.Map<Selectable, String> selectableOrderMap = new HashMap<>();
@ -54,6 +54,14 @@ public class Index implements Exportable, Serializable {
return unique;
}
public String getOptions() {
return options;
}
public void setOptions(String options) {
this.options = options;
}
public int getColumnSpan() {
return selectables.size();
}
@ -71,8 +79,7 @@ public class Index implements Exportable, Serializable {
*/
@Deprecated(since = "6.3")
public java.util.List<Column> getColumns() {
return selectables.stream()
.map( s -> (Column) s ).collect( toUnmodifiableList() );
return selectables.stream().map( s -> (Column) s ).toList();
}
/**

View File

@ -24,7 +24,7 @@ public class ManyToOne extends ToOne {
private boolean isLogicalOneToOne;
private NotFoundAction notFoundAction;
private Type resolvedType;
private transient Type resolvedType;
public ManyToOne(MetadataBuildingContext buildingContext, Table table) {
super( buildingContext, table );
@ -95,8 +95,8 @@ public class ManyToOne extends ToOne {
}
else {
// Make sure synthetic properties are sorted
if ( property.getValue() instanceof Component ) {
( (Component) property.getValue() ).sortProperties();
if ( property.getValue() instanceof Component component ) {
component.sortProperties();
}
// todo : if "none" another option is to create the ForeignKey object still but to set its #disableCreation flag
if ( isForeignKeyEnabled() && !hasFormula() ) {
@ -105,6 +105,7 @@ public class ManyToOne extends ToOne {
getConstraintColumns(),
( (EntityType) getType() ).getAssociatedEntityName(),
getForeignKeyDefinition(),
getForeignKeyOptions(),
new ArrayList<>( property.getColumns() )
);
foreignKey.setReferencedTable( property.getValue().getTable() );

View File

@ -96,6 +96,7 @@ public abstract class SimpleValue implements KeyValue {
private Table table;
private String foreignKeyName;
private String foreignKeyDefinition;
private String foreignKeyOptions;
private boolean alternateUniqueKey;
private OnDeleteAction onDeleteAction;
private boolean foreignKeyEnabled = true;
@ -347,7 +348,8 @@ public abstract class SimpleValue implements KeyValue {
getForeignKeyName(),
getConstraintColumns(),
entityName,
getForeignKeyDefinition()
getForeignKeyDefinition(),
getForeignKeyOptions()
);
foreignKey.setOnDeleteAction( onDeleteAction );
return foreignKey;
@ -443,6 +445,14 @@ public abstract class SimpleValue implements KeyValue {
return isForeignKeyEnabled() && !hasFormula();
}
public String getForeignKeyOptions() {
return foreignKeyOptions;
}
public void setForeignKeyOptions(String foreignKeyOptions) {
this.foreignKeyOptions = foreignKeyOptions;
}
public String getForeignKeyDefinition() {
return foreignKeyDefinition;
}

View File

@ -576,8 +576,13 @@ public class Table implements Serializable, ContributableDatabaseObject {
public void createForeignKeys(MetadataBuildingContext context) {
}
@Deprecated(since="7.0", forRemoval = true)
public ForeignKey createForeignKey(String keyName, List<Column> keyColumns, String referencedEntityName, String keyDefinition) {
return createForeignKey( keyName, keyColumns, referencedEntityName, keyDefinition, null );
return createForeignKey( keyName, keyColumns, referencedEntityName, keyDefinition, null, null );
}
public ForeignKey createForeignKey(String keyName, List<Column> keyColumns, String referencedEntityName, String keyDefinition, String options) {
return createForeignKey( keyName, keyColumns, referencedEntityName, keyDefinition, options, null );
}
public ForeignKey createForeignKey(
@ -585,6 +590,7 @@ public class Table implements Serializable, ContributableDatabaseObject {
List<Column> keyColumns,
String referencedEntityName,
String keyDefinition,
String options,
List<Column> referencedColumns) {
final ForeignKeyKey key = new ForeignKeyKey( keyColumns, referencedEntityName, referencedColumns );
@ -593,6 +599,7 @@ public class Table implements Serializable, ContributableDatabaseObject {
foreignKey = new ForeignKey( this );
foreignKey.setReferencedEntityName( referencedEntityName );
foreignKey.setKeyDefinition( keyDefinition );
foreignKey.setOptions( options );
for ( Column keyColumn : keyColumns ) {
foreignKey.addColumn( keyColumn );
}
@ -773,12 +780,11 @@ public class Table implements Serializable, ContributableDatabaseObject {
}
public boolean equals(Object other) {
if ( !( other instanceof ForeignKeyKey ) ) {
if ( !(other instanceof ForeignKeyKey foreignKeyKey) ) {
return false;
}
ForeignKeyKey fkk = (ForeignKeyKey) other;
return Arrays.equals( fkk.columns, columns )
&& Arrays.equals( fkk.referencedColumns, referencedColumns );
return Arrays.equals( foreignKeyKey.columns, columns )
&& Arrays.equals( foreignKeyKey.referencedColumns, referencedColumns );
}
@Override

View File

@ -175,8 +175,7 @@ public abstract class ToOne extends SimpleValue implements Fetchable, SortableVa
final Value value = referencedPropertyName == null
? entityBinding.getIdentifier()
: entityBinding.getRecursiveProperty( referencedPropertyName ).getValue();
if ( value instanceof Component ) {
final Component component = (Component) value;
if ( value instanceof Component component ) {
final int[] originalPropertyOrder = component.sortProperties();
if ( !sorted ) {
if ( originalPropertyOrder != null ) {
@ -201,15 +200,15 @@ public abstract class ToOne extends SimpleValue implements Fetchable, SortableVa
if ( isConstrained() ) {
final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
final Object owner = findReferencedColumnOwner( referencedEntity, firstColumn, getBuildingContext() );
if ( owner instanceof Join ) {
if ( owner instanceof Join join ) {
// Here we handle the case of a foreign key that refers to the
// primary key of a secondary table of the referenced entity
final Join join = (Join) owner;
final ForeignKey foreignKey = getTable().createForeignKey(
getForeignKeyName(),
getConstraintColumns(),
referencedEntity.getEntityName(),
getForeignKeyDefinition(),
getForeignKeyOptions(),
join.getKey().getColumns()
);
foreignKey.setOnDeleteAction( getOnDeleteAction() );

View File

@ -28,7 +28,6 @@ import org.hibernate.engine.jdbc.internal.FormatStyle;
import org.hibernate.engine.jdbc.internal.Formatter;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.Index;
import org.hibernate.mapping.Table;
@ -388,7 +387,7 @@ public abstract class AbstractSchemaMigrator implements SchemaMigrator {
}
if ( uniqueConstraintStrategy != SKIP ) {
final Exporter<Constraint> exporter = dialect.getUniqueKeyExporter();
final Exporter<UniqueKey> exporter = dialect.getUniqueKeyExporter();
for ( UniqueKey uniqueKey : table.getUniqueKeys().values() ) {
// Skip if index already exists. Most of the time, this
// won't work since most Dialects use Constraints. However,

View File

@ -11,7 +11,6 @@ import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.CheckConstraint;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;
@ -27,6 +26,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.type.SqlTypes.isNumericOrDecimal;
import static org.hibernate.type.SqlTypes.isStringType;
@ -122,7 +122,7 @@ class ColumnDefinitions {
private static void appendOptions(StringBuilder statement, Column column, Dialect dialect) {
final String options = column.getOptions();
if ( StringHelper.isNotEmpty( options ) ) {
if ( isNotEmpty( options ) ) {
statement.append( " " ).append( options );
}
}

View File

@ -96,13 +96,14 @@ public class SchemaCreatorImpl implements SchemaCreator {
}
public SchemaCreatorImpl(ServiceRegistry serviceRegistry, SchemaFilter schemaFilter) {
SchemaManagementTool smt = serviceRegistry.getService( SchemaManagementTool.class );
if ( !(smt instanceof HibernateSchemaManagementTool) ) {
smt = new HibernateSchemaManagementTool();
( (HibernateSchemaManagementTool) smt ).injectServices( (ServiceRegistryImplementor) serviceRegistry );
if ( serviceRegistry.getService( SchemaManagementTool.class )
instanceof HibernateSchemaManagementTool schemaManagementTool ) {
tool = schemaManagementTool;
}
else {
tool = new HibernateSchemaManagementTool();
tool.injectServices( (ServiceRegistryImplementor) serviceRegistry );
}
this.tool = (HibernateSchemaManagementTool) smt;
this.schemaFilter = schemaFilter;
}

View File

@ -93,13 +93,14 @@ public class SchemaDropperImpl implements SchemaDropper {
}
public SchemaDropperImpl(ServiceRegistry serviceRegistry, SchemaFilter schemaFilter) {
SchemaManagementTool smt = serviceRegistry.getService( SchemaManagementTool.class );
if ( !(smt instanceof HibernateSchemaManagementTool) ) {
smt = new HibernateSchemaManagementTool();
( (HibernateSchemaManagementTool) smt ).injectServices( (ServiceRegistryImplementor) serviceRegistry );
if ( serviceRegistry.getService( SchemaManagementTool.class )
instanceof HibernateSchemaManagementTool schemaManagementTool ) {
tool = schemaManagementTool;
}
else {
tool = new HibernateSchemaManagementTool();
tool.injectServices( (ServiceRegistryImplementor) serviceRegistry );
}
this.tool = (HibernateSchemaManagementTool) smt;
this.schemaFilter = schemaFilter;
}
@ -401,7 +402,8 @@ public class SchemaDropperImpl implements SchemaDropper {
GenerationTarget[] targets) {
for ( Namespace namespace : metadata.getDatabase().getNamespaces() ) {
if ( schemaFilter.includeNamespace( namespace ) ) {
final List<UserDefinedType> dependencyOrderedUserDefinedTypes = namespace.getDependencyOrderedUserDefinedTypes();
final List<UserDefinedType> dependencyOrderedUserDefinedTypes =
namespace.getDependencyOrderedUserDefinedTypes();
Collections.reverse( dependencyOrderedUserDefinedTypes );
for ( UserDefinedType userDefinedType : dependencyOrderedUserDefinedTypes ) {
applySqlStrings(

View File

@ -39,6 +39,7 @@ import org.jboss.logging.Logger;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.hibernate.cfg.AvailableSettings.HBM2DDL_CHARSET_NAME;
@ -73,8 +74,10 @@ public class SchemaTruncatorImpl implements SchemaTruncator {
ContributableMatcher contributableInclusionFilter,
TargetDescriptor targetDescriptor) {
final JdbcContext jdbcContext = tool.resolveJdbcContext( options.getConfigurationValues() );
final GenerationTarget[] targets = tool.buildGenerationTargets( targetDescriptor, jdbcContext, options.getConfigurationValues(),
final Map<String, Object> configurationValues = options.getConfigurationValues();
final JdbcContext jdbcContext = tool.resolveJdbcContext(configurationValues);
final GenerationTarget[] targets =
tool.buildGenerationTargets( targetDescriptor, jdbcContext, configurationValues,
true ); //we need autocommit on for DB2 at least
doTruncate( metadata, options, contributableInclusionFilter, jdbcContext.getDialect(), targets );
@ -211,9 +214,7 @@ public class SchemaTruncatorImpl implements SchemaTruncator {
for ( ForeignKey foreignKey : table.getForeignKeys().values() ) {
if ( dialect.canDisableConstraints() ) {
applySqlString(
dialect.getTableCleaner().getSqlDisableConstraintString( foreignKey, metadata,
context
),
dialect.getTableCleaner().getSqlDisableConstraintString( foreignKey, metadata, context ),
formatter,
options,
targets
@ -221,9 +222,7 @@ public class SchemaTruncatorImpl implements SchemaTruncator {
}
else if ( !dialect.canBatchTruncate() ) {
applySqlStrings(
dialect.getForeignKeyExporter().getSqlDropStrings( foreignKey, metadata,
context
),
dialect.getForeignKeyExporter().getSqlDropStrings( foreignKey, metadata, context ),
formatter,
options,
targets
@ -258,9 +257,7 @@ public class SchemaTruncatorImpl implements SchemaTruncator {
for ( ForeignKey foreignKey : table.getForeignKeys().values() ) {
if ( dialect.canDisableConstraints() ) {
applySqlString(
dialect.getTableCleaner().getSqlEnableConstraintString( foreignKey, metadata,
context
),
dialect.getTableCleaner().getSqlEnableConstraintString( foreignKey, metadata, context ),
formatter,
options,
targets
@ -268,9 +265,7 @@ public class SchemaTruncatorImpl implements SchemaTruncator {
}
else if ( !dialect.canBatchTruncate() ) {
applySqlStrings(
dialect.getForeignKeyExporter().getSqlCreateStrings( foreignKey, metadata,
context
),
dialect.getForeignKeyExporter().getSqlCreateStrings( foreignKey, metadata, context ),
formatter,
options,
targets

View File

@ -18,6 +18,8 @@ import org.hibernate.mapping.Column;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.tool.schema.spi.Exporter;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
/**
* An {@link Exporter} for {@linkplain ForeignKey foreign key constraints}.
*
@ -78,12 +80,16 @@ public class StandardForeignKeyExporter implements Exporter<ForeignKey> {
);
if ( dialect.supportsCascadeDelete() ) {
OnDeleteAction onDeleteAction = foreignKey.getOnDeleteAction();
final OnDeleteAction onDeleteAction = foreignKey.getOnDeleteAction();
if ( onDeleteAction != null && onDeleteAction != OnDeleteAction.NO_ACTION ) {
buffer.append( " on delete " ).append( onDeleteAction.toSqlString() );
}
}
if ( isNotEmpty( foreignKey.getOptions() ) ) {
buffer.append( " " ).append( foreignKey.getOptions() );
}
return new String[] { buffer.toString() };
}

View File

@ -17,6 +17,7 @@ import org.hibernate.mapping.Index;
import org.hibernate.mapping.Selectable;
import org.hibernate.tool.schema.spi.Exporter;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.StringHelper.qualify;
/**
@ -47,6 +48,9 @@ public class StandardIndexExporter implements Exporter<Index> {
.append( " (" );
appendColumnList( index, createIndex );
createIndex.append( ")" );
if ( isNotEmpty( index.getOptions() ) ) {
createIndex.append( " " ).append( index.getOptions() );
}
return new String[] { createIndex.toString() };
}

View File

@ -14,7 +14,7 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.tool.schema.spi.Exporter;
/**
* An {@link Exporter} for {@link Sequence sequences}.
* An {@link Exporter} for {@linkplain Sequence sequences}.
*
* @author Steve Ebersole
*/

View File

@ -186,8 +186,7 @@ public class StandardTableExporter implements Exporter<Table> {
final AggregateSupport aggregateSupport = dialect.getAggregateSupport();
if ( aggregateSupport != null && aggregateSupport.supportsComponentCheckConstraints() ) {
for ( Column column : table.getColumns() ) {
if ( column instanceof AggregateColumn ) {
final AggregateColumn aggregateColumn = (AggregateColumn) column;
if ( column instanceof AggregateColumn aggregateColumn ) {
if ( !isArray( aggregateColumn ) ) {
applyAggregateColumnCheck( buf, aggregateColumn );
}
@ -241,8 +240,7 @@ public class StandardTableExporter implements Exporter<Table> {
String aggregatePath,
AggregateSupport aggregateSupport,
Value value) {
if ( value instanceof Component ) {
final Component component = (Component) value;
if ( value instanceof Component component ) {
final AggregateColumn subAggregateColumn = component.getAggregateColumn();
if ( subAggregateColumn != null && !isArray( subAggregateColumn ) ) {
final String subAggregatePath = subAggregateColumn.getAggregateReadExpressionTemplate( dialect )

View File

@ -9,18 +9,15 @@ package org.hibernate.tool.schema.internal;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.tool.schema.spi.Exporter;
/**
* An {@link Exporter} for {@link UniqueKey unique constraints}. The type argument is
* {@link Constraint}, rather than {@link UniqueKey}, allowing for {@link Dialect}s
* which create unique constraints for unique indexes.
* An {@link Exporter} for {@linkplain UniqueKey unique constraints}.
*
* @author Brett Meyer
*/
public class StandardUniqueKeyExporter implements Exporter<Constraint> {
public class StandardUniqueKeyExporter implements Exporter<UniqueKey> {
private final Dialect dialect;
public StandardUniqueKeyExporter(Dialect dialect) {
@ -28,26 +25,14 @@ public class StandardUniqueKeyExporter implements Exporter<Constraint> {
}
@Override
public String[] getSqlCreateStrings(Constraint constraint, Metadata metadata,
SqlStringGenerationContext context) {
return new String[] {
dialect.getUniqueDelegate().getAlterTableToAddUniqueKeyCommand(
(UniqueKey) constraint,
metadata,
context
)
};
public String[] getSqlCreateStrings(UniqueKey constraint, Metadata metadata, SqlStringGenerationContext context) {
return new String[] { dialect.getUniqueDelegate()
.getAlterTableToAddUniqueKeyCommand( constraint, metadata, context ) };
}
@Override
public String[] getSqlDropStrings(Constraint constraint, Metadata metadata,
SqlStringGenerationContext context) {
return new String[] {
dialect.getUniqueDelegate().getAlterTableToDropUniqueKeyCommand(
(UniqueKey) constraint,
metadata,
context
)
};
public String[] getSqlDropStrings(UniqueKey constraint, Metadata metadata, SqlStringGenerationContext context) {
return new String[] { dialect.getUniqueDelegate()
.getAlterTableToDropUniqueKeyCommand( constraint, metadata, context ) };
}
}

View File

@ -0,0 +1,45 @@
package org.hibernate.orm.test.schemaupdate.options;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SchemaManager;
import jakarta.persistence.SchemaValidationException;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.junit.jupiter.api.Test;
@Jpa(annotatedClasses = OptionsTest.WithOptions.class,
useCollectingStatementInspector = true)
@RequiresDialect(PostgreSQLDialect.class)
public class OptionsTest {
@Test void test(EntityManagerFactoryScope scope) throws SchemaValidationException {
SchemaManager schemaManager = scope.getEntityManagerFactory().getSchemaManager();
schemaManager.drop(true);
schemaManager.create(true);
schemaManager.validate();
}
@Entity
@Table(name = "TableWithOptions",
indexes = @Index(columnList = "name", options = "nulls distinct"),
uniqueConstraints = @UniqueConstraint(columnNames = "name", options = "deferrable"))
static class WithOptions {
@Id
long id;
@Column(name = "name", options = "compression pglz")
String name;
@ManyToOne
@JoinColumn(foreignKey = @ForeignKey(name = "ToOther", options = "match full"))
WithOptions other;
}
}