HHH-7092 : Create default name for foreign and unique key constraints

This commit is contained in:
Gail Badner 2012-06-26 14:32:59 -07:00
parent c01104fbae
commit 7e6ea21908
14 changed files with 784 additions and 44 deletions

View File

@ -40,7 +40,7 @@ import org.hibernate.dialect.Dialect;
*/
public abstract class AbstractConstraint implements Constraint {
private final TableSpecification table;
private final String name;
private String name;
private List<Column> columns = new ArrayList<Column>();
protected AbstractConstraint(TableSpecification table, String name) {
@ -48,14 +48,64 @@ public abstract class AbstractConstraint implements Constraint {
this.name = name;
}
@Override
public TableSpecification getTable() {
return table;
}
/**
* Returns the constraint name, or null if the name has not been set.
*
* @return the constraint name, or null if the name has not been set
*/
public String getName() {
return name;
}
/**
* Sets a constraint name that is unique across
* all database objects.
*
* @param name - the unique constraint name; must be non-null.
*
* @throws IllegalArgumentException if name is null.
* @throws IllegalStateException if this constraint already has a non-null name.
*/
public void setName(String name) {
if ( name == null ) {
throw new IllegalArgumentException( "name must be non-null." );
}
if ( this.name != null ) {
throw new IllegalStateException(
String.format(
"This constraint already has a name (%s) and cannot be renamed to (%s).",
this.name,
name
)
);
}
this.name = name;
}
protected abstract String getGeneratedNamePrefix();
protected String getOrGenerateName() {
// TODO: if name is null, should it be set to the generated name when the relational model is "complete"?
return name != null ? name : generateName();
}
protected String generateName() {
return new StringBuilder()
.append( getGeneratedNamePrefix() )
.append( Integer.toHexString( table.getLogicalName().hashCode() ).toUpperCase() )
.append( Integer.toHexString( generateConstraintColumnListId() ).toUpperCase() )
.toString();
}
protected int generateConstraintColumnListId() {
return table.generateColumnListId( columns );
}
public List<Column> getColumns() {
return Collections.unmodifiableList( columns );
}
@ -101,7 +151,7 @@ public abstract class AbstractConstraint implements Constraint {
.append( "alter table " )
.append( getTable().getQualifiedName( dialect ) )
.append( " drop constraint " )
.append( dialect.quote( getName() ) )
.append( dialect.quote( getOrGenerateName() ) )
.toString()
};
}

View File

@ -24,9 +24,11 @@
package org.hibernate.metamodel.spi.relational;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
/**
@ -108,9 +110,16 @@ public abstract class AbstractTableSpecification implements TableSpecification {
@Override
public ForeignKey locateForeignKey(String name) {
for ( ForeignKey fk : foreignKeys ) {
if ( fk.getName().equals( name ) ) {
return fk;
return locateConstraint( foreignKeys, name );
}
protected <T extends Constraint> T locateConstraint(Iterable<T> constraints, String name) {
if ( name == null ) {
throw new IllegalArgumentException( "name must be non-null." );
}
for ( T constraint : constraints ) {
if ( name.equals( constraint.getName() ) ) {
return constraint;
}
}
return null;
@ -135,4 +144,15 @@ public abstract class AbstractTableSpecification implements TableSpecification {
public PrimaryKey getPrimaryKey() {
return primaryKey;
}
public int generateColumnListId(Iterable<Column> columns) {
int result = getLogicalName().hashCode();
for ( Column column : columns ) {
if ( !this.equals( column.getTable() ) ) {
throw new IllegalArgumentException( "All columns must be from this table." );
}
result = 31 * result + column.getColumnName().hashCode();
}
return result;
}
}

View File

@ -49,6 +49,8 @@ public class ForeignKey extends AbstractConstraint implements Constraint, Export
private static final String ON_DELETE = " on delete ";
private static final String ON_UPDATE = " on update ";
private static final String GENERATED_NAME_PREFIX = "FK";
private final TableSpecification targetTable;
private List<Column> targetColumns;
@ -82,6 +84,15 @@ public class ForeignKey extends AbstractConstraint implements Constraint, Export
: Collections.unmodifiableList( targetColumns );
}
@Override
protected String getGeneratedNamePrefix() {
return GENERATED_NAME_PREFIX;
}
protected int generateConstraintColumnListId() {
return 31 * super.generateConstraintColumnListId() + targetTable.generateColumnListId( getTargetColumns() );
}
@Override
public void addColumn(Column column) {
addColumnMapping( column, null );
@ -93,7 +104,7 @@ public class ForeignKey extends AbstractConstraint implements Constraint, Export
LOG.debugf(
"Attempt to map column [%s] to no target column after explicit target column(s) named for FK [name=%s]",
sourceColumn.toLoggableString(),
getName()
getOrGenerateName()
);
}
}
@ -104,7 +115,7 @@ public class ForeignKey extends AbstractConstraint implements Constraint, Export
LOG.debugf(
"Value mapping mismatch as part of FK [table=%s, name=%s] while adding source column [%s]",
getTable().toLoggableString(),
getName(),
getOrGenerateName(),
sourceColumn.toLoggableString()
);
}
@ -129,7 +140,7 @@ public class ForeignKey extends AbstractConstraint implements Constraint, Export
@Override
public String getExportIdentifier() {
return getSourceTable().getLoggableValueQualifier() + ".FK-" + getName();
return getSourceTable().getLoggableValueQualifier() + ".FK-" + getOrGenerateName();
}
public ReferentialAction getDeleteRule() {
@ -154,7 +165,7 @@ public class ForeignKey extends AbstractConstraint implements Constraint, Export
"alter table " +
getTable().getQualifiedName( dialect ) +
dialect.getDropForeignKeyString() +
getName()
getOrGenerateName()
};
}
@ -177,11 +188,12 @@ public class ForeignKey extends AbstractConstraint implements Constraint, Export
StringBuilder sb =
new StringBuilder(
dialect.getAddForeignKeyConstraintString(
getName(),
getOrGenerateName(),
columnNames,
targetTable.getQualifiedName( dialect ),
targetColumnNames,
this.targetColumns == null
this.targetColumns == null ||
this.targetColumns.equals( targetTable.getPrimaryKey().getColumns() )
)
);
// TODO: If a dialect does not support cascade-delete, can it support other actions? (HHH-6428)

View File

@ -51,7 +51,7 @@ public class Index extends AbstractConstraint implements Constraint {
public String[] sqlCreateStrings(Dialect dialect) {
return new String[] {
buildSqlCreateIndexString(
dialect, getName(), getTable(), getColumns(), false
dialect, getOrGenerateName(), getTable(), getColumns(), false
)
};
}
@ -89,6 +89,11 @@ public class Index extends AbstractConstraint implements Constraint {
return buf.toString();
}
@Override
protected String getGeneratedNamePrefix() {
return "IDX";
}
public String sqlConstraintStringInAlterTable(Dialect dialect) {
StringBuilder buf = new StringBuilder( " index (" );
boolean first = true;
@ -110,7 +115,7 @@ public class Index extends AbstractConstraint implements Constraint {
.append(
StringHelper.qualify(
getTable().getQualifiedName( dialect ),
getName()
getOrGenerateName()
)
).toString()
};

View File

@ -35,25 +35,24 @@ import org.hibernate.dialect.Dialect;
* @author Steve Ebersole
*/
public class PrimaryKey extends AbstractConstraint implements Constraint, Exportable {
// IMPL NOTE : I override the name behavior here because:
// (1) primary keys are not required to be named.
// (2) because a primary key is required for each table, it is easier to allow setting the constraint name
// later in terms of building the metamodel
//
// todo : default name? {TABLE_NAME}_PK maybe?
private String name;
private static final String GENERATED_NAME_PREFIX = "PK";
protected PrimaryKey(TableSpecification table) {
super( table, null );
}
@Override
public String getName() {
return name;
protected String generateName() {
return new StringBuilder()
.append( GENERATED_NAME_PREFIX )
.append( getTable().getLogicalName().getName().toUpperCase() )
.toString();
}
public void setName(String name) {
this.name = name;
@Override
protected String getGeneratedNamePrefix() {
return GENERATED_NAME_PREFIX;
}
@Override
@ -78,7 +77,7 @@ public class PrimaryKey extends AbstractConstraint implements Constraint, Export
public String sqlConstraintStringInAlterTable(Dialect dialect) {
StringBuilder buf = new StringBuilder(
dialect.getAddPrimaryKeyConstraintString( getName() )
dialect.getAddPrimaryKeyConstraintString( getOrGenerateName() )
).append('(');
boolean first = true;
for ( Column column : getColumns() ) {

View File

@ -24,8 +24,10 @@
package org.hibernate.metamodel.spi.relational;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.dialect.Dialect;
@ -42,8 +44,8 @@ public class Table extends AbstractTableSpecification implements Exportable {
private ObjectName objectName;
private String exportIdentifier;
private final LinkedHashMap<String,Index> indexes = new LinkedHashMap<String,Index>();
private final LinkedHashMap<String,UniqueKey> uniqueKeys = new LinkedHashMap<String,UniqueKey>();
private final Set<Index> indexes = new LinkedHashSet<Index>();
private final Set<UniqueKey> uniqueKeys = new LinkedHashSet<UniqueKey>();
private final List<CheckConstraint> checkConstraints = new ArrayList<CheckConstraint>();
private final List<String> comments = new ArrayList<String>();
@ -102,34 +104,39 @@ public class Table extends AbstractTableSpecification implements Exportable {
@Override
public Iterable<Index> getIndexes() {
return indexes.values();
return Collections.unmodifiableSet( indexes );
}
@Override
public Index getOrCreateIndex(String name) {
if( indexes.containsKey( name ) ){
return indexes.get( name );
Index result = null;
if ( name != null ) {
result = locateConstraint( indexes, name );
}
Index index = new Index( this, name );
indexes.put(name, index );
return index;
if ( result == null ) {
result = new Index( this, name );
indexes.add( result );
}
return result;
}
@Override
public Iterable<UniqueKey> getUniqueKeys() {
return uniqueKeys.values();
public Set<UniqueKey> getUniqueKeys() {
return Collections.unmodifiableSet( uniqueKeys );
}
@Override
public UniqueKey getOrCreateUniqueKey(String name) {
if( uniqueKeys.containsKey( name ) ){
return uniqueKeys.get( name );
UniqueKey result = null;
if ( name != null ) {
result = locateConstraint( uniqueKeys, name );
}
UniqueKey uniqueKey = new UniqueKey( this, name );
uniqueKeys.put(name, uniqueKey );
return uniqueKey;
if ( result == null ) {
result = new UniqueKey( this, name );
uniqueKeys.add( result );
}
return result;
}
@Override
public Iterable<CheckConstraint> getCheckConstraints() {
@ -250,7 +257,7 @@ public class Table extends AbstractTableSpecification implements Exportable {
}
if ( dialect.supportsUniqueConstraintInCreateAlterTable() ) {
for ( UniqueKey uk : uniqueKeys.values() ) {
for ( UniqueKey uk : uniqueKeys ) {
String constraint = uk.sqlConstraintStringInCreateTable( dialect );
if ( constraint != null ) {
buf.append( ", " ).append( constraint );

View File

@ -88,6 +88,14 @@ public interface TableSpecification extends ValueContainer, Loggable {
*/
public DerivedValue locateOrCreateDerivedValue(String fragment);
/**
* Generates a unique ID for the specified columns in this table.
*
* @param columns - the columns used to generate the ID
* @return the ID unique to the specified columns in this table.
*/
public int generateColumnListId(Iterable<Column> columns);
/**
* Retrieve all foreign keys currently defined for this table.
*

View File

@ -32,6 +32,8 @@ import org.hibernate.dialect.Dialect;
* @author Steve Ebersole
*/
public class UniqueKey extends AbstractConstraint implements Constraint {
private static final String GENERATED_NAME_PREFIX = "UK";
protected UniqueKey(Table table, String name) {
super( table, name );
}
@ -46,6 +48,11 @@ public class UniqueKey extends AbstractConstraint implements Constraint {
return sb.toString();
}
@Override
protected String getGeneratedNamePrefix() {
return GENERATED_NAME_PREFIX;
}
@Override
public boolean isCreationVetoed(Dialect dialect) {
if ( dialect.supportsNotNullUnique() ) {
@ -85,7 +92,7 @@ public class UniqueKey extends AbstractConstraint implements Constraint {
@Override
public String sqlConstraintStringInAlterTable(Dialect dialect) {
StringBuilder buf = new StringBuilder(
dialect.getAddUniqueConstraintString( getName() )
dialect.getAddUniqueConstraintString( getOrGenerateName() )
).append( '(' );
boolean nullable = false;
boolean first = true;

View File

@ -0,0 +1,184 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* 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, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY 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
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.relational;
import java.sql.Types;
import org.junit.Test;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Gail Badner
*/
public abstract class AbstractConstraintNameTests extends BaseUnitTestCase {
private static final JdbcDataType INTEGER = new JdbcDataType( Types.INTEGER, "INTEGER", Long.class );
protected static final String[] COLUMN_NAMES = new String[] { "col_1", "col_2", "col_3" };
private Dialect dialect = new H2Dialect();
@Test
public void testConstraintNameUninitializedInConstructor() {
AbstractConstraint constraint = createConstraintAndAddColumns( "my_table", null, COLUMN_NAMES[0] );
assertEquals( null, constraint.getName() );
String generatedName = constraint.generateName();
checkGeneratedName( constraint );
// ensure the generated name doesn't change when constraint.generateName() is called again
assertEquals( generatedName, constraint.generateName() );
// since the constraint name is null, the DDL should contain the generated name;
checkNameInDDL( constraint, generatedName );
}
@Test
public void testConstraintNameInitializedInConstructor() {
AbstractConstraint constraint = createConstraintAndAddColumns( "my_table", "AName", COLUMN_NAMES[0] );
assertEquals( "AName", constraint.getName() );
// since the constraint name is non-null, the DDL should contain the constraint name;
checkNameInDDL( constraint, constraint.getName() );
}
@Test
public void testConstraintNameUninitializedInConstructorThenSet() {
AbstractConstraint constraint = createConstraintAndAddColumns( "my_table", null, COLUMN_NAMES[0] );
assertEquals( null, constraint.getName() );
constraint.setName( "AName" );
assertEquals( "AName", constraint.getName() );
// since the constraint name is non-null now, the DDL should contain the constraint name;
checkNameInDDL( constraint, constraint.getName() );
}
@Test
public void testResetConstraintNameToNull() {
AbstractConstraint constraint = createConstraintAndAddColumns( "my_table", "AName", COLUMN_NAMES[0] );
assertEquals( "AName", constraint.getName() );
try {
constraint.setName( null );
fail( "should have thrown exception" );
}
catch (IllegalArgumentException ex) {
// expected
}
}
@Test
public void testResetConstraintNameToNewValue() {
AbstractConstraint constraint = createConstraintAndAddColumns( "my_table", "AName", COLUMN_NAMES[0] );
assertEquals( "AName", constraint.getName() );
try {
constraint.setName( "ANewName" );
fail( "should have thrown exception" );
}
catch (IllegalStateException ex) {
// expected
}
}
@Test
public void testConstraintsOnSameColumnInDiffTableHaveDiffGeneratedName() {
AbstractConstraint constraint1 = createConstraintAndAddColumns( "my_table", null, COLUMN_NAMES[0] );
AbstractConstraint constraint2 = createConstraintAndAddColumns( "my_other_table", null, COLUMN_NAMES[0] );
// generated names should be different because the constraints are on different tables
assertTrue( ! constraint1.generateName().equals( constraint2.generateName() ) );
}
@Test
public void testConstraintNameOnDiffColumnInSameTableHaveDiffName() {
AbstractConstraint constraint1 = createConstraintAndAddColumns( "my_table", null, COLUMN_NAMES[0] );
AbstractConstraint constraint2 = createConstraintAndAddColumns( "my_table", null, COLUMN_NAMES[1] );
// generated names should be different because the constraints are on different columns in the same table
if ( constraint1 instanceof PrimaryKey && constraint2 instanceof PrimaryKey ) {
// generated name for primary keys does not depend on column name; this is ok
// because there is only 1 primary key can be defined on the table
assertTrue( constraint1.generateName().equals( constraint2.generateName() ) );
}
else {
// generated names for non-primary key constraints does depend on the column,
// so the generated names should be different.
assertTrue( ! constraint1.generateName().equals( constraint2.generateName() ) );
}
}
protected abstract AbstractConstraint createConstraint(TableSpecification table, String constraintName);
private AbstractConstraint createConstraintAndAddColumns(
String tableName,
String constraintName,
String constraintColumn) {
final Table table = createTable( tableName );
AbstractConstraint constraint = createConstraint( table, constraintName );
constraint.addColumn( table.locateColumn( constraintColumn ) );
return constraint;
}
protected void checkGeneratedName(AbstractConstraint constraint) {
assertTrue(
constraint.generateName().startsWith(
constraint.getGeneratedNamePrefix() +
Integer.toHexString(
constraint.getTable().getLogicalName().hashCode()
).toUpperCase()
)
);
}
private void checkNameInDDL(AbstractConstraint constraint, String expectedNameInDDL) {
// since the name is null, the generated name should be in the DDL
String sqlConstraintStringInAlterTable = constraint.sqlConstraintStringInAlterTable( dialect );
assertTrue( sqlConstraintStringInAlterTable.contains( expectedNameInDDL ));
String[] sqlCreateStrings = constraint.sqlCreateStrings( dialect );
assertEquals( 1, sqlCreateStrings.length );
assertTrue( sqlCreateStrings[0].contains( sqlConstraintStringInAlterTable ) );
String[] sqlDropStrings = constraint.sqlDropStrings( dialect );
assertEquals( 1, sqlDropStrings.length );
assertTrue( sqlDropStrings[0].contains( expectedNameInDDL ) );
}
protected Table createTable(String name) {
Schema schema = new Schema( null, null );
Table table = schema.createTable( Identifier.toIdentifier( name ), Identifier.toIdentifier( name ) );
for ( String colName : COLUMN_NAMES ) {
Column column = table.locateOrCreateColumn( colName );
column.setJdbcDataType( INTEGER );
}
return table;
}
}

View File

@ -0,0 +1,43 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* 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, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY 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
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.relational;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
/**
* @author Gail Badner
*/
public class ForeignKeyConstraintNameTests extends AbstractConstraintNameTests {
@Override
protected AbstractConstraint createConstraint(TableSpecification table, String constraintName) {
// create referenced table with primary key; foreign key will reference
// referencedTable's primary key
TableSpecification referencedTable = createTable( "my_referenced_table" );
referencedTable.getPrimaryKey().addColumn( referencedTable.locateColumn( COLUMN_NAMES[0] ) );
return table.createForeignKey( referencedTable, constraintName );
}
}

View File

@ -0,0 +1,260 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* 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, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY 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
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.relational;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Tests that there is no collision between the generated names for different types of constraints.
* @author Gail Badner
*/
public class GeneratedNamesForDifferentConstraintTypes {
private static final JdbcDataType INTEGER = new JdbcDataType( Types.INTEGER, "INTEGER", Long.class );
protected static final String[] COLUMN_NAMES = new String[] { "col_1", "col_2", "col_3" };
@Test
public void testGeneratedNamesDoNotCollide() {
Set<String> generatedNames = new HashSet<String>();
// create a table for constraints
TableSpecification tab1 = createTable( "my_table" );
Column pkColTab1 = tab1.locateColumn( COLUMN_NAMES[0] );
Column col1Tab1 = tab1.locateColumn( COLUMN_NAMES[1] );
Column col2Tab1 = tab1.locateColumn( COLUMN_NAMES[2] );
// create another table for constraints
TableSpecification tab2 = createTable( "my_other_table" );
Column pkColTab2 = tab2.locateColumn( COLUMN_NAMES[0] );
Column col1Tab2 = tab2.locateColumn( COLUMN_NAMES[1] );
Column col2Tab2 = tab2.locateColumn( COLUMN_NAMES[2] );
// create a target table for foreign keys
TableSpecification refTab1 = createTable( "my_referenced_table" );
Column pkColTab1Ref = refTab1.locateColumn( COLUMN_NAMES[0] );
Column col1Tab1Ref = refTab1.locateColumn( COLUMN_NAMES[1] );
Column col2Tab1Ref = refTab1.locateColumn( COLUMN_NAMES[2] );
// create another target table for foreign keys
TableSpecification refTab2 = createTable( "other_referenced_table" );
Column pkColTab2Ref = refTab2.locateColumn( COLUMN_NAMES[0] );
Column col1Tab2Ref = refTab2.locateColumn( COLUMN_NAMES[1] );
Column col2Tab2Ref = refTab2.locateColumn( COLUMN_NAMES[2] );
// Add primary key columns to PK constraints and add generated name
assertTrue( generatedNames.add( addColumnToPrimaryKey( pkColTab1 ).generateName() ) );
assertTrue( generatedNames.add( addColumnToPrimaryKey( pkColTab2 ).generateName() ) );
assertTrue( generatedNames.add( addColumnToPrimaryKey( pkColTab1Ref ).generateName() ) );
assertTrue( generatedNames.add( addColumnToPrimaryKey( pkColTab2Ref ).generateName() ) );
// add constraints to tab1
// add other types of constraints to the PK column for tab1
assertTrue( generatedNames.add( createUniqueKey( pkColTab1 ).generateName() ) );
assertTrue( generatedNames.add( createIndex( pkColTab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( pkColTab1, tab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( pkColTab1, tab1, col1Tab1 ).generateName() ) );
// add constraints to 1st non-PK column for tab1 (col1Tab1)
assertTrue( generatedNames.add( createUniqueKey( col1Tab1 ).generateName() ) );
assertTrue( generatedNames.add( createIndex( col1Tab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab1, tab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab1, tab1, col2Tab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab1, refTab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab1, refTab1, col1Tab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab1, refTab1, col2Tab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab1, refTab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab1, refTab2, col1Tab2Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab1, refTab2, col2Tab2Ref ).generateName() ) );
// add constraints to 2nd non-PK column for tab1 (col2Tab1)
assertTrue( generatedNames.add( createUniqueKey( col2Tab1 ).generateName() ) );
assertTrue( generatedNames.add( createIndex( col2Tab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab1, tab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab1, tab1, col1Tab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab1, refTab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab1, refTab1, col1Tab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab1, refTab1, col2Tab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab1, refTab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab1, refTab2, col1Tab2Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab1, refTab2, col2Tab2Ref ).generateName() ) );
// add multi-column constraints to tab1
List<Column> colsTab1 = new ArrayList<Column>( );
colsTab1.add( col1Tab1 );
colsTab1.add( col2Tab1 );
List<Column> colsTab1Reversed = new ArrayList<Column>( );
colsTab1Reversed.add( col2Tab1 );
colsTab1Reversed.add( col1Tab1 );
List<Column> colsTab1Ref = new ArrayList<Column>( );
colsTab1Ref.add( col1Tab1Ref );
colsTab1Ref.add( col2Tab1Ref );
List<Column> colsTab1RefReversed = new ArrayList<Column>( );
colsTab1RefReversed.add( col2Tab1Ref );
colsTab1RefReversed.add( col1Tab1Ref );
assertTrue( generatedNames.add( createUniqueKey( tab1, colsTab1 ).generateName() ) );
assertTrue( generatedNames.add( createIndex( tab1, colsTab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( tab1, colsTab1, refTab1, colsTab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( tab1, colsTab1, refTab1, colsTab1RefReversed ).generateName() ) );
assertTrue( generatedNames.add( createUniqueKey( tab1, colsTab1Reversed ).generateName() ) );
assertTrue( generatedNames.add( createIndex( tab1, colsTab1Reversed ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( tab1, colsTab1Reversed, refTab1, colsTab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( tab1, colsTab1Reversed, refTab1, colsTab1RefReversed ).generateName() ) );
// add constraints to tab2
// add other types of constraints to the PK column for tab2
assertTrue( generatedNames.add( createUniqueKey( pkColTab2 ).generateName() ) );
assertTrue( generatedNames.add( createIndex( pkColTab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( pkColTab2, tab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( pkColTab2, tab2, col1Tab2 ).generateName() ) );
// add constraints to 1st non-PK column for tab2 (col1Tab2)
assertTrue( generatedNames.add( createUniqueKey( col1Tab2 ).generateName() ) );
assertTrue( generatedNames.add( createIndex( col1Tab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab2, tab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab2, tab2, col2Tab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab2, refTab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab2, refTab1, col1Tab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab2, refTab1, col2Tab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab2, refTab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab2, refTab2, col1Tab2Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col1Tab2, refTab2, col2Tab2Ref ).generateName() ) );
// add constraints to 2nd non-PK column (col2Tab1) for tab1
assertTrue( generatedNames.add( createUniqueKey( col2Tab2 ).generateName() ) );
assertTrue( generatedNames.add( createIndex( col2Tab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab2, tab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab2, tab2, col1Tab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab2, refTab1 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab2, refTab1, col1Tab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab2, refTab1, col2Tab1Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab2, refTab2 ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab2, refTab2, col1Tab2Ref ).generateName() ) );
assertTrue( generatedNames.add( createForeignKey( col2Tab2, refTab2, col2Tab2Ref ).generateName() ) );
}
@Test
public void testForeignKeySameColumnMappingGeneratedName() {
TableSpecification table = createTable( "my_table" );
Column fkColumn = table.locateColumn( COLUMN_NAMES[0] );
// create a target table for foreign keys
TableSpecification referencedTable = createTable( "my_referenced_table" );
Column referencedPKColumn = referencedTable.locateColumn( COLUMN_NAMES[0] );
referencedTable.getPrimaryKey().addColumn( referencedPKColumn );
ForeignKey fkImplicitFKMapping = createForeignKey( fkColumn, referencedTable );
ForeignKey fkExplicitFKMappingToPK = createForeignKey(
fkColumn,
referencedTable,
referencedPKColumn
);
assertEquals( fkImplicitFKMapping.generateName(), fkExplicitFKMappingToPK.generateName() );
}
private PrimaryKey addColumnToPrimaryKey(Column column) {
PrimaryKey primaryKey = column.getTable().getPrimaryKey();
primaryKey.addColumn( column );
return primaryKey;
}
private ForeignKey createForeignKey(Column column, TableSpecification referencedTable ) {
ForeignKey foreignKey = column.getTable().createForeignKey( referencedTable, null );
foreignKey.addColumn( column );
return foreignKey;
}
private ForeignKey createForeignKey(Column column, TableSpecification referencedTable, Column referencedColumn ) {
ForeignKey foreignKey = column.getTable().createForeignKey( referencedTable, null );
foreignKey.addColumnMapping( column, referencedColumn );
return foreignKey;
}
private ForeignKey createForeignKey(
TableSpecification table,
List<Column> columns,
TableSpecification referencedTable,
List<Column> referencedColumns) {
ForeignKey foreignKey = table.createForeignKey( referencedTable, null );
for ( int i = 0 ; i < columns.size() ; i++ ) {
foreignKey.addColumnMapping( columns.get( i ), referencedColumns.get( i ) );
}
return foreignKey;
}
private UniqueKey createUniqueKey(Column column) {
UniqueKey uniqueKey = column.getTable().getOrCreateUniqueKey( null );
uniqueKey.addColumn( column );
return uniqueKey;
}
private UniqueKey createUniqueKey(TableSpecification table, List<Column> columns) {
UniqueKey uniqueKey = table.getOrCreateUniqueKey( null );
for ( Column column : columns ) {
uniqueKey.addColumn( column );
}
return uniqueKey;
}
private Index createIndex(Column column) {
Index index = column.getTable().getOrCreateIndex( null );
index.addColumn( column );
return index;
}
private Index createIndex(TableSpecification table, List<Column> columns) {
Index index = table.getOrCreateIndex( null );
for ( Column column : columns ) {
index.addColumn( column );
}
return index;
}
protected TableSpecification createTable(String name) {
Schema schema = new Schema( null, null );
Table table = schema.createTable( Identifier.toIdentifier( name ), Identifier.toIdentifier( name ) );
for ( String colName : COLUMN_NAMES ) {
Column column = table.locateOrCreateColumn( colName );
column.setJdbcDataType( INTEGER );
}
return table;
}
}

View File

@ -0,0 +1,59 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* 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, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY 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
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.relational;
import org.junit.Test;
import org.hibernate.testing.FailureExpected;
/**
* @author Gail Badner
*/
public class IndexConstraintNameTests extends AbstractConstraintNameTests {
@Override
protected AbstractConstraint createConstraint(TableSpecification table, String constraintName) {
return table.getOrCreateIndex( constraintName );
}
@Test
@FailureExpected( jiraKey = "HHH-7408")
@Override
public void testConstraintNameInitializedInConstructor() {
super.testConstraintNameInitializedInConstructor();
}
@Test
@FailureExpected( jiraKey = "HHH-7408")
@Override
public void testConstraintNameUninitializedInConstructor() {
super.testConstraintNameInitializedInConstructor();
}
@Test
@FailureExpected( jiraKey = "HHH-7408")
@Override
public void testConstraintNameUninitializedInConstructorThenSet() {
super.testConstraintNameInitializedInConstructor();
}
}

View File

@ -0,0 +1,52 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* 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, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY 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
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.relational;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Gail Badner
*/
public class PrimaryKeyConstraintNameTests extends AbstractConstraintNameTests {
protected void checkGeneratedName(AbstractConstraint constraint) {
assertEquals(
constraint.getGeneratedNamePrefix() + constraint.getTable()
.getLogicalName()
.getName()
.toUpperCase(),
constraint.generateName()
);
}
@Override
protected AbstractConstraint createConstraint(TableSpecification table, String constraintName) {
if ( constraintName != null ) {
table.getPrimaryKey().setName( constraintName );
}
return table.getPrimaryKey();
}
}

View File

@ -0,0 +1,34 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* 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, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY 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
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.relational;
/**
* @author Gail Badner
*/
public class UniqueKeyConstraintNameTests extends AbstractConstraintNameTests {
@Override
protected AbstractConstraint createConstraint(TableSpecification table, String constraintName) {
return table.getOrCreateUniqueKey( constraintName );
}
}