HHH-1904 Identifier too long

Conflicts:
	hibernate-core/src/main/java/org/hibernate/mapping/Table.java
This commit is contained in:
Brett Meyer 2013-03-20 16:33:19 -04:00
parent d9673b8a70
commit 4f0344dbbe
4 changed files with 96 additions and 46 deletions

View File

@ -1372,11 +1372,9 @@ public class Configuration implements Serializable {
for ( Map.Entry<Table, List<UniqueConstraintHolder>> tableListEntry : uniqueConstraintHoldersByTable.entrySet() ) {
final Table table = tableListEntry.getKey();
final List<UniqueConstraintHolder> uniqueConstraints = tableListEntry.getValue();
int uniqueIndexPerTable = 0;
for ( UniqueConstraintHolder holder : uniqueConstraints ) {
uniqueIndexPerTable++;
final String keyName = StringHelper.isEmpty( holder.getName() )
? "UK_" + table.getName() + "_" + uniqueIndexPerTable
? StringHelper.randomFixedLengthHex("UK_")
: holder.getName();
buildUniqueKeyFromColumnNames( table, keyName, holder.getColumns() );
}

View File

@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.UUID;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.util.collections.ArrayHelper;
@ -758,4 +759,18 @@ public final class StringHelper {
public static String[] toArrayElement(String s) {
return ( s == null || s.length() == 0 ) ? new String[0] : new String[] { s };
}
// Oracle restricts identifier lengths to 30. Rather than tie this to
// Dialect, simply restrict randomly-generated constrain names across
// the board.
private static final int MAX_NAME_LENGTH = 30;
public static String randomFixedLengthHex(String prefix) {
int length = MAX_NAME_LENGTH - prefix.length();
String s = UUID.randomUUID().toString();
s = s.replace( "-", "" );
if (s.length() > length) {
s = s.substring( 0, length );
}
return prefix + s;
}
}

View File

@ -36,6 +36,7 @@ import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.tool.hbm2ddl.ColumnMetadata;
import org.hibernate.tool.hbm2ddl.TableMetadata;
@ -395,8 +396,6 @@ public class Table implements RelationalModel, Serializable {
Iterator iter = getColumnIterator();
List results = new ArrayList();
int uniqueIndexInteger = 0;
while ( iter.hasNext() ) {
Column column = (Column) iter.next();
@ -423,9 +422,8 @@ public class Table implements RelationalModel, Serializable {
}
if ( column.isUnique() ) {
uniqueIndexInteger++;
UniqueKey uk = getOrCreateUniqueKey(
"UK_" + name + "_" + uniqueIndexInteger);
StringHelper.randomFixedLengthHex("UK_"));
uk.addColumn( column );
alter.append( dialect.getUniqueDelegate()
.applyUniqueToColumn( column ) );
@ -494,7 +492,6 @@ public class Table implements RelationalModel, Serializable {
}
Iterator iter = getColumnIterator();
int uniqueIndexInteger = 0;
while ( iter.hasNext() ) {
Column col = (Column) iter.next();
@ -528,9 +525,8 @@ public class Table implements RelationalModel, Serializable {
}
if ( col.isUnique() ) {
uniqueIndexInteger++;
UniqueKey uk = getOrCreateUniqueKey(
"uc_" + name + "_" + uniqueIndexInteger);
StringHelper.randomFixedLengthHex("UK_"));
uk.addColumn( col );
buf.append( dialect.getUniqueDelegate()
.applyUniqueToColumn( col ) );
@ -626,7 +622,7 @@ public class Table implements RelationalModel, Serializable {
}
public UniqueKey createUniqueKey(List keyColumns) {
String keyName = "UK_" + uniqueColumnString( keyColumns.iterator() );
String keyName = StringHelper.randomFixedLengthHex("UK_");
UniqueKey uk = getOrCreateUniqueKey( keyName );
uk.addColumns( keyColumns.iterator() );
return uk;
@ -666,9 +662,7 @@ public class Table implements RelationalModel, Serializable {
fk.setName( keyName );
}
else {
fk.setName( "FK" + uniqueColumnString( keyColumns.iterator(), referencedEntityName ) );
//TODO: add referencedClass to disambiguate to FKs on the same
// columns, pointing to different tables
fk.setName( StringHelper.randomFixedLengthHex("FK_") );
}
fk.setTable( this );
foreignKeys.put( key, fk );
@ -686,23 +680,6 @@ public class Table implements RelationalModel, Serializable {
return fk;
}
public String uniqueColumnString(Iterator iterator) {
return uniqueColumnString( iterator, null );
}
public String uniqueColumnString(Iterator iterator, String referencedEntityName) {
int result = 0;
if ( referencedEntityName != null ) {
result += referencedEntityName.hashCode();
}
while ( iterator.hasNext() ) {
result += iterator.next().hashCode();
}
return ( Integer.toHexString( name.hashCode() ) + Integer.toHexString( result ) ).toUpperCase();
}
public String getSchema() {
return schema;
}

View File

@ -20,57 +20,100 @@
*/
package org.hibernate.test.constraint;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Iterator;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
/**
* HHH-7797 re-wrote the way dialects handle unique constraints. Test
* variations of unique & not null to ensure the constraints are created
* correctly for each dialect.
*
* @author Brett Meyer
*/
@TestForIssue( jiraKey = "HHH-7797" )
public class ConstraintTest extends BaseCoreFunctionalTestCase {
private static final int MAX_NAME_LENGTH = 30;
private static final String EXPLICIT_FK_NAME = "fk_explicit";
private static final String EXPLICIT_UK_NAME = "uk_explicit";
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Entity1.class
DataPoint.class, DataPoint2.class
};
}
@Test
public void testConstraints() {
Column column = (Column) configuration().getClassMapping( Entity1.class.getName() )
@TestForIssue( jiraKey = "HHH-7797" )
public void testUniqueConstraints() {
Column column = (Column) configuration().getClassMapping( DataPoint.class.getName() )
.getProperty( "foo1" ).getColumnIterator().next();
assertFalse( column.isNullable() );
assertTrue( column.isUnique() );
column = (Column) configuration().getClassMapping( Entity1.class.getName() )
column = (Column) configuration().getClassMapping( DataPoint.class.getName() )
.getProperty( "foo2" ).getColumnIterator().next();
assertTrue( column.isNullable() );
assertTrue( column.isUnique() );
column = (Column) configuration().getClassMapping( Entity1.class.getName() )
column = (Column) configuration().getClassMapping( DataPoint.class.getName() )
.getProperty( "id" ).getColumnIterator().next();
assertFalse( column.isNullable() );
assertTrue( column.isUnique() );
}
@Test
@TestForIssue( jiraKey = "HHH-1904" )
public void testConstraintNameLength() {
Iterator<org.hibernate.mapping.Table> tableItr = configuration().getTableMappings();
while (tableItr.hasNext()) {
org.hibernate.mapping.Table table = tableItr.next();
Iterator fkItr = table.getForeignKeyIterator();
while (fkItr.hasNext()) {
ForeignKey fk = (ForeignKey) fkItr.next();
assertTrue( fk.getName().length() <= MAX_NAME_LENGTH );
// ensure the randomly generated constraint name doesn't
// happen if explicitly given
Column column = fk.getColumn( 0 );
if ( column.getName().equals( "explicit" ) ) {
assertEquals( fk.getName(), EXPLICIT_FK_NAME );
}
}
Iterator ukItr = table.getUniqueKeyIterator();
while (ukItr.hasNext()) {
UniqueKey uk = (UniqueKey) ukItr.next();
assertTrue( uk.getName().length() <= MAX_NAME_LENGTH );
// ensure the randomly generated constraint name doesn't
// happen if explicitly given
Column column = uk.getColumn( 0 );
if ( column.getName().equals( "explicit" ) ) {
assertEquals( uk.getName(), EXPLICIT_UK_NAME );
}
}
}
}
@Entity
@Table( name = "Entity1" )
public static class Entity1 {
@Table( name = "DataPoint", uniqueConstraints = {
@UniqueConstraint( name = EXPLICIT_UK_NAME, columnNames = { "explicit" } )
} )
public static class DataPoint {
@Id
@GeneratedValue
@javax.persistence.Column( nullable = false, unique = true)
@ -81,5 +124,22 @@ public class ConstraintTest extends BaseCoreFunctionalTestCase {
@javax.persistence.Column( nullable = true, unique = true)
public String foo2;
public String explicit;
}
@Entity
@Table( name = "DataPoint2" )
public static class DataPoint2 {
@Id
@GeneratedValue
public long id;
@OneToOne
public DataPoint dp;
@OneToOne
@org.hibernate.annotations.ForeignKey(name = EXPLICIT_FK_NAME)
public DataPoint explicit;
}
}