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>