Skip to content

Commit 268592f

Browse files
Timothy Rundletgrundle
Timothy Rundle
authored andcommitted
Add enum support for H2 / MySql to ColumnSnapshotGenerator
1 parent 7f50bc5 commit 268592f

File tree

2 files changed

+55
-29
lines changed

2 files changed

+55
-29
lines changed

src/main/java/liquibase/ext/hibernate/snapshot/ColumnSnapshotGenerator.java

+48-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package liquibase.ext.hibernate.snapshot;
22

33
import java.util.List;
4+
import java.util.Optional;
45
import java.util.Properties;
56
import java.util.regex.Matcher;
67
import java.util.regex.Pattern;
@@ -11,6 +12,7 @@
1112
import org.hibernate.dialect.PostgreSQLDialect;
1213
import org.hibernate.id.ExportableColumn;
1314
import org.hibernate.mapping.SimpleValue;
15+
import org.hibernate.type.SqlTypes;
1416

1517
import liquibase.Scope;
1618
import liquibase.datatype.DataTypeFactory;
@@ -28,8 +30,9 @@
2830
import liquibase.util.SqlUtil;
2931
import liquibase.util.StringUtil;
3032

33+
3134
/**
32-
* Columns are snapshotted along with with Tables in {@link TableSnapshotGenerator} but this class needs to be here to keep the default ColumnSnapshotGenerator from running.
35+
* Columns are snapshotted along with Tables in {@link TableSnapshotGenerator} but this class needs to be here to keep the default ColumnSnapshotGenerator from running.
3336
* Ideally the column logic would be moved out of the TableSnapshotGenerator to better work in situations where the object types to snapshot are being controlled, but that is not the case yet.
3437
*/
3538
public class ColumnSnapshotGenerator extends HibernateSnapshotGenerator {
@@ -102,7 +105,8 @@ protected void snapshotColumn(Column column, DatabaseSnapshot snapshot) throws D
102105
if (hibernateColumn.getName().equalsIgnoreCase(column.getName())) {
103106

104107
String defaultValue = null;
105-
String hibernateType = hibernateColumn.getSqlType(metadata.getTypeConfiguration(), dialect, metadata);
108+
String hibernateType = hibernateColumn.getSqlType(metadata);
109+
106110
Matcher defaultValueMatcher = Pattern.compile("(?i) DEFAULT\\s+(.*)").matcher(hibernateType);
107111
if (defaultValueMatcher.find()) {
108112
defaultValue = defaultValueMatcher.group(1);
@@ -118,7 +122,15 @@ protected void snapshotColumn(Column column, DatabaseSnapshot snapshot) throws D
118122
Scope.getCurrentScope().getLog(getClass()).info("Found column " + column.getName() + " " + column.getType().toString());
119123

120124
column.setRemarks(hibernateColumn.getComment());
121-
if (hibernateColumn.getValue() instanceof SimpleValue) {
125+
126+
// DataTypeFactory.from and SqlUtil.parseValue rely on the database type however,
127+
// the liquibase-core does not know about the fake hibernate database so not all conditions
128+
// are handled correctly for enums.
129+
boolean isEnumType = Optional.ofNullable(dataType.getDataTypeId())
130+
.map(SqlTypes::isEnumType)
131+
.orElse(false);
132+
133+
if (!isEnumType && hibernateColumn.getValue() instanceof SimpleValue) {
122134
DataType parseType;
123135
if (DataTypeFactory.getInstance().from(dataType, database) instanceof UnknownType) {
124136
parseType = new DataType(((SimpleValue) hibernateColumn.getValue()).getTypeName());
@@ -181,46 +193,53 @@ protected void snapshotColumn(Column column, DatabaseSnapshot snapshot) throws D
181193
}
182194
}
183195

184-
protected DataType toDataType(String hibernateType, Integer sqlTypeCode) throws DatabaseException {
196+
protected DataType toDataType(String hibernateType, Integer sqlTypeCode) {
185197
Matcher matcher = pattern.matcher(hibernateType);
186198
if (!matcher.matches()) {
187199
return null;
188200
}
189201

190-
String typeName = matcher.group(1);
202+
DataType dataType;
191203

192-
// Liquibase seems to use 'with timezone' instead of 'with time zone',
193-
// so we remove any 'with time zone' suffixes here.
194-
// The corresponding 'with timezone' suffix will then be added below,
195-
// because in that case hibernateType also ends with 'with time zone'.
196-
if (typeName.toLowerCase().endsWith(SQL_TIMEZONE_SUFFIX)) {
197-
typeName = typeName.substring(0, typeName.length() - SQL_TIMEZONE_SUFFIX.length()).stripTrailing();
198-
}
204+
// Small hack for enums until DataType adds support for them
205+
if (Optional.ofNullable(sqlTypeCode).map(SqlTypes::isEnumType).orElse(false)) {
206+
dataType = new DataType(hibernateType);
207+
} else {
208+
String typeName = matcher.group(1);
209+
210+
// Liquibase seems to use 'with timezone' instead of 'with time zone',
211+
// so we remove any 'with time zone' suffixes here.
212+
// The corresponding 'with timezone' suffix will then be added below,
213+
// because in that case hibernateType also ends with 'with time zone'.
214+
if (typeName.toLowerCase().endsWith(SQL_TIMEZONE_SUFFIX)) {
215+
typeName = typeName.substring(0, typeName.length() - SQL_TIMEZONE_SUFFIX.length()).stripTrailing();
216+
}
199217

200-
// If hibernateType ends with 'with time zone' we need to add the corresponding
201-
// 'with timezone' suffix to the Liquibase type.
202-
if (hibernateType.toLowerCase().endsWith(SQL_TIMEZONE_SUFFIX)) {
203-
typeName += (" " + LIQUIBASE_TIMEZONE_SUFFIX);
204-
}
218+
// If hibernateType ends with 'with time zone' we need to add the corresponding
219+
// 'with timezone' suffix to the Liquibase type.
220+
if (hibernateType.toLowerCase().endsWith(SQL_TIMEZONE_SUFFIX)) {
221+
typeName += (" " + LIQUIBASE_TIMEZONE_SUFFIX);
222+
}
205223

206-
DataType dataType = new DataType(typeName);
207-
if (matcher.group(3).isEmpty()) {
208-
if (!matcher.group(2).isEmpty()) {
224+
dataType = new DataType(typeName);
225+
if (matcher.group(3).isEmpty()) {
226+
if (!matcher.group(2).isEmpty()) {
227+
dataType.setColumnSize(Integer.parseInt(matcher.group(2)));
228+
}
229+
} else {
209230
dataType.setColumnSize(Integer.parseInt(matcher.group(2)));
231+
dataType.setDecimalDigits(Integer.parseInt(matcher.group(3)));
210232
}
211-
} else {
212-
dataType.setColumnSize(Integer.parseInt(matcher.group(2)));
213-
dataType.setDecimalDigits(Integer.parseInt(matcher.group(3)));
214-
}
215233

216-
String extra = StringUtil.trimToNull(matcher.group(4));
217-
if (extra != null) {
218-
if (extra.equalsIgnoreCase("char")) {
219-
dataType.setColumnSizeUnit(DataType.ColumnSizeUnit.CHAR);
234+
String extra = StringUtil.trimToNull(matcher.group(4));
235+
if (extra != null) {
236+
if (extra.equalsIgnoreCase("char")) {
237+
dataType.setColumnSizeUnit(DataType.ColumnSizeUnit.CHAR);
238+
}
220239
}
221240
}
222241

223-
Scope.getCurrentScope().getLog(getClass()).info("Converted column data type - hibernate type: " + hibernateType + ", SQL type: " + sqlTypeCode + ", type name: " + typeName);
242+
Scope.getCurrentScope().getLog(getClass()).info("Converted column data type - hibernate type: " + hibernateType + ", SQL type: " + sqlTypeCode + ", type name: " + dataType.getTypeName());
224243

225244
dataType.setDataTypeId(sqlTypeCode);
226245
return dataType;

src/test/java/liquibase/ext/hibernate/snapshot/ColumnSnapshotGeneratorTest.java

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import liquibase.exception.DatabaseException;
44
import liquibase.structure.core.DataType;
5+
import org.hibernate.type.SqlTypes;
56
import org.junit.Test;
67

78
import java.sql.Types;
@@ -27,5 +28,11 @@ public void toDataType() throws DatabaseException {
2728
assertEquals(30, varcharChar.getColumnSize().intValue());
2829
assertEquals(DataType.ColumnSizeUnit.CHAR, varcharChar.getColumnSizeUnit());
2930

31+
32+
DataType enumType = columnSnapshotGenerator.toDataType("enum ('a', 'b', 'c')", SqlTypes.ENUM);
33+
assertEquals("enum ('a', 'b', 'c')", enumType.getTypeName());
34+
assertNull(enumType.getColumnSize());
35+
assertEquals(SqlTypes.ENUM, enumType.getDataTypeId().intValue());
36+
assertNull(enumType.getColumnSizeUnit());
3037
}
3138
}

0 commit comments

Comments
 (0)