1
1
package liquibase .ext .hibernate .snapshot ;
2
2
3
3
import java .util .List ;
4
+ import java .util .Optional ;
4
5
import java .util .Properties ;
5
6
import java .util .regex .Matcher ;
6
7
import java .util .regex .Pattern ;
11
12
import org .hibernate .dialect .PostgreSQLDialect ;
12
13
import org .hibernate .id .ExportableColumn ;
13
14
import org .hibernate .mapping .SimpleValue ;
15
+ import org .hibernate .type .SqlTypes ;
14
16
15
17
import liquibase .Scope ;
16
18
import liquibase .datatype .DataTypeFactory ;
28
30
import liquibase .util .SqlUtil ;
29
31
import liquibase .util .StringUtil ;
30
32
33
+
31
34
/**
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.
33
36
* 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.
34
37
*/
35
38
public class ColumnSnapshotGenerator extends HibernateSnapshotGenerator {
@@ -102,7 +105,8 @@ protected void snapshotColumn(Column column, DatabaseSnapshot snapshot) throws D
102
105
if (hibernateColumn .getName ().equalsIgnoreCase (column .getName ())) {
103
106
104
107
String defaultValue = null ;
105
- String hibernateType = hibernateColumn .getSqlType (metadata .getTypeConfiguration (), dialect , metadata );
108
+ String hibernateType = hibernateColumn .getSqlType (metadata );
109
+
106
110
Matcher defaultValueMatcher = Pattern .compile ("(?i) DEFAULT\\ s+(.*)" ).matcher (hibernateType );
107
111
if (defaultValueMatcher .find ()) {
108
112
defaultValue = defaultValueMatcher .group (1 );
@@ -118,7 +122,15 @@ protected void snapshotColumn(Column column, DatabaseSnapshot snapshot) throws D
118
122
Scope .getCurrentScope ().getLog (getClass ()).info ("Found column " + column .getName () + " " + column .getType ().toString ());
119
123
120
124
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 ) {
122
134
DataType parseType ;
123
135
if (DataTypeFactory .getInstance ().from (dataType , database ) instanceof UnknownType ) {
124
136
parseType = new DataType (((SimpleValue ) hibernateColumn .getValue ()).getTypeName ());
@@ -181,46 +193,53 @@ protected void snapshotColumn(Column column, DatabaseSnapshot snapshot) throws D
181
193
}
182
194
}
183
195
184
- protected DataType toDataType (String hibernateType , Integer sqlTypeCode ) throws DatabaseException {
196
+ protected DataType toDataType (String hibernateType , Integer sqlTypeCode ) {
185
197
Matcher matcher = pattern .matcher (hibernateType );
186
198
if (!matcher .matches ()) {
187
199
return null ;
188
200
}
189
201
190
- String typeName = matcher . group ( 1 ) ;
202
+ DataType dataType ;
191
203
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
+ }
199
217
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
+ }
205
223
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 {
209
230
dataType .setColumnSize (Integer .parseInt (matcher .group (2 )));
231
+ dataType .setDecimalDigits (Integer .parseInt (matcher .group (3 )));
210
232
}
211
- } else {
212
- dataType .setColumnSize (Integer .parseInt (matcher .group (2 )));
213
- dataType .setDecimalDigits (Integer .parseInt (matcher .group (3 )));
214
- }
215
233
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
+ }
220
239
}
221
240
}
222
241
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 () );
224
243
225
244
dataType .setDataTypeId (sqlTypeCode );
226
245
return dataType ;
0 commit comments