Update an existing trigger into Liquibase - sql

I'm very new at Liquibase, and I need some help.
I have an existing trigger that was not capturing all the data; I made some changes to my local Oracle database. Now I need to add those changes into the Liquibase, but I'm lost how to do that.
I know you cannot breach the contract in liquibase by updating the original .xml file directly.
From my understanding, I need to create a new changelog .XML file and then include the path on the other post_migration file.
My confusion is, do I have to drop the original trigger, then create a new file or?
Thanks!

I never create triggers, procedures or even views within the XML file exactly because this makes things more complicated (I think).
I typically move the actual trigger definition into a SQL script (that I can also run separately during development and testing), then include that SQL file from within the Liquibase changelog:
<changeSet id="42" author="arthur" runOnChange="true">
<sqlFile path="triggers/some_trigger.sql"
stripComments="false"
splitStatements="true"
endDelimiter="/"
relativeToChangelogFile="true"/>
</changeSet>
The some_trigger.sql script is stored in git (svn, ...) together with the XML changelog. The runOnChange="true" is the "magical ingredient" here. You don't have to touch the XML file, you just edit the SQL script. During deployment, Liquibase will check if the (SQL) file has changed and run the script if needec.

So, I believe that you create/update/replace the SQL trigger in your local developer database and right now you want to include the liquibase script to the release distribution package of your product.
The liquibase doesn't provide special xml syntax to create triggers, so you will just add a new changeset that holds your pl/sql script inside the <SQL> tag. The script will be the same that you run on your local database.
The example code here:
<changeSet id="1" author="me">
<sql endDelimiter="/">
CREATE OR REPLACE TRIGGER trigger_name before insert
on table1_name for each row
BEGIN
select seq_myseq.nextval
into :new.myid
from dual;
END;
/
</sql>
</changeSet>
This code just compile trigger in the aimed database when you call liquibase update. In most cases, it is enough. But I strictly recommend you to ask your DBA or team led for rules that your team enforced for writing liquibase scripts. For this reason, the result may be much more complicated.

Related

How to rollback multiple databaseChangeLog file at once

I perform a liquibase update command with a given ChangeLog XML file and tag it with tag1.
For example:
liquibase --driver=org.postgresql.Driver --url=... --changeLogFile=change1.xml update
liquibase --driver=org.postgresql.Driver --url=... --tag tag1
I then perform several additional updates commands with other ChangeLog XML files:
liquibase --driver=org.postgresql.Driver --url=... --changeLogFile=change2.xml update
liquibase --driver=org.postgresql.Driver --url=... --changeLogFile=change3.xml update
Now I would like to rollback to tag1:
liquibase --driver=org.postgresql.Driver --url=... --changeLogFile=??? rollback tag1
Which file should I specify in --ChangeLogFile? Is there a way to define multiple files? Is there a way Liquibase can store embed the rollback commands without the need to supply the update XMLs?
Rather than using multiple changelog files from the command line, typical usage is to just have one changelog file that is used for the whole application. It is possible to have multiple changelogs, but in that pattern you have a single 'master' changelog that then includes other changelogs. see https://www.liquibase.org/bestpractices.html for some examples of this.
When rolling back, liquibase needs to know what the actual changes are, so it can then do something else to do the rollback. The DATABASECHANGELOG table does not store the actual contents of each changeset that has been applied, it just keeps the id, author, filepath, and a checksum. It has no way of knowing that changeset id 123778 by steve in file changelog.xml was a create table or an alter column or anything. So the changelog file MUST be there to be able to roll things back.
For certain change types like 'create table', Liquibase can 'automatically' generate a rollback for you - it is just 'drop table'. But if the change was something like 'drop table', it cannot generate a rollback - drop table command only has the name of the table to drop, and doesn't know what columns were in that table, etc.
So that is why Liquibase requires that you always supply a changelog file, and if you want to be able to do rollbacks, you may also need to specify how to roll back each change.

execute parameterized liquibase changeset multiple times with different parameters

I have been struggling with a liquibase challenge for some time and I hope somebody here can help me:
I would like to execute a simple parameterized liquibase script multiple times on the same db schema with different parameters:
<changeSet id="1" author="me" dbms="Oracle" runOnChange="false" failOnError="true">
<sql splitStatements="true">
GRANT SELECT on SOME_VIEW to ${db_user};
</sql>
</changeSet>
Now I execute liquibase one time with -Ddb_user=first_user and than with -Ddb_user=second_user. The second run fails, because liquibase calculates the checkSum after replacing the ${db_user} parameter (what makes perfect sense) and therefore the combination of id/author/filename and checkSum is already present in the DATABASECHANGELOG table.
Is there a best practice way to solve this problem?
Thanks in advance.
There is a runOnChange as an attribute for the changeSet which will run your changeset each time it was changed. Maybe this does what you are looking for?
You can always use runOnChange=true or <validCheckSum>any</validCheckSum>
There is an issue that explains this decision here: https://liquibase.jira.com/browse/CORE-2506

tagDatabase in Formatted SQL changeset

I'm trying to tag a Formatted SQL changeset so a matching ID and tag are written to the DATABASECHANGELOG table (for rollback purposes - see changeset fragment below). The Phing liquibase task is being used to apply the 'update' command for a single changelog.
Although the 'tagDatabase' attribute isn't listed for Formatted SQL changelogs (http://www.liquibase.org/documentation/sql_format.html), neither is logicalFilePath, and that seems to be working OK!
Can someone let me know definitively if tagDatabase is not supported for a Formatted SQL changeset?
Many thanks in advance,
IR8
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
--changeset id:123 logicalFilePath:path-independent
ALTER TABLE test1
ADD COLUMN text_column
text NULL;
--rollback ALTER TABLE test1 DROP COLUMN text_column;
--changeset id:tag123 tagDatabase:123;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Unexpected error running Liquibase: No SQL for changeset ../db/changelog/databaseChangeLog.sql::tag123::id
Execution of target "migrate" failed for the following reason: C:\data\htdocs\TestLiquibase\deploy\build.xml:49:1: Liquibase exited with code -1
I think it's not included.
The java class FormattedSqlChangeLogParser takes care of parsing the formatted sql file and has a couple of Patterns defined for this. There is a logicalFilePathPattern but nothing for tagDatabase.
So this is not implemented yet.
From the official document,
When you run the updateToTag command or the Maven update goal with the liquibase.toTag attribute, and there is a row in the DATABASECHANGELOG table corresponding to the tagDatabase changeset in the changelog, the updateToTag command or the update Maven goal deploys all changesets starting with the first changeset at the top of the changelog file and moving down to the changeset up to the tag specified by the tagDatabase Change Type.
We can do one thing that is, after you executing all the SQL format changesets, we can create a new database tag changeset and update with liquibase
<?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-4.3.xsd">
<changeSet author="sivaramr" id="7">
<tagDatabase tag="v_1.0.0"/>
</changeSet>
</databaseChangeLog>
If you are using any liquibase command tool or liquibase plugins, then you can perform tag command to add the tag to the last changelog as follow
Here It is illustrated with gradle plugin.
./gradlew tag -PliquibaseCommandValue=v1.0.0
Before executing the above tag command, you can check the tag is already exist or not by tagexists command
./gradlew tagExists -PliquibaseCommandValue=v1.0.0

Run rollback when checksum is changed for changeset in Liquibase

I see an attribute runOnChange that re-runs changeset when it is changed. But is it possible to apply a rollback for this changeset before re-applying automatically?
For example, I have a script that is called from changeset. I made some changes there and want to re-apply, but before it rollback need to be called and after it new version of the script should be applied.
Thank you!
There is no feature to automatically roll back a changeSet on checksum change. Not sure if it is possible in general because if the configuration has changed you don't know what the old value was to roll back.
Depending on what you are doing in your script and your database, can roll back the changes manually in the script and use the liquibase runOnChange="true" changeSet flag.
For example, if you have a script that creates a stored procedure, you could use <changeSet runOnChange="true"> and then define your procedure as "CREATE OR REPLACE"
If you have a script that defines a view, you could add a <sql>IF EXISTS VIEW_NAME DROP VIEW VIEW_NAME</sql>

Liquibase: Convert createTable changeSet entry to DDL SQL statement

I'd like to use JDBC to create tables in a database agnostic way. I'm pretty sure that Liquibase has solved this problem since it can take a generic createTable XML changeSet element and convert it into a database specific SQL DDL statement.
Can someone please tell me which liquibase classes / utililities are involved in converting a generic createTable changeSet into a database specific create table SQL script?. Sample usage (ie a test case) would be great.
Please note that I do not wish to invoke the entire liquibase pipeline. In particular I do NOT want the databasechangelog table.
I'd recommend reading the liquibase unit tests.