Rollback to previous changeset

the feature implemented to rollback to a different/previous changeset is working only if the referenced changeset and the changelog are present in the same folder level, is there a way that we can overcome this?

I need that rollback changeset and changelog to be present in a different folder. I use SQL formatted changelogs.

–rollback changeSetId:create-table-demo changeSetAuthor:atzawada changeSetPath:src/main/resources/testCreate.sql

@atzawada can you help me with this please, if you can?
my rollback changeset and changelog are in a different folder or a sub directory to the actual changeset where the rollback is referenced from.

I got it to work, whether the changsets were in the same file, or in different files.

Here’s my “different files” example:

db-changelog1.sql:

--liquibase formatted sql

--changeset BOB:create_functionv1 endDelimiter:/ runOnChange:true
    create or replace function test_func return date is
      v_dummy1 date;
    begin
      select sysdate into v_dummy1 from dual;
      return v_dummy1;
    end test_func;
    /  

--rollback drop function test_func;

db-changelog2.sql:

--liquibase formatted sql

--changeset BOB:create_functionv2 endDelimiter:/ runOnChange:true
    create or replace function test_func return date is
      v_dummy1 date;
    begin
      select sysdate-1 into v_dummy1 from dual;
      return v_dummy1;
    end test_func;
    /  

--rollback changeSetId:create_functionv1 changeSetAuthor:BOB changeSetPath:db-changelog1.sql

Both files are in the same folder.

Thank you @daryldoak , but I want it to be in a different folder not the same folder. Is that not possible?

I did not test that.

I’d try using a relative path to the current file.

Tried that, but it does not seem to be working. I will look if I can find a work around for it. Having rollback script in the same folder will make our repository messy.

I got it to work in different folders.

The file reference in changeSetPath is relative to the root directory.

I put the changelog2.sql into a folder, but left the changeSetPath the same, and it worked.

Thank you @daryldoak let me try try that

1 Like

Hey @daryldoak , I can’t seem to get it work. I tried all possible ways, It seems to work only when both changelogs are in the same folder level. Could you please show me how you did it?

db-changelog-master.xml:

  <include file="folder1/db-changelog1.sql"  relativeToChangelogFile="true"/>
  <include file="folder2/db-changelog2.sql"  relativeToChangelogFile="true"/>

folder1/db-changelog1.sql:

--liquibase formatted sql

--changeset BOB:create_functionv1 endDelimiter:/ runOnChange:true
    create or replace function test_func return date is
      v_dummy1 date;
    begin
      select sysdate into v_dummy1 from dual;
      return v_dummy1;
    end test_func;
    /  

--rollback drop function test_func;

folder2/db-changelog2.sql:

--liquibase formatted sql

--changeset BOB:create_functionv2 endDelimiter:/ runOnChange:true
    create or replace function test_func return date is
      v_dummy1 date;
    begin
      select sysdate-1 into v_dummy1 from dual;
      return v_dummy1;
    end test_func;
    /  

--rollback changeSetId:create_functionv1 changeSetAuthor:BOB changeSetPath:folder1/db-changelog1.sql

Thanks @daryldoak , I found what I was doing wrong:

This is how my master-changelog looked earlier:

  <include file="folder2/db-changelog2.sql"  relativeToChangelogFile="true"/>
  <include file="folder1/db-changelog1.sql"  relativeToChangelogFile="true"/>

The mistake I did was the file I was referring in the changSetPath was placed after the original changelog. which kept throwing the changeset not found error.

Changing my Changelog.xml to below, resolved the error:

  <include file="folder1/db-changelog1.sql"  relativeToChangelogFile="true"/>
 <include file="folder2/db-changelog2.sql"  relativeToChangelogFile="true"/>
1 Like

If I am creating a new function I can add --rollback DROP FUNCTION function_name. After this I make a change to the function and update. But now I want to revert it to first version. And I am changing just this function. In this case how does this work?
In fact, in your example wouldn’t the second changeset create_functionv2 overwrite the test_func created by create_functionv1?

I see Liquibase deployments as going either forward (normal execution) or backwards (rollback execution).

It depends on what you mean by “revert”. I assume you mean go backwards. So in my example you would rollback-count 1 to revert to v1 of test_func.

From my experience with hundreds of developers using Liquibase is that most people only think about going forwards, so they would probably add a new changeset after create_functionv2 which installs v1 of test_func again, instead of using rollback. And that may be appropriate, depending on the situation.

Revert=rollback
I came across another post that confused me about best practices for handling stored logic in Liquibase. Specifically, in this discussion (How do I manage rolling back changes made to "rerunnable" (runOnChange=true) changelogs that contain stored logic?), you seem to suggest avoiding runOnChange:true for stored logic.

However, my understanding was that runOnChange:true allows us to maintain a single SQL file for stored logic without needing to create multiple files for each change.

Could you clarify your recommendation? When is it appropriate to use runOnChange:true, and what is the best practice for managing changes and rollbacks with stored logic?

I was answering a specific question about rolling-back to a prior version of code. There are two perfectly valid options for managing stored code, each with pros and cons:

  1. Use runOnChange:true, and maintain the code in the same changeset.
    pros: easy to implement, no replication of code in changelogs over time
    cons: not possible to rollback to prior version

  2. Don’t use runOnChange:true, add a new changeset for every code change.
    pros: easy rollback to prior code version
    cons: replicated code in changelogs over time.

You need to decide which is best for you.

1 Like

Let me understand second option first.
So, in case of stored logic if I decide not to use runOnChange=true does “add a new changeset for every code change” mean separate .sql file (assume a lenghty stored procedure) each time I need to change the stored procedure logic?

Separate files are not required, you can add a new changeset to an existing file.

Considering a very lengthy stored procedure and on top of that multiple changes over a period of time I can see this one file growing very fast in number of lines. Would you still suggest single file?

I’m just telling you what is possible. Your mileage may vary.

I would likely use separate files for large code.

Thank you for your guidance. If I understand correctly, if I would like to use inline “–rollback changeSetId:xxx changeSetAuthor:yyy changeSetPath:aaa/bbb.sql” approach for rollback I should not use runOnChange=true in the changeset and for large code use separate files for each change or append the changset to the same file.
If this is correct I think the example given above may need to be corrected by removing runOnChange=true.

1 Like