Is it possible to classify Liquibase changesets - liquibase

I would like to classify Liquibase changesets like
"must run" (e.g. add column)
"can run" (e.g. change column size)
Is there a way to do something like that?
The reason to do this is that the execution of changesets should not stop if a changeset from class "can run" runs in a ValidationFailedException or something similar.
Thanks

You can mark your changesets with an attribute
failOnError
Example:
<changeSet id="changeset1" failOnError="true">
<!-- do important stuff here -->
</changeSet>
<changeSet id="changeset2" failOnError="false">
<!-- do not so important stuff here -->
</changeSet>

Related

How to pass property value dynamically to sql tag in liquibase changelog

I'm currently assigning a predefined property value to some tag's attributes, but I want to use it as well inside xml tags. Below is an example based on Liquibase documentation:
<?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.4.xsd"
>
<property name="schema.name" value="DBPECG"/>
<changeSet id="20201005103200-1" author="felipe.rudolfe" objectQuotingStrategy="QUOTE_ALL_OBJECTS">
<createTable schemaName="${schema.name}" tableName="TB_IES" >
.
.
.
</createTable>
</changeSet>
</databaseChangeLog>
And here is what I want to do. I want to use schema.name in a way such as this, inside sql tag:
<changeSet id="20201005103200-3" author="felipe.rudolfe" objectQuotingStrategy="LEGACY">
<sql>
ALTER TABLE ${schema.name}.TB_IES ADD CONSTRAINT...
</sql>
</changeSet>
Is there a way to do this?
Liquibase allows dynamic substitution of properties in changelog files. We can configure multiple properties inside a file and then use them wherever required. In your case, we can just configure property "schemaName" with some value and then use it in changelog file using ${schemaName} syntax.
Liquibase assigns or prioritizes value for configured property in below order:
As an attribute passed to your liquibase runner.
As a JVM sytem property
As an environment variable
As a CLI attribute if you are running liquibase through command line
In liquibase.properties file
In the parameters block (property element of the DATABASECHANGELOG
table)
You can do it as below example code snippet:
<?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.8.xsd">
<changeSet author="author" id="some-unique-id" context="some-context">
**Your SQL query/ transactional logic goes here**
<sql>
ALTER TABLE ${schemaName}.TB_IES ADD CONSTRAINT...
</sql>
</changeSet>
</databaseChangeLog>
In liquibase.properties file, I will configure this property as follows:
schemaName=DBPECG
Note: above example is using 1 property (schemaName). You can use only even more than that.
If you need help with creating "liquibase.properties" file, visit this link
Cheers!

How to execute a CustomSqlChange manually

I'm writing a CustomSqlChange for the first time and want to test the outcome by running it on my current database. Of course I could start up the application and execute all change sets via liquibase (including the one that executes my CustomSqlChange), but that takes a lot of time.
Is there a way to manually execute the java class implementing CustomSqlChange from my IDE (IntelliJ) as if it would be from liquibase? Could one maybe even debug that execution?
You can create a separate changelog file, where only your's custom change will be included. Point Liquibase to use it instead of base one. This will give you ability to debug it as well.
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog .....>
<changeSet id="custom-change" author="author" runOnChange="true" >
<customChange param="..." />
</changeSet>
</databaseChangeLog>

Handle sqlplus substitution variables (&&vars) in Liquibase

my project is trying to migrate to liquibase but the lack of support for bind variables is making this difficult.
During our deployment we have sql scripts containing sqlplus substitution variables, like for example.
-- load_seed.sql ---
insert into <table>
values('&&host', '&&port', '&&user');
The value of these variables is different per environment, therefore we define profiles like these.
<DEV_profile.sql>
DEFINE host='dev.company.org'
DEFINE port=4008
..
<UAT_profile.sql>
DEFINE host='uat.company.org'
...
and the we run the deployment like this:
./deploy.ksh DEV
---- deploy.ksh ---
sqlplus <<END
<connection>
#$1_profile
#load_seed
The correct profile is picked up at execution time and the variables replaced.
Could you please suggest how to handle a case like this with Liquibase?
The equivalent functionality in Liquibase is provided by changelog parameters.
In your changelog, you define parameters, which are basically key-value pairs, and liquibase decides which value to use based on the value of a context or a label or a dbms.
When you want to apply the changeset to a given environment, you specify the context or label on the command line or in the liquibase.properties. Liquibase can determine the dbms based on the connection URL.
Here's an example that is somewhat similar to what you describe:
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<property name="host" value="dev.company.org" context="DEV"/>
<property name="port" value="4008" context="DEV"/>
<property name="user" value="DEV_USER" context="DEV"/>
<property name="host" value="uat.company.org" context="UAT"/>
<property name="port" value="4321" context="UAT"/>
<property name="user" value="UAT_USER" context="UAT"/>
<changeSet id="1" author="joe">
<insert tableName="someTableName">
<column name="host" type="varchar(255)" value="${host}"/>
<column name="port" type="varchar(8)" value="${port}"/>
<column name="user" type="varchar(255)" value="${user}"/>
</insert>
</changeSet>
</databaseChangeLog>
https://docs.liquibase.com/concepts/basic/changelog-property-substitution.html
does not support sql changelog property substitution. you would have to migrate to (xml, yaml, json)

Referencing a sibling changeset in a rollback section

I'm having an issue trying to rollback a changeSet by referring sibling-changeset.
master-changelog.xml
includes v.1.changes.xml (here is the table created)
includes v.2.changes xml (here the table dropped and I would like to refer a changeset from v.1.changes.xml as a rollback)
However no matter how do I reference the changeset in v.1.changes.xml it's not visible to v.2.changes.xml and I'm getting liquibase.exception.SetupException: liquibase.parser.core.ParsedNodeException: Change set not found.
master-changelog.xml
<include file="v1/v1.changes.xml" relativeToChangelogFile="true"/>
<include file="v2/v2.changes.xml" relativeToChangelogFile="true"/>
v1.changes.xml
<changeSet id="1" author="dima">
<createTable tableName="test-table">
<column name="test" type="number"></column>
</createTable>
</changeSet>
v2.changes.xml
<changeSet id="1" author="dima">
<dropTable tableName="test"/>
<rollback changeSetAuthor="dima" changeSetId="1" changeSetPath="src/main/resources/std/v1/v1.changes.xml"/>
</changeSet>
It appears that you're using Maven, so this answer will be Maven specific, as I have not been able to reproduce the solution on the command line.
First of all, it's possible that Liquibase is confused because you're using the same changeSet id in both files, and I'm not sure if it correctly scopes those ids to the changeSet file, or if the ids need to be global. You might first try changing the id on the second changeSet and see if it clears it up for you.
If that's not the issue, then the trick to getting this to work is to make sure your relative references are all in the context of the Java classpath. As I interpret your example, the classpath resources of your files would be:
std/master-changelog.xml
std/v1/v1.changes.xml
std/v2/v2.changes.xml
When running your migration, your changeLogFile setting should reference the classpath resource, not the disk file; i.e. std/master-changelog.xml instead of src/main/resources/std/master-changelog.xml. This puts the origin changelog in a classpath context rather than a file context.
In your v2.changes.xml, you then refer to the first change using the classpath resource name: v1/v1.changes.xml. This should allow Liquibase to find it correctly.
If you have more than one level of changeLog file inclusion, you might be running into this issue which prevents Liquibase from finding sibling changeLogs below the first level of inclusion. Until the pull request is merged and released, you'll be limited to a single level of file inclusion.
This solution is assuming you're using the Maven plugin, liquibase will still find the changelog, since Maven puts your resource files on the classpath by default. I also attach the plugin to the process-resources step (or later) so that the source resources will be in the target/classes directory when the migration is run.

Liquibase: changeLogPropertyDefined doesn't work

I'm trying to execute one of two insert depending on value of Java system property 'type'. But when I run updateSQL, it generates both insert entries despite of value and even presence of variable 'type'. This are my change sets:
<!--changes for CS only-->
<changeSet id="57" author="mborodin">
<preConditions onFail="CONTINUE">
<changeLogPropertyDefined property="type" value="cs"/>
</preConditions>
<sql>INSERT INTO cs.config(key, value) values('autochecks.findProfilesInDb', 'true'),
('web.type', 'cs'), ('globalFailureDetectorEnabled', 'true');
</sql>
</changeSet>
<!--changes for LCS only-->
<changeSet id="58" author="mborodin">
<preConditions onFail="CONTINUE">
<and>
<changeLogPropertyDefined property="type" value="lcs"/>
<not>
<changeSetExecuted
id="57"
author="mborodin"
changeLogFile="${changeLogFile}"
/>
</not>
</and>
</preConditions>
<sql>INSERT INTO cs.config(key, value) values('autochecks.findProfilesInDb', 'false'),
('web.type', 'local-cs'), ('globalFailureDetectorEnabled', 'false');
</sql>
</changeSet>
What's wrong? Is there a better way to work it?
From the first nvoxland's answer at liquibase forum:
… we added the onSqlOutput tag. IGNORE just assumes that the
precondition cannot be applied, but you should continue to "run" the
changeLog. TEST means to actually run the precondition. FAIL mean to
stop the execution of the changelog, alerting you that you cannot run
in updateSql mode because a correct execution of the precondtion is
required to continue.
The problem has been solved by adding onSqlOutput="TEST" tag.