tagging the database

Question/suggestion about “database tagging” feature in Liquibase.


Currently, when you tag the database, the tag will be associated with the latest changeset and tagging it again with a different tag will overwrite the previous one. In our use case it would be useful if we could tag the same database state with multiple different tags.


Why? Imagine that each time you update your software (e.g. from 1.0 to 1.1), you perform the following steps:

  1. tag database with tag "pre-1.1"
  2. apply database changes
  3. apply application code changes
  4. if update failed, roll back to tag "pre-1.1"

This workflow will work, if there are database changes in each new version or if you never want to roll back more than one version. However, it will fail if there are updates with no database changes and you would like to roll back more than just one version.


Example: Upgrade from 1.0 to 1.1 and to 1.2.

1.0 had one changeset, let’s call it CS.

1.1 contains no new changesets.

1.2 contains no new changesets.


When update to 1.1 starts, CS is tagged with “pre-1.1”.

When update to 1.2 starts, CS is tagged with “pre-1.2” (replaces “pre-1.1”).

Now, if user wants to roll back to version 1.1, he is able to roll database to tag “pre-1.2”.

However, if he would like to roll back to version 1.0, he no longer has the tag “pre-1.1” to roll back to.


Solution? Do not overwrite existing tags, keep old tags in addition to new ones. Could be achieved by a separate “tags” table or some hack of storing more than one tag name in same column.


If you can provide some pointers, I would be happy to help in getting this implemented.


Neeme

I think having a separate DATABASECHANGELOGTAGS table is what we would have to do. I’ve generally tried to avoid creating new tables which is part of the reason I just implemented the current version as another column on DATABASECHANGELOG.


It is an often requested and confusing feature, and would be nice to get changed.


If you are looking to try to help implement it, there are a couple places to deal with:

  • You would need to create a CreateDatabaseChangeLogTagTableStatement and the corresponding Generator classes, like you see with CreateDatabaseChangeLogLockTableStatement and friends.
  • The liquibase.Liquibase.checkDatabaseChangeLogTable() method is the main facade point to make sure the Liquibase metadata tables are correct. Ironically we don't have a nice way to know if they are correct besides doing a manual databaseSnapshot and writing the logic to figure out what is going on based on the state. In there, you would have to check for the existence of the tag table, and if it doesn't exist then create it, insert into it based on the data in the existing TAG column, then drop the TAG column
  • The TagDatabaseGenerator would have to be updated to insert into the new table instead of updating the old column
  • The RemoveRanStatusGenerator would have to try to delete from the new tag table after each change is rolled back

That is all I can think of off hand.


Nathan

Thanks, I’ll come back to this in couple of weeks and have a shot at implementing it.