How to handle migrations with multiple RDBMS?

Hello,


We have started to use liquibase internally and found it quite good so far, with some minor issues I will not detail here but that we might want to provide a patch for. 


Our product supports 2 RDBMS, Sybase and Oracle, which have somewhat different capabilities and quirks. We try to handle changesets as rdbms-agnostically as possible, but for some cases we need to be more specific. We do this using context information that are applied using 2 techniques:

  1. Define rdbms-dependent variables that will be interpolated and replaced within changesets according to the actual RDBMS used. This is mostly useful to handle specific types,
  2. Define rdbms-dependent whole changes.

While this is not the standard use case, we sometimes need to migrate a DB from one system to another  and of course this is where troubles start:

  1. Hash stored within DBCHANGELOG tables are invalidated when moving the DBCHANGELOG table from one rdbms to another as the variables' values change,
  2. DB can easily get corrupted, or migration fails, when liquibase will try to apply changes that have not been previously applied because they were not related to the source rdbms. Those changes could be applied in an untimely manner.

In particular, we do not know how to handle correctly sequences. In Sybase, sequential unique ids should be handled using identity attribute on column whereas in Oracle a specific Sequence object should be created then later used to retrieve unique ids. Historically we have been using some custom code to handle incremental sequences uniformly across databases, but as we are moving towards standardized RDBMS access through JPA, we would like to make things more uniform.


Assuming we are not the only people to handle multiple databases, I would be interested to know what best practices/advices/strategies other people use to handle this case (apart from the obvious “don’t do it” :-)). 


Thanks in advance,


Arnaud

Multiple database support is a fairly common use case, but how to handle it can vary significantly depending on the company’s particular usage. Sequences are always a big issue :slight_smile:


It sounds like you have the two major ways to handle it: contexts and changelog parameters. There is also the “dbms” attribute that works like an auto-set context. 


The issue with the changing changelog hashes is an issue I hadn’t thought through. You can set the column to null and it will recompute and re-store the hashes, but liquibase will not run any “runOnChange” changesets in that scenario. 


If you have particular cross-database patterns you use that you want to be more liquibase-friendly, I’d suggest looking at the extension system (liquibase.org/extensions). That will allow you to override almost any liquibase functionality you need to have it work they way you want it to. 


Nathan

Hi Nathan,

Thanks for your answer. Migrating native sequences appeared very complex to handle, especially in a cross-RDBMS migration scenario (looks like just branch merging with cherry-picking…), so we went back and replaced native sequences with a custom mechanism based on a table and a dbms-specific stored procedure. The advantage being that the sequences table is preserved across databases and migrations without having to consider dbms-specific changes.

The hash issue is a bit more annoying but anyway import/export is a relatively rare occurence so we can accept to handle it with setting hash column to null.

Regards,
Arnaud

Hi again,

Is it possible to replace hash computation in some way through extension mechanism ? I would think it is possible to override changelog serializers hence we could imagine generating a string that would be uniform across databases thus generating consistent hash but there might be unknown side-effects.

If this is not possible, would you accept a patch that would compute hashing on the raw text of changesets ?

Thanks

Arnaud

Nathan,

Thanks for your reply. I planned to work on this issue this week given we have internal deadlines to meet. We are currently heading towards the simpler solution of nulling hash values in the DB should we migrate our data between various database vendors (currently supporting only oracle and sybase though). The way we plan to do it is simple:

  1. Each time we do a migration, update a special table defining the latest known database vendor we applied migration to;
  2. If latest DB vendor is not the same as current one, null hash values in DBCHANGELOG and record a new entry.

We have had a lengthy discussion on this subject and I leant towards proposing pull request to liquibase but in the end it appears I somewhat lost the argument given the simplicity of the above scheme.

Anyway, I will still have a closer look at it later on this week and will keep you posted on whether or not I can came up with something interesting.


It should be possible to do in an extension, <a class=“boldText header” href=“http://forum.liquibase.org/#User/arnaud.bailly” vs. going through a ServiceLocator. Also individual change implementationscan can generate checksums however they feel they should which makes a generic case more difficult. If you wanted to take a stab at it and send a pull request and/or extension code I’d be very interested in seeing what it takes. Otherwise I’ll get to it at some point, but it hasn’t been a high enough priority yet.


Nathan

Thanks for the update, glad to hear you figured something out.


Let me know if you get to look into it more.


Nathan