Skip to content

Commit

Permalink
CORE-1215 Unable to 'update' or 'generateChangeLog' in MS SQL Server …
Browse files Browse the repository at this point in the history
…'08 or '12 due to SQLServerException

Made sure sql2008 was running tests correctly
  • Loading branch information
nvoxland committed Oct 17, 2012
1 parent 4af092b commit 1144d44
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 29 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -246,11 +246,7 @@ public boolean supportsRestrictForeignKeys() {


@Override @Override
public boolean supportsDropTableCascadeConstraints() { public boolean supportsDropTableCascadeConstraints() {
try { return false;
return this.getDatabaseMajorVersion() >= 10;
} catch (DatabaseException e) {
return true;
}
} }


@Override @Override
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@


import liquibase.database.Database; import liquibase.database.Database;
import liquibase.database.structure.DataType; import liquibase.database.structure.DataType;
import liquibase.datatype.core.BigIntType;
import liquibase.datatype.core.IntType;
import liquibase.datatype.core.UnknownType; import liquibase.datatype.core.UnknownType;
import liquibase.exception.UnexpectedLiquibaseException; import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.servicelocator.ServiceLocator; import liquibase.servicelocator.ServiceLocator;
Expand Down Expand Up @@ -88,6 +90,11 @@ public LiquibaseDataType fromDescription(String dataTypeDefinition) {
if (dataTypeName.matches(".+\\{.*")) { if (dataTypeName.matches(".+\\{.*")) {
dataTypeName = dataTypeDefinition.replaceFirst("\\s*\\{.*", ""); dataTypeName = dataTypeDefinition.replaceFirst("\\s*\\{.*", "");
} }
boolean primaryKey = false;
if (dataTypeName.endsWith(" identity")) {
dataTypeName = dataTypeName.replaceFirst(" identity$", "");
primaryKey = true;
}


SortedSet<Class<? extends LiquibaseDataType>> classes = registry.get(dataTypeName.toLowerCase()); SortedSet<Class<? extends LiquibaseDataType>> classes = registry.get(dataTypeName.toLowerCase());


Expand Down Expand Up @@ -141,6 +148,13 @@ public LiquibaseDataType fromDescription(String dataTypeDefinition) {
} }
} }


if (primaryKey && liquibaseDataType instanceof IntType) {
((IntType) liquibaseDataType).setAutoIncrement(true);
}
if (primaryKey && liquibaseDataType instanceof BigIntType) {
((BigIntType) liquibaseDataType).setAutoIncrement(true);
}

return liquibaseDataType; return liquibaseDataType;


} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public DatabaseDataType toDatabaseDataType(Database database) {
if (database instanceof OracleDatabase) { if (database instanceof OracleDatabase) {
return new DatabaseDataType("NUMBER", 38,0); return new DatabaseDataType("NUMBER", 38,0);
} }
if (database instanceof DB2Database || database instanceof DerbyDatabase) { if (database instanceof DB2Database || database instanceof DerbyDatabase || database instanceof MSSQLDatabase) {
return new DatabaseDataType("BIGINT"); return new DatabaseDataType("BIGINT");
} }
if (database instanceof PostgresDatabase) { if (database instanceof PostgresDatabase) {
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import liquibase.datatype.DatabaseDataType; import liquibase.datatype.DatabaseDataType;
import liquibase.datatype.LiquibaseDataType; import liquibase.datatype.LiquibaseDataType;


@DataTypeInfo(name="blob", aliases = {"longblob", "longvarbinary", "java.sql.Types.BLOB", "java.sql.Types.LONGBLOB", "java.sql.Types.LONGVARBINARY"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT) @DataTypeInfo(name="blob", aliases = {"longblob", "longvarbinary", "java.sql.Types.BLOB", "java.sql.Types.LONGBLOB", "java.sql.Types.LONGVARBINARY", "varbinary"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT)
public class BlobType extends LiquibaseDataType { public class BlobType extends LiquibaseDataType {
@Override @Override
public DatabaseDataType toDatabaseDataType(Database database) { public DatabaseDataType toDatabaseDataType(Database database) {
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import liquibase.datatype.DatabaseDataType; import liquibase.datatype.DatabaseDataType;
import liquibase.datatype.LiquibaseDataType; import liquibase.datatype.LiquibaseDataType;
import liquibase.exception.UnexpectedLiquibaseException; import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.statement.DatabaseFunction;


@DataTypeInfo(name = "boolean", aliases = {"java.sql.Types.BOOLEAN", "java.lang.Boolean"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT) @DataTypeInfo(name = "boolean", aliases = {"java.sql.Types.BOOLEAN", "java.lang.Boolean", "bit"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT)
public class BooleanType extends LiquibaseDataType { public class BooleanType extends LiquibaseDataType {


@Override @Override
Expand Down Expand Up @@ -52,6 +53,8 @@ public String objectToSql(Object value, Database database) {
} else { } else {
returnValue = this.getFalseBooleanValue(database); returnValue = this.getFalseBooleanValue(database);
} }
} else if (value instanceof DatabaseFunction) {
return ((DatabaseFunction) value).toString();
} else if (((Boolean) value)) { } else if (((Boolean) value)) {
returnValue = this.getTrueBooleanValue(database); returnValue = this.getTrueBooleanValue(database);
} else { } else {
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import liquibase.statement.DatabaseFunction; import liquibase.statement.DatabaseFunction;
import liquibase.database.Database; import liquibase.database.Database;


@DataTypeInfo(name="date", aliases = {"java.sql.Types.DATE", "java.sql.Date"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT) @DataTypeInfo(name="date", aliases = {"java.sql.Types.DATE", "java.sql.Date", "smalldatetime"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT)
public class DateType extends LiquibaseDataType { public class DateType extends LiquibaseDataType {
@Override @Override
public DatabaseDataType toDatabaseDataType(Database database) { public DatabaseDataType toDatabaseDataType(Database database) {
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public DatabaseDataType toDatabaseDataType(Database database) {
return new DatabaseDataType("SERIAL"); return new DatabaseDataType("SERIAL");
} }
} }
if (database instanceof MSSQLDatabase) {
return new DatabaseDataType("INT");
}
return super.toDatabaseDataType(database); return super.toDatabaseDataType(database);


//sqllite //sqllite
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import liquibase.database.Database; import liquibase.database.Database;
import liquibase.database.core.HsqlDatabase; import liquibase.database.core.HsqlDatabase;
import liquibase.database.core.MSSQLDatabase;
import liquibase.database.core.OracleDatabase; import liquibase.database.core.OracleDatabase;
import liquibase.datatype.DataTypeInfo; import liquibase.datatype.DataTypeInfo;
import liquibase.datatype.DatabaseDataType; import liquibase.datatype.DatabaseDataType;
Expand All @@ -18,6 +19,12 @@ public DatabaseDataType toDatabaseDataType(Database database) {
if (database instanceof OracleDatabase) { if (database instanceof OracleDatabase) {
return new DatabaseDataType("NVARCHAR2", getParameters()); return new DatabaseDataType("NVARCHAR2", getParameters());
} }
if (database instanceof MSSQLDatabase) {
if (getParameters() != null && getParameters().length > 0 && getParameters()[0].equals("2147483647")) {
return new DatabaseDataType("NVARCHAR", "MAX");
}
return new DatabaseDataType("NVARCHAR", getParameters());
}
return super.toDatabaseDataType(database); return super.toDatabaseDataType(database);
} }


Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import liquibase.database.Database; import liquibase.database.Database;
import liquibase.database.core.DerbyDatabase; import liquibase.database.core.DerbyDatabase;
import liquibase.database.core.MSSQLDatabase;
import liquibase.database.core.OracleDatabase; import liquibase.database.core.OracleDatabase;
import liquibase.database.core.PostgresDatabase; import liquibase.database.core.PostgresDatabase;
import liquibase.datatype.DataTypeInfo; import liquibase.datatype.DataTypeInfo;
Expand All @@ -27,6 +28,9 @@ public DatabaseDataType toDatabaseDataType(Database database) {
if (database instanceof DerbyDatabase || database instanceof PostgresDatabase) { if (database instanceof DerbyDatabase || database instanceof PostgresDatabase) {
return new DatabaseDataType("SMALLINT"); return new DatabaseDataType("SMALLINT");
} }
if (database instanceof MSSQLDatabase) {
return new DatabaseDataType("TINYINT");
}
if (database instanceof OracleDatabase) { if (database instanceof OracleDatabase) {
return new DatabaseDataType("NUMBER",3); return new DatabaseDataType("NUMBER",3);
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import liquibase.datatype.LiquibaseDataType; import liquibase.datatype.LiquibaseDataType;
import liquibase.exception.DatabaseException; import liquibase.exception.DatabaseException;


@DataTypeInfo(name="uuid", minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT) @DataTypeInfo(name="uuid", aliases = {"uniqueidentifier"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT)
public class UUIDType extends LiquibaseDataType { public class UUIDType extends LiquibaseDataType {
@Override @Override
public DatabaseDataType toDatabaseDataType(Database database) { public DatabaseDataType toDatabaseDataType(Database database) {
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,7 @@
package liquibase.snapshot.jvm; package liquibase.snapshot.jvm;


import liquibase.database.Database; import liquibase.database.Database;
import liquibase.database.core.MSSQLDatabase;
import liquibase.database.jvm.JdbcConnection; import liquibase.database.jvm.JdbcConnection;
import liquibase.database.core.InformixDatabase; import liquibase.database.core.InformixDatabase;
import liquibase.database.core.OracleDatabase; import liquibase.database.core.OracleDatabase;
Expand Down Expand Up @@ -152,7 +153,7 @@ public Column getColumn(Schema schema, String tableName, String columnName, Data


Table table = new Table(database.correctObjectName(tableName, Table.class)); Table table = new Table(database.correctObjectName(tableName, Table.class));
table.setSchema(schema); table.setSchema(schema);
return readColumn(convertResultSetToMap(rs), table, database); return readColumn(convertResultSetToMap(rs, database), table, database);
} catch (Exception e) { } catch (Exception e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} finally { } finally {
Expand Down Expand Up @@ -184,7 +185,7 @@ protected Table readTable(ResultSet tableMetadataResultSet, Database database, b
ResultSet columnMetadataResultSet = getMetaData(database).getColumns(getJdbcCatalogName(rawSchema), getJdbcSchemaName(rawSchema), rawTableName, null); ResultSet columnMetadataResultSet = getMetaData(database).getColumns(getJdbcCatalogName(rawSchema), getJdbcSchemaName(rawSchema), rawTableName, null);
try { try {
while (columnMetadataResultSet.next()) { while (columnMetadataResultSet.next()) {
table.getColumns().add(readColumn(convertResultSetToMap(columnMetadataResultSet), table, database)); table.getColumns().add(readColumn(convertResultSetToMap(columnMetadataResultSet, database), table, database));
} }
} finally { } finally {
columnMetadataResultSet.close(); columnMetadataResultSet.close();
Expand Down Expand Up @@ -251,7 +252,9 @@ protected Column readColumn(Map<String, Object> columnMetadataResultSet, Relatio
if (table instanceof Table) { if (table instanceof Table) {
if (columnMetadataResultSet.containsKey("IS_AUTOINCREMENT")) { if (columnMetadataResultSet.containsKey("IS_AUTOINCREMENT")) {
String isAutoincrement = (String) columnMetadataResultSet.get("IS_AUTOINCREMENT"); String isAutoincrement = (String) columnMetadataResultSet.get("IS_AUTOINCREMENT");
if (isAutoincrement.equals("YES")) { if (isAutoincrement == null) {
column.setAutoIncrement(false);
} else if (isAutoincrement.equals("YES")) {
column.setAutoIncrement(true); column.setAutoIncrement(true);
} else if (isAutoincrement.equals("NO")) { } else if (isAutoincrement.equals("NO")) {
column.setAutoIncrement(false); column.setAutoIncrement(false);
Expand Down Expand Up @@ -425,7 +428,7 @@ protected void readColumns(DatabaseSnapshot snapshot, Schema schema, DatabaseMet
try { try {
allColumnsMetadataRs = databaseMetaData.getColumns(getJdbcCatalogName(schema), getJdbcSchemaName(schema), null, null); allColumnsMetadataRs = databaseMetaData.getColumns(getJdbcCatalogName(schema), getJdbcSchemaName(schema), null, null);
while (allColumnsMetadataRs.next()) { while (allColumnsMetadataRs.next()) {
Map<String, Object> data = convertResultSetToMap(allColumnsMetadataRs); Map<String, Object> data = convertResultSetToMap(allColumnsMetadataRs, database);
String tableOrViewName = cleanObjectNameFromDatabase((String) data.get("TABLE_NAME")); String tableOrViewName = cleanObjectNameFromDatabase((String) data.get("TABLE_NAME"));
Relation relation = snapshot.getDatabaseObject(schema, tableOrViewName, Table.class); Relation relation = snapshot.getDatabaseObject(schema, tableOrViewName, Table.class);
if (relation == null) { if (relation == null) {
Expand Down Expand Up @@ -460,7 +463,7 @@ protected void readColumns(DatabaseSnapshot snapshot, Schema schema, DatabaseMet
} }
} }


private Map<String, Object> convertResultSetToMap(ResultSet rs) throws SQLException { private Map<String, Object> convertResultSetToMap(ResultSet rs, Database database) throws SQLException {
Class[] types = new Class[]{ //matches tableMetadata.getColumns() types. Ugly, but otherwise get wrong types Class[] types = new Class[]{ //matches tableMetadata.getColumns() types. Ugly, but otherwise get wrong types
null, //no zero index null, //no zero index
String.class, String.class,
Expand All @@ -485,20 +488,51 @@ private Map<String, Object> convertResultSetToMap(ResultSet rs) throws SQLExcept
String.class, String.class,
String.class, String.class,
short.class, short.class,
String.class,
String.class String.class
}; };
// TABLE_CAT String => table catalog (may be null)
// TABLE_SCHEM String => table schema (may be null)
// TABLE_NAME String => table name
// COLUMN_NAME String => column name
// DATA_TYPE int => SQL type from java.sql.Types
// TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
// COLUMN_SIZE int => column size.
// BUFFER_LENGTH is not used.
// DECIMAL_DIGITS int => the number of fractional digits. Null is returned for data types where DECIMAL_DIGITS is not applicable.
// NUM_PREC_RADIX int => Radix (typically either 10 or 2)
// NULLABLE int => is NULL allowed.
// columnNoNulls - might not allow NULL values
// columnNullable - definitely allows NULL values
// columnNullableUnknown - nullability unknown
// REMARKS String => comment describing column (may be null)
// COLUMN_DEF String => default value for the column, which should be interpreted as a string when the value is enclosed in single quotes (may be null)
// SQL_DATA_TYPE int => unused
// SQL_DATETIME_SUB int => unused
// CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
// ORDINAL_POSITION int => index of column in table (starting at 1)
// IS_NULLABLE String => ISO rules are used to determine the nullability for a column.
// YES --- if the parameter can include NULLs
// NO --- if the parameter cannot include NULLs
// empty string --- if the nullability for the parameter is unknown
// SCOPE_CATLOG String => catalog of table that is the scope of a reference attribute (null if DATA_TYPE isn't REF)
// SCOPE_SCHEMA String => schema of table that is the scope of a reference attribute (null if the DATA_TYPE isn't REF)
// SCOPE_TABLE String => table name that this the scope of a reference attribure (null if the DATA_TYPE isn't REF)
// SOURCE_DATA_TYPE short => source type of a distinct type or user-generated Ref type, SQL type from java.sql.Types (null if DATA_TYPE isn't DISTINCT or user-generated REF)
// IS_AUTOINCREMENT String => Indicates whether this column is auto incremented
// YES --- if the column is auto incremented
// NO --- if the column is not auto incremented
// empty string --- if it cannot be determined whether the column is auto incremented parameter is unknown


Map<String, Object> data = new HashMap<String, Object>(); Map<String, Object> data = new HashMap<String, Object>();
for (int i=1; i<= rs.getMetaData().getColumnCount(); i++) { for (int i=1; i< types.length; i++) {
Class classType = types[i]; Class classType = types[i];
Object value; Object value;
if (classType.equals(String.class)) { if (classType.equals(String.class)) {
value = rs.getString(i); value = rs.getString(i);
} else if (classType.equals(int.class)) { } else if (classType.equals(int.class)) {
value = rs.getInt(i); value = rs.getInt(i);
} else if (classType.equals(short.class)) { } else if (classType.equals(short.class)) {
value = rs.getShort(i); value = null; //SOURCE_DATA_TYPE is not used and causes problems on sqlserver jdbc 3.0
} else { } else {
value = rs.getObject(i); value = rs.getObject(i);
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@


import liquibase.database.Database; import liquibase.database.Database;
import liquibase.database.core.MSSQLDatabase; import liquibase.database.core.MSSQLDatabase;
import liquibase.database.structure.Column;
import liquibase.database.structure.ForeignKeyConstraintType; import liquibase.database.structure.ForeignKeyConstraintType;
import liquibase.exception.DatabaseException; import liquibase.exception.DatabaseException;


import java.sql.SQLException;
import java.util.Map;

public class MSSQLDatabaseSnapshotGenerator extends JdbcDatabaseSnapshotGenerator { public class MSSQLDatabaseSnapshotGenerator extends JdbcDatabaseSnapshotGenerator {
public boolean supports(Database database) { public boolean supports(Database database) {
return database instanceof MSSQLDatabase; return database instanceof MSSQLDatabase;
Expand Down Expand Up @@ -34,4 +38,17 @@ protected ForeignKeyConstraintType convertToForeignKeyConstraintType(int jdbcTyp
} }
} }


@Override
protected Object readDefaultValue(Map<String, Object> columnMetadataResultSet, Column columnInfo, Database database) throws SQLException, DatabaseException {
Object defaultValue = columnMetadataResultSet.get("COLUMN_DEF");

if (defaultValue != null && defaultValue instanceof String) {
String newValue = null;
if (defaultValue.equals("(NULL)")) {
newValue = null;
}
columnMetadataResultSet.put("COLUMN_DEF", newValue);
}
return super.readDefaultValue(columnMetadataResultSet, columnInfo, database);
}
} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public Sql[] generateSql(DropIndexStatement statement, Database database, SqlGen
if (database instanceof MySQLDatabase) { if (database instanceof MySQLDatabase) {
return new Sql[] {new UnparsedSql("DROP INDEX " + database.escapeIndexName(null, null, statement.getIndexName()) + " ON " + database.escapeTableName(statement.getTableCatalogName(), schemaName, statement.getTableName())) }; return new Sql[] {new UnparsedSql("DROP INDEX " + database.escapeIndexName(null, null, statement.getIndexName()) + " ON " + database.escapeTableName(statement.getTableCatalogName(), schemaName, statement.getTableName())) };
} else if (database instanceof MSSQLDatabase) { } else if (database instanceof MSSQLDatabase) {
return new Sql[] {new UnparsedSql("DROP INDEX " + database.escapeTableName(statement.getTableCatalogName(), schemaName, statement.getTableName()) + "." + database.escapeIndexName(null, null, statement.getIndexName())) }; return new Sql[] {new UnparsedSql("DROP INDEX " + database.escapeTableName(null, schemaName, statement.getTableName()) + "." + database.escapeIndexName(null, null, statement.getIndexName())) };
} else if (database instanceof PostgresDatabase) { } else if (database instanceof PostgresDatabase) {
return new Sql[]{new UnparsedSql("DROP INDEX " + database.escapeIndexName(statement.getTableCatalogName(),schemaName, statement.getIndexName()))}; return new Sql[]{new UnparsedSql("DROP INDEX " + database.escapeIndexName(statement.getTableCatalogName(),schemaName, statement.getIndexName()))};
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ public void smartDataLoad() throws Exception {
} }
} }


@Override // @Override
//Mssql has problems with insert data in autoincrement tables. Because diff detects the id of that inserts and when it is ran the diff // //Mssql has problems with insert data in autoincrement tables. Because diff detects the id of that inserts and when it is ran the diff
//it tries to insert values in identity columns that isn't allowed in mssql // //it tries to insert values in identity columns that isn't allowed in mssql
@Test(expected = MigrationFailedException.class) // @Test(expected = MigrationFailedException.class)
public void testRerunDiffChangeLog() throws Exception { // public void testRerunDiffChangeLog() throws Exception {
if (getDatabase() == null) { // if (getDatabase() == null) {
throw new MigrationFailedException(); // throw new MigrationFailedException();
} // }
super.testRerunDiffChangeLog(); // super.testRerunDiffChangeLog();
} // }


} }
Binary file not shown.

0 comments on commit 1144d44

Please sign in to comment.