package liquibase.change.core; import liquibase.change.*; import liquibase.database.Database; import liquibase.snapshot.SnapshotGeneratorFactory; import liquibase.statement.SqlStatement; import liquibase.statement.core.SetNullableStatement; import liquibase.structure.core.Column; import liquibase.structure.core.Table; /** * Drops a not-null constraint from an existing column. */ @DatabaseChange(name="dropNotNullConstraint", description = "Makes a column nullable", priority = ChangeMetaData.PRIORITY_DEFAULT, appliesTo = "column") public class DropNotNullConstraintChange extends AbstractChange { private String catalogName; private String schemaName; private String tableName; private String columnName; private String columnDataType; @DatabaseChangeProperty(mustEqualExisting ="notNullConstraint.table.catalog", since = "3.0") public String getCatalogName() { return catalogName; } public void setCatalogName(String catalogName) { this.catalogName = catalogName; } @DatabaseChangeProperty(mustEqualExisting ="notNullConstraint.table.schema") public String getSchemaName() { return schemaName; } public void setSchemaName(String schemaName) { this.schemaName = schemaName; } @DatabaseChangeProperty(mustEqualExisting = "notNullConstraint.table", description = "Name of the table containing that the column to drop the constraint from") public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } @DatabaseChangeProperty(mustEqualExisting = "notNullConstraint.column", description = "Name of the column to drop the constraint from") public String getColumnName() { return columnName; } public void setColumnName(String columnName) { this.columnName = columnName; } @DatabaseChangeProperty(description = "Current data type of the column") public String getColumnDataType() { return columnDataType; } public void setColumnDataType(String columnDataType) { this.columnDataType = columnDataType; } @Override public SqlStatement[] generateStatements(Database database) { //todo if (database instanceof SQLiteDatabase) { // // return special statements for SQLite databases // return generateStatementsForSQLiteDatabase(database); // } return new SqlStatement[] { new SetNullableStatement( getCatalogName(), getSchemaName(), getTableName(), getColumnName(), getColumnDataType(), true) }; } @Override public ChangeStatus checkStatus(Database database) { try { Column snapshot = SnapshotGeneratorFactory.getInstance().createSnapshot(new Column(Table.class, getCatalogName(), getSchemaName(), getTableName(), getColumnName()), database); Boolean nullable = snapshot.isNullable(); return new ChangeStatus().assertComplete(nullable == null || nullable, "Column is not null"); } catch (Exception e) { return new ChangeStatus().unknown(e); } } // private SqlStatement[] generateStatementsForSQLiteDatabase(Database database) { // // SQLite does not support this ALTER TABLE operation until now. // // For more information see: http://www.sqlite.org/omitted.html. // // This is a small work around... // // List<SqlStatement> statements = new ArrayList<SqlStatement>(); // // // define alter table logic // AlterTableVisitor rename_alter_visitor = new AlterTableVisitor() { // public ColumnConfig[] getColumnsToAdd() { // return new ColumnConfig[0]; // } // public boolean copyThisColumn(ColumnConfig column) { // return true; // } // public boolean createThisColumn(ColumnConfig column) { // if (column.getName().equals(getColumnName())) { // column.getConstraints().setNullable(true); // } // return true; // } // public boolean createThisIndex(Index index) { // return true; // } // }; // // try { // // alter table // statements.addAll(SQLiteDatabase.getAlterTableStatements( // rename_alter_visitor, // database,getCatalogName(), getSchemaName(),getTableName())); // } catch (Exception e) { // e.printStackTrace(); // } // return statements.toArray(new SqlStatement[statements.size()]); // } @Override protected Change[] createInverses() { AddNotNullConstraintChange inverse = new AddNotNullConstraintChange(); inverse.setColumnName(getColumnName()); inverse.setSchemaName(getSchemaName()); inverse.setTableName(getTableName()); inverse.setColumnDataType(getColumnDataType()); return new Change[]{ inverse }; } @Override public String getConfirmationMessage() { return "Null constraint dropped from " + getTableName() + "." + getColumnName(); } @Override public String getSerializedObjectNamespace() { return STANDARD_CHANGELOG_NAMESPACE; } }