liquibase / liquibase-hibernate

Liquibase Hibernate Integration
Apache License 2.0
271 stars 157 forks source link

Hibernet6 Enum type DDL issue #652

Open frangere opened 9 months ago

frangere commented 9 months ago

Env:

Spring Boot - 3.2.1
Hibernet  - 6.4.1
Mysql - 5.7
Liquibase : 4.25.1
Liquibase Hibernate6: 4.25.1

Gradle:

liquibase {
    activities {
        main {
            defaultsFile "liquibase.properties"
            changelogFile "base.mysql.sql"
            referenceUrl "hibernate:spring:com.xxx.model?dialect=org.hibernate.dialect.MySQLDialect"
        }
    }
}

dependencies {
    liquibaseRuntime 'com.mysql:mysql-connector-j'
    liquibaseRuntime 'org.liquibase:liquibase-core:4.25.1'
    liquibaseRuntime 'info.picocli:picocli:4.7.5'
    liquibaseRuntime 'org.yaml:snakeyaml:2.0'
    liquibaseRuntime 'org.liquibase.ext:liquibase-hibernate6:4.25.1'
    liquibaseRuntime 'org.springframework.boot:spring-boot-starter'
    liquibaseRuntime 'org.springframework.boot:spring-boot-starter-data-jpa'
    liquibaseRuntime sourceSets.main.output
}

Entity class:


public enum Status {
    ACTIVE,
    INACTIVE
}

@Entity
@Getter
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private Status status;
}

Try to use: gradle diffChangelog to generate sql file, got:

CREATE TABLE user (id BIGINT AUTO_INCREMENT NOT NULL,  status ENUM NOT NULL, CONSTRAINT userPK PRIMARY KEY (id));

which result in wrong SQL.

expected:

CREATE TABLE user (id BIGINT AUTO_INCREMENT NOT NULL,  status ENUM('ACTIVE', 'INACTIVE') NOT NULL, CONSTRAINT userPK PRIMARY KEY (id));

Root cause: According https://docs.jboss.org/hibernate/orm/6.2/migration-guide/migration-guide.html#ddl-implicit-datatype-enum, Hibernate 6 uses enum types on MySQL by default, but Liquibase hibernate6 class ColumnSnapshotGenerator#toDataType cannot process hibernateType with ENUM('ACTIVE', 'INACTIVE'), this method just keep ENUM as sql type.

Workaround: Right now, we are add:

   @JdbcTypeCode(SqlTypes.VARCHAR)
   private Status status;

to make sure still using old stype VARCHAR for ENUM.

jrpedrianes commented 4 months ago

In Postgres, there's a similar problem when we use an "Instant" column with Hibernate. Hibernate creates a type like timestamp(6) with time zone. But the toDataType function doesn't handle this properly and removes the time zone info, so it ends up as just timestamp(6).

MikeFear commented 3 months ago

Any updates on this? This bug requires us to write all changelogs regarding enums manually.