Liquibase update applies same changeset multiple times

Description

Liquibase does not properly identify applied changesets and therefore attempts to execute a unique changeset multiple times. It appears that rather than using a hash code of the actual content of the changeset, liquibase is using some other metadata to determine if the changeset has already been applied.

Let's assume we run liquibase with a changelog specified as `/changes/changelog.xml` and with the following directory structure:

File system root:

changes/
changes/changelog.xml
changes/sql/
changes/sql/00000000000000_initial_schema.xml

changes/changelog.xml:

<?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-3.5.xsd">

<include file="sql/00000000000000_initial_schema.xml" relativeToChangelogFile="true"/>

</databaseChangeLog>

changes/sql/00000000000000_initial_schema.xml:

<?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-3.5.xsd">

<property name="now" value="current_timestamp" dbms="postgresql"/>

<changeSet id="00000000000000" author="jhipster">
<createSequence sequenceName="hibernate_sequence" startValue="1000" incrementBy="50"/>
</changeSet>

</databaseChangeLog>

Doing so will cause an entry to be created in the `databasechangelog` table where the filename field is: `/changes/sql/00000000000000_initial_schema.xml`

This is all fine and works well for the initial migration.

Later we decide, for one reason or another, that we want to reorganize our database migration scripts (without actually changing their content) and apply them to an already existing database.

As an example, we decided that rather than applying the database migration script directly from the local file system as done before, we want to package these migration scripts inside a jar file and apply them at application run time from the jar file rather than from the file system. So, without changing the content of any of the database migration xml files, and without changing their relative locations to each other, we simply package them inside a jar file:

Pertinent content of `migration-scripts-1.0.0.jar`:

changes/
changes/changelog.xml
changes/sql/
changes/sql/00000000000000_initial_schema.xml

This time, when we run liquibase and specify the location of the changelog file we provide this url:

"jar:file:/app/libs/migration-scripts-1.0.0.jar!/changes/changelog.xml"

Now when we run liquibase against the same database, liquibase thinks this is a new changeset even though none of the actual content of the xml files (or their relative paths to each other) have changed. They are identical, yet, based on packaging or maybe the absolute path to the changelog liquibase thinks they are different changesets and tries to apply them again. In this case, the migration fails because the sequence already exists. But Liquibase should not have attempted to migrate the database because the content of the changelog is identical to how it was before it was packaged inside the jar file.

The checksum used by Liquibase to determine if a changeset has already been applied should be limited to using a hash code on the bytes of the changelog file (and associated files) rather than using the location of the changelog file.

Environment

docker, postgres, liquibase, spring boot

Status

Assignee

Unassigned

Reporter

Elliot Huntington

Labels

None

Affects versions

3.6.3

Priority

Major