Jakob Külzer Ninja Coding Monkey goes Canada

25Sep/081

LiquiBase, addForeignKeyConstraint and Column Types do not Match

Today I encountered some weird errors while migrating my database using LiquiBase. It took me quite some time to figure out what was wrong as no one has encountered this error before. So, here's the problem and the solution. ;-)

Ugly but simple example: I have two domain classes, say Book and Author and a Book has an Author. How Author looks like is not important. Book looks like this

class Book {
  Author author
}

Due to changes in the requirements the author needs to be optional thus nullable. With updated constraints the Book class looks like this:

class Book {
  Author author
  static constraints = { author(nullable:true) }
}

So upgrading the database with LiquiBase should be as easy as adding a couple of lines to the changelog file:

<changeSet author="jakob" id="foo-1">
  <dropForeignKeyConstraint baseTableName="BOOK" constraintName="FK2E3AE9CD85EDFA"/>
  <dropNotNullConstraint tableName="BOOK" columnName="AUTHOR_ID"/>
  <addForeignKeyConstraint baseColumnNames="AUTHOR_ID"
    baseTableName="BOOK" constraintName="FK2E3AE9CD85EDFA"
    deferrable="false" initiallyDeferred="false"
    referencedColumnNames="ID" referencedTableName="AUTHOR"/>
</changeSet>

Basically this changeset drops the foreign key constraint on AUTHOR_ID, drops the not-null-constraints and re-adds the foreign key constraint which is required to handle the association between the Book and the Author class.

Unfortunately the addForeignKeyConstraint will cause an error, something like this:

Caused by: java.sql.SQLException: Column types do not match in statement [ALTER TABLE...

The reason why this happens is that: when dropping the not-null constraint the type of the AUTHOR_ID column is re-set to something unusable. Inspecting the database with the HSQLDB Databasemanager showed that the type of the is set to NULL which is weird. The solution to this is easy however. All you need to do is to provide LiquiBase the type with the columnDataType attribute of the column in the dropNotNullConstraint element:

<changeSet author="jakob" id="foo-1">
  <dropForeignKeyConstraint baseTableName="BOOK" constraintName="FK2E3AE9CD85EDFA"/>
  <dropNotNullConstraint tableName="BOOK" columnName="AUTHOR_ID"/>
  <addForeignKeyConstraint baseColumnNames="AUTHOR_ID" columnDataType="BIGINT" 
    baseTableName="BOOK" constraintName="FK2E3AE9CD85EDFA"
    deferrable="false" initiallyDeferred="false"
    referencedColumnNames="ID" referencedTableName="AUTHOR"/>
</changeSet>

With this in place it will work like a charm.

Comments (1) Trackbacks (0)
  1. That was really helpful thanks I was having the exact same problem.


Leave a comment


No trackbacks yet.