I need to do a diff between a Liquibase changelog and a database, so first I need to load the changelog into another database so I can run the diff. If I load it into an in-memory DB like HSQL I’ll get all kinds of invalid differences such as data types, indexes, foreign keys… because HSQL works differently than DB2 or MySQL…
So I decided to try to build my own generic SnapshotGenerator that I can use to mirror any other type of database.
I would load the changelog into my GenericSnapshotGenerator and also pass it a reference to the other Database that I’ll be comparing it with (such as DB2Database). Then I would forward any read-only calls to the other database class (such as getDatabaseProductVersion(), isSystemTable()…) but handle calls that modify the DB myself (such as adding tables…) by creating the SQL objects in-memory using the classes already defined by Liquibase.
I have some questions though.
First, can anyone think of a better way to do this?
Second, how can I translate the SQL statements into Liquibase SQL objects (without reinventing the wheel)?
I think the generic SnapShotGenerator would be the best way to go. I’ve thought a bit about implementing the feature you are attempting, and that seemed like the best route to go. One issue I saw is how you handle tags since liquibase does not have an SQL parser in it. Is that what you are talking about with “how can I translate the SQL statements into Liquibase SQL” ?
Yeah, that would also be a problem, but I’m stuck on how you take the Liquibase XML file and turn it into the Liquibase SQL objects that are stored in the DatabaseSnapshot class.
The DatabaseSnapshot object does not contain any SQL itself, it’s job is to contain a description of the current state of the database (what tables it has, what views, what the column types are, etc).
Once you have two snapshots, you create a DiffResult which compares the two snapshots to create a description of the differences. Still no SQL, just descriptive. From the DiffResult object, there are methods such as printChangeLog() and printResult() which will take that DiffResult state and do somethign with it. printChangeLog generates changeSets necessary to go from the target snapshot to snapshot. For our standard diff integration, the diff creates the changeSets and then we just run the changeset through the normal update process and it is the changeset execute functionality that creates the actual SQL.
Note: the diff APIs extensibility/sanity hasn’t been as fully thought trough as the rest of liquibase. That was what got pushed to 2.1 so I could (finally) get 2.0 out. There may be changes going forward, and any suggestions you have would be great.