package liquibase.change.core;
import liquibase.change.AbstractChange;
import liquibase.change.Change;
import liquibase.change.ChangeMetaData;
import liquibase.database.Database;
import liquibase.database.structure.ForeignKeyConstraintType;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.statement.SqlStatement;
import liquibase.statement.core.AddForeignKeyConstraintStatement;
/**
* Adds a foreign key constraint to an existing column.
*/
public class AddForeignKeyConstraintChange extends AbstractChange {
private String baseTableSchemaName;
private String baseTableName;
private String baseColumnNames;
private String referencedTableSchemaName;
private String referencedTableName;
private String referencedColumnNames;
private String constraintName;
private Boolean deferrable;
private Boolean initiallyDeferred;
private String onUpdate;
private String onDelete;
// Some databases supports creation of FK with referention to column marked as unique, not primary
// If FK referenced to such unique column this option should be set to false
private Boolean referencesUniqueColumn;
public AddForeignKeyConstraintChange() {
super("addForeignKeyConstraint", "Add Foreign Key Constraint", ChangeMetaData.PRIORITY_DEFAULT);
}
public String getBaseTableSchemaName() {
return baseTableSchemaName;
}
public void setBaseTableSchemaName(String baseTableSchemaName) {
this.baseTableSchemaName = baseTableSchemaName;
}
public String getBaseTableName() {
return baseTableName;
}
public void setBaseTableName(String baseTableName) {
this.baseTableName = baseTableName;
}
public String getBaseColumnNames() {
return baseColumnNames;
}
public void setBaseColumnNames(String baseColumnNames) {
this.baseColumnNames = baseColumnNames;
}
public String getReferencedTableSchemaName() {
return referencedTableSchemaName;
}
public void setReferencedTableSchemaName(String referencedTableSchemaName) {
this.referencedTableSchemaName = referencedTableSchemaName;
}
public String getReferencedTableName() {
return referencedTableName;
}
public void setReferencedTableName(String referencedTableName) {
this.referencedTableName = referencedTableName;
}
public String getReferencedColumnNames() {
return referencedColumnNames;
}
public void setReferencedColumnNames(String referencedColumnNames) {
this.referencedColumnNames = referencedColumnNames;
}
public String getConstraintName() {
return constraintName;
}
public void setConstraintName(String constraintName) {
this.constraintName = constraintName;
}
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 getDeleteCascade() {
// return deleteCascade;
// }
public void setDeleteCascade(Boolean deleteCascade) {
if (deleteCascade != null && deleteCascade) {
setOnDelete("CASCADE");
}
}
public void setOnUpdate(String rule) {
this.onUpdate = rule;
}
public String getOnUpdate() {
return onUpdate;
}
public void setOnDelete(String onDelete) {
this.onDelete = onDelete;
}
public String getOnDelete() {
return this.onDelete;
}
public Boolean getReferencesUniqueColumn() {
return referencesUniqueColumn;
}
public void setReferencesUniqueColumn(Boolean referencesUniqueColumn) {
this.referencesUniqueColumn = referencesUniqueColumn;
}
public void setOnDelete(ForeignKeyConstraintType rule) {
if (rule == null) {
//nothing
} else if (rule == ForeignKeyConstraintType.importedKeyCascade) {
setOnDelete("CASCADE");
} else if (rule == ForeignKeyConstraintType.importedKeySetNull) {
setOnDelete("SET NULL");
} else if (rule == ForeignKeyConstraintType.importedKeySetDefault) {
setOnDelete("SET DEFAULT");
} else if (rule == ForeignKeyConstraintType.importedKeyRestrict) {
setOnDelete("RESTRICT");
} else if (rule == ForeignKeyConstraintType.importedKeyNoAction){
setOnDelete("NO ACTION");
} else {
throw new UnexpectedLiquibaseException("Unknown onDelete action: "+rule);
}
}
public void setOnUpdate(ForeignKeyConstraintType rule) {
if (rule == null) {
//nothing
} else if (rule == ForeignKeyConstraintType.importedKeyCascade) {
setOnUpdate("CASCADE");
} else if (rule == ForeignKeyConstraintType.importedKeySetNull) {
setOnUpdate("SET NULL");
} else if (rule == ForeignKeyConstraintType.importedKeySetDefault) {
setOnUpdate("SET DEFAULT");
} else if (rule == ForeignKeyConstraintType.importedKeyRestrict) {
setOnUpdate("RESTRICT");
} else if (rule == ForeignKeyConstraintType.importedKeyNoAction) {
setOnUpdate("NO ACTION");
} else {
throw new UnexpectedLiquibaseException("Unknown onUpdate action: "+onUpdate);
}
}
public SqlStatement[] generateStatements(Database database) {
boolean deferrable = false;
if (getDeferrable() != null) {
deferrable = getDeferrable();
}
boolean initiallyDeferred = false;
if (getInitiallyDeferred() != null) {
initiallyDeferred = getInitiallyDeferred();
}
return new SqlStatement[]{
new AddForeignKeyConstraintStatement(getConstraintName(),
getBaseTableSchemaName() == null ? database.getDefaultSchemaName() : getBaseTableSchemaName(),
getBaseTableName(),
getBaseColumnNames(),
getReferencedTableSchemaName() == null ? database.getDefaultSchemaName() : getReferencedTableSchemaName(),
getReferencedTableName(),
getReferencedColumnNames())
.setDeferrable(deferrable)
.setInitiallyDeferred(initiallyDeferred)
.setOnUpdate(getOnUpdate())
.setOnDelete(getOnDelete())
.setReferencesUniqueColumn(getReferencesUniqueColumn())
};
}
@Override
protected Change[] createInverses() {
DropForeignKeyConstraintChange inverse = new DropForeignKeyConstraintChange();
inverse.setBaseTableSchemaName(getBaseTableSchemaName());
inverse.setBaseTableName(getBaseTableName());
inverse.setConstraintName(getConstraintName());
return new Change[]{
inverse
};
}
public String getConfirmationMessage() {
return "Foreign key contraint added to " + getBaseTableName() + " (" + getBaseColumnNames() + ")";
}
}