HHH-9850 - Primary key generated for nullable column in sequence table

This commit is contained in:
Steve Ebersole 2015-08-05 09:09:07 -05:00
parent 182146f0ad
commit 1556c272d5
3 changed files with 131 additions and 65 deletions

View File

@ -17,7 +17,7 @@ import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.relational.QualifiedName;
@ -94,7 +94,8 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
private QualifiedName qualifiedTableName;
private String tableName;
private String pkColumnName;
private String segmentColumnName;
private String segmentName;
private String valueColumnName;
private String query;
private String insert;
@ -254,62 +255,58 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
@SuppressWarnings({"StatementWithEmptyBody", "deprecation"})
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
returnClass = type.getReturnedClass();
final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
final ObjectNameNormalizer normalizer = (ObjectNameNormalizer) params.get( IDENTIFIER_NORMALIZER );
qualifiedTableName = QualifiedNameParser.INSTANCE.parse(
ConfigurationHelper.getString( ID_TABLE, params, DEFAULT_TABLE ),
normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) ),
normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) )
);
tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
qualifiedTableName,
jdbcEnvironment.getDialect()
);
pkColumnName = normalizer.toDatabaseIdentifierText(
ConfigurationHelper.getString( PK_COLUMN_NAME, params, DEFAULT_PK_COLUMN )
);
valueColumnName = normalizer.toDatabaseIdentifierText(
ConfigurationHelper.getString( VALUE_COLUMN_NAME, params, DEFAULT_VALUE_COLUMN )
);
qualifiedTableName = determineGeneratorTableName( params, jdbcEnvironment );
segmentColumnName = determineSegmentColumnName( params, jdbcEnvironment );
keySize = ConfigurationHelper.getInt( PK_LENGTH_NAME, params, DEFAULT_PK_LENGTH );
String keyValue = ConfigurationHelper.getString( PK_VALUE_NAME, params, params.getProperty( TABLE ) );
query = "select " +
valueColumnName +
" from " +
jdbcEnvironment.getDialect().appendLockHint( LockMode.PESSIMISTIC_WRITE, tableName ) +
" where " + pkColumnName + " = '" + keyValue + "'" +
jdbcEnvironment.getDialect().getForUpdateString();
update = "update " +
tableName +
" set " +
valueColumnName +
" = ? where " +
valueColumnName +
" = ? and " +
pkColumnName +
" = '" +
keyValue
+ "'";
insert = "insert into " + tableName +
"(" + pkColumnName + ", " + valueColumnName + ") " +
"values('" + keyValue + "', ?)";
segmentName = ConfigurationHelper.getString( PK_VALUE_NAME, params, params.getProperty( TABLE ) );
valueColumnName = determineValueColumnName( params, jdbcEnvironment );
//hilo config
maxLo = ConfigurationHelper.getInt( MAX_LO, params, Short.MAX_VALUE );
returnClass = type.getReturnedClass();
if ( maxLo >= 1 ) {
hiloOptimizer = new LegacyHiLoAlgorithmOptimizer( returnClass, maxLo );
}
}
protected QualifiedName determineGeneratorTableName(Properties params, JdbcEnvironment jdbcEnvironment) {
final String tableName = ConfigurationHelper.getString( ID_TABLE, params, DEFAULT_TABLE );
if ( tableName.contains( "." ) ) {
return QualifiedNameParser.INSTANCE.parse( tableName );
}
else {
// todo : need to incorporate implicit catalog and schema names
final Identifier catalog = jdbcEnvironment.getIdentifierHelper().toIdentifier(
ConfigurationHelper.getString( CATALOG, params )
);
final Identifier schema = jdbcEnvironment.getIdentifierHelper().toIdentifier(
ConfigurationHelper.getString( SCHEMA, params )
);
return new QualifiedNameParser.NameParts(
catalog,
schema,
jdbcEnvironment.getIdentifierHelper().toIdentifier( tableName )
);
}
}
protected String determineSegmentColumnName(Properties params, JdbcEnvironment jdbcEnvironment) {
final String name = ConfigurationHelper.getString( PK_COLUMN_NAME, params, DEFAULT_PK_COLUMN );
return jdbcEnvironment.getIdentifierHelper().toIdentifier( name ).render( jdbcEnvironment.getDialect() );
}
protected String determineValueColumnName(Properties params, JdbcEnvironment jdbcEnvironment) {
final String name = ConfigurationHelper.getString( VALUE_COLUMN_NAME, params, DEFAULT_VALUE_COLUMN );
return jdbcEnvironment.getIdentifierHelper().toIdentifier( name ).render( jdbcEnvironment.getDialect() );
}
@Override
public void registerExportables(Database database) {
final Namespace namespace = database.locateNamespace(
@ -317,16 +314,21 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
qualifiedTableName.getSchemaName()
);
final Table table = namespace.createTable( qualifiedTableName.getObjectName(), false );
Table table = namespace.locateTable( qualifiedTableName.getObjectName() );
if ( table == null ) {
table = namespace.createTable( qualifiedTableName.getObjectName(), false );
// todo : note sure the best solution here. do we add the columns if missing? other?
table.setPrimaryKey( new PrimaryKey() );
final Column pkColumn = new ExportableColumn(
database,
table,
pkColumnName,
segmentColumnName,
StringType.INSTANCE,
database.getDialect().getTypeName( Types.VARCHAR, keySize, 0, 0 )
);
pkColumn.setNullable( false );
table.addColumn( pkColumn );
table.getPrimaryKey().addColumn( pkColumn );
@ -339,11 +341,46 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
table.addColumn( valueColumn );
}
final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment();
// allow physical naming strategies a chance to kick in
tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
table.getQualifiedTableName(),
jdbcEnvironment.getDialect()
);
query = "select " +
valueColumnName +
" from " +
jdbcEnvironment.getDialect().appendLockHint( LockMode.PESSIMISTIC_WRITE, tableName ) +
" where " + segmentColumnName + " = '" + segmentName + "'" +
jdbcEnvironment.getDialect().getForUpdateString();
update = "update " +
tableName +
" set " +
valueColumnName +
" = ? where " +
valueColumnName +
" = ? and " +
segmentColumnName +
" = '" +
segmentName
+ "'";
insert = "insert into " + tableName +
"(" + segmentColumnName + ", " + valueColumnName + ") " +
"values('" + segmentName + "', ?)";
}
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
return new String[] {
dialect.getCreateTableString()
+ ' ' + tableName + " ( "
+ pkColumnName + ' ' + dialect.getTypeName( Types.VARCHAR, keySize, 0, 0 ) + ", "
+ segmentColumnName + ' ' + dialect.getTypeName( Types.VARCHAR, keySize, 0, 0 ) + ", "
+ valueColumnName + ' ' + dialect.getTypeName( Types.INTEGER )
+ " )" + dialect.getTableTypeString()
};

View File

@ -349,7 +349,6 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
identifierType = type;
final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
final Dialect dialect = jdbcEnvironment.getDialect();
qualifiedTableName = determineGeneratorTableName( params, jdbcEnvironment );
segmentColumnName = determineSegmentColumnName( params, jdbcEnvironment );

View File

@ -14,6 +14,7 @@ import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.id.MultipleHiLoPerTableGenerator;
import org.hibernate.id.enhanced.TableGenerator;
import org.hibernate.mapping.Table;
import org.hibernate.type.IntegerType;
@ -24,7 +25,6 @@ import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Steve Ebersole
@ -32,7 +32,7 @@ import static org.junit.Assert.assertTrue;
public class Db2GenerationTest extends BaseUnitTestCase {
@Test
@TestForIssue( jiraKey = "HHH-9850" )
public void testDb2TableGeneratorCreation() {
public void testNewGeneratorTableCreationOnDb2() {
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
.applySetting( AvailableSettings.DIALECT, DB2Dialect.class.getName() )
.build();
@ -66,4 +66,34 @@ public class Db2GenerationTest extends BaseUnitTestCase {
Assert.fail( "String [" + str + "] did not contain expected substring [" + subStr + "]" );
}
}
@Test
@TestForIssue( jiraKey = "HHH-9850" )
public void testLegacyGeneratorTableCreationOnDb2() {
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
.applySetting( AvailableSettings.DIALECT, DB2Dialect.class.getName() )
.build();
try {
Metadata metadata = new MetadataSources( ssr )
.buildMetadata();
assertEquals( 0, metadata.getDatabase().getDefaultNamespace().getTables().size() );
MultipleHiLoPerTableGenerator generator = new MultipleHiLoPerTableGenerator();
Properties properties = new Properties();
generator.configure( IntegerType.INSTANCE, properties, ssr );
generator.registerExportables( metadata.getDatabase() );
assertEquals( 1, metadata.getDatabase().getDefaultNamespace().getTables().size() );
final Table table = metadata.getDatabase().getDefaultNamespace().getTables().iterator().next();
final String[] createCommands = new DB2Dialect().getTableExporter().getSqlCreateStrings( table, metadata );
assertContains( "sequence_name varchar(255) not null", createCommands[0] );
}
finally {
StandardServiceRegistryBuilder.destroy( ssr );
}
}
}