Liquibase PreConditions

Sometimes before actually running the ChangeLog or ChangeSet, it's required to check the state of the database, user permissions, table, or schema, or sometimes skip certain changes as per environment ect, If these conditions pass, then only ChangeLog or individual ChangeSet should execute otherwise abort the execution.
In this scenario, Liquibase provides and Preconditions attribute, which checks for conditions, and if all pass then only proceed. Preconditions can be as easy as checking database type.

<preConditions>
      <dbms type="oracle" />
</preConditions>

or complex as well, like running queries and asserting the result.

<preConditions>
      <sqlCheck expectedResult="0">
          SELECT COUNT(*) FROM apple
      </sqlCheck>
</preConditions>

except sqlCheck , SQL doesn't support any preconditions

Preconditions can be added before executing individual ChangeSet These are also known as local Preconditions and Preconditions for entire ChangeLog files are also known as Global Preconditions.

Global Preconditions

Preconditions can be added to a ChangeLog which will make sure all conditions pass otherwise, they will not run the entire ChangeLog file. On the other hand Preconditions on the ChangeLog hold true for all individual ChangeSet in the ChangeLog tag.
In the below example, Liquibase will check if the database is Oracle, then only it will execute the ChangeSet, or else fail the execution and abort

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
	<preConditions>
		<dbms type="oracle" />
	</preConditions>
	<changeSet author="wesome" id="1692599548266-1">
		<createTable catalogName="appledb" tableName="apple">
			<column autoIncrement="true" name="apple_id" type="BIGINT">
				<constraints nullable="false" primaryKey="true" />
			</column>
			<column name="apple_name" type="VARCHAR(255)" />
			<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
		</createTable>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
</databaseChangeLog>

liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.<format>)

changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot

local preconditions

Preconditions and can be added to  individual ChangeSet as well, in which, Liquibase will validate each ChangeSet Preconditions, and if pass then only run otherwise skip it. Preconditions on individual ChangeSet doesn't affect other changeSet.
In the Below example, the ChangeSet with id="1692599548266-1 has Preconditions that table doesn't exist then only create a table ChangeSet will execute, on the other hand ChangeSet with id="1692599548266-2 has no Preconditions, hence it will execute irrespective of the table exist Preconditions.

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
	<changeSet author="wesome" id="1692599548266-1">
		<preConditions>
			<not><tableExists tableName="apple" /></not>
		</preConditions>
		<createTable catalogName="appledb" tableName="apple">
			<column autoIncrement="true" name="apple_id" type="BIGINT">
				<constraints nullable="false" primaryKey="true" />
			</column>
			<column name="apple_name" type="VARCHAR(255)" />
			<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
		</createTable>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<preConditions>
			<tableExists tableName="apple" />
		</preConditions>
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
</databaseChangeLog>

liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)

changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot

Liquibase allows the combination of Preconditions for complex requirements

<preConditions>
    <or>
       <and>
          <dbms  type="oracle"  />  
          <runningAs  username="SYSTEM"  />
       </and>
       <and>
          <dbms  type="mssql"  />
          <runningAs  username="sa"  />
       </and>
     </or>
</preConditions>

follow us on