HHH-17908 Allow varchar for STRING enums on MySQL in schema validation

This commit is contained in:
Christian Beikov 2024-03-28 16:00:40 +01:00
parent 0389fed095
commit f7805e952b
2 changed files with 116 additions and 0 deletions

View File

@ -236,6 +236,7 @@ import static org.hibernate.type.SqlTypes.TIME_WITH_TIMEZONE;
import static org.hibernate.type.SqlTypes.TINYINT;
import static org.hibernate.type.SqlTypes.VARBINARY;
import static org.hibernate.type.SqlTypes.VARCHAR;
import static org.hibernate.type.SqlTypes.isEnumType;
import static org.hibernate.type.SqlTypes.isFloatOrRealOrDouble;
import static org.hibernate.type.SqlTypes.isNumericOrDecimal;
import static org.hibernate.type.SqlTypes.isVarbinaryType;
@ -1609,6 +1610,9 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
|| isFloatOrRealOrDouble(typeCode1) && isFloatOrRealOrDouble(typeCode2)
|| isVarcharType(typeCode1) && isVarcharType(typeCode2)
|| isVarbinaryType(typeCode1) && isVarbinaryType(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 )
|| sameColumnType(typeCode1, typeCode2);
}

View File

@ -0,0 +1,112 @@
package org.hibernate.orm.test.schemavalidation;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.tool.hbm2ddl.SchemaValidator;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.transaction.TransactionUtil;
import org.hibernate.testing.util.ServiceRegistryUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import static jakarta.persistence.GenerationType.IDENTITY;
@JiraKey("HHH-17908")
@RequiresDialect( H2Dialect.class )
@RequiresDialect( MySQLDialect.class )
public class ExistingVarcharEnumColumnValidationTest extends BaseCoreFunctionalTestCase {
private StandardServiceRegistry ssr;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { EntityE.class };
}
@Before
public void setUp() {
try {
tearDown();
}
catch (Exception ex) {
// ignore
}
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
session.createNativeQuery(
"create table en (id integer not null, sign_position varchar(255) check (sign_position in ('AFTER_NO_SPACE','AFTER_WITH_SPACE','BEFORE_NO_SPACE','BEFORE_WITH_SPACE')), primary key (id))" )
.executeUpdate();
} );
}
@After
public void tearDown() {
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
session.createNativeQuery( "drop table en cascade" ).executeUpdate();
} );
}
@Test
public void testEnumDataTypeSchemaValidator() {
ssr = ServiceRegistryUtil.serviceRegistryBuilder()
.applySetting( AvailableSettings.HBM2DDL_AUTO, "validate" )
.build();
try {
final MetadataSources metadataSources = new MetadataSources( ssr );
metadataSources.addAnnotatedClass( EntityE.class );
new SchemaValidator().validate( metadataSources.buildMetadata() );
}
finally {
StandardServiceRegistryBuilder.destroy( ssr );
}
}
@Entity(name = "en")
@Table(name = "en")
public static class EntityE {
@Id
@Column(name = "id", nullable = false, updatable = false)
private Integer id;
@Enumerated(EnumType.STRING)
@Column(name = "sign_position")
private SignPosition signPosition;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public SignPosition getSignPosition() {
return signPosition;
}
public void setSignPosition(SignPosition signPosition) {
this.signPosition = signPosition;
}
}
public enum SignPosition {
AFTER_NO_SPACE, AFTER_WITH_SPACE, BEFORE_NO_SPACE, BEFORE_WITH_SPACE
}
}