HHH-7797 Use unique indexes on nullable columns for DB2. Correctly
handle @UniqueConstraint table annotations on second passes.
This commit is contained in:
parent
2cd062058c
commit
e629feee8a
|
@ -1540,7 +1540,6 @@ public class Configuration implements Serializable {
|
||||||
private void buildUniqueKeyFromColumnNames(Table table, String keyName, String[] columnNames) {
|
private void buildUniqueKeyFromColumnNames(Table table, String keyName, String[] columnNames) {
|
||||||
keyName = normalizer.normalizeIdentifierQuoting( keyName );
|
keyName = normalizer.normalizeIdentifierQuoting( keyName );
|
||||||
|
|
||||||
UniqueKey uc;
|
|
||||||
int size = columnNames.length;
|
int size = columnNames.length;
|
||||||
Column[] columns = new Column[size];
|
Column[] columns = new Column[size];
|
||||||
Set<Column> unbound = new HashSet<Column>();
|
Set<Column> unbound = new HashSet<Column>();
|
||||||
|
@ -1559,8 +1558,10 @@ public class Configuration implements Serializable {
|
||||||
}
|
}
|
||||||
for ( Column column : columns ) {
|
for ( Column column : columns ) {
|
||||||
if ( table.containsColumn( column ) ) {
|
if ( table.containsColumn( column ) ) {
|
||||||
uc = table.getOrCreateUniqueKey( keyName );
|
Column tableColumn = table.getColumn( column );
|
||||||
uc.addColumn( table.getColumn( column ) );
|
tableColumn.setUnique( true );
|
||||||
|
Dialect.getDialect().getUniqueDelegate().generateUniqueKey(
|
||||||
|
table, tableColumn );
|
||||||
unbound.remove( column );
|
unbound.remove( column );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ import org.hibernate.dialect.function.NoArgSQLFunction;
|
||||||
import org.hibernate.dialect.function.SQLFunctionTemplate;
|
import org.hibernate.dialect.function.SQLFunctionTemplate;
|
||||||
import org.hibernate.dialect.function.StandardSQLFunction;
|
import org.hibernate.dialect.function.StandardSQLFunction;
|
||||||
import org.hibernate.dialect.function.VarArgsSQLFunction;
|
import org.hibernate.dialect.function.VarArgsSQLFunction;
|
||||||
|
import org.hibernate.dialect.unique.DB2UniqueDelegate;
|
||||||
|
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||||
import org.hibernate.exception.LockTimeoutException;
|
import org.hibernate.exception.LockTimeoutException;
|
||||||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||||
|
@ -48,6 +50,8 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class DB2Dialect extends Dialect {
|
public class DB2Dialect extends Dialect {
|
||||||
|
|
||||||
|
private final UniqueDelegate uniqueDelegate;
|
||||||
|
|
||||||
public DB2Dialect() {
|
public DB2Dialect() {
|
||||||
super();
|
super();
|
||||||
|
@ -174,6 +178,8 @@ public class DB2Dialect extends Dialect {
|
||||||
registerKeyword( "only" );
|
registerKeyword( "only" );
|
||||||
|
|
||||||
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
|
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
|
||||||
|
|
||||||
|
uniqueDelegate = new DB2UniqueDelegate( this );
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public String getLowercaseFunction() {
|
public String getLowercaseFunction() {
|
||||||
|
@ -451,5 +457,10 @@ public class DB2Dialect extends Dialect {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UniqueDelegate getUniqueDelegate() {
|
||||||
|
return uniqueDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
* Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @authors tag. All rights reserved.
|
||||||
|
* See the copyright.txt in the distribution for a
|
||||||
|
* full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License, v. 2.1.
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT A
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License,
|
||||||
|
* v.2.1 along with this distribution; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.unique;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.metamodel.relational.Column;
|
||||||
|
import org.hibernate.metamodel.relational.Index;
|
||||||
|
import org.hibernate.metamodel.relational.UniqueKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB2 does not allow unique constraints on nullable columns. Rather than
|
||||||
|
* forcing "not null", use unique *indexes* instead.
|
||||||
|
*
|
||||||
|
* @author Brett Meyer
|
||||||
|
*/
|
||||||
|
public class DB2UniqueDelegate extends DefaultUniqueDelegate {
|
||||||
|
|
||||||
|
public DB2UniqueDelegate( Dialect dialect ) {
|
||||||
|
super( dialect );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String applyUniquesOnAlter( org.hibernate.mapping.UniqueKey uniqueKey,
|
||||||
|
String defaultCatalog, String defaultSchema ) {
|
||||||
|
if ( hasNullable( uniqueKey ) ) {
|
||||||
|
return org.hibernate.mapping.Index.buildSqlCreateIndexString(
|
||||||
|
dialect, uniqueKey.getName(), uniqueKey.getTable(),
|
||||||
|
uniqueKey.columnIterator(), true, defaultCatalog,
|
||||||
|
defaultSchema );
|
||||||
|
} else {
|
||||||
|
return super.applyUniquesOnAlter(
|
||||||
|
uniqueKey, defaultCatalog, defaultSchema );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String applyUniquesOnAlter( UniqueKey uniqueKey ) {
|
||||||
|
if ( hasNullable( uniqueKey ) ) {
|
||||||
|
return Index.buildSqlCreateIndexString(
|
||||||
|
dialect, uniqueKey.getName(), uniqueKey.getTable(),
|
||||||
|
uniqueKey.getColumns(), true );
|
||||||
|
} else {
|
||||||
|
return super.applyUniquesOnAlter( uniqueKey );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String dropUniquesOnAlter( org.hibernate.mapping.UniqueKey uniqueKey,
|
||||||
|
String defaultCatalog, String defaultSchema ) {
|
||||||
|
if ( hasNullable( uniqueKey ) ) {
|
||||||
|
return org.hibernate.mapping.Index.buildSqlDropIndexString(
|
||||||
|
dialect, uniqueKey.getTable(), uniqueKey.getName(),
|
||||||
|
defaultCatalog, defaultSchema );
|
||||||
|
} else {
|
||||||
|
return super.dropUniquesOnAlter(
|
||||||
|
uniqueKey, defaultCatalog, defaultSchema );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String dropUniquesOnAlter( UniqueKey uniqueKey ) {
|
||||||
|
if ( hasNullable( uniqueKey ) ) {
|
||||||
|
return Index.buildSqlDropIndexString(
|
||||||
|
dialect, uniqueKey.getTable(), uniqueKey.getName() );
|
||||||
|
} else {
|
||||||
|
return super.dropUniquesOnAlter( uniqueKey );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasNullable( org.hibernate.mapping.UniqueKey uniqueKey ) {
|
||||||
|
Iterator iter = uniqueKey.getColumnIterator();
|
||||||
|
while ( iter.hasNext() ) {
|
||||||
|
if ( ( ( org.hibernate.mapping.Column ) iter.next() ).isNullable() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasNullable( UniqueKey uniqueKey ) {
|
||||||
|
Iterator iter = uniqueKey.getColumns().iterator();
|
||||||
|
while ( iter.hasNext() ) {
|
||||||
|
if ( ( ( Column ) iter.next() ).isNullable() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ import org.hibernate.metamodel.relational.UniqueKey;
|
||||||
*/
|
*/
|
||||||
public class DefaultUniqueDelegate implements UniqueDelegate {
|
public class DefaultUniqueDelegate implements UniqueDelegate {
|
||||||
|
|
||||||
private final Dialect dialect;
|
protected final Dialect dialect;
|
||||||
|
|
||||||
public DefaultUniqueDelegate( Dialect dialect ) {
|
public DefaultUniqueDelegate( Dialect dialect ) {
|
||||||
this.dialect = dialect;
|
this.dialect = dialect;
|
||||||
|
@ -57,7 +57,12 @@ public class DefaultUniqueDelegate implements UniqueDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String applyUniqueToColumn() {
|
public String applyUniqueToColumn( org.hibernate.mapping.Column column ) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String applyUniqueToColumn( Column column ) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,9 +68,20 @@ public interface UniqueDelegate {
|
||||||
* return the syntax necessary to mutate the column definition
|
* return the syntax necessary to mutate the column definition
|
||||||
* (usually "unique").
|
* (usually "unique").
|
||||||
*
|
*
|
||||||
|
* @param column
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
public String applyUniqueToColumn();
|
public String applyUniqueToColumn( org.hibernate.mapping.Column column );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the dialect does not supports unique constraints, this method should
|
||||||
|
* return the syntax necessary to mutate the column definition
|
||||||
|
* (usually "unique").
|
||||||
|
*
|
||||||
|
* @param column
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String applyUniqueToColumn( Column column );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If constraints are supported, but not in seperate alter statements,
|
* If constraints are supported, but not in seperate alter statements,
|
||||||
|
|
|
@ -79,7 +79,6 @@ public class Index implements RelationalModel, Serializable {
|
||||||
String defaultCatalog,
|
String defaultCatalog,
|
||||||
String defaultSchema
|
String defaultSchema
|
||||||
) {
|
) {
|
||||||
//TODO handle supportsNotNullUnique=false, but such a case does not exist in the wild so far
|
|
||||||
StringBuilder buf = new StringBuilder( "create" )
|
StringBuilder buf = new StringBuilder( "create" )
|
||||||
.append( unique ?
|
.append( unique ?
|
||||||
" unique" :
|
" unique" :
|
||||||
|
|
|
@ -425,8 +425,8 @@ public class Table implements RelationalModel, Serializable {
|
||||||
if ( column.isUnique() ) {
|
if ( column.isUnique() ) {
|
||||||
dialect.getUniqueDelegate().generateUniqueKey(
|
dialect.getUniqueDelegate().generateUniqueKey(
|
||||||
this, column );
|
this, column );
|
||||||
alter.append(
|
alter.append( dialect.getUniqueDelegate()
|
||||||
dialect.getUniqueDelegate().applyUniqueToColumn() );
|
.applyUniqueToColumn( column ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( column.hasCheckConstraint() && dialect.supportsColumnCheck() ) {
|
if ( column.hasCheckConstraint() && dialect.supportsColumnCheck() ) {
|
||||||
|
@ -526,7 +526,9 @@ public class Table implements RelationalModel, Serializable {
|
||||||
|
|
||||||
if ( col.isUnique() ) {
|
if ( col.isUnique() ) {
|
||||||
dialect.getUniqueDelegate().generateUniqueKey( this, col );
|
dialect.getUniqueDelegate().generateUniqueKey( this, col );
|
||||||
buf.append( dialect.getUniqueDelegate().applyUniqueToColumn() ); }
|
buf.append( dialect.getUniqueDelegate()
|
||||||
|
.applyUniqueToColumn( col ) );
|
||||||
|
}
|
||||||
|
|
||||||
if ( col.hasCheckConstraint() && dialect.supportsColumnCheck() ) {
|
if ( col.hasCheckConstraint() && dialect.supportsColumnCheck() ) {
|
||||||
buf.append( " check (" )
|
buf.append( " check (" )
|
||||||
|
|
|
@ -57,17 +57,4 @@ public class UniqueKey extends Constraint {
|
||||||
this, defaultCatalog, defaultSchema );
|
this, defaultCatalog, defaultSchema );
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public boolean isGenerated(Dialect dialect) {
|
|
||||||
// if ( !dialect.supportsUniqueConstraintInCreateAlterTable() ) return false;
|
|
||||||
// if ( dialect.supportsNotNullUnique() ) return true;
|
|
||||||
//
|
|
||||||
// Iterator iter = getColumnIterator();
|
|
||||||
// while ( iter.hasNext() ) {
|
|
||||||
// // Dialect does not support "not null unique" and this column is not null.
|
|
||||||
// if ( ! ( (Column) iter.next() ).isNullable() ) return false;
|
|
||||||
// }
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,6 @@ public class Index extends AbstractConstraint implements Constraint {
|
||||||
Iterable<Column> columns,
|
Iterable<Column> columns,
|
||||||
boolean unique
|
boolean unique
|
||||||
) {
|
) {
|
||||||
//TODO handle supportsNotNullUnique=false, but such a case does not exist in the wild so far
|
|
||||||
StringBuilder buf = new StringBuilder( "create" )
|
StringBuilder buf = new StringBuilder( "create" )
|
||||||
.append( unique ?
|
.append( unique ?
|
||||||
" unique" :
|
" unique" :
|
||||||
|
@ -89,6 +88,18 @@ public class Index extends AbstractConstraint implements Constraint {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String buildSqlDropIndexString(
|
||||||
|
Dialect dialect,
|
||||||
|
TableSpecification table,
|
||||||
|
String name
|
||||||
|
) {
|
||||||
|
return "drop index " +
|
||||||
|
StringHelper.qualify(
|
||||||
|
table.getQualifiedName( dialect ),
|
||||||
|
name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public String sqlConstraintStringInAlterTable(Dialect dialect) {
|
public String sqlConstraintStringInAlterTable(Dialect dialect) {
|
||||||
StringBuilder buf = new StringBuilder( " index (" );
|
StringBuilder buf = new StringBuilder( " index (" );
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
|
|
|
@ -201,7 +201,8 @@ public class Table extends AbstractTableSpecification implements Exportable {
|
||||||
|
|
||||||
if ( col.isUnique() ) {
|
if ( col.isUnique() ) {
|
||||||
dialect.getUniqueDelegate().generateUniqueKey( this, col );
|
dialect.getUniqueDelegate().generateUniqueKey( this, col );
|
||||||
buf.append( dialect.getUniqueDelegate().applyUniqueToColumn() );
|
buf.append( dialect.getUniqueDelegate()
|
||||||
|
.applyUniqueToColumn( col ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( col.getCheckCondition() != null && dialect.supportsColumnCheck() ) {
|
if ( col.getCheckCondition() != null && dialect.supportsColumnCheck() ) {
|
||||||
|
|
Loading…
Reference in New Issue