Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default Value ON UPDATE Liquibase

I am using Liquibase for generating a MySQL and a HSQLDB databases.
In several tables I have a column called 'last_modified' which is the TIMESTAMP of the last update on that particular record.

<changeSet author="bob" id="7">
    <createTable tableName="myTable">
        <column autoIncrement="true" name="id" type="INT">
            <constraints nullable="false" primaryKey="true" />
        </column>
        <column name="name" type="VARCHAR(128)">
            <constraints nullable="false" />
        </column>
        <column name="description" type="VARCHAR(512)" />
        <column defaultValueBoolean="true" name="enabled" type="BIT">
            <constraints nullable="false" />
        </column>
        <column name="last_modified" type="TIMESTAMP"/>
    </createTable>
    <modifySql dbms="mysql">
        <append value=" engine innodb" />
    </modifySql>
</changeSet>

I noticed that if I use MySQL, the generated SQL for that column is:

`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

While if I use HSQLDB, in case of update nothing happens, but I would like to have the same behaviour of the MySQL database with a default value on update equals to the CURRENT_TIMESTAMP.

How can I set the CURRENT_TIMESTAMP as a default value ON UPDATE?

like image 493
cloudy_weather Avatar asked Oct 07 '13 16:10

cloudy_weather


People also ask

How do I set default value in Liquibase?

You can typically use the addDefaultValue Change Type when you want to set the default value for the column definition.

What is a change set in Liquibase?

The changeset tag is a unit of change that Liquibase executes on a database and which is used to group database Liquibase Change Types together. A list of changes created by multiple changesets are tracked in a changelog.


3 Answers

You can't do this with a default value. The MySQL behaviour is non-standard and not supported by other databases. The proper way to do this is with a TRIGGER which is defined as BEFORE UPDATE and sets the timestamp each time the row is updated.

Update: From HSQLDB version 2.3.4 this feature is supported. For example: CREATE TABLE T1(ID INT, last_modified timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL). Note the NOT NULL constraint must appear after the DEFAULT and ON UPDATE clauses.

like image 181
fredt Avatar answered Oct 13 '22 20:10

fredt


we actually use Liquibase for the exact same use-case. You'll want to make an update trigger as fredt described. Otherwise, you can't be sure the update will occur on other databases besides MySQL. Your changeset tag will log something like this:

<sql splitStatements="false">
  CREATE TRIGGER update_${tableName}_trg
    BEFORE UPDATE ON ${tableName}
      FOR EACH ROW BEGIN
        SET NEW.updated_at = NOW();
      END
</sql>

Also, I have a question on Stack Overflow about how to refactor some of this code you can see at How do you refactor similar looking code and provide params in Liquibase?.

like image 24
David Groff Avatar answered Oct 13 '22 20:10

David Groff


Or you could try this, as you have already have modifySql tag added:

<column defaultValue="CURRENT_TIMESTAMP"
             name="timestamp"
             type="TIMESTAMP">
            <constraints nullable="false"/>
 </column>
<modifySql dbms="mysql">
    <regExpReplace replace="'CURRENT_TIMESTAMP'" with="CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"/>
    <append value=" engine innodb" />
</modifySql>

Liquibase 3.1.1 does not produce what you described above. I have to deal with it as given above

like image 25
sakhunzai Avatar answered Oct 13 '22 18:10

sakhunzai