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.
Related
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>
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
I am trying to use PreConditions to skip CreateTable changesets and MARK_RAN if the table exists. The PreConditions seem to be ignored as Liquibase logs a table exists error as it tries to create an existing table in MYSQL (in AWS Aurora).
<?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.10.xsd">
<changeSet author="xxx" id="1231">
<preConditions onFail="MARK_RAN">
<not>
<tableExists tableName="tenant"/>
</not>
</preConditions>
<createTable tableName="tenant">
<column autoIncrement="true" name="tenantId" type="int(11)">
<constraints primaryKey="true" nullable="false"
unique="false" />
</column>
...
The changelogs are being applied using the following Java code:
final Database dataBase = DatabaseFactory.getInstance()
.findCorrectDatabaseImplementation(new JdbcConnection(connection));
final Liquibase liquiBase = new liquibase.Liquibase(CHANGE_LOG_FILE, RESOURCE_ACCESSOR, dataBase);
liquiBase.update(CONTEXTS, LABEL_EXPRESSION);
The error:
Response: {"errorMessage":"Failed to connect to Liquibase due to Migration failed for change set db.changelog-1.1.xml::1231::xxx:\n Reason: liquibase.exception.DatabaseException: Table 'tenant' already exists [Failed SQL: CREATE TABLE xxx_global.tenant (tenantId INT AUTO_INCREMENT NOT NULL, region VARCHAR(255) NULL, tenantName VARCHAR(255) NULL, CONSTRAINT PK_TENANT PRIMARY KEY (tenantId))]"}
My only other thought would be to try to use a custom context on the CreateTable changesets for clean installations
I found the issue and it was not a Liquibase issue. The AWS stack containing the Lambda code to call Liquibase was not updating. I deleted and recreated the stack and it started working.
The Problem
I recently upgraded Liquibase to 3.6.2 from 3.4.2.
Loading seed data from a CSV into text fields now results in a CLOB resource error. Before it would simply insert the text as a value.
The Setup
I'm using Liquibase to manage migrations of my data.
I have a table with an code and description column. description is of type TEXT.
<changeSet author="" id="create-table-degrees">
<createTable tableName="degrees">
<column name="code"
type="varchar(2)">
<constraints primaryKey="true"/>
</column>
<column name="description"
type="text">
<constraints unique="true"/>
</column>
</createTable>
<rollback>
<dropTable tableName="degrees"/>
</rollback>
</changeSet>
I have seed data in a CSV:
code,description
"D1","MASTERS"
"D2","DOCTORATE"
I load it using loadData:
<changeSet author="" id="seed-degrees">
<loadData file="seeds/degrees.csv"
tableName="degrees" />
</changeSet>
The Error
Unexpected error running Liquibase: CLOB resource not found: MASTERS
The Question
Is there a way to keep Liquibase from interpreting seed values as file paths instead of strings, or do I need to manually define the column types as String in loadData.
e.g. I would like to avoid having to modify the old changeSet to:
<changeSet author="" id="seed-degrees">
<loadData file="seeds/degrees.csv"
tableName="roles">
<column name="description" type="string" />
</loadData>
</changeSet>
The workaround listed in CORE-3287: Anver S December 3, 2018, 3:07 PM
While adding an explicit column type definition as defined in original
stackoverflow post
<column name="description" type="string" />
does the trick - for me it effectively requires to update already
applied changesets which ideally I'd try to avoid.
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>