Liquibase Type Mapping MySQL & SQL Server - liquibase

From command line I let liquibase run in the version 4.19.0.
liquibase --changeLogFile=update.xml update
where update.xml is a bundle of changelogs:
<databaseChangeLog ...
<include file="changelog_1.xml" relativeToChangelogFile="true"/>
<include file="changelog_2.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
The first run ends with an error:
Unexpected error running Liquibase: Data type definition contains unparseable embedded information: ${dbtype.varchar}(20)
So far as I understand the ${dbtype.varchar} comes from my company and in Java code I see a replacement.
My question is for MySQL ${dbtype.varchar} should be replaced with VARCHAR and for SQL Server with nvarchar.
Is there an easy way to tell liquibase to replace this placeholder with MySQL values?
In the liquibase.properties I tell liquibase that it should be done for MySQL.
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
classpath: /home/markus/drivers/mysql-connector-java-5.1.49.jar
EDIT:
I found inside the Liquibase documentation how I can do it with properties from outside.
liquibase --changeLogFile=batch_changelogs.xml update -Ddbtype.bigint=BIGINT -Ddbtype.ubigint='BIGINT UNSIGNED'
It's not exaclty what I'm looking for but at the momement is comfortable to use.
Thanks,
Markus

Finally I found it inside the documentation
In liquibase.properties I can add with the parameter.
parameter.dbtype.bigint=BIGINT
parameter.dbtype.ubigint='BIGINT UNSIGNED'
Solved for MySql. For MSSQL I will generate a new property file and change by exeuction.

Related

Liquibase equivalent of beforeEachMigrate in Flyway

I am trying to find the Flyway's beforeEachMigrate equivalent functionality in liquibase. Does liquibase have a way to execute an SQL script before each new migration script is executed?
My current liquibase structure looks like follows.
application.properties file
spring.liquibase.change-log=classpath:db/changelog/changelog-master.yaml
changelog-master.yaml file
databaseChangeLog:
- include:
file: db/changelog/1-initial-schema.sql
- include:
file: db/changelog/2-schema-update.sql
create something like db/changelog/00-init.sql
and put there something like
<changeSet id="1" author="you" runAlways="true">
<sql>...or whatever change</sql>
</changeSet>
note: use runAlways
EDIT: I'm looking into beforeEachMigrate and it executes change before each let's say changeSet. There is no equivalent for that in liquibase so far.
Adding onto what #bilak said, you can also set the parameter using runOrder in addition to runAlways.
Documentation: To always run a changeset before OR after an update - runAlways/runOrder - https://docs.liquibase.com/concepts/changelogs/changelog-formats.html

can't get liquibase executeCommand changeset to do anything

From the liquibase docs, it looks like an executeCommand changeset should just shell out and execute the given command (e.g., mysqldump). But if I specify some changeset like
<changeSet author="me" id="test">
<executeCommand executable="date" />
</changeSet>
then all I get is this error message
2016-07-20 10:02:43,675 ERROR [main] liquibase
even though the changeset gets marked as EXECUTED in the db.
Even if I specify some different executable like a tiny test shell script, it doesn't look like it actually gets executed.
Is there anything else that I need to specify in the changeset, or do I have some incorrect expectation about how an executeCommand changeset should work?

Using Liquibase contexts to conditionally activate/deactivate a change set

We have changeset one:
--changeset change_one runOnChange:true
And changeset two:
--changeset change_two runOnChange:true context:kansas
change_one applies to all our installations but change_two only applies to our "kansas" installation. We want to ensure that change_two is executed whenever change_one is changed - how can we do this?
change_one has runOnChange:true so it will run whenever changed. But how can we ensure change_two runs when change_one executes - but only when we pass context:kansas?
When you run Liquibase without specifying any contexts, you might expect that no contexts should be activated, but in fact it works as documented in that ALL contexts will be activated. If you use contexts in your change logs to disable change sets, you will have to set a contexts parameter whenever you execute Liquibase. e.g.
mvn process-resources liquibase:update -Dliquibase.contexts=production
You should also check into the labels feature added in Liquibase 3.3. The difference is that the caller can specify some sophisticated expressions. e.g.
mvn process-resources liquibase:update -Dliquibase.labels=!kansas
Note, however, that the behavior is the same as contexts when no label expression is specified.
Example Change Sets:
<changeSet id="tag-v1" author="a">
<tagDatabase tag="v1"/>
</changeSet>
<changeSet id="tag-v1a" author="a" context="kansas">
<tagDatabase tag="v1a"/>
</changeSet>
<changeSet id="tag-v1b" author="a" labels="kansas">
<tagDatabase tag="v1b"/>
</changeSet>

Liquibase: How to disable FILENAME column check?

For our application we use liquibase. We have a need to run DB migrations both from command line (manually on production) AND automatically as the application starts up (test environment etc).
The problem is that Liquibase considers the whole filename as a portion of a changeSet's identity, therefore it tries to reapply the changesets if the path is different. For example, in case of "fully qualified path" VS "relative path" to to the db-changelog file.
How to disable FILENAME column check?
Based on this, the approach is as follows:
Always use the logicalFilePath attribute on both the databaseChangeLog element and every changeSet element.
Example:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog logicalFilePath="does-not-matter" 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-2.0.xsd">
<changeSet logicalFilePath="path-independent" author="authorId" id="1">
...
</changeSet>
</databaseChangeLog>
As result, FILENAME column for all changesets will contain 'path-independent' and check will be omitted.
#snowindy's answer is good. Alternately, you can always refer to your changeLogs in a classpath-relative manner such as com/example/changelog.xml. if you configure the classpath correctly in both environments the same "com/example/changelog.xml" can be used.
There's another factor that comes into play. There are different ways to reference the changeLogFile (absolute/relative path or by classpath). I wrote about it in detail here: https://stackoverflow.com/a/45644695/4176104

How to configure liquibase not to include file path or name for calculating checksum?

I found that liquibase uses the full path of the change log file to calculate the checksum.
This behavior restricts to modify change log file names and tries to reapply the change sets again once renamed the file.
Is there a way to configure liquibase to use only the changelog id to
calculate cuecksum?
Please provide your valuable thoughts.
Use the attribute logicalFilePath of the databaseChangeLog tag.
Upstream developers recommend to use logicalFilePath and suggest to perform direct update on DATABASECHANGELOG.FILENAME column:
https://forum.liquibase.org/t/why-does-the-change-log-contain-the-file-name/481
to fix broken entries with full paths.
If you set hashes DATABASECHANGELOG.MD5SUM to null that triggers hashes recalculation on next LiquiBase run. It is necessary as hash algorithm includes moving parts too into the result.
One really similar issue- you may just want to ignore the portion of the path before the changelog-master.xml file. In my scenario, I've checked out a project in C:\DEV\workspace and my colleague has the project checked out in C:\another_folder\TheWorkspace.
I'd recommend reading through http://forum.liquibase.org/topic/changeset-uniqueness-causing-issues-with-branched-releases-overlapped-changes-not-allowed-in-different-files first.
Like others have suggested, you'll want the logicalFilePath property set on the <databaseChangeLog> element.
You'll also need to specify the changeLogFile property in a certain way when calling liquibase. I'm calling it from the command line. If you specify an absolute or relative path to the changeLogFile without the classpath, like this, it will include the whole path in the DATABASECHANGELOG table:
liquibase.bat ^
--changeLogFile=C:\DEV\more\folders\schema\changelog-master.xml ^
...
then liquibase will break if you move your migrations to any folder other than that one listed above. To fix it (and ensure that other developers can use whatever workspace location they want), you need to reference the changelogFile from the classpath:
liquibase.bat ^
--classpath=C:\DEV\more\folders ^
--changeLogFile=schema/changelog-master.xml ^
...
The first way, my DATABASECHANGELOG table had FILENAME values (I might have the slash backwards) like
C:\DEV\more\folders\schema\subfolder\script.sql
The second way, my DATABASECHANGELOG table has FILENAME values like
subfolder/script.sql
I'm content to go with filenames like that. Each developer can run liquibase from whatever folder they want. If we decide we want to rename or move an individual SQL file later on, then we can specify the old value in the logicalFilePath property of the <changeSet> element.
For reference, my changelog-master.xml just consists of elements like
<include file="subfolder/script.sql" relativeToChangelogFile="true"/>
I have faced the same problem and found solution below.
If you are using liquibase sql format then simply put below in your sql file:
--liquibase formatted sql logicalFilePath:<relative SQL file path like(liquibase/changes.sql)>
If you are using liquibase xml format then simply put below in your xml file:
<databaseChangeLog logicalFilePath=relative XML file path like(liquibase/changes.xml)" ...>
...
</databaseChangeLog>
After adding above logicalFilePath attribute, run the liquibase update command.
It will put relative file path whatever you put in logicalFilePath in FILENAME column of table DATABASECHANGELOG