HHH-16531 be more forgiving in handling of integral types in schema validation/update

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-05-21 11:07:16 +02:00
parent 0f8ef48e7b
commit 4791b41cf5
3 changed files with 33 additions and 5 deletions

View File

@ -1591,6 +1591,10 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
* {@link Types#VARBINARY BINARY} and
* {@link Types#LONGVARBINARY LONGVARBINARY} as the same type, since
* Hibernate doesn't really differentiate these types.
* <p>
* On the other hand, integral types are not treated as equivalent,
* instead, {@link #isCompatibleIntegralType(int, int)} is responsible
* for determining if the types are compatible.
*
* @param typeCode1 the first column type info
* @param typeCode2 the second column type info
@ -1600,16 +1604,39 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
public boolean equivalentTypes(int typeCode1, int typeCode2) {
return typeCode1==typeCode2
|| isNumericOrDecimal(typeCode1) && isNumericOrDecimal(typeCode2)
// || isIntegral(typeCode1) && isIntegral(typeCode2)
|| isFloatOrRealOrDouble(typeCode1) && isFloatOrRealOrDouble(typeCode2)
|| isVarcharType(typeCode1) && isVarcharType(typeCode2)
|| isVarbinaryType(typeCode1) && isVarbinaryType(typeCode2)
|| isCompatibleIntegralType(typeCode1, typeCode2)
// HHH-17908: Since the runtime can cope with enum on the DDL side,
// but varchar on the ORM expectation side, let's treat the types as equivalent
|| isEnumType( typeCode1 ) && isVarcharType( typeCode2 )
|| isEnumType(typeCode1) && isVarcharType(typeCode2)
|| sameColumnType(typeCode1, typeCode2);
}
/**
* Tolerate storing {@code short} in {@code INTEGER} or {@code BIGINT}
* or {@code int} in {@code BIGINT} for the purposes of schema validation
* and migration.
*/
private boolean isCompatibleIntegralType(int typeCode1, int typeCode2) {
switch (typeCode1) {
case TINYINT:
return typeCode2 == TINYINT
|| typeCode2 == SMALLINT
|| typeCode2 == INTEGER
|| typeCode2 == BIGINT;
case SMALLINT:
return typeCode2 == SMALLINT
|| typeCode2 == INTEGER
|| typeCode2 == BIGINT;
case INTEGER:
return typeCode2 == INTEGER
|| typeCode2 == BIGINT;
}
return false;
}
private boolean sameColumnType(int typeCode1, int typeCode2) {
try {
return Objects.equals( columnType(typeCode1), columnType(typeCode2) );

View File

@ -33,6 +33,7 @@ import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.jboss.logging.Logger;
import static org.hibernate.boot.model.naming.Identifier.toIdentifier;
import static org.hibernate.tool.schema.internal.ColumnDefinitions.hasMatchingType;
/**
* Base implementation of {@link SchemaValidator}.
@ -163,7 +164,7 @@ public abstract class AbstractSchemaValidator implements SchemaValidator {
Metadata metadata,
ExecutionOptions options,
Dialect dialect) {
if ( !ColumnDefinitions.hasMatchingType( column, columnInformation, metadata, dialect ) ) {
if ( !hasMatchingType( column, columnInformation, metadata, dialect ) ) {
throw new SchemaManagementException(
String.format(
"Schema-validation: wrong column type encountered in column [%s] in " +

View File

@ -27,7 +27,7 @@ import static org.hibernate.type.SqlTypes.isStringType;
class ColumnDefinitions {
static boolean hasMatchingType(Column column, ColumnInformation columnInformation, Metadata metadata, Dialect dialect) {
boolean typesMatch = dialect.equivalentTypes( column.getSqlTypeCode(metadata), columnInformation.getTypeCode() )
final boolean typesMatch = dialect.equivalentTypes( column.getSqlTypeCode( metadata ), columnInformation.getTypeCode() )
|| normalize( stripArgs( column.getSqlType( metadata ) ) ).equals( normalize( columnInformation.getTypeName() ) );
if ( typesMatch ) {
return true;
@ -42,7 +42,7 @@ class ColumnDefinitions {
columnInformation.getDecimalDigits(),
metadata.getDatabase().getTypeConfiguration().getJdbcTypeRegistry()
);
return dialect.equivalentTypes( column.getSqlTypeCode(metadata), jdbcType.getDefaultSqlTypeCode() );
return dialect.equivalentTypes( column.getSqlTypeCode( metadata ), jdbcType.getDefaultSqlTypeCode() );
}
}