package liquibase.change.core; import liquibase.change.*; import liquibase.database.Database; import liquibase.snapshot.SnapshotGeneratorFactory; import liquibase.statement.SqlStatement; import liquibase.statement.core.AddUniqueConstraintStatement; import liquibase.structure.core.Column; import liquibase.structure.core.UniqueConstraint; /** * Adds a unique constraint to an existing column. */ @DatabaseChange(name="addUniqueConstraint", description = "Adds a unique constrant to an existing column or set of columns.", priority = ChangeMetaData.PRIORITY_DEFAULT, appliesTo = "column") public class AddUniqueConstraintChange extends AbstractChange { private String catalogName; private String schemaName; private String tableName; private String columnNames; private String constraintName; private String tablespace; private Boolean deferrable; private Boolean initiallyDeferred; private Boolean disabled; private Boolean clustered; private String forIndexName; private String forIndexSchemaName; private String forIndexCatalogName; @DatabaseChangeProperty(mustEqualExisting ="column.relation.catalog", since = "3.0") public String getCatalogName() { return catalogName; } public void setCatalogName(String catalogName) { this.catalogName = catalogName; } @DatabaseChangeProperty(mustEqualExisting ="column.relation.schema") public String getSchemaName() { return schemaName; } public void setSchemaName(String schemaName) { this.schemaName = schemaName; } @DatabaseChangeProperty(mustEqualExisting = "column.relation", description = "Name of the table to create the unique constraint on") public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } @DatabaseChangeProperty(mustEqualExisting = "column", description = "Name of the column(s) to create the unique constraint on. Comma separated if multiple") public String getColumnNames() { return columnNames; } public void setColumnNames(String columnNames) { this.columnNames = columnNames; } @DatabaseChangeProperty(description = "Name of the unique constraint") public String getConstraintName() { return constraintName; } public void setConstraintName(String constraintName) { this.constraintName = constraintName; } @DatabaseChangeProperty(description = "'Tablespace' to create the index in. Corresponds to file group in mssql") public String getTablespace() { return tablespace; } public void setTablespace(String tablespace) { this.tablespace = tablespace; } public Boolean getDeferrable() { return deferrable; } public void setDeferrable(Boolean deferrable) { this.deferrable = deferrable; } public Boolean getInitiallyDeferred() { return initiallyDeferred; } public void setInitiallyDeferred(Boolean initiallyDeferred) { this.initiallyDeferred = initiallyDeferred; } public Boolean getDisabled() { return disabled; } public void setDisabled(Boolean disabled) { this.disabled = disabled; } public Boolean getClustered() { return clustered; } public void setClustered(Boolean clustered) { this.clustered = clustered; } public String getForIndexName() { return forIndexName; } public void setForIndexName(String forIndexName) { this.forIndexName = forIndexName; } public String getForIndexSchemaName() { return forIndexSchemaName; } public void setForIndexSchemaName(String forIndexSchemaName) { this.forIndexSchemaName = forIndexSchemaName; } public String getForIndexCatalogName() { return forIndexCatalogName; } public void setForIndexCatalogName(String forIndexCatalogName) { this.forIndexCatalogName = forIndexCatalogName; } @Override public SqlStatement[] generateStatements(Database database) { //todo if (database instanceof SQLiteDatabase) { // // return special statements for SQLite databases // return generateStatementsForSQLiteDatabase(database); // } boolean deferrable = false; if (getDeferrable() != null) { deferrable = getDeferrable(); } boolean initiallyDeferred = false; if (getInitiallyDeferred() != null) { initiallyDeferred = getInitiallyDeferred(); } boolean disabled = false; if (getDisabled() != null) { disabled = getDisabled(); } boolean clustered = false; if (getClustered() != null) { clustered = getClustered(); } AddUniqueConstraintStatement statement = new AddUniqueConstraintStatement(getCatalogName(), getSchemaName(), getTableName(), ColumnConfig.arrayFromNames(getColumnNames()), getConstraintName()); statement.setTablespace(getTablespace()) .setDeferrable(deferrable) .setInitiallyDeferred(initiallyDeferred) .setDisabled(disabled) .setClustered(clustered); statement.setForIndexName(getForIndexName()); statement.setForIndexSchemaName(getForIndexSchemaName()); statement.setForIndexCatalogName(getForIndexCatalogName()); return new SqlStatement[] { statement }; } @Override public ChangeStatus checkStatus(Database database) { ChangeStatus result = new ChangeStatus(); try { UniqueConstraint example = new UniqueConstraint(getConstraintName(), getCatalogName(), getSchemaName(), getTableName(), Column.arrayFromNames(getColumnNames())); UniqueConstraint snapshot = SnapshotGeneratorFactory.getInstance().createSnapshot(example, database); result.assertComplete(snapshot != null, "Unique constraint does not exist"); return result; } catch (Exception e) { return result.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) { // String[] split_columns = getColumnNames().split("[ ]*,[ ]*"); // for (String split_column:split_columns) { // if (column.getName().equals(split_column)) { // column.getConstraints().setUnique(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 public String getConfirmationMessage() { return "Unique constraint added to "+getTableName()+"("+getColumnNames()+")"; } @Override protected Change[] createInverses() { DropUniqueConstraintChange inverse = new DropUniqueConstraintChange(); inverse.setSchemaName(getSchemaName()); inverse.setTableName(getTableName()); inverse.setConstraintName(getConstraintName()); return new Change[]{ inverse, }; } @Override public String getSerializedObjectNamespace() { return STANDARD_CHANGELOG_NAMESPACE; } }