HHH-15762 nicer DDL for unique constraints
- prefer 'unique' in 'create table' except in migrations - also ignore unique=true for PK column - introduce AlterTableUniqueDelegate and CreateTableUniqueDelegate - fix the tests / delete test that makes no sense now - improve javadoc of UniqueDelegate
This commit is contained in:
parent
41fb50f18e
commit
3ba90c004c
|
@ -24,7 +24,6 @@ import org.hibernate.testing.util.ExceptionUtil;
|
|||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
|
|
|
@ -276,6 +276,11 @@ public class CUBRIDDialect extends Dialect {
|
|||
return " drop foreign key ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDropUniqueKeyString() {
|
||||
return " drop index ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean qualifyIndexName() {
|
||||
return false;
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.sequence.DB2iSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.NoSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -70,7 +70,7 @@ public class DB2iLegacyDialect extends DB2LegacyDialect {
|
|||
@Override
|
||||
protected UniqueDelegate createUniqueDelegate() {
|
||||
return getVersion().isSameOrAfter(7, 3)
|
||||
? new DefaultUniqueDelegate(this)
|
||||
? new AlterTableUniqueDelegate(this)
|
||||
: super.createUniqueDelegate();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,6 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.pagination.LimitLimitHandler;
|
||||
import org.hibernate.dialect.sequence.NoSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.MySQLUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
|
@ -94,7 +92,6 @@ import static org.hibernate.type.SqlTypes.*;
|
|||
*/
|
||||
public class MySQLLegacyDialect extends Dialect {
|
||||
|
||||
private final UniqueDelegate uniqueDelegate = new MySQLUniqueDelegate( this );
|
||||
private final MySQLStorageEngine storageEngine = createStorageEngine();
|
||||
private final SizeStrategy sizeStrategy = new SizeStrategyImpl() {
|
||||
@Override
|
||||
|
@ -775,6 +772,11 @@ public class MySQLLegacyDialect extends Dialect {
|
|||
return " drop foreign key ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDropUniqueKeyString() {
|
||||
return " drop index ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimitHandler getLimitHandler() {
|
||||
//also supports LIMIT n OFFSET m
|
||||
|
@ -943,11 +945,6 @@ public class MySQLLegacyDialect extends Dialect {
|
|||
return ps.getResultSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNullPrecedence() {
|
||||
return false;
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.hibernate.dialect.function.CommonFunctionFactory;
|
|||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.LimitOffsetLimitHandler;
|
||||
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -141,7 +141,7 @@ public class SQLiteDialect extends Dialect {
|
|||
return -1;
|
||||
}
|
||||
|
||||
private static class SQLiteUniqueDelegate extends DefaultUniqueDelegate {
|
||||
private static class SQLiteUniqueDelegate extends AlterTableUniqueDelegate {
|
||||
public SQLiteUniqueDelegate(Dialect dialect) {
|
||||
super( dialect );
|
||||
}
|
||||
|
|
|
@ -56,7 +56,6 @@ import java.sql.CallableStatement;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
|
|
@ -9,7 +9,7 @@ package org.hibernate.community.dialect.unique;
|
|||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@ import org.hibernate.mapping.UniqueKey;
|
|||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public class InformixUniqueDelegate extends DefaultUniqueDelegate {
|
||||
public class InformixUniqueDelegate extends AlterTableUniqueDelegate {
|
||||
|
||||
public InformixUniqueDelegate( Dialect dialect ) {
|
||||
super( dialect );
|
||||
|
@ -29,7 +29,7 @@ public class InformixUniqueDelegate extends DefaultUniqueDelegate {
|
|||
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata,
|
||||
SqlStringGenerationContext context) {
|
||||
// Do this here, rather than allowing UniqueKey/Constraint to do it.
|
||||
// We need full, simplified control over whether or not it happens.
|
||||
// We need full, simplified control over whether it happens.
|
||||
final String tableName = context.format( uniqueKey.getTable().getQualifiedTableName() );
|
||||
final String constraintName = dialect.quote( uniqueKey.getName() );
|
||||
return dialect.getAlterTableString( tableName )
|
||||
|
|
|
@ -2026,7 +2026,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
final Table table = tableListEntry.getKey();
|
||||
final List<UniqueConstraintHolder> uniqueConstraints = tableListEntry.getValue();
|
||||
for ( UniqueConstraintHolder holder : uniqueConstraints ) {
|
||||
buildUniqueKeyFromColumnNames( table, holder.getName(), holder.getColumns(), buildingContext );
|
||||
buildUniqueKeyFromColumnNames( table, holder.getName(), holder.isNameExplicit(), holder.getColumns(), buildingContext );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2036,14 +2036,16 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
private void buildUniqueKeyFromColumnNames(
|
||||
Table table,
|
||||
String keyName,
|
||||
boolean nameExplicit,
|
||||
String[] columnNames,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
buildUniqueKeyFromColumnNames( table, keyName, columnNames, null, true, buildingContext );
|
||||
buildUniqueKeyFromColumnNames( table, keyName, nameExplicit, columnNames, null, true, buildingContext );
|
||||
}
|
||||
|
||||
private void buildUniqueKeyFromColumnNames(
|
||||
final Table table,
|
||||
String keyName,
|
||||
boolean nameExplicit,
|
||||
final String[] columnNames,
|
||||
String[] orderings,
|
||||
boolean unique,
|
||||
|
@ -2104,6 +2106,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
keyName = keyNameIdentifier.render( getDatabase().getJdbcEnvironment().getDialect() );
|
||||
|
||||
UniqueKey uk = table.getOrCreateUniqueKey( keyName );
|
||||
uk.setNameExplicit( nameExplicit );
|
||||
for ( int i = 0; i < columns.length; i++ ) {
|
||||
Column column = columns[i];
|
||||
String order = orderings != null ? orderings[i] : null;
|
||||
|
@ -2193,6 +2196,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
buildUniqueKeyFromColumnNames(
|
||||
table,
|
||||
holder.getName(),
|
||||
!holder.getName().isEmpty(),
|
||||
holder.getColumns(),
|
||||
holder.getOrdering(),
|
||||
holder.isUnique(),
|
||||
|
|
|
@ -108,4 +108,10 @@ public interface SqlStringGenerationContext {
|
|||
*/
|
||||
String formatWithoutCatalog(QualifiedSequenceName qualifiedName);
|
||||
|
||||
/**
|
||||
* Is the generated SQL for use in {@linkplain org.hibernate.tool.schema.spi.SchemaMigrator schema migration}?
|
||||
*
|
||||
* @return {@code true} if and only if this is a migration
|
||||
*/
|
||||
boolean isMigration();
|
||||
}
|
||||
|
|
|
@ -37,7 +37,22 @@ public class SqlStringGenerationContextImpl
|
|||
Map<String, Object> configurationMap) {
|
||||
String defaultCatalog = (String) configurationMap.get( AvailableSettings.DEFAULT_CATALOG );
|
||||
String defaultSchema = (String) configurationMap.get( AvailableSettings.DEFAULT_SCHEMA );
|
||||
return fromExplicit( jdbcEnvironment, database, defaultCatalog, defaultSchema );
|
||||
return create( jdbcEnvironment, database, defaultCatalog, defaultSchema, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jdbcEnvironment The JDBC environment, to extract the dialect, identifier helper, etc.
|
||||
* @param database The database metadata, to retrieve the implicit namespace name configured through XML mapping.
|
||||
* @param configurationMap The configuration map, holding settings such as {@value AvailableSettings#DEFAULT_SCHEMA}.
|
||||
* @return An {@link SqlStringGenerationContext}.
|
||||
*/
|
||||
public static SqlStringGenerationContext fromConfigurationMapForMigration(
|
||||
JdbcEnvironment jdbcEnvironment,
|
||||
Database database,
|
||||
Map<String, Object> configurationMap) {
|
||||
String defaultCatalog = (String) configurationMap.get( AvailableSettings.DEFAULT_CATALOG );
|
||||
String defaultSchema = (String) configurationMap.get( AvailableSettings.DEFAULT_SCHEMA );
|
||||
return create( jdbcEnvironment, database, defaultCatalog, defaultSchema, true );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,6 +67,15 @@ public class SqlStringGenerationContextImpl
|
|||
Database database,
|
||||
String defaultCatalog,
|
||||
String defaultSchema) {
|
||||
return create( jdbcEnvironment, database, defaultCatalog, defaultSchema, false );
|
||||
}
|
||||
|
||||
private static SqlStringGenerationContext create(
|
||||
JdbcEnvironment jdbcEnvironment,
|
||||
Database database,
|
||||
String defaultCatalog,
|
||||
String defaultSchema,
|
||||
boolean forMigration) {
|
||||
final Namespace.Name implicitNamespaceName = database.getPhysicalImplicitNamespaceName();
|
||||
final IdentifierHelper identifierHelper = jdbcEnvironment.getIdentifierHelper();
|
||||
final NameQualifierSupport nameQualifierSupport = jdbcEnvironment.getNameQualifierSupport();
|
||||
|
@ -72,7 +96,7 @@ public class SqlStringGenerationContextImpl
|
|||
}
|
||||
}
|
||||
|
||||
return new SqlStringGenerationContextImpl( jdbcEnvironment, actualDefaultCatalog, actualDefaultSchema );
|
||||
return new SqlStringGenerationContextImpl( jdbcEnvironment, actualDefaultCatalog, actualDefaultSchema, forMigration );
|
||||
}
|
||||
|
||||
public static SqlStringGenerationContext forTests(JdbcEnvironment jdbcEnvironment) {
|
||||
|
@ -83,7 +107,8 @@ public class SqlStringGenerationContextImpl
|
|||
String defaultCatalog, String defaultSchema) {
|
||||
IdentifierHelper identifierHelper = jdbcEnvironment.getIdentifierHelper();
|
||||
return new SqlStringGenerationContextImpl( jdbcEnvironment,
|
||||
identifierHelper.toIdentifier( defaultCatalog ), identifierHelper.toIdentifier( defaultSchema ) );
|
||||
identifierHelper.toIdentifier( defaultCatalog ), identifierHelper.toIdentifier( defaultSchema ),
|
||||
false );
|
||||
}
|
||||
|
||||
private final Dialect dialect;
|
||||
|
@ -92,16 +117,20 @@ public class SqlStringGenerationContextImpl
|
|||
private final Identifier defaultCatalog;
|
||||
private final Identifier defaultSchema;
|
||||
|
||||
private final boolean migration;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private SqlStringGenerationContextImpl(
|
||||
JdbcEnvironment jdbcEnvironment,
|
||||
Identifier defaultCatalog,
|
||||
Identifier defaultSchema) {
|
||||
Identifier defaultSchema,
|
||||
boolean migration) {
|
||||
this.dialect = jdbcEnvironment.getDialect();
|
||||
this.identifierHelper = jdbcEnvironment.getIdentifierHelper();
|
||||
this.qualifiedObjectNameFormatter = jdbcEnvironment.getQualifiedObjectNameFormatter();
|
||||
this.defaultCatalog = defaultCatalog;
|
||||
this.defaultSchema = defaultSchema;
|
||||
this.migration = migration;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -194,4 +223,9 @@ public class SqlStringGenerationContextImpl
|
|||
}
|
||||
return qualifiedObjectNameFormatter.format( nameToFormat, dialect );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMigration() {
|
||||
return migration;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.hibernate.cfg;
|
|||
*/
|
||||
public class UniqueConstraintHolder {
|
||||
private String name;
|
||||
private boolean nameExplicit;
|
||||
private String[] columns;
|
||||
|
||||
public String getName() {
|
||||
|
@ -30,6 +31,10 @@ public class UniqueConstraintHolder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public boolean isNameExplicit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
@ -38,4 +43,9 @@ public class UniqueConstraintHolder {
|
|||
this.columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UniqueConstraintHolder setName(String name, boolean nameExplicit) {
|
||||
this.nameExplicit = nameExplicit;
|
||||
return setName(name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -794,7 +794,7 @@ public class TableBinder {
|
|||
else {
|
||||
result = arrayList( annotations.length );
|
||||
for ( UniqueConstraint uc : annotations ) {
|
||||
result.add( new UniqueConstraintHolder().setName( uc.name() ).setColumns( uc.columnNames() ) );
|
||||
result.add( new UniqueConstraintHolder().setName( uc.name(), !uc.name().isEmpty() ).setColumns( uc.columnNames() ) );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -10,6 +10,8 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.function.CastingConcatFunction;
|
||||
import org.hibernate.dialect.function.TransactSQLStrFunction;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.query.sqm.NullOrdering;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
|
@ -49,6 +51,8 @@ import static org.hibernate.type.SqlTypes.*;
|
|||
*/
|
||||
public abstract class AbstractTransactSQLDialect extends Dialect {
|
||||
|
||||
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
|
||||
|
||||
public AbstractTransactSQLDialect(DatabaseVersion version) {
|
||||
super(version);
|
||||
}
|
||||
|
@ -388,4 +392,9 @@ public abstract class AbstractTransactSQLDialect extends Dialect {
|
|||
appender.appendSql( "0x" );
|
||||
PrimitiveByteArrayJavaType.INSTANCE.appendString( appender, bytes );
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
|
|||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.sequence.DB2iSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
|
||||
/**
|
||||
|
@ -28,7 +28,7 @@ public class DB2400V7R3Dialect extends DB2400Dialect {
|
|||
public DB2400V7R3Dialect() {
|
||||
super();
|
||||
|
||||
uniqueDelegate = new DefaultUniqueDelegate(this);
|
||||
uniqueDelegate = new AlterTableUniqueDelegate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.sequence.DB2iSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.NoSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -75,7 +75,7 @@ public class DB2iDialect extends DB2Dialect {
|
|||
@Override
|
||||
protected UniqueDelegate createUniqueDelegate() {
|
||||
return getVersion().isSameOrAfter(7, 3)
|
||||
? new DefaultUniqueDelegate(this)
|
||||
? new AlterTableUniqueDelegate(this)
|
||||
: super.createUniqueDelegate();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ import org.hibernate.dialect.pagination.DerbyLimitHandler;
|
|||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.sequence.DerbySequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
||||
|
@ -96,6 +98,7 @@ public class DerbyDialect extends Dialect {
|
|||
private final static DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 10, 14, 2 );
|
||||
|
||||
private final LimitHandler limitHandler = new DerbyLimitHandler( true );
|
||||
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
|
||||
|
||||
public DerbyDialect() {
|
||||
this( MINIMUM_VERSION);
|
||||
|
@ -926,4 +929,9 @@ public class DerbyDialect extends Dialect {
|
|||
builder.setAutoQuoteInitialUnderscore(true);
|
||||
return super.buildIdentifierHelper(builder, dbMetaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ import org.hibernate.dialect.temptable.StandardTemporaryTableExporter;
|
|||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableExporter;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
|
@ -289,8 +289,6 @@ public abstract class Dialect implements ConversionContext {
|
|||
private final Properties properties = new Properties();
|
||||
private final Set<String> sqlKeywords = new HashSet<>();
|
||||
|
||||
private final UniqueDelegate uniqueDelegate = new DefaultUniqueDelegate( this );
|
||||
|
||||
private final SizeStrategy sizeStrategy = new SizeStrategyImpl();
|
||||
|
||||
private final DatabaseVersion version;
|
||||
|
@ -2699,10 +2697,20 @@ public abstract class Dialect implements ConversionContext {
|
|||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@code alter table} subcommand used to drop a foreign key constraint.
|
||||
*/
|
||||
public String getDropForeignKeyString() {
|
||||
return " drop constraint ";
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@code alter table} subcommand used to drop a unique key constraint.
|
||||
*/
|
||||
public String getDropUniqueKeyString() {
|
||||
return " drop constraint ";
|
||||
}
|
||||
|
||||
public String getTableTypeString() {
|
||||
// grrr... for differentiation of mysql storage engines
|
||||
return "";
|
||||
|
@ -3291,7 +3299,7 @@ public abstract class Dialect implements ConversionContext {
|
|||
* @return The UniqueDelegate
|
||||
*/
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
return new AlterTableUniqueDelegate( this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,8 @@ import org.hibernate.dialect.sequence.H2V2SequenceSupport;
|
|||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
|
@ -109,6 +111,7 @@ public class H2Dialect extends Dialect {
|
|||
|
||||
private final SequenceInformationExtractor sequenceInformationExtractor;
|
||||
private final String querySequenceString;
|
||||
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
|
||||
|
||||
public H2Dialect(DialectResolutionInfo info) {
|
||||
this( parseVersion( info ) );
|
||||
|
@ -813,4 +816,9 @@ public class H2Dialect extends Dialect {
|
|||
public String getDisableConstraintsStatement() {
|
||||
return "set referential_integrity false";
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ import org.hibernate.dialect.sequence.HSQLSequenceSupport;
|
|||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
||||
|
@ -83,6 +85,7 @@ public class HSQLDialect extends Dialect {
|
|||
);
|
||||
|
||||
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 2, 6, 1 );
|
||||
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
|
||||
|
||||
public HSQLDialect(DialectResolutionInfo info) {
|
||||
super( info );
|
||||
|
@ -702,4 +705,9 @@ public class HSQLDialect extends Dialect {
|
|||
builder.setAutoQuoteInitialUnderscore(true);
|
||||
return super.buildIdentifierHelper(builder, dbMetaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.pagination.LimitLimitHandler;
|
||||
import org.hibernate.dialect.sequence.NoSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.MySQLUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
|
@ -90,7 +88,6 @@ public class MySQLDialect extends Dialect {
|
|||
|
||||
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 5, 7 );
|
||||
|
||||
private final UniqueDelegate uniqueDelegate = new MySQLUniqueDelegate( this );
|
||||
private final MySQLStorageEngine storageEngine = createStorageEngine();
|
||||
private final SizeStrategy sizeStrategy = new SizeStrategyImpl() {
|
||||
@Override
|
||||
|
@ -786,6 +783,11 @@ public class MySQLDialect extends Dialect {
|
|||
return " drop foreign key ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDropUniqueKeyString() {
|
||||
return " drop index ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimitHandler getLimitHandler() {
|
||||
//also supports LIMIT n OFFSET m
|
||||
|
@ -954,11 +956,6 @@ public class MySQLDialect extends Dialect {
|
|||
return ps.getResultSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNullPrecedence() {
|
||||
return false;
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.pagination.Oracle12LimitHandler;
|
||||
import org.hibernate.dialect.sequence.OracleSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
|
@ -118,6 +120,7 @@ public class OracleDialect extends Dialect {
|
|||
private final LimitHandler limitHandler = supportsFetchClause( FetchClauseType.ROWS_ONLY )
|
||||
? Oracle12LimitHandler.INSTANCE
|
||||
: new LegacyOracleLimitHandler( getVersion() );
|
||||
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
|
||||
|
||||
public OracleDialect() {
|
||||
this( MINIMUM_VERSION );
|
||||
|
@ -1318,4 +1321,9 @@ public class OracleDialect extends Dialect {
|
|||
public String getEnableConstraintStatement(String tableName, String name) {
|
||||
return "alter table " + tableName + " enable constraint " + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
|
||||
import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
|
@ -127,6 +129,7 @@ public class PostgreSQLDialect extends Dialect {
|
|||
private static final PostgreSQLIdentityColumnSupport IDENTITY_COLUMN_SUPPORT = new PostgreSQLIdentityColumnSupport();
|
||||
|
||||
private final PostgreSQLDriverKind driverKind;
|
||||
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
|
||||
|
||||
public PostgreSQLDialect() {
|
||||
this( MINIMUM_VERSION );
|
||||
|
@ -1278,6 +1281,11 @@ public class PostgreSQLDialect extends Dialect {
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true}, but only because we can "batch" truncate
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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.dialect.unique;
|
||||
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
|
||||
/**
|
||||
* A {@link UniqueDelegate} which uses {@code alter table} commands to create and drop
|
||||
* the unique constraint. When possible, prefer {@link CreateTableUniqueDelegate}.
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public class AlterTableUniqueDelegate implements UniqueDelegate {
|
||||
protected final Dialect dialect;
|
||||
|
||||
/**
|
||||
* @param dialect The dialect for which we are handling unique constraints
|
||||
*/
|
||||
public AlterTableUniqueDelegate(Dialect dialect ) {
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
// legacy model ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public String getColumnDefinitionUniquenessFragment(Column column,
|
||||
SqlStringGenerationContext context) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableCreationUniqueConstraintsFragment(Table table,
|
||||
SqlStringGenerationContext context) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata,
|
||||
SqlStringGenerationContext context) {
|
||||
final String tableName = context.format( uniqueKey.getTable().getQualifiedTableName() );
|
||||
final String constraintName = dialect.quote( uniqueKey.getName() );
|
||||
return dialect.getAlterTableString( tableName )
|
||||
+ " add constraint " + constraintName + " " + uniqueConstraintSql( uniqueKey );
|
||||
}
|
||||
|
||||
protected String uniqueConstraintSql(UniqueKey uniqueKey) {
|
||||
final StringBuilder fragment = new StringBuilder();
|
||||
fragment.append( "unique (" );
|
||||
boolean first = true;
|
||||
for ( Column column : uniqueKey.getColumns() ) {
|
||||
if ( first ) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
fragment.append(", ");
|
||||
}
|
||||
fragment.append( column.getQuotedName( dialect ) );
|
||||
if ( uniqueKey.getColumnOrderMap().containsKey( column ) ) {
|
||||
fragment.append( " " ).append( uniqueKey.getColumnOrderMap().get( column ) );
|
||||
}
|
||||
}
|
||||
return fragment.append( ')' ).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata,
|
||||
SqlStringGenerationContext context) {
|
||||
final String tableName = context.format( uniqueKey.getTable().getQualifiedTableName() );
|
||||
|
||||
final StringBuilder buf = new StringBuilder( dialect.getAlterTableString(tableName) );
|
||||
buf.append( dialect.getDropUniqueKeyString() );
|
||||
if ( dialect.supportsIfExistsBeforeConstraintName() ) {
|
||||
buf.append( "if exists " );
|
||||
}
|
||||
buf.append( dialect.quote( uniqueKey.getName() ) );
|
||||
if ( dialect.supportsIfExistsAfterConstraintName() ) {
|
||||
buf.append( " if exists" );
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.dialect.unique;
|
||||
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
|
||||
/**
|
||||
* A {@link UniqueDelegate} which includes the unique constraint in the {@code create table}
|
||||
* statement, except when called during schema migration.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class CreateTableUniqueDelegate extends AlterTableUniqueDelegate {
|
||||
|
||||
public CreateTableUniqueDelegate( Dialect dialect ) {
|
||||
super( dialect );
|
||||
}
|
||||
|
||||
// legacy model ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public String getColumnDefinitionUniquenessFragment(Column column, SqlStringGenerationContext context) {
|
||||
// It would be nice to detect that the column belongs to a named unique
|
||||
// constraint so that we could skip it here, but we don't have the Table.
|
||||
return context.isMigration()
|
||||
? super.getColumnDefinitionUniquenessFragment( column, context )
|
||||
: column.isUnique() ? " unique" : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableCreationUniqueConstraintsFragment(Table table, SqlStringGenerationContext context) {
|
||||
if ( context.isMigration() ) {
|
||||
return super.getTableCreationUniqueConstraintsFragment( table, context );
|
||||
}
|
||||
else {
|
||||
StringBuilder fragment = new StringBuilder();
|
||||
for ( UniqueKey uniqueKey : table.getUniqueKeys().values() ) {
|
||||
// If the unique key has a single column which is already marked unique,
|
||||
// then getColumnDefinitionUniquenessFragment() already handled it, and
|
||||
// so we don't need to bother creating a constraint. The only downside
|
||||
// to this is that if the user added a column marked unique=true to a
|
||||
// named unique constraint, then the name gets lost. Unfortunately the
|
||||
// signature of getColumnDefinitionUniquenessFragment() doesn't let me
|
||||
// detect this case. (But that would be easy to fix!)
|
||||
if ( !isSingleColumnUnique( uniqueKey ) ) {
|
||||
fragment.append( ", " );
|
||||
if ( uniqueKey.isNameExplicit() ) {
|
||||
fragment.append( "constraint " ).append( uniqueKey.getName() ).append( " " );
|
||||
}
|
||||
fragment.append( uniqueConstraintSql( uniqueKey ) );
|
||||
}
|
||||
}
|
||||
return fragment.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSingleColumnUnique(UniqueKey uniqueKey) {
|
||||
return uniqueKey.getColumns().size() == 1
|
||||
&& uniqueKey.getColumn(0).isUnique();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, SqlStringGenerationContext context) {
|
||||
return context.isMigration() ? super.getAlterTableToAddUniqueKeyCommand( uniqueKey, metadata, context ) : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, SqlStringGenerationContext context) {
|
||||
return context.isMigration() ? super.getAlterTableToDropUniqueKeyCommand(uniqueKey, metadata, context) : "";
|
||||
}
|
||||
|
||||
}
|
|
@ -15,12 +15,13 @@ import org.hibernate.mapping.UniqueKey;
|
|||
import static org.hibernate.mapping.Index.buildSqlCreateIndexString;
|
||||
|
||||
/**
|
||||
* DB2 does not allow unique constraints on nullable columns. Rather than
|
||||
* forcing "not null", use unique *indexes* instead.
|
||||
* DB2 does not allow unique constraints on nullable columns, but it
|
||||
* does allow the creation of unique <em>indexes</em> instead, using
|
||||
* a different syntax.
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public class DB2UniqueDelegate extends DefaultUniqueDelegate {
|
||||
public class DB2UniqueDelegate extends AlterTableUniqueDelegate {
|
||||
/**
|
||||
* Constructs a DB2UniqueDelegate
|
||||
*
|
||||
|
|
|
@ -6,93 +6,14 @@
|
|||
*/
|
||||
package org.hibernate.dialect.unique;
|
||||
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
|
||||
/**
|
||||
* The default UniqueDelegate implementation for most dialects. Uses
|
||||
* separate create/alter statements to apply uniqueness to a column.
|
||||
*
|
||||
* @author Brett Meyer
|
||||
* @deprecated use {@link org.hibernate.dialect.unique.AlterTableUniqueDelegate}
|
||||
*/
|
||||
public class DefaultUniqueDelegate implements UniqueDelegate {
|
||||
protected final Dialect dialect;
|
||||
|
||||
/**
|
||||
* Constructs DefaultUniqueDelegate
|
||||
*
|
||||
* @param dialect The dialect for which we are handling unique constraints
|
||||
*/
|
||||
public DefaultUniqueDelegate( Dialect dialect ) {
|
||||
this.dialect = dialect;
|
||||
@Deprecated(since="6.2")
|
||||
public class DefaultUniqueDelegate extends AlterTableUniqueDelegate {
|
||||
public DefaultUniqueDelegate(Dialect dialect) {
|
||||
super(dialect);
|
||||
}
|
||||
|
||||
// legacy model ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public String getColumnDefinitionUniquenessFragment(Column column,
|
||||
SqlStringGenerationContext context) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableCreationUniqueConstraintsFragment(Table table,
|
||||
SqlStringGenerationContext context) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata,
|
||||
SqlStringGenerationContext context) {
|
||||
final String tableName = context.format( uniqueKey.getTable().getQualifiedTableName() );
|
||||
|
||||
final String constraintName = dialect.quote( uniqueKey.getName() );
|
||||
return dialect.getAlterTableString( tableName )
|
||||
+ " add constraint " + constraintName + " " + uniqueConstraintSql( uniqueKey );
|
||||
}
|
||||
|
||||
protected String uniqueConstraintSql(UniqueKey uniqueKey) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "unique (" );
|
||||
boolean first = true;
|
||||
for ( org.hibernate.mapping.Column column : uniqueKey.getColumns() ) {
|
||||
if ( first ) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append( column.getQuotedName( dialect ) );
|
||||
if ( uniqueKey.getColumnOrderMap().containsKey( column ) ) {
|
||||
sb.append( " " ).append( uniqueKey.getColumnOrderMap().get( column ) );
|
||||
}
|
||||
}
|
||||
return sb.append( ')' ).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata,
|
||||
SqlStringGenerationContext context) {
|
||||
final String tableName = context.format( uniqueKey.getTable().getQualifiedTableName() );
|
||||
|
||||
final StringBuilder buf = new StringBuilder( dialect.getAlterTableString(tableName) );
|
||||
buf.append( getDropUnique() );
|
||||
if ( dialect.supportsIfExistsBeforeConstraintName() ) {
|
||||
buf.append( "if exists " );
|
||||
}
|
||||
buf.append( dialect.quote( uniqueKey.getName() ) );
|
||||
if ( dialect.supportsIfExistsAfterConstraintName() ) {
|
||||
buf.append( " if exists" );
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected String getDropUnique(){
|
||||
return " drop constraint ";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,29 +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.dialect.unique;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class MySQLUniqueDelegate extends DefaultUniqueDelegate {
|
||||
|
||||
/**
|
||||
* Constructs MySQLUniqueDelegate
|
||||
*
|
||||
* @param dialect The dialect for which we are handling unique constraints
|
||||
*/
|
||||
public MySQLUniqueDelegate(Dialect dialect) {
|
||||
super( dialect );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDropUnique() {
|
||||
return " drop index ";
|
||||
}
|
||||
}
|
|
@ -13,35 +13,35 @@ import org.hibernate.mapping.Table;
|
|||
import org.hibernate.mapping.UniqueKey;
|
||||
|
||||
/**
|
||||
* Dialect-level delegate in charge of applying "uniqueness" to a column. Uniqueness can
|
||||
* be defined in 1 of 3 ways:
|
||||
* Dialect-level delegate in charge of applying unique constraints in DDL. Uniqueness can
|
||||
* be specified in any of three ways:
|
||||
* <ol>
|
||||
* <li>
|
||||
* Add a unique constraint via separate alter table statements.
|
||||
* See {@link #getAlterTableToAddUniqueKeyCommand}.
|
||||
* Also, see {@link #getAlterTableToDropUniqueKeyCommand}
|
||||
* For single-column constraints, by adding {@code unique} to the column definition.
|
||||
* See {@link #getColumnDefinitionUniquenessFragment}
|
||||
* </li>
|
||||
* <li>
|
||||
* Add a unique constraint via dialect-specific syntax in table create statement.
|
||||
* By inclusion of the unique constraint in the {@code create table} statement.
|
||||
* See {@link #getTableCreationUniqueConstraintsFragment}
|
||||
* </li>
|
||||
* <li>
|
||||
* Add "unique" syntax to the column itself.
|
||||
* See {@link #getColumnDefinitionUniquenessFragment}
|
||||
* By creation of a unique constraint using separate {@code alter table} statements.
|
||||
* See {@link #getAlterTableToAddUniqueKeyCommand}.
|
||||
* Also, see {@link #getAlterTableToDropUniqueKeyCommand}.
|
||||
* </li>
|
||||
* </ol>
|
||||
* The first two options are generally preferred.
|
||||
*
|
||||
* #1 & #2 are preferred, if possible; #3 should be solely a fall-back.
|
||||
*
|
||||
* See HHH-7797.
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public interface UniqueDelegate {
|
||||
/**
|
||||
* Get the fragment that can be used to make a column unique as part of its column definition.
|
||||
* Get the SQL fragment used to make the given column unique as part of its column definition,
|
||||
* usually just {@code " unique"}, or return an empty string if uniqueness does not belong in
|
||||
* the column definition.
|
||||
* <p>
|
||||
* This is intended for {@code Dialect}s which do not support unique constraints.
|
||||
* This is for handling single columns explicitly marked {@linkplain Column#isUnique() unique},
|
||||
* not for dealing with {@linkplain UniqueKey unique keys}.
|
||||
*
|
||||
* @param column The column to which to apply the unique
|
||||
* @param context A context for SQL string generation
|
||||
|
@ -51,38 +51,43 @@ public interface UniqueDelegate {
|
|||
String getColumnDefinitionUniquenessFragment(Column column, SqlStringGenerationContext context);
|
||||
|
||||
/**
|
||||
* Get the fragment that can be used to apply unique constraints as part of table creation.
|
||||
* The implementation should iterate over the {@link UniqueKey} instances for the given table
|
||||
* (see {@link org.hibernate.mapping.Table#getUniqueKeys()} and generate the whole fragment
|
||||
* for all unique keys.
|
||||
* Get the SQL fragment used to specify the unique constraints on the given table as part of
|
||||
* the {@code create table} command, with a leading comma, usually something like:
|
||||
* <pre>{@code , unique(x,y), constraint abc unique(a,b,c)}</pre>
|
||||
* or return an empty string if there are no unique constraints or if the unique constraints
|
||||
* do not belong in the table definition.
|
||||
* <p>
|
||||
* Intended for {@code Dialect}s which support unique constraint definitions, but just not in
|
||||
* separate ALTER statements.
|
||||
* The implementation should iterate over the {@linkplain UniqueKey unique keys} of the given
|
||||
* table by calling {@link org.hibernate.mapping.Table#getUniqueKeys()} and generate a fragment
|
||||
* which includes all the unique key declarations.
|
||||
*
|
||||
* @param table The table for which to generate the unique constraints fragment
|
||||
* @param context A context for SQL string generation
|
||||
* @return The fragment, typically in the form {@code ", unique(col1, col2), unique( col20)"}.
|
||||
* @return The fragment, typically in the form {@code ", unique(col1, col2), unique(col20)"}.
|
||||
* NOTE: The leading comma is important!
|
||||
*/
|
||||
String getTableCreationUniqueConstraintsFragment(Table table, SqlStringGenerationContext context);
|
||||
|
||||
/**
|
||||
* Get the SQL ALTER TABLE command to be used to create the given {@link UniqueKey}.
|
||||
* Get the {@code alter table} command used to create the given {@linkplain UniqueKey unique key}
|
||||
* constraint, or return the empty string if the constraint was already included in the {@code
|
||||
* create table} statement by {@link #getTableCreationUniqueConstraintsFragment}.
|
||||
*
|
||||
* @param uniqueKey The {@link UniqueKey} instance. Contains all information about the columns
|
||||
* @param metadata Access to the bootstrap mapping information
|
||||
* @param context A context for SQL string generation
|
||||
* @return The ALTER TABLE command
|
||||
* @return The {@code alter table} command
|
||||
*/
|
||||
String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, SqlStringGenerationContext context);
|
||||
|
||||
/**
|
||||
* Get the SQL ALTER TABLE command to be used to drop the given {@link UniqueKey}.
|
||||
* Get the {@code alter table} command used to drop the given {@linkplain UniqueKey unique key}
|
||||
* which was previously created by {@link #getAlterTableToAddUniqueKeyCommand}.
|
||||
*
|
||||
* @param uniqueKey The {@link UniqueKey} instance. Contains all information about the columns
|
||||
* @param metadata Access to the bootstrap mapping information
|
||||
* @param context A context for SQL string generation
|
||||
* @return The ALTER TABLE command
|
||||
* @return The {@code alter table} command
|
||||
*/
|
||||
String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, SqlStringGenerationContext context);
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ public abstract class Constraint implements Exportable, Serializable {
|
|||
public void addColumns(Value value) {
|
||||
for ( Selectable selectable : value.getSelectables() ) {
|
||||
if ( selectable.isFormula() ) {
|
||||
throw new MappingException( "constraint involves a formula: " + this.name );
|
||||
throw new MappingException( "constraint involves a formula: " + name );
|
||||
}
|
||||
else {
|
||||
addColumn( (Column) selectable );
|
||||
|
|
|
@ -472,7 +472,7 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
|||
alter.append( " not null" );
|
||||
}
|
||||
|
||||
if ( column.isUnique() ) {
|
||||
if ( column.isUnique() && !isPrimaryKey( column ) ) {
|
||||
String keyName = Constraint.generateName( "UK_", this, column );
|
||||
UniqueKey uk = getOrCreateUniqueKey( keyName );
|
||||
uk.addColumn( column );
|
||||
|
@ -504,6 +504,12 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
|||
return results.iterator();
|
||||
}
|
||||
|
||||
public boolean isPrimaryKey(Column column) {
|
||||
return hasPrimaryKey()
|
||||
&& getPrimaryKey().getColumnSpan() == 1
|
||||
&& getPrimaryKey().containsColumn( column );
|
||||
}
|
||||
|
||||
public boolean hasPrimaryKey() {
|
||||
return getPrimaryKey() != null;
|
||||
}
|
||||
|
@ -549,13 +555,21 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
|||
return uniqueKey;
|
||||
}
|
||||
|
||||
public UniqueKey createUniqueKey(List<Column> keyColumns) {
|
||||
String keyName = Constraint.generateName( "UK_", this, keyColumns );
|
||||
UniqueKey uniqueKey = getOrCreateUniqueKey( keyName );
|
||||
for (Column keyColumn : keyColumns) {
|
||||
uniqueKey.addColumn( keyColumn );
|
||||
/**
|
||||
* If there is one given column, mark it unique, otherwise
|
||||
* create a {@link UniqueKey} comprising the given columns.
|
||||
*/
|
||||
public void createUniqueKey(List<Column> keyColumns) {
|
||||
if ( keyColumns.size() == 1 ) {
|
||||
keyColumns.get(0).setUnique( true );
|
||||
}
|
||||
else {
|
||||
String keyName = Constraint.generateName( "UK_", this, keyColumns );
|
||||
UniqueKey uniqueKey = getOrCreateUniqueKey( keyName );
|
||||
for ( Column keyColumn : keyColumns ) {
|
||||
uniqueKey.addColumn( keyColumn );
|
||||
}
|
||||
}
|
||||
return uniqueKey;
|
||||
}
|
||||
|
||||
public UniqueKey getUniqueKey(String keyName) {
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.hibernate.internal.util.StringHelper;
|
|||
*/
|
||||
public class UniqueKey extends Constraint {
|
||||
private final Map<Column, String> columnOrderMap = new HashMap<>();
|
||||
private boolean nameExplicit;
|
||||
|
||||
@Override @Deprecated(since="6.2")
|
||||
public String sqlConstraintString(
|
||||
|
@ -51,4 +52,12 @@ public class UniqueKey extends Constraint {
|
|||
public String getExportIdentifier() {
|
||||
return StringHelper.qualify( getTable().getExportIdentifier(), "UK-" + getName() );
|
||||
}
|
||||
|
||||
public boolean isNameExplicit() {
|
||||
return nameExplicit;
|
||||
}
|
||||
|
||||
public void setNameExplicit(boolean nameExplicit) {
|
||||
this.nameExplicit = nameExplicit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,10 @@ public interface Value extends Serializable {
|
|||
boolean isNullable();
|
||||
|
||||
void createForeignKey();
|
||||
|
||||
// called when this is the foreign key of a
|
||||
// @OneToOne with a FK, or a @OneToMany with
|
||||
// a join table
|
||||
void createUniqueKey();
|
||||
|
||||
boolean isSimpleValue();
|
||||
|
|
|
@ -150,7 +150,7 @@ public abstract class AbstractSchemaMigrator implements SchemaMigrator {
|
|||
}
|
||||
|
||||
private SqlStringGenerationContext sqlGenerationContext(Metadata metadata, ExecutionOptions options) {
|
||||
return SqlStringGenerationContextImpl.fromConfigurationMap(
|
||||
return SqlStringGenerationContextImpl.fromConfigurationMapForMigration(
|
||||
tool.getServiceRegistry().getService( JdbcEnvironment.class ),
|
||||
metadata.getDatabase(),
|
||||
options.getConfigurationValues()
|
||||
|
|
|
@ -18,6 +18,8 @@ import org.hibernate.mapping.ForeignKey;
|
|||
import org.hibernate.tool.schema.spi.Exporter;
|
||||
|
||||
/**
|
||||
* An {@link Exporter} for {@linkplain ForeignKey foreign key constraints}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardForeignKeyExporter implements Exporter<ForeignKey> {
|
||||
|
|
|
@ -19,6 +19,8 @@ import org.hibernate.mapping.Index;
|
|||
import org.hibernate.tool.schema.spi.Exporter;
|
||||
|
||||
/**
|
||||
* An {@link Exporter} for {@linkplain Index indexes}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardIndexExporter implements Exporter<Index> {
|
||||
|
|
|
@ -14,6 +14,8 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.tool.schema.spi.Exporter;
|
||||
|
||||
/**
|
||||
* An {@link Exporter} for {@link Sequence sequences}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardSequenceExporter implements Exporter<Sequence> {
|
||||
|
|
|
@ -20,9 +20,11 @@ import java.util.Collection;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The basic implementation of {@link Cleaner}.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class StandardTableCleaner implements Cleaner {
|
||||
public class StandardTableCleaner implements Cleaner {
|
||||
protected final Dialect dialect;
|
||||
|
||||
public StandardTableCleaner(Dialect dialect) {
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.hibernate.mapping.UniqueKey;
|
|||
import org.hibernate.tool.schema.spi.Exporter;
|
||||
|
||||
/**
|
||||
* An {@link Exporter} for {@linkplain Table tables}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardTableExporter implements Exporter<Table> {
|
||||
|
@ -123,7 +125,7 @@ public class StandardTableExporter implements Exporter<Table> {
|
|||
|
||||
}
|
||||
|
||||
if ( col.isUnique() ) {
|
||||
if ( col.isUnique() && !table.isPrimaryKey( col ) ) {
|
||||
String keyName = Constraint.generateName( "UK_", table, col );
|
||||
UniqueKey uk = table.getOrCreateUniqueKey( keyName );
|
||||
uk.addColumn( col );
|
||||
|
|
|
@ -14,8 +14,9 @@ import org.hibernate.mapping.UniqueKey;
|
|||
import org.hibernate.tool.schema.spi.Exporter;
|
||||
|
||||
/**
|
||||
* Unique constraint Exporter. Note that it's parameterized for Constraint, rather than UniqueKey. This is
|
||||
* to allow Dialects to decide whether or not to create unique constraints for unique indexes.
|
||||
* 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.
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
|
|
|
@ -63,7 +63,7 @@ public class Trainer {
|
|||
joinColumns = @JoinColumn(name = "trainer_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "monkey_id")
|
||||
)
|
||||
@ForeignKey(name = "TM_TRA_FK", inverseName = "TM_MON_FK")
|
||||
// @ForeignKey(name = "TM_TRA_FK", inverseName = "TM_MON_FK")
|
||||
public Set<Monkey> getTrainedMonkeys() {
|
||||
return trainedMonkeys;
|
||||
}
|
||||
|
|
|
@ -1,164 +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.orm.test.annotations.uniqueconstraint;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.MariaDBDialect;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.hibernate.testing.orm.junit.BaseUnitTest;
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-11236")
|
||||
@RequiresDialect(value = MySQLDialect.class, majorVersion = 5)
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsJdbcDriverProxying.class)
|
||||
@BaseUnitTest
|
||||
public class MySQLDropConstraintThrowsExceptionTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
|
||||
.enableAutoClose()
|
||||
.applySetting( AvailableSettings.HBM2DDL_AUTO, "drop" )
|
||||
.build();
|
||||
|
||||
SessionFactoryImplementor sessionFactory = null;
|
||||
|
||||
try {
|
||||
final Metadata metadata = new MetadataSources( serviceRegistry )
|
||||
.addAnnotatedClass( Customer.class )
|
||||
.buildMetadata();
|
||||
sessionFactory = (SessionFactoryImplementor) metadata.buildSessionFactory();
|
||||
}
|
||||
finally {
|
||||
if ( sessionFactory != null ) {
|
||||
sessionFactory.close();
|
||||
}
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
|
||||
.enableAutoClose()
|
||||
.applySetting( AvailableSettings.HBM2DDL_AUTO, "drop" )
|
||||
.build();
|
||||
|
||||
SessionFactoryImplementor sessionFactory = null;
|
||||
|
||||
try {
|
||||
final Metadata metadata = new MetadataSources( serviceRegistry )
|
||||
.addAnnotatedClass( Customer.class )
|
||||
.buildMetadata();
|
||||
sessionFactory = (SessionFactoryImplementor) metadata.buildSessionFactory();
|
||||
}
|
||||
finally {
|
||||
if ( sessionFactory != null ) {
|
||||
sessionFactory.close();
|
||||
}
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumTypeInterpretation() {
|
||||
final PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider(
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
|
||||
.enableAutoClose()
|
||||
.applySetting( AvailableSettings.HBM2DDL_AUTO, "update" )
|
||||
.applySetting(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
)
|
||||
.build();
|
||||
|
||||
SessionFactory sessionFactory = null;
|
||||
try {
|
||||
final Metadata metadata = new MetadataSources( serviceRegistry )
|
||||
.addAnnotatedClass( Customer.class )
|
||||
.buildMetadata();
|
||||
sessionFactory = metadata.buildSessionFactory();
|
||||
List<String> alterStatements = connectionProvider.getExecuteStatements().stream()
|
||||
.filter(
|
||||
sql -> sql.toLowerCase().contains( "alter " )
|
||||
).map( String::trim ).collect( Collectors.toList() );
|
||||
if ( metadata.getDatabase().getDialect().supportsIfExistsAfterAlterTable() ) {
|
||||
assertTrue( alterStatements.get( 0 ).matches( "alter table if exists CUSTOMER\\s+drop index .*?" ) );
|
||||
assertTrue( alterStatements.get( 1 )
|
||||
.matches( "alter table if exists CUSTOMER\\s+add constraint .*? unique \\(CUSTOMER_ID\\)" ) );
|
||||
|
||||
}
|
||||
else {
|
||||
assertTrue( alterStatements.get( 0 ).matches( "alter table CUSTOMER\\s+drop index .*?" ) );
|
||||
assertTrue( alterStatements.get( 1 )
|
||||
.matches( "alter table CUSTOMER\\s+add constraint .*? unique \\(CUSTOMER_ID\\)" ) );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ( sessionFactory != null ) {
|
||||
sessionFactory.close();
|
||||
}
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "CUSTOMER")
|
||||
public static class Customer {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(name = "CUSTOMER_ACCOUNT_NUMBER")
|
||||
public Long customerAccountNumber;
|
||||
|
||||
@Basic
|
||||
@Column(name = "CUSTOMER_ID", unique = true)
|
||||
public String customerId;
|
||||
|
||||
@Basic
|
||||
@Column(name = "BILLING_ADDRESS")
|
||||
public String billingAddress;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
|||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Table;
|
||||
|
@ -92,7 +92,7 @@ public class UniqueDelegateTest extends BaseUnitTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public static class MyUniqueDelegate extends DefaultUniqueDelegate {
|
||||
public static class MyUniqueDelegate extends AlterTableUniqueDelegate {
|
||||
|
||||
/**
|
||||
* Constructs DefaultUniqueDelegate
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.sql.Types;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -73,24 +74,25 @@ public class SchemaCreationTest {
|
|||
|
||||
boolean isUniqueConstraintCreated = false;
|
||||
for ( String statement : sqlLines ) {
|
||||
statement = statement.toLowerCase();
|
||||
assertThat(
|
||||
"Should not try to create the unique constraint for the non existing table element",
|
||||
statement.toLowerCase()
|
||||
.matches( dialect.getAlterTableString( "element" ) ),
|
||||
statement.matches( dialect.getAlterTableString( "element" ) ),
|
||||
is( false )
|
||||
);
|
||||
if (statement.toLowerCase().startsWith("create unique index")
|
||||
&& statement.toLowerCase().contains("category (code)")) {
|
||||
isUniqueConstraintCreated = true;
|
||||
}
|
||||
else if (statement.toLowerCase().startsWith("alter table if exists category add constraint")
|
||||
&& statement.toLowerCase().contains("unique (code)")) {
|
||||
isUniqueConstraintCreated = true;
|
||||
}
|
||||
else if (statement.toLowerCase().startsWith("alter table category add constraint")
|
||||
&& statement.toLowerCase().contains("unique (code)")) {
|
||||
isUniqueConstraintCreated = true;
|
||||
}
|
||||
String varchar255 = metadata.getTypeConfiguration().getDdlTypeRegistry()
|
||||
.getTypeName(Types.VARCHAR,255L,0,0);
|
||||
isUniqueConstraintCreated = isUniqueConstraintCreated
|
||||
|| statement.startsWith("create unique index")
|
||||
&& statement.contains("category (code)")
|
||||
|| statement.startsWith("alter table if exists category add constraint")
|
||||
&& statement.contains("unique (code)")
|
||||
|| statement.startsWith("alter table category add constraint")
|
||||
&& statement.contains("unique (code)")
|
||||
|| statement.startsWith("create table category")
|
||||
&& statement.contains("code " + varchar255 + dialect.getNullColumnString() + " unique")
|
||||
|| statement.startsWith("create table category")
|
||||
&& statement.contains("unique(code)");
|
||||
}
|
||||
|
||||
assertThat(
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.tool.schema.TargetType;
|
||||
|
@ -113,22 +114,24 @@ public class UniqueConstraintDropTest {
|
|||
new TargetDescriptorImpl()
|
||||
);
|
||||
|
||||
if ( getDialect() instanceof MySQLDialect ) {
|
||||
assertThat(
|
||||
"The test_entity_item table unique constraint has not been dropped",
|
||||
checkDropIndex( "test_entity_item", "item" ),
|
||||
is( true )
|
||||
);
|
||||
}
|
||||
else if ( getDialect() instanceof DB2Dialect ) {
|
||||
checkDB2DropIndex( "test_entity_item", "item" );
|
||||
}
|
||||
else {
|
||||
assertThat(
|
||||
"The test_entity_item table unique constraint has not been dropped",
|
||||
checkDropConstraint( "test_entity_item", "item" ),
|
||||
is( true )
|
||||
);
|
||||
if ( getDialect().getUniqueDelegate() instanceof AlterTableUniqueDelegate ) {
|
||||
if ( getDialect() instanceof MySQLDialect ) {
|
||||
assertThat(
|
||||
"The test_entity_item table unique constraint has not been dropped",
|
||||
checkDropIndex( "test_entity_item", "item" ),
|
||||
is( true )
|
||||
);
|
||||
}
|
||||
else if ( getDialect() instanceof DB2Dialect ) {
|
||||
checkDB2DropIndex( "test_entity_item", "item" );
|
||||
}
|
||||
else {
|
||||
assertThat(
|
||||
"The test_entity_item table unique constraint has not been dropped",
|
||||
checkDropConstraint( "test_entity_item", "item" ),
|
||||
is( true )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +140,6 @@ public class UniqueConstraintDropTest {
|
|||
}
|
||||
|
||||
private boolean checkDropConstraint(String tableName, String columnName) throws IOException {
|
||||
boolean matches = false;
|
||||
String regex = getDialect().getAlterTableString( tableName ) + " drop constraint";
|
||||
|
||||
if ( getDialect().supportsIfExistsBeforeConstraintName() ) {
|
||||
|
@ -148,11 +150,10 @@ public class UniqueConstraintDropTest {
|
|||
regex += " if exists";
|
||||
}
|
||||
|
||||
return isMatching( matches, regex );
|
||||
return isMatching( regex );
|
||||
}
|
||||
|
||||
private boolean checkDropIndex(String tableName, String columnName) throws IOException {
|
||||
boolean matches = false;
|
||||
String regex = "alter table ";
|
||||
|
||||
if ( getDialect().supportsIfExistsAfterAlterTable() ) {
|
||||
|
@ -167,31 +168,30 @@ public class UniqueConstraintDropTest {
|
|||
if ( getDialect().supportsIfExistsBeforeConstraintName() ) {
|
||||
regex += " if exists";
|
||||
}
|
||||
regex += " uk_(.)*";
|
||||
regex += " uk.*";
|
||||
if ( getDialect().supportsIfExistsAfterConstraintName() ) {
|
||||
regex += " if exists";
|
||||
}
|
||||
|
||||
return isMatching( matches, regex );
|
||||
return isMatching( regex );
|
||||
}
|
||||
|
||||
private boolean checkDB2DropIndex(String tableName, String columnName) throws IOException {
|
||||
boolean matches = false;
|
||||
String regex = "drop index " + tableName + ".uk_(.)*";
|
||||
return isMatching( matches, regex );
|
||||
String regex = "drop index " + tableName + ".uk.*";
|
||||
return isMatching( regex );
|
||||
}
|
||||
|
||||
private boolean isMatching(boolean matches, String regex) throws IOException {
|
||||
private boolean isMatching(String regex) throws IOException {
|
||||
final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase();
|
||||
final String[] split = fileContent.split( System.lineSeparator() );
|
||||
Pattern p = Pattern.compile( regex );
|
||||
for ( String line : split ) {
|
||||
final Matcher matcher = p.matcher( line );
|
||||
if ( matcher.matches() ) {
|
||||
matches = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
return false;
|
||||
}
|
||||
|
||||
private class TargetDescriptorImpl implements TargetDescriptor {
|
||||
|
|
|
@ -20,6 +20,8 @@ import org.hibernate.boot.spi.MetadataImplementor;
|
|||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.unique.AlterTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
||||
import org.hibernate.tool.schema.TargetType;
|
||||
|
@ -92,34 +94,40 @@ public class UniqueConstraintGenerationTest {
|
|||
}
|
||||
|
||||
private boolean isUniqueConstraintGenerated(String tableName, String columnName) throws IOException {
|
||||
boolean matches = false;
|
||||
final String regex = getDialect().getAlterTableString( tableName ) + " add constraint uk_(.)* unique \\(" + columnName + "\\);";
|
||||
final String regex;
|
||||
Dialect dialect = getDialect();
|
||||
if ( dialect.getUniqueDelegate() instanceof CreateTableUniqueDelegate ) {
|
||||
regex = dialect.getCreateTableString() + " " + tableName + " .* " + columnName + " .+ unique.*\\)"
|
||||
+ dialect.getTableTypeString().toLowerCase() + ";";
|
||||
}
|
||||
else if ( dialect.getUniqueDelegate() instanceof AlterTableUniqueDelegate) {
|
||||
regex = dialect.getAlterTableString( tableName ) + " add constraint uk.* unique \\(" + columnName + "\\);";
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase();
|
||||
final String[] split = fileContent.split( System.lineSeparator() );
|
||||
Pattern p = Pattern.compile( regex );
|
||||
for ( String line : split ) {
|
||||
final Matcher matcher = p.matcher( line );
|
||||
if ( matcher.matches() ) {
|
||||
matches = true;
|
||||
if ( line.matches(regex) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCreateUniqueIndexGenerated(String tableName, String columnName) throws IOException {
|
||||
boolean matches = false;
|
||||
String regex = "create unique index uk_(.)* on " + tableName + " \\(" + columnName + "\\);";
|
||||
|
||||
String regex = "create unique index uk.* on " + tableName + " \\(" + columnName + "\\);";
|
||||
final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase();
|
||||
final String[] split = fileContent.split( System.lineSeparator() );
|
||||
Pattern p = Pattern.compile( regex );
|
||||
for ( String line : split ) {
|
||||
final Matcher matcher = p.matcher( line );
|
||||
if ( matcher.matches() ) {
|
||||
matches = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue