Liquibase changelog parameters in liquibase.properties - liquibase

As per documentation parameter values are looked up in the following order:
Passed as a parameter to your Liquibase runner (see Ant, command_line, etc. documentation for how to pass them)
As a JVM system property
In the parameters block ( Tag) of the DatabaseChangeLog file itself.
Can I set these parameters in the standard properties file?

It is possible to put changelog parameters in liquibase.properties, or a custom --defaultsFile. Reading the source indicates that you must prefix the properties with "parameter.".
Your error probably looks something like this:
SEVERE 11/4/16 10:26 AM: liquibase: Unknown parameter: 'read_only_user'
liquibase.exception.CommandLineParsingException: Unknown parameter: 'read_only_user'
at liquibase.integration.commandline.Main.parsePropertiesFile(Main.java:453)
Example liquibase.properties:
driver=oracle.jdbc.driver.OracleDriver
url="jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dbhost)(PORT=1600))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=devdb)))"
username=scott
password=tiger
defaultSchemaName=app_admin
promptOnNonLocalDatabase=false
parameter.read_only_user=app_read
Using the parameter in a changeset:
<changeset author="Ryan" id="1">
<sql>GRANT SELECT ON APP.SOME_TABLE TO ${read_only_user}</sql>
</changeset>

Yes, and is very usefull if you want to manage information under control...like passwords in differents enviroments:
liquibase.properties:
parameter.pass_admin=idonthavepassword
and the changelog:
<changeSet author="rbs" id="create_user_admin" labels="inicial">
<preConditions onFail="CONTINUE">
<sqlCheck expectedResult="0">SELECT COUNT(1) FROM pg_roles WHERE rolname='admin'</sqlCheck>
</preConditions>
<sql>CREATE USER admin PASSWORD '${pass_admin}' LOGIN SUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOREPLICATION CONNECTION LIMIT -1
<comment>Creating admin user</comment>
</sql>
</changeSet>

Yes, it is possible: http://www.liquibase.org/documentation/liquibase.properties.html.
And use --defaultsFile to pass property file.

Related

Add new column via liquibase only if not already exists

I want to use liquibase on spring boot startup to add a new column to an existing table.
But in the particular schema I'm working with I have already added it manually.
So I get an error on startup indicating the column already exists (because it does):
Error creating bean with name 'liquibase' defined in class path resource
[...LiquibaseConfiguration.class]: LiquibaseException:
liquibase.exception.MigrationFailedException: Migration failed for
change set db/changelog/AlterTable_MyTable_AddNewCol.xml::1::me (manual):
Reason: liquibase.exception.DatabaseException:
Duplicate column name 'new_col' [Failed SQL: (1060)
ALTER TABLE my_schema.my_table ADD new_col INT NULL]
Is there a liquibase precondition option to add the column only if it does not already exist; and if it already exists, don't error out?
I tried the following and the process errors out with the above error:
<databaseChangeLog ... >
<changeSet author="me (manual)" id="1">
<preConditions onFail="WARN">
<columnExists tableName="my_table" columnName="new_col" />
</preConditions>
<addColumn tableName="my_table">
<column name="new_col" type="integer"/>
</addColumn>
</changeSet>
</databaseChangeLog>

Condition in creating view - liquibase xml

I want to make some view but with condition in my fourth column.
CONDITION:
If epr.j_id is not null then fill lj.id BUT WHEN epr.j_id is null then fill 'NONE'
I've found some condition tag there but I have no idea how I can use it or maybe there is some another way...
<changeSet id="103" author="m">
<createView replaceIfExists="true"
schemaName="public"
viewName="report">
SELECT DISTINCT l.id,
l.name,
l.gis_ext_id AS gis_ext_id_line,
condition (epr.j_id is not null ),
From a previous StackOverflow question: How to add condition to changeSet
If you want to update the columns datatype depending on certain conditions, you can use <preConditions> with <sqlCheck>, and then use <modifyDataType>.
So supposing that there's already a table with name TASK and it contains a column named STATUS, you can modify it's datatype as such:
<changeSet id="1" author="xxx">
<comment>Update Asset table</comment>
<preConditions onFail="MARK_RAN">
<and>
<columnExists tableName="TASK" columnName="STATUS"/>
<sqlCheck expectedResult="0"> SELECT COUNT(*) FROM TASK WHERE STATUS = "pending";</sqlCheck>
</and>
</preConditions>
<modifyDataType tableName="TASK" columnName="STATUS" newDataType="VARCHAR(10)"/>
</changeSet>
Or perhaps you'd like another onFail-behaviour. Check out this link
HALT - Immediately halt execution of entire change log [default]
CONTINUE - Skip over change set. Execution of change set will be attempted again on the next update. Continue with change log.
MARK_RAN - Skip over change set, but mark it as ran. Continue with change log
WARN - Output warning and continue executing change set as normal.
Additional Documentation:
Liquibase: Create View
Mohit Goyal: Check database state and conditionally apply changes in the Liquibase

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!

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.

Is it possible to classify Liquibase changesets

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>