package liquibase.sqlgenerator.core; import java.util.ArrayList; import java.util.List; import liquibase.database.Database; import liquibase.database.core.*; import liquibase.exception.ValidationErrors; import liquibase.sql.Sql; import liquibase.sql.UnparsedSql; import liquibase.sqlgenerator.SqlGeneratorChain; import liquibase.statement.core.DropColumnStatement; import liquibase.structure.core.Column; import liquibase.structure.core.Table; public class DropColumnGenerator extends AbstractSqlGenerator<DropColumnStatement> { @Override public ValidationErrors validate(DropColumnStatement dropColumnStatement, Database database, SqlGeneratorChain sqlGeneratorChain) { if (dropColumnStatement.isMultiple()) { ValidationErrors validationErrors = new ValidationErrors(); DropColumnStatement firstColumn = dropColumnStatement.getColumns().get(0); for (DropColumnStatement drop : dropColumnStatement.getColumns()) { validationErrors.addAll(validateSingleColumn(drop)); if (drop.getTableName() != null && !drop.getTableName().equals(firstColumn.getTableName())) { validationErrors.addError("All columns must be targeted at the same table"); } if (drop.isMultiple()) { validationErrors.addError("Nested multiple drop column statements are not supported"); } } return validationErrors; } else { return validateSingleColumn(dropColumnStatement); } } private ValidationErrors validateSingleColumn(DropColumnStatement dropColumnStatement) { ValidationErrors validationErrors = new ValidationErrors(); validationErrors.checkRequiredField("tableName", dropColumnStatement.getTableName()); validationErrors.checkRequiredField("columnName", dropColumnStatement.getColumnName()); return validationErrors; } @Override public Sql[] generateSql(DropColumnStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) { if (statement.isMultiple()) { return generateMultipleColumnSql(statement.getColumns(), database); } else { return generateSingleColumnSql(statement, database); } } private Sql[] generateMultipleColumnSql(List<DropColumnStatement> columns, Database database) { List<Sql> result = new ArrayList<Sql>(); if (database instanceof MySQLDatabase) { String alterTable = "ALTER TABLE " + database.escapeTableName(columns.get(0).getCatalogName(), columns.get(0).getSchemaName(), columns.get(0).getTableName()); for (int i = 0; i < columns.size(); i++) { alterTable += " DROP " + database.escapeColumnName(columns.get(i).getCatalogName(), columns.get(i).getSchemaName(), columns.get(i).getTableName(), columns.get(i).getColumnName()); if (i < columns.size() - 1) { alterTable += ","; } } result.add(new UnparsedSql(alterTable, getAffectedColumns(columns))); } else { for (DropColumnStatement column : columns) { result.add(generateSingleColumnSql(column, database)[0]); } } return result.toArray(new Sql[result.size()]); } private Sql[] generateSingleColumnSql(DropColumnStatement statement, Database database) { if (database instanceof DB2Database) { return new Sql[] {new UnparsedSql("ALTER TABLE " + database.escapeTableName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName()) + " DROP COLUMN " + database.escapeColumnName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), statement.getColumnName()), getAffectedColumn(statement))}; } else if (database instanceof SybaseDatabase || database instanceof SybaseASADatabase || database instanceof FirebirdDatabase || database instanceof InformixDatabase) { return new Sql[] {new UnparsedSql("ALTER TABLE " + database.escapeTableName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName()) + " DROP " + database.escapeColumnName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), statement.getColumnName()), getAffectedColumn(statement))}; } return new Sql[] {new UnparsedSql("ALTER TABLE " + database.escapeTableName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName()) + " DROP COLUMN " + database.escapeColumnName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), statement.getColumnName()), getAffectedColumn(statement))}; } private Column[] getAffectedColumns(List<DropColumnStatement> columns) { List<Column> affected = new ArrayList<Column>(); for (DropColumnStatement column : columns) { affected.add(getAffectedColumn(column)); } return affected.toArray(new Column[affected.size()]); } protected Column getAffectedColumn(DropColumnStatement statement) { return new Column().setName(statement.getColumnName()).setRelation(new Table().setName(statement.getTableName()).setSchema(statement.getCatalogName(), statement.getSchemaName())); } }