Reputation: 33
We have the foreign key set up on a table and would now like to delete them. In order to delete them, I have the following changeset
<changeSet author="me" id="drop-foreign-key-constraints-my_table_1">
<!-- if either or both foreign key exists, drop the foreign keys-->
<preConditions onFail="MARK_RAN">
<or>
<foreignKeyConstraintExists foreignKeyName="fk_ref_1"/>
<foreignKeyConstraintExists foreignKeyName="fk_ref_2"/>
</or>
</preConditions>
<dropAllForeignKeyConstraints baseTableName="my_table_1"/>
</changeSet>
So, the table my_table_1
has two foreign keys and if either exists, I would like to execute the changeset. I do not see any mistake in the definition, however, I see the below liquibase exception and cannot seem to figure out why this error is thrown at all.
liquibase.exception.MigrationFailedException: Migration failed for change set classpath:/create-table-my_table_1.xml::drop-foreign-key-constraints_my_table_1::me:
Reason: liquibase.exception.UnexpectedLiquibaseException: Expected to return only foreign keys for base table name: my_table_1 and got results for table: my_table_1
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:659)
at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:53)
at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:97)
at liquibase.Liquibase.update(Liquibase.java:201)
at liquibase.Liquibase.update(Liquibase.java:178)
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:368)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:316)
Upvotes: 0
Views: 2617
Reputation: 33
Answering it for future reference: Liquibase does not consider the table name for the
<foreignKeyConstraintExists>
check. We wrote a custom Constraint that handles this
private static final String SELECT_QUERY = "SELECT COUNT(*) from INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME = ? AND TABLE_NAME =? AND TABLE_SCHEMA=?";
@Override
public void check(final Database database)
throws CustomPreconditionFailedException, CustomPreconditionErrorException {
final JdbcConnection databaseConnection = (JdbcConnection) database.getConnection();
final String schema = database.getDefaultSchemaName();
try {
final int numberOfRows = this.getRowCount(databaseConnection, schema);
if (numberOfRows == 0) {
throw new CustomPreconditionFailedException(
String.format("Foreign key %s does not exist in the table %s, nothing to delete.",
this.tableName, this.foreignKeyName));
}
} catch (DatabaseException | SQLException exception) {
throw new CustomPreconditionErrorException("Unable to check if foreign key exists", exception);
}
}
private int getRowCount(final JdbcConnection databaseConnection, final String schema)
throws DatabaseException, SQLException {
try (PreparedStatement pstmt = databaseConnection.prepareStatement(SELECT_QUERY)) {
pstmt.setString(1, this.foreignKeyName);
pstmt.setString(2, this.tableName);
pstmt.setString(3, schema);
try (ResultSet resultSet = pstmt.executeQuery()) {
if (resultSet.next()) {
return resultSet.getInt(1);
} else {
final String msg = String.format(
"Unable to check if foreign key %s exists in table %s, result-set is empty",
this.foreignKeyName, this.tableName);
log.error(msg);
throw new DatabaseException(msg);
}
}
}
}
Upvotes: 1