Changeset Checksums

When Liquibase reaches a Changeset in your Changelog during execution, it computes a checksum. Then it does one of the following things:

  • If the change has never been executed on the database, Liquibase stores it in the MD5SUM column of the DATABASECHANGELOG table.
  • If the change has already been executed, Liquibase compares the two checksums in order to check whether it has been modified since it was run.

Note: The checksum is not the checksum of file containing the changeset, so you may modify the file (such as to make formatting fixes) and still get the same checksum. The checksum stored in DATABASECHANGELOG can also change even if the changeset has not changed; this is done to allow for checksum algorithm improvement, and limited to the first digit. For example, 8:9df0 will become 9:0312. In this case, the validation will not fail and the checksum will be updated silently.

4.22.0 and later

Note: We have removed the 4.22.0 release of Liquibase. This version contains an updated algorithm for determining which changes Liquibase needs to deploy to a database. In some situations, the conversion to this new algorithm could result in eligible changes not being deployed to a target database.

Specifically, currently undeployed changesets with the runOnChange=true attribute may not be deployed if they were present in the first execution of Liquibase 4.22.0 against a given target database. If you have not upgraded to Liquibase 4.22.0, you are not impacted by this issue, or if you do not rely on runOnChange changesets which have changed before your upgrade.

To remedy this issue, run the clear-checksums command, then revert to Liquibase 4.21.1, and then run the changelog-sync command to recalculate the v8 checksums.

The checksum logic in Liquibase version 4.22.0 improves whitespace handling in views, procedures, and Liquibase Pro stored logic objects. This prevents checksum validation errors when whitespace is changed, as can sometimes happen if a SQL script is open in an IDE. Liquibase continues to detect non-whitespace changes and throw checksum validation errors.

Checksums are silently recalculated upon the initial run with the new version. This impacts users who rely on the detection of a changed changeset (runOnChange=true) or have more complex workflows. It is recommended that you run liquibase clear-checksums in the old version of Liquibase before running the new Liquibase version against a database.

Note: Users with large changelogs and DATABASECHANGELOG tables will have a one-time performance degradation as the new checksums are calculated. If this is a concern, users should schedule the upgrade to Liquibase 4.24.0 in a maintenance window.

Upgrade to checksum version 9

Checksum upgrades automatically to version 9 when a status or any of the rollback, update or changelog-sync families of commands are executed. The corresponding helper *-sql commands do not upgrade the checksums. Other commands or combination of commands and command properties may set all or some checksums to NULL; the NULLs will be replaced with version 9 checksums on the next status, rollback, update or changelog-sync command.

Complex workflows or automation factors

Users with complex workflows or automation that rely on detection of a modified changeset (runOnChange=true) should run update-sql and validate prior to upgrading to Liquibase v4.22.0. The update-sql shows which changesets are pending execution, as well as providing the SQL that will run. The validate ensures there are no checksum validation errors prior to Liquibase upgrade.

  • If there are no pending changes and no checksum validation errors, users can safely upgrade to Liquibase v4.22.0.
  • If there are pending changes or checksum validation errors users wish to ignore, they should execute clear-checksums on the currently installed Liquibase version prior to upgrading to Liquibase v4.22 to ensure a successful checksum upgrade.

Validation failures

If the changeset has been modified since it was run, Liquibase halts and displays an error:

Validation Failed:
 1 change sets check sum
com/example/changelog.xml::1::example was: 8:63f82d4ff1b9dfa113739b7f362bd37d but is now: 8:b4fd16a20425fe377b00d81df722d604

In this example, com/example/changelog.xml::1::example is the changeset identifier, 8:63f… is the old checksum, and 8:b4f… is the new checksum.

This message displays because Liquibase cannot identify what was changed and the database may be in a state different than what the changelog is expecting. If there was a valid reason for the changeset to be changed and you want to ignore this error, there are three options:

DATABASECHANGELOG

The first option is to manually update the DATABASECHANGELOG table so that the row with the corresponding id/author/filepath has a null value for the checksum. You must do this for all environments where the changeset has been deployed.

The next time you run the update command, Liquibase updates the checksum value to the new correct value.

validCheckSum

The second option is to add a <validCheckSum> tag to the changeset. The validCheckSum tag can contain either the old checksum or the new checksum from the error message.

For example:

Note: The attribute must be in a different line than the changeset declaration when using SQL.

--liquibase formatted sql

--changeset sql-test:1
--validCheckSum: 8:b4fd16a20425fe377b00d81df722d604
create table test2(
id int
);
databaseChangeLog:
- changeSet:
      id: 1
      author: yml-test
      validCheckSum: 8:b4fd16a20425fe377b00d81df722d604
      changes:
        - createTable:
            tableName: test2
            columns:
              - column:
                  name: id
                  type: int
{
  "databaseChangeLog": [
    {
	  "changeSet": {
		"id": "1",
		"author": "json-test",
		"validCheckSums": ["8:b4fd16a20425fe377b00d81df722d604"],
		"changes": [
		  {
			"createTable": {
              "tableName": "test2",
              "columns": [
                {
                  "column": {
					"name": "id",
					"type": "int"
                  }
                }
              ]
            }
          }
        ]
      }
    }
  ]
}
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
  xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">


  <changeSet id="1" author="xml-test">
    <validCheckSum>8:b4fd16a20425fe377b00d81df722d604</validCheckSum>
    <createTable tableName="test2">
      <column name="id" type="int" />
    </createTable>
  </changeSet>
</databaseChangeLog>

clear-checksums

The third option is to use the clear-checksums command to resolve the checksum error. However, it will clear the entire MD5SUM column of checksums in your DATABASECHANGELOG table. When you run the command, Liquibase calculates new checksums for all deployed changesets, and deploys any undeployed changesets. In the CLI, enter:

liquibase clear-checksums

runOnChange attribute

Checksums are also used in conjunction with the runOnChange changeset attribute. There are times you may not want to add a new changeset because you only need to know about the current version, but you want this change to be applied whenever it is updated. For example, you can do this with stored procedures.

If you copy the entire text of the stored procedure to a new changeset each time you make a change, you will not only end up with a very long changelog, but you will lose the merging and diffing power of your source control. Instead, put the text of the stored procedure in a changeset with a runOnChange="true" attribute. The stored procedure will be re-created when there is a change to the text of it. For example:

<changeSet  author="your.name"  id="changeset01"  runOnChange="true" >
    <createProcedure>
    . . .
    </createProcedure>
</changeSet>

Related links