I need to add changeSet with only preConditions tag and if it failed then stop execute. This is my changeset:
<?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.3.xsd">
<changeSet id="GEO-6154_2" author="kadzhaev">
<preConditions onFail="HALT">
<sqlCheck expectedResult="0">select count(*) from "public"."messages" where key = 'branding.region.oktmo' and value != '';</sqlCheck>
</preConditions>
</changeSet>
</databaseChangeLog>
but it doesn't work cause:
liquibase: cvc-complex-type.2.4.a: Invalid content was found starting with element 'preConditions'. I think I should add some tag after preConditions but I do not need it. How to solve this problem?
Related
I have a change log file,part of which looks like:
<include file="ChangeSets/00_SessionAuth.xml"/>
<include file="ChangeSets/01_Legacy_Baseline_V197_ANB.xml" context="legacy"/>
<include file="ChangeSets/02_V198_ANB.xml" context="non-legacy"/>
The change set 01_Legacy_Baseline_V197_ANB.xml has 197 sql scripts included,which are part of legacy database.
The change set 02_V198_ANB.xml is defined as:
<?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"
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.5.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<include file="ChangeSets/sql/Dummy_schema/V198_AddColumn.sql"/>
</databaseChangeLog>
When i run the Liquibase update with context as non legacy, i get the following error :
Unexpected error running Liquibase: DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=SET SCEHMA = Dummy_schema;;BEGIN-OF-STATEMENT;<space>, DRIVER=3.62.56 [Failed SQL: SET SCEHMA = Dummy_schema;
The SQL file itself is correct.
I think this is an issue related to end delimiter or splitStatements.
The SQL goes like this:
SET SCEHMA = Dummy_schema;
ALTER TABLE T1 ADD COLUMN C1 VARCHAR(35)
ADD COLUMN C2 INTEGER;
Call Sysproc.admin_cmd ('REORG TABLE dummy_schema.T1');
ALTER TABLE T2 ADD COLUMN CT1 INTEGER;
Call Sysproc.admin_cmd ('REORG TABLE dummy_schema.T2');
We are using DB2 V10.5.
Can someone also provide the list of attributes,we can use with tag.
Regards
I think your assertion that
the SQL file itself is correct
is incorrect. That is valid SQL if it was run through the db2 command line application, but it is not valid SQL to be sent through a JDBC query, which is what Liquibase does.
Is it possible to create two preconditons for single elements of a changeset? Like generating a column if the changelog file is run at a SQL Server database and generating another column if the changelog file is run at an Oracle database. In a way like this for example:
<changeSet author="Me" id="1528876614155">
<createTable tableName="ELECTRICITY_PRODUCTS">
<preConditions onFail="MARK_RAN" onSqlOutput="TEST">
<dbms type="mssql" />
<column autoIncrement="true" name="EP_ID" type="NUMBER">
</preConditions>
<preConditions onFail="MARK_RAN" onSqlOutput="TEST">
<dbms type="oracle" />
<column autoIncrement="false" name="EP_ID" type="FLOAT">
</preConditions>
</createTable>
</changeset>
It's not possible to create column inside condition.
If I understand your problem, then you have two (maybe more) options:
Separte the changeSets for each dbms
Create property for dbms and use them like:
<property dbms="oracle" name="autoincrement" value="true" />
<property dbms="oracle" name="autoincrementType" value="NUMBER" />
<property dbms="mssql" name="autoincrement" value="false" />
<property dbms="mssql" name="autoincrementType" value="FLOAT" />
<changeSet id="create_a_table" author="system">
<createTable tableName="a_table">
<column name="a_column" autoIncrement="${autoincrement}" type="${autoincrementType}" />
</createTable>
</changeSet>
I didn't tested that, it's just idea how to solve the problem.
This seems to be not possible but another good solution is to create changesets for these single elements. In this example it could be:
<changeSet author="Me" id="1528876614155">
<createTable tableName="DAILY DATA">
<column name="ID" type="NUMBER"/>
</createTable>
</changeset>
<changeSet author="Me" id="1528876614156">
<preConditions onFail="MARK_RAN" onSqlOutput="TEST">
<dbms type="oracle" />
</preConditions>
<addColumn tableName="DAILY_DATA">
<column name="VALUE" type="NUMBER"/>
</addColumn>
</changeset>
<changeSet author="Me" id="1528876614157">
<preConditions onFail="MARK_RAN" onSqlOutput="TEST">
<dbms type="mssql" />
</preConditions>
<addColumn tableName="DAILY_DATA">
<column name="VALUE" type="NUMBER"/>
</addColumn>
</changeset>
I understand dropwizard expects all DB migrations to be in migrations.xml.
Let's say I'm starting a new project and create my tables:
<changeSet id="1" author="codahale">
<createTable tableName="people">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="fullname" type="varchar(255)">
<constraints nullable="false"/>
</column>
<column name="jobtitle" type="varchar(255)"/>
</createTable>
</changeSet>
At the next iteration I have to add a new column so I ad another changeSet to migrations.xml:
<changeSet id="2" author="dbdemopostgres">
<addColumn tableName="people">
<column name="description" type="varchar(255)">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
Then let's say I have to make a column longer so I add:
<changeSet id="3" author="dbdemopostgres">
<modifyDataType tableName="people" columnName="description" newDataType="varchar(300)"/>
</changeSet>
And so it goes. I keep appending all changes to my migrations.xml which grows indefinitely. On a large project it's just a matter of time when it becomes unmanagable. Does anyone has any recommendations for strategy to maintain ongoing database changes?
You can divide your migrations.xml file to multiple files as documented here apparently.
<?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.1.xsd">
<include file="com/example/db/changelog/db.changelog-1.0.xml"/>
<include file="com/example/db/changelog/db.changelog-1.1.xml"/>
<include file="com/example/db/changelog/db.changelog-2.0.xml"/>
</databaseChangeLog>
I'm wondering if there is an easy way to create liquibase precondition checking if particular value is NULL or NOT NULL. My approach doesn't work.
I created the following test changeset:
<?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.1.xsd">
<changeSet id="1" author="test">
<createTable tableName="test_table">
<column name="id" type="int">
<constraints primaryKey="true" nullable="false" />
</column>
<column name="test_text" type="varchar(50)">
<constraints nullable="true" />
</column>
</createTable>
</changeSet>
<changeSet id="2" author="test">
<insert tableName="test_table">
<column name="id" value="1" />
<column name="test_text" value="test1" />
</insert>
<insert tableName="test_table">
<column name="id" value="2" />
<column name="test_text" value="null" />
</insert>
</changeSet>
<changeSet id="3" author="test">
<preConditions onFail="HALT">
<sqlCheck expectedResult="test1">select test_text from test_table where id=1</sqlCheck>
</preConditions>
<insert tableName="test_table">
<column name="id" value="3" />
<column name="test_text" value="foo" />
</insert>
</changeSet>
<changeSet id="4" author="test">
<preConditions onFail="HALT">
<sqlCheck expectedResult="NULL">select test_text from test_table where id=2</sqlCheck>
</preConditions>
<insert tableName="test_table">
<column name="id" value="4" />
<column name="test_text" value="bar" />
</insert>
</changeSet>
</databaseChangeLog>
Everything works fine except the changeset 4, which is failing with surprising error message "No rows returned from SQL Precondition". However the data is there:
$ psql -U test -c 'select * from test_table'
id | test_text
----+-----------
1 | test1
2 |
3 | foo
(3 rows)
It seems the result is interpreted as empty. In fact it returns one row with one column containing NULL value. Any ideas how to make this working?
I'm using Liquibase 3.3.5 with PostgreSQL 9.3 on Ubuntu 14.04.
Here is the full output (info level):
$ ./liquibase --driver=org.postgresql.Driver --url="jdbc:postgresql://localhost:5432/test" --username=test --password="" --changeLogFile=/tmp/test.changeset.xml --logLevel=info update
Liquibase Home is not set.
INFO 02.06.15 09:57: liquibase: Successfully acquired change log lock
INFO 02.06.15 09:57: liquibase: Creating database history table with name: public.databasechangelog
INFO 02.06.15 09:57: liquibase: Reading from public.databasechangelog
INFO 02.06.15 09:57: liquibase: /tmp/test.changeset.xml: /tmp/test.changeset.xml::1::test: Table test_table created
INFO 02.06.15 09:57: liquibase: /tmp/test.changeset.xml: /tmp/test.changeset.xml::1::test: ChangeSet /tmp/test.changeset.xml::1::test ran successfully in 15ms
INFO 02.06.15 09:57: liquibase: /tmp/test.changeset.xml: /tmp/test.changeset.xml::2::test: New row inserted into test_table
INFO 02.06.15 09:57: liquibase: /tmp/test.changeset.xml: /tmp/test.changeset.xml::2::test: New row inserted into test_table
INFO 02.06.15 09:57: liquibase: /tmp/test.changeset.xml: /tmp/test.changeset.xml::2::test: ChangeSet /tmp/test.changeset.xml::2::test ran successfully in 10ms
INFO 02.06.15 09:57: liquibase: /tmp/test.changeset.xml: /tmp/test.changeset.xml::3::test: New row inserted into test_table
INFO 02.06.15 09:57: liquibase: /tmp/test.changeset.xml: /tmp/test.changeset.xml::3::test: ChangeSet /tmp/test.changeset.xml::3::test ran successfully in 3ms
SEVERE 02.06.15 09:57: liquibase: /tmp/test.changeset.xml: /tmp/test.changeset.xml::4::test: Change Set /tmp/test.changeset.xml::4::test failed. Error: Migration failed for change set /tmp/test.changeset.xml::4::test:
Reason:
/tmp/test.changeset.xml : No rows returned from SQL Precondition
liquibase.exception.MigrationFailedException: Migration failed for change set /tmp/test.changeset.xml::4::test:
Reason:
/tmp/test.changeset.xml : No rows returned from SQL Precondition
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:485)
at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:43)
at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:73)
at liquibase.Liquibase.update(Liquibase.java:200)
at liquibase.integration.commandline.Main.doMigration(Main.java:1044)
at liquibase.integration.commandline.Main.run(Main.java:175)
at liquibase.integration.commandline.Main.main(Main.java:94)
Caused by: liquibase.exception.PreconditionFailedException: Preconditions Failed
at liquibase.precondition.core.AndPrecondition.check(AndPrecondition.java:51)
at liquibase.precondition.core.PreconditionContainer.check(PreconditionContainer.java:201)
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:471)
... 6 more
INFO 02.06.15 09:57: liquibase: /tmp/test.changeset.xml::4::test: Successfully released change log lock
Unexpected error running Liquibase: Preconditions Failed
SEVERE 02.06.15 09:57: liquibase: /tmp/test.changeset.xml::4::test: Preconditions Failed
liquibase.exception.MigrationFailedException: Migration failed for change set /tmp/test.changeset.xml::4::test:
Reason:
/tmp/test.changeset.xml : No rows returned from SQL Precondition
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:485)
at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:43)
at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:73)
at liquibase.Liquibase.update(Liquibase.java:200)
at liquibase.integration.commandline.Main.doMigration(Main.java:1044)
at liquibase.integration.commandline.Main.run(Main.java:175)
at liquibase.integration.commandline.Main.main(Main.java:94)
Caused by: liquibase.exception.PreconditionFailedException: Preconditions Failed
at liquibase.precondition.core.AndPrecondition.check(AndPrecondition.java:51)
at liquibase.precondition.core.PreconditionContainer.check(PreconditionContainer.java:201)
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:471)
... 6 more
Might not be the most simple or elegant way but you could use a <customPrecondition>.
You would write your own class that has to implement CustomPrecondition.
Checkout this example class: ExampleCustomPrecondition as a reference.
You get a Database object at hand and could do a query to the database yourself and throw a CustomPreconditionFailedException.
(Alternatively create a Jira-Ticket to file a request for changing this behavior or adding a way to achieve the null preCondition check.)
This workaround might work
<sqlCheck expectedResult="1">select COUNT(id) from test_table where id=2 AND test_text IS NULL</sqlCheck>
I have a trigger written like below
create or replace trigger departments_bi before insert on departments_test
for each row
when (new.id is null)
begin
select departments_seq.nextval into :new.id from dual;
end;
/
I am referring to this trigger inside a changeset xml using sqlfile
<?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.1.xsd">
<changeSet author="raghav" id="004" runOnChange="true">
<sqlFile dbms="oracle"
encoding="ASCII"
endDelimiter="\n"
path="Triggers.sql"
relativeToChangelogFile="true"
splitStatements="false"
stripComments="false"/>
<rollback>
drop trigger departments_bi
</rollback>
</changeSet>
</databaseChangeLog>
Using Ant UpdateDatabase command am generating a SQL File with all the changes. Am also using exec task to execute the generated SQL with all changes against a target DB.
<updateDatabase
changeLogFile="${checkout}/Trigger.xml"
driver="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#${machineId}:${targetDB_Port}:${targetDB}"
username="${targetDB_User}"
password="${targetDB_Password}"
classpathref="classpath"
outputFile="${env1.WORKSPACE}/Update_MNT.sql"
/>
<echo message="Beginning to execute Update_MNT.sql to target DB ${targetDB} using username ${targetDB_user}"/>
<exec dir="${env1.WORKSPACE}" executable="sqlplus" failonerror="true">
<arg value="${targetDB_User}/${targetDB_Password}#${tnstargetDB}"/>
<arg value="#Update_MNT.sql"/>
</exec>
The problem am having is with the generated SQL file. Its including the contents of the Trigger.sql file with an extra ; at the end .. So while executing the Update_MNT.sql using exec command. The sqlplus fails because of the additional ; after / in the generated SQL file. How to resolve this issue?
-- Changeset E:/Jenkins_Liquibase_Test/Triggers.xml::004::raghav
create or replace trigger departments_bi before insert on departments_test
for each row
when (new.id is null)
begin
select departments_seq.nextval into :new.id from dual;
end;
/;
There are currently some issues with endDelimiter, formatted SQL changeset and updateSQL command:
CORE-1097,
CORE-1877,
CORE-2199.