I need to change a table to add a column and include it to the Primary Key. So I have a luiqbase changeset:
I wonder how to separate concerns and implement rollback correctly.
<changeSet author="rahul" id="change_pk">
<addColumn tableName="posts">
<column name="aux_id" type="INT" defaultValue="0"/>
</addColumn>
<dropPrimaryKey tableName="posts"/>
<addPrimaryKey tableName="posts" columnNames="id,aux_id"/>
<rollback>
<dropPrimaryKey tableName="posts"/>
<addPrimaryKey tableName="posts" columnNames="id"/>
</rollback>
</changeSet>
What concerns me in this approach is that if I am unable to create a column, I will drop PK and recreate it, which may affect DB response time, assuming the table is quite big. However, this makes all these changes atomic.
<changeSet author="rahul" id="add_col">
<addColumn tableName="posts">
<column name="aux_id" type="INT" defaultValue="0"/>
</addColumn>
</changeSet>
<changeSet author="rahul" id="change_pk">
<dropPrimaryKey tableName="posts"/>
<addPrimaryKey tableName="posts" columnNames="id,aux_id"/>
<rollback>
<dropPrimaryKey tableName="posts"/>
<addPrimaryKey tableName="posts" columnNames="id"/>
</rollback>
</changeSet>
Thus I will be able to have more control over rollback for PK changes, which will drop and recreate the old one. However, there is a problem, when change_pk
changeset is not applied - that I have a column, which should be included to a PK, but it is not, making system vulnerable to unique constraint violations.
You can do the following, using runAlways attribute. Also, check out different onFail options
<changeSet author="rahul" id="add_col" runAlways="true">
<preConditions (perhaps, some non-default onFail option) >
<not>
<columnExists tableName="posts" columnName="aux_id"/>
</not>
</preConditions>
<addColumn tableName="posts">
<column name="aux_id" type="INT" defaultValue="0"/>
</addColumn>
</changeSet>
<changeSet author="rahul" id="change_pk">
<preConditions>
<and>
<columnExists tableName="posts" columnName="aux_id"/>
<!-- perhaps some other precondition -->
<sqlCheck expectedResult="id">
SELECT key_column_usage.column_name
FROM information_schema.key_column_usage
WHERE table_schema = SCHEMA()
AND constraint_name = 'PRIMARY'
AND table_name = 'posts'
</sqlCheck>
</and>
</preConditions>
<dropPrimaryKey tableName="posts"/>
<addPrimaryKey tableName="posts" columnNames="id,aux_id"/>
<rollback>
<dropPrimaryKey tableName="posts"/>
<addPrimaryKey tableName="posts" columnNames="id"/>
<dropColumn tableName="posts" columnName="aux_id">
</rollback>
</changeSet>