generate-changelog
The generate-changelog
command creates a changelog file that has a sequence of changesets which describe how to re-create the current state of the database.
Uses
The generate-changelog
command is typically used when you want to capture the current state of a database, then apply those changes to any number of databases. This is typically only done when a project has an existing database, but hasn't used Liquibase before. See How to set up Liquibase with an Existing Project and Multiple Environments for more details.
Note: When using the update command to apply the changes in the changelog, Liquibase will not create a new database or schema. You must create them before applying the changelog to it.
Run the generate-changelog
command
In this example, our sample database has the following content:
Database snapshot for jdbc:postgresql://localhost:54322/lbadmindb
-----------------------------------------------------------------
Database type: PostgreSQL
Database version: 16.0 (Debian 16.0-1.pgdg120+1)
Database user: lbadminuser
Included types:
com.datical.liquibase.ext.appdba.synonym.Synonym
com.datical.liquibase.ext.storedlogic.checkconstraint.CheckConstraint
com.datical.liquibase.ext.storedlogic.databasepackage.DatabasePackage
com.datical.liquibase.ext.storedlogic.databasepackage.DatabasePackageBody
com.datical.liquibase.ext.storedlogic.function.Function
com.datical.liquibase.ext.storedlogic.trigger.Trigger
liquibase.structure.core.Catalog
liquibase.structure.core.Column
liquibase.structure.core.ForeignKey
liquibase.structure.core.Index
liquibase.structure.core.PrimaryKey
liquibase.structure.core.Schema
liquibase.structure.core.Sequence
liquibase.structure.core.StoredProcedure
liquibase.structure.core.Table
liquibase.structure.core.UniqueConstraint
liquibase.structure.core.View
Catalog & Schema: lbadmindb / public
com.datical.liquibase.ext.storedlogic.checkconstraint.CheckConstraint:
testtable_check
body: ((number > 0))
disabled: false
table: testtable
com.datical.liquibase.ext.storedlogic.function.Function:
customfunction()
body: CREATE OR REPLACE FUNCTION public.customfunction()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
IF NEW.text <> OLD.text THEN
INSERT INTO testtable (text,number,date)
VALUES(new.text,new.number,new.date);
END IF;
RETURN NEW;
END;
$function$
functionName: customfunction
valid: true
com.datical.liquibase.ext.storedlogic.trigger.Trigger:
customtrigger
body: CREATE TRIGGER customtrigger BEFORE UPDATE ON public.testtable FOR EACH ROW EXECUTE FUNCTION customfunction()
disabled: false
tableName: testtable
valid: true
liquibase.structure.core.ForeignKey:
fk_foreigntable
deferrable: false
deleteRule: importedKeyNoAction
foreignKeyColumns:
foreignid
foreignKeyTable: foreigntable
initiallyDeferred: false
primaryKeyColumns:
number
primaryKeyTable: testtable
updateRule: importedKeyNoAction
liquibase.structure.core.Index:
testtable_un
columns:
number
table: testtable
unique: true
liquibase.structure.core.StoredProcedure:
customProcedure
body: CREATE OR REPLACE PROCEDURE public."customProcedure"()
LANGUAGE plpgsql
AS $procedure$
BEGIN
insert into public.testtable (text,date) values ('first',CURRENT_DATE);
END;
$procedure$
type: plpgsql
liquibase.structure.core.Table:
foreigntable
columns:
foreignid
nullable: false
order: 2
type: int4
id
autoIncrementInformation: GENERATED null AUTO INCREMENT START WITH 1 INCREMENT BY 1
nullable: false
order: 1
type: int4
default_tablespace: false
outgoingForeignKeys:
fk_foreigntable
deferrable: false
deleteRule: importedKeyNoAction
foreignKeyColumns:
foreignid
initiallyDeferred: false
primaryKeyColumns:
number
primaryKeyTable: testtable
updateRule: importedKeyNoAction
testtable
checkConstraints:
testtable_check
body: ((number > 0))
disabled: false
columns:
date
nullable: false
order: 3
type: date
number
autoIncrementInformation: GENERATED null AUTO INCREMENT START WITH 1 INCREMENT BY 1
nullable: false
order: 2
type: int4
text
defaultValue: My text value
nullable: true
order: 1
type: varchar
default_tablespace: false
indexes:
testtable_un
columns:
number
unique: true
uniqueConstraints:
testtable_un
backingIndex: testtable_un
clustered: false
columns:
number
deferrable: false
disabled: false
initiallyDeferred: false
validate: true
liquibase.structure.core.UniqueConstraint:
testtable_un
backingIndex: testtable_un
clustered: false
columns:
number
deferrable: false
disabled: false
initiallyDeferred: false
table: testtable
validate: true
liquibase.structure.core.View:
customview
columns:
foreignid
nullable: true
order: 2
type: int4
id
nullable: true
order: 1
type: int4
definition: SELECT id,
foreignid
FROM foreigntable;
To generate a changelog from our sample database:
- Configure the Liquibase properties file to include your driver, classpath, and URL for the database you want to capture. Alternatively, you can pass the necessary information as environment variables or from the command line.
- Decide which data types you want to include. You can specify these with the
--diff-types
parameter. - Open your CLI and run one of the following commands:
- Generate a changelog without specifying diff types (Liquibase uses the default diff types:
columns
,foreignkeys
,indexes
,primarykeys
,tables
,uniqueconstraints
, andviews
): - Generate a changelog with specific diff types:
liquibase generate-changelog --changelog-file=example-changelog.xml
liquibase generate-changelog --changelog-file=example-changelog.xml --diff-types=catalogs,checkconstraints,columns,databasepackage,databasepackagebody,foreignkeys,functions,indexes,primarykeys,sequences,storedprocedures,tables,triggers,uniqueconstraints,views
Liquibase then generates your changelog and displays the following message:
BEST PRACTICE: The changelog generated by diffChangeLog/generateChangeLog should be inspected for correctness and completeness before being deployed. Some database objects and their dependencies cannot be represented automatically, and they may need to be manually updated before being deployed.
Generated changelog written to example-changelog.xml
Liquibase command 'generate-changelog' was executed successfully.
Output changelogs
The generate-changelog
command generates a changelog that contains all your objects (represented as changesets) and places the file in the same directory where the command was ran.
The extension you provide determines the format of the changelog, so if you specify the filename as changelog.xml
, you will get an XML formatted changelog. However, if you specify the filename as changelog.yaml
, changelog.json
, or changelog.sql
, you will get changelogs formatted in YAML, JSON, or SQL, respectively.
Default diff types
<?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="tfernandez (generated)" id="1704821089427-1">
<createTable tableName="testtable">
<column defaultValue="My text value" name="text" type="VARCHAR" />
<column autoIncrement="true" name="number" type="INTEGER">
<constraints nullable="false" />
</column>
<column name="date" type="date">
<constraints nullable="false" />
</column>
</createTable>
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821089427-2">
<pro:createFunction functionName="customfunction"
path="objects/function/customfunction-bcd8b0c2.sql" relativeToChangelogFile="true" />
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821089427-3">
<createTable tableName="foreigntable">
<column autoIncrement="true" name="id" type="INTEGER">
<constraints nullable="false" />
</column>
<column name="foreignid" type="INTEGER">
<constraints nullable="false" />
</column>
</createTable>
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821089427-4">
<pro:createTrigger disabled="false"
path="objects/trigger/testtable_customtrigger-41365cf7.sql"
relativeToChangelogFile="true" tableName="testtable" triggerName="customtrigger" />
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821089427-5">
<addUniqueConstraint columnNames="number" constraintName="testtable_un"
tableName="testtable" />
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821089427-6">
<createView fullDefinition="false" viewName="customview">SELECT id,
foreignid
FROM foreigntable;
</createView>
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821089427-7">
<createProcedure path="objects/storedprocedure/customProcedure.sql"
procedureName="customProcedure" relativeToChangelogFile="true" />
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821089427-8">
<addForeignKeyConstraint baseColumnNames="foreignid" baseTableName="foreigntable"
constraintName="fk_foreigntable" deferrable="false" initiallyDeferred="false"
onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="number"
referencedTableName="testtable" validate="true" />
</changeSet>
</databaseChangeLog>
databaseChangeLog:
- changeSet:
id: 1704821121380-1
author: tfernandez (generated)
changes:
- createTable:
columns:
- column:
defaultValue: My text value
name: text
type: VARCHAR
- column:
autoIncrement: true
constraints:
nullable: false
name: number
type: INTEGER
- column:
constraints:
nullable: false
name: date
type: date
tableName: testtable
- changeSet:
id: 1704821121380-2
author: tfernandez (generated)
changes:
- createFunction:
functionName: customfunction
path: objects/function/customfunction-bcd8b0c2.sql
relativeToChangelogFile: true
- changeSet:
id: 1704821121380-3
author: tfernandez (generated)
changes:
- createTable:
columns:
- column:
autoIncrement: true
constraints:
nullable: false
name: id
type: INTEGER
- column:
constraints:
nullable: false
name: foreignid
type: INTEGER
tableName: foreigntable
- changeSet:
id: 1704821121380-4
author: tfernandez (generated)
changes:
- createTrigger:
disabled: false
path: objects/trigger/testtable_customtrigger-41365cf7.sql
relativeToChangelogFile: true
tableName: testtable
triggerName: customtrigger
- changeSet:
id: 1704821121380-5
author: tfernandez (generated)
changes:
- addUniqueConstraint:
columnNames: number
constraintName: testtable_un
tableName: testtable
- changeSet:
id: 1704821121380-6
author: tfernandez (generated)
changes:
- createView:
fullDefinition: false
selectQuery: |-
SELECT id,
foreignid
FROM foreigntable;
viewName: customview
- changeSet:
id: 1704821121380-7
author: tfernandez (generated)
changes:
- createProcedure:
path: objects/storedprocedure/customProcedure.sql
procedureName: customProcedure
relativeToChangelogFile: true
- changeSet:
id: 1704821121380-8
author: tfernandez (generated)
changes:
- addForeignKeyConstraint:
baseColumnNames: foreignid
baseTableName: foreigntable
constraintName: fk_foreigntable
deferrable: false
initiallyDeferred: false
onDelete: NO ACTION
onUpdate: NO ACTION
referencedColumnNames: number
referencedTableName: testtable
validate: true
{ "databaseChangeLog": [
{
"changeSet": {
"id": "1704821132889-1",
"author": "tfernandez (generated)",
"changes": [
{
"createTable": {
"columns": [
{
"column": {
"defaultValue": "My text value",
"name": "text",
"type": "VARCHAR"
}
},
{
"column": {
"autoIncrement": true,
"constraints": {
"nullable": false
},
"name": "number",
"type": "INTEGER"
}
},
{
"column": {
"constraints": {
"nullable": false
},
"name": "date",
"type": "date"
}
}
]
,
"tableName": "testtable"
}
}
]
}
},
{
"changeSet": {
"id": "1704821132889-2",
"author": "tfernandez (generated)",
"changes": [
{
"createFunction": {
"functionName": "customfunction",
"path": "objects/function/customfunction-bcd8b0c2.sql",
"relativeToChangelogFile": true
}
}
]
}
},
{
"changeSet": {
"id": "1704821132889-3",
"author": "tfernandez (generated)",
"changes": [
{
"createTable": {
"columns": [
{
"column": {
"autoIncrement": true,
"constraints": {
"nullable": false
},
"name": "id",
"type": "INTEGER"
}
},
{
"column": {
"constraints": {
"nullable": false
},
"name": "foreignid",
"type": "INTEGER"
}
}
]
,
"tableName": "foreigntable"
}
}
]
}
},
{
"changeSet": {
"id": "1704821132889-4",
"author": "tfernandez (generated)",
"changes": [
{
"createTrigger": {
"disabled": false,
"path": "objects/trigger/testtable_customtrigger-41365cf7.sql",
"relativeToChangelogFile": true,
"tableName": "testtable",
"triggerName": "customtrigger"
}
}
]
}
},
{
"changeSet": {
"id": "1704821132889-5",
"author": "tfernandez (generated)",
"changes": [
{
"addUniqueConstraint": {
"columnNames": "number",
"constraintName": "testtable_un",
"tableName": "testtable"
}
}
]
}
},
{
"changeSet": {
"id": "1704821132889-6",
"author": "tfernandez (generated)",
"changes": [
{
"createView": {
"fullDefinition": false,
"selectQuery": "SELECT id,\n foreignid\n FROM foreigntable;",
"viewName": "customview"
}
}
]
}
},
{
"changeSet": {
"id": "1704821132889-7",
"author": "tfernandez (generated)",
"changes": [
{
"createProcedure": {
"path": "objects/storedprocedure/customProcedure.sql",
"procedureName": "customProcedure",
"relativeToChangelogFile": true
}
}
]
}
},
{
"changeSet": {
"id": "1704821132889-8",
"author": "tfernandez (generated)",
"changes": [
{
"addForeignKeyConstraint": {
"baseColumnNames": "foreignid",
"baseTableName": "foreigntable",
"constraintName": "fk_foreigntable",
"deferrable": false,
"initiallyDeferred": false,
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"referencedColumnNames": "number",
"referencedTableName": "testtable",
"validate": true
}
}
]
}
}
]}
--liquibase formatted sql
--changeset tfernandez:1704821094961-1
CREATE TABLE "testtable" ("text" VARCHAR DEFAULT 'My text value', "number" INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, "date" date NOT NULL);
--changeset tfernandez:1704821094961-2 splitStatements:false
CREATE OR REPLACE FUNCTION "public".customfunction()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
IF NEW.text <> OLD.text THEN
INSERT INTO testtable (text,number,date)
VALUES(new.text,new.number,new.date);
END IF;
RETURN NEW;
END;
$function$;
--changeset tfernandez:1704821094961-3
CREATE TABLE "foreigntable" ("id" INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, "foreignid" INTEGER NOT NULL);
--changeset tfernandez:1704821094961-4 splitStatements:false
CREATE TRIGGER customtrigger BEFORE UPDATE ON "public".testtable FOR EACH ROW EXECUTE FUNCTION customfunction();
--changeset tfernandez:1704821094961-5
ALTER TABLE "testtable" ADD CONSTRAINT "testtable_un" UNIQUE ("number");
--changeset tfernandez:1704821094961-6
CREATE VIEW "customview" AS SELECT id,
foreignid
FROM foreigntable;
--changeset tfernandez:1704821094961-7 splitStatements:false
CREATE OR REPLACE PROCEDURE public."customProcedure"()
LANGUAGE plpgsql
AS $procedure$
BEGIN
insert into public.testtable (text,date) values ('first',CURRENT_DATE);
END;
$procedure$;
--changeset tfernandez:1704821094961-8
ALTER TABLE "foreigntable" ADD CONSTRAINT "fk_foreigntable" FOREIGN KEY ("foreignid") REFERENCES "testtable" ("number") ON UPDATE NO ACTION ON DELETE NO ACTION;
Specific diff types
<?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="tfernandez (generated)" id="1704821340603-1">
<createTable tableName="testtable">
<column defaultValue="My text value" name="text" type="VARCHAR" />
<column autoIncrement="true" name="number" type="INTEGER">
<constraints nullable="false" />
</column>
<column name="date" type="date">
<constraints nullable="false" />
</column>
</createTable>
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821340603-2">
<insert tableName="testtable">
<column name="text" value="one" />
<column name="number" valueNumeric="1" />
<column name="date" valueDate="2024-01-09" />
</insert>
<insert tableName="testtable">
<column name="text" value="three" />
<column name="number" valueNumeric="2" />
<column name="date" valueDate="2024-01-09" />
</insert>
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821340603-3">
<pro:createFunction functionName="customfunction"
path="objects/function/customfunction-bcd8b0c2.sql" relativeToChangelogFile="true" />
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821340603-4">
<createTable tableName="foreigntable">
<column autoIncrement="true" name="id" type="INTEGER">
<constraints nullable="false" />
</column>
<column name="foreignid" type="INTEGER">
<constraints nullable="false" />
</column>
</createTable>
</changeSet>
<changeSet author="tfernandez (generated)" id="1704822563807-1">
<pro:addCheckConstraint constraintName="testtable_check" disabled="false" tableName="testtable">
((number > 0))
</pro:addCheckConstraint>
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821340603-5">
<pro:createTrigger disabled="false"
path="objects/trigger/testtable_customtrigger-41365cf7.sql"
relativeToChangelogFile="true" tableName="testtable" triggerName="customtrigger" />
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821340603-6">
<addUniqueConstraint columnNames="number" constraintName="testtable_un"
tableName="testtable" />
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821340603-7">
<createView fullDefinition="false" viewName="customview">SELECT id,
foreignid
FROM foreigntable;
</createView>
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821340603-8">
<addForeignKeyConstraint baseColumnNames="foreignid" baseTableName="foreigntable"
constraintName="fk_foreigntable" deferrable="false" initiallyDeferred="false"
onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="number"
referencedTableName="testtable" validate="true" />
</changeSet>
<changeSet author="tfernandez (generated)" id="1704821340603-9">
<createProcedure path="objects/storedprocedure/customProcedure.sql"
procedureName="customProcedure" relativeToChangelogFile="true" />
</changeSet>
</databaseChangeLog>
databaseChangeLog:
- changeSet:
id: 1704821709768-1
author: tfernandez (generated)
changes:
- createTable:
columns:
- column:
defaultValue: My text value
name: text
type: VARCHAR
- column:
autoIncrement: true
constraints:
nullable: false
name: number
type: INTEGER
- column:
constraints:
nullable: false
name: date
type: date
tableName: testtable
- changeSet:
id: 1704821709768-2
author: tfernandez (generated)
changes:
- insert:
columns:
- column:
name: text
value: one
- column:
name: number
valueNumeric: 1
- column:
name: date
valueDate: 2024-01-09
tableName: testtable
- insert:
columns:
- column:
name: text
value: three
- column:
name: number
valueNumeric: 2
- column:
name: date
valueDate: 2024-01-09
tableName: testtable
- changeSet:
id: 1704821709768-3
author: tfernandez (generated)
changes:
- createFunction:
functionName: customfunction
path: objects/function/customfunction-bcd8b0c2.sql
relativeToChangelogFile: true
- changeSet:
id: 1704821709768-4
author: tfernandez (generated)
changes:
- createTable:
columns:
- column:
autoIncrement: true
constraints:
nullable: false
name: id
type: INTEGER
- column:
constraints:
nullable: false
name: foreignid
type: INTEGER
tableName: foreigntable
- changeSet:
id: 1704822601396-1
author: tfernandez (generated)
changes:
- addCheckConstraint:
constraintBody: ((number > 0))
constraintName: testtable_check
disabled: false
tableName: testtable
- changeSet:
id: 1704821709768-5
author: tfernandez (generated)
changes:
- createTrigger:
disabled: false
path: objects/trigger/testtable_customtrigger-41365cf7.sql
relativeToChangelogFile: true
tableName: testtable
triggerName: customtrigger
- changeSet:
id: 1704821709768-6
author: tfernandez (generated)
changes:
- addUniqueConstraint:
columnNames: number
constraintName: testtable_un
tableName: testtable
- changeSet:
id: 1704821709768-7
author: tfernandez (generated)
changes:
- createView:
fullDefinition: false
selectQuery: |-
SELECT id,
foreignid
FROM foreigntable;
viewName: customview
- changeSet:
id: 1704821709768-8
author: tfernandez (generated)
changes:
- addForeignKeyConstraint:
baseColumnNames: foreignid
baseTableName: foreigntable
constraintName: fk_foreigntable
deferrable: false
initiallyDeferred: false
onDelete: NO ACTION
onUpdate: NO ACTION
referencedColumnNames: number
referencedTableName: testtable
validate: true
- changeSet:
id: 1704821709768-9
author: tfernandez (generated)
changes:
- createProcedure:
path: objects/storedprocedure/customProcedure.sql
procedureName: customProcedure
relativeToChangelogFile: true
{ "databaseChangeLog": [
{
"changeSet": {
"id": "1704821676788-1",
"author": "tfernandez (generated)",
"changes": [
{
"createTable": {
"columns": [
{
"column": {
"defaultValue": "My text value",
"name": "text",
"type": "VARCHAR"
}
},
{
"column": {
"autoIncrement": true,
"constraints": {
"nullable": false
},
"name": "number",
"type": "INTEGER"
}
},
{
"column": {
"constraints": {
"nullable": false
},
"name": "date",
"type": "date"
}
}
]
,
"tableName": "testtable"
}
}
]
}
},
{
"changeSet": {
"id": "1704821676788-2",
"author": "tfernandez (generated)",
"changes": [
{
"insert": {
"columns": [
{
"column": {
"name": "text",
"value": "one"
}
},
{
"column": {
"name": "number",
"valueNumeric": 1
}
},
{
"column": {
"name": "date",
"valueDate": "2024-01-09"
}
}
]
,
"tableName": "testtable"
}
},
{
"insert": {
"columns": [
{
"column": {
"name": "text",
"value": "three"
}
},
{
"column": {
"name": "number",
"valueNumeric": 2
}
},
{
"column": {
"name": "date",
"valueDate": "2024-01-09"
}
}
]
,
"tableName": "testtable"
}
}
]
}
},
{
"changeSet": {
"id": "1704821676788-3",
"author": "tfernandez (generated)",
"changes": [
{
"createFunction": {
"functionName": "customfunction",
"path": "objects/function/customfunction-bcd8b0c2.sql",
"relativeToChangelogFile": true
}
}
]
}
},
{
"changeSet": {
"id": "1704821676788-4",
"author": "tfernandez (generated)",
"changes": [
{
"createTable": {
"columns": [
{
"column": {
"autoIncrement": true,
"constraints": {
"nullable": false
},
"name": "id",
"type": "INTEGER"
}
},
{
"column": {
"constraints": {
"nullable": false
},
"name": "foreignid",
"type": "INTEGER"
}
}
]
,
"tableName": "foreigntable"
}
}
]
}
},
{
"changeSet": {
"id": "1704822683055-1",
"author": "tfernandez (generated)",
"changes": [
{
"addCheckConstraint": {
"constraintBody": "((number > 0))",
"constraintName": "testtable_check",
"disabled": false,
"tableName": "testtable"
}
}
]
}
},
{
"changeSet": {
"id": "1704821676788-5",
"author": "tfernandez (generated)",
"changes": [
{
"createTrigger": {
"disabled": false,
"path": "objects/trigger/testtable_customtrigger-41365cf7.sql",
"relativeToChangelogFile": true,
"tableName": "testtable",
"triggerName": "customtrigger"
}
}
]
}
},
{
"changeSet": {
"id": "1704821676788-6",
"author": "tfernandez (generated)",
"changes": [
{
"addUniqueConstraint": {
"columnNames": "number",
"constraintName": "testtable_un",
"tableName": "testtable"
}
}
]
}
},
{
"changeSet": {
"id": "1704821676788-7",
"author": "tfernandez (generated)",
"changes": [
{
"createView": {
"fullDefinition": false,
"selectQuery": "SELECT id,\n foreignid\n FROM foreigntable;",
"viewName": "customview"
}
}
]
}
},
{
"changeSet": {
"id": "1704821676788-8",
"author": "tfernandez (generated)",
"changes": [
{
"addForeignKeyConstraint": {
"baseColumnNames": "foreignid",
"baseTableName": "foreigntable",
"constraintName": "fk_foreigntable",
"deferrable": false,
"initiallyDeferred": false,
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"referencedColumnNames": "number",
"referencedTableName": "testtable",
"validate": true
}
}
]
}
},
{
"changeSet": {
"id": "1704821676788-9",
"author": "tfernandez (generated)",
"changes": [
{
"createProcedure": {
"path": "objects/storedprocedure/customProcedure.sql",
"procedureName": "customProcedure",
"relativeToChangelogFile": true
}
}
]
}
}
]}
--liquibase formatted sql
--changeset tfernandez:1704821730934-1
CREATE TABLE "testtable" ("text" VARCHAR DEFAULT 'My text value', "number" INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, "date" date NOT NULL);
--changeset tfernandez:1704821730934-2
INSERT INTO "testtable" ("text", "number", "date") VALUES ('one', 1, '2024-01-09');
INSERT INTO "testtable" ("text", "number", "date") VALUES ('three', 2, '2024-01-09');
--changeset tfernandez:1704821730934-3 splitStatements:false
CREATE OR REPLACE FUNCTION "public".customfunction()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
IF NEW.text <> OLD.text THEN
INSERT INTO testtable (text,number,date)
VALUES(new.text,new.number,new.date);
END IF;
RETURN NEW;
END;
$function$;
--changeset tfernandez:1704821730934-4
CREATE TABLE "foreigntable" ("id" INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, "foreignid" INTEGER NOT NULL);
--changeset tfernandez:1704822632841-1
ALTER TABLE "testtable" ADD CONSTRAINT "testtable_check" CHECK (((number > 0)));
--changeset tfernandez:1704821730934-5 splitStatements:false
CREATE TRIGGER customtrigger BEFORE UPDATE ON "public".testtable FOR EACH ROW EXECUTE FUNCTION customfunction();
--changeset tfernandez:1704821730934-6
ALTER TABLE "testtable" ADD CONSTRAINT "testtable_un" UNIQUE ("number");
--changeset tfernandez:1704821730934-7
CREATE VIEW "customview" AS SELECT id,
foreignid
FROM foreigntable;
--changeset tfernandez:1704821730934-8
ALTER TABLE "foreigntable" ADD CONSTRAINT "fk_foreigntable" FOREIGN KEY ("foreignid") REFERENCES "testtable" ("number") ON UPDATE NO ACTION ON DELETE NO ACTION;
--changeset tfernandez:1704821730934-9 splitStatements:false
CREATE OR REPLACE PROCEDURE public."customProcedure"()
LANGUAGE plpgsql
AS $procedure$
BEGIN
insert into public.testtable (text,date) values ('first',CURRENT_DATE);
END;
$procedure$;
Parameters
Global parameters
Attribute | Definition | Requirement |
---|---|---|
|
Your Liquibase Pro license key |
Required |
Command parameters
Attribute | Definition | Requirement |
---|---|---|
|
The JDBC database connection URL. See Using JDBC URL in Liquibase. |
Required |
|
Specifies the author for changesets in the generated changelog. |
Optional |
|
Changelog file to write results |
Optional |
|
Specifies the context filter to generate and apply to all changesets in your changelog. Useful to set many contexts quickly. Similar to the set-contexts command. Available in Liquibase 4.24.0 and later. Contexts are tags you can add to changesets to control which changesets will be executed in any particular migration run. After generating changesets with contexts, to deploy specific changes according to these contexts, you must run a command that specifies a context filter. For example, |
Optional |
|
Specifies a directory to send the data output of the command as a CSV file. |
Optional |
|
Name of the default catalog to use for the database connection |
Optional |
|
Name of the default schema to use for the database connection. If Tip: In Liquibase v4.23.0+, camelCase for Note: The syntax |
Optional |
|
Specifies the types of objects to compare. Specify multiple values as a comma-separated list (without spaces). Valid values are: If null, default types are Note: The diff types |
Optional |
|
The JDBC driver class |
Optional |
|
The JDBC driver properties file |
Optional |
|
Objects to exclude from diff |
Optional |
|
If |
Optional |
|
Objects to include in diff |
Optional |
|
If |
Optional |
|
Includes the tablespace of tables and indexes in a generated changesets if the value is |
Optional * |
|
Specifies the label filter to generate and apply to all changesets in your changelog. Useful to set many labels quickly. Similar to the set-labels command. Available in Liquibase 4.24.0 and later. Labels are tags you can add to changesets to control which changeset will be executed in any migration run. After generating changesets with labels, to deploy specific changes according to these labels, you must run a command that specifies a label filter. For example, |
Optional |
|
Lets you replace the schemas in the output changelog. This is a CSV list. The parameter size must match Example: |
Optional |
|
Determines whether |
Optional |
|
Password to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specifies database schemas you want to include |
Optional |
|
Liquibase 4.27.0+. Specifies how Liquibase sorts a list of objects in your database to generate a changelog. When Note: If you set this parameter to |
Optional |
|
Username to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
Global parameters
Attribute | Definition | Requirement |
---|---|---|
|
Your Liquibase Pro license key |
Required |
Command parameters
Attribute | Definition | Requirement |
---|---|---|
|
The JDBC database connection URL. See Using JDBC URL in Liquibase. |
Required |
|
Specifies the author for changesets in the generated changelog. |
Optional |
|
Changelog file to write results |
Optional |
|
Specifies the context filter to generate and apply to all changesets in your changelog. Useful to set many contexts quickly. Similar to the set-contexts command. Available in Liquibase 4.24.0 and later. Contexts are tags you can add to changesets to control which changesets will be executed in any particular migration run. After generating changesets with contexts, to deploy specific changes according to these contexts, you must run a command that specifies a context filter. For example, |
Optional |
|
Specifies a directory to send the data output of the command as a CSV file. |
Optional |
|
Name of the default catalog to use for the database connection |
Optional |
|
Name of the default schema to use for the database connection. If Tip: In Liquibase v4.23.0+, camelCase for Note: The syntax |
Optional |
|
Specifies the types of objects to compare. Specify multiple values as a comma-separated list (without spaces). Valid values are: If null, default types are Note: The diff types |
Optional |
|
The JDBC driver class |
Optional |
|
The JDBC driver properties file |
Optional |
|
Objects to exclude from diff |
Optional |
|
If |
Optional |
|
Objects to include in diff |
Optional |
|
If |
Optional |
|
Includes the tablespace of tables and indexes in a generated changesets if the value is |
Optional * |
|
Specifies the label filter to generate and apply to all changesets in your changelog. Useful to set many labels quickly. Similar to the set-labels command. Available in Liquibase 4.24.0 and later. Labels are tags you can add to changesets to control which changeset will be executed in any migration run. After generating changesets with labels, to deploy specific changes according to these labels, you must run a command that specifies a label filter. For example, |
Optional |
|
Lets you replace the schemas in the output changelog. This is a CSV list. The parameter size must match Example: |
Optional |
|
Determines whether |
Optional |
|
Password to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specifies database schemas you want to include |
Optional |
|
Liquibase 4.27.0+. Specifies how Liquibase sorts a list of objects in your database to generate a changelog. When Note: If you set this parameter to |
Optional |
|
Username to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
Global parameters
Attribute | Definition | Requirement |
---|---|---|
|
Your Liquibase Pro license key |
Required |
Command parameters
Attribute | Definition | Requirement |
---|---|---|
|
The JDBC database connection URL. See Using JDBC URL in Liquibase. |
Required |
|
Specifies the author for changesets in the generated changelog. |
Optional |
|
Changelog file to write results |
Optional |
|
Specifies the context filter to generate and apply to all changesets in your changelog. Useful to set many contexts quickly. Similar to the set-contexts command. Available in Liquibase 4.24.0 and later. Contexts are tags you can add to changesets to control which changesets will be executed in any particular migration run. After generating changesets with contexts, to deploy specific changes according to these contexts, you must run a command that specifies a context filter. For example, |
Optional |
|
Specifies a directory to send the data output of the command as a CSV file. |
Optional |
|
Name of the default catalog to use for the database connection |
Optional |
|
Name of the default schema to use for the database connection. If Tip: In Liquibase v4.23.0+, camelCase for Note: The syntax |
Optional |
|
Specifies the types of objects to compare. Specify multiple values as a comma-separated list (without spaces). Valid values are: If null, default types are Note: The diff types |
Optional |
|
The JDBC driver class |
Optional |
|
The JDBC driver properties file |
Optional |
|
Objects to exclude from diff |
Optional |
|
If |
Optional |
|
Objects to include in diff |
Optional |
|
If |
Optional |
|
Includes the tablespace of tables and indexes in a generated changesets if the value is |
Optional * |
|
Specifies the label filter to generate and apply to all changesets in your changelog. Useful to set many labels quickly. Similar to the set-labels command. Available in Liquibase 4.24.0 and later. Labels are tags you can add to changesets to control which changeset will be executed in any migration run. After generating changesets with labels, to deploy specific changes according to these labels, you must run a command that specifies a label filter. For example, |
Optional |
|
Lets you replace the schemas in the output changelog. This is a CSV list. The parameter size must match Example: |
Optional |
|
Determines whether |
Optional |
|
Password to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specifies database schemas you want to include |
Optional |
|
Liquibase 4.27.0+. Specifies how Liquibase sorts a list of objects in your database to generate a changelog. When Note: If you set this parameter to |
Optional |
|
Username to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
Global parameters
Attribute | Definition | Requirement |
---|---|---|
|
Your Liquibase Pro license key |
Required |
Command parameters
Attribute | Definition | Requirement |
---|---|---|
|
The JDBC database connection URL. See Using JDBC URL in Liquibase. |
Required |
|
Specifies the author for changesets in the generated changelog. |
Optional |
|
Changelog file to write results |
Optional |
|
Specifies the context filter to generate and apply to all changesets in your changelog. Useful to set many contexts quickly. Similar to the set-contexts command. Available in Liquibase 4.24.0 and later. Contexts are tags you can add to changesets to control which changesets will be executed in any particular migration run. After generating changesets with contexts, to deploy specific changes according to these contexts, you must run a command that specifies a context filter. For example, |
Optional |
|
Specifies a directory to send the data output of the command as a CSV file. |
Optional |
|
Name of the default catalog to use for the database connection |
Optional |
|
Name of the default schema to use for the database connection. If Tip: In Liquibase v4.23.0+, camelCase for Note: The syntax |
Optional |
|
Specifies the types of objects to compare. Specify multiple values as a comma-separated list (without spaces). Valid values are: If null, default types are Note: The diff types |
Optional |
|
The JDBC driver class |
Optional |
|
The JDBC driver properties file |
Optional |
|
Objects to exclude from diff |
Optional |
|
If |
Optional |
|
Objects to include in diff |
Optional |
|
If |
Optional |
|
Includes the tablespace of tables and indexes in a generated changesets if the value is |
Optional * |
|
Specifies the label filter to generate and apply to all changesets in your changelog. Useful to set many labels quickly. Similar to the set-labels command. Available in Liquibase 4.24.0 and later. Labels are tags you can add to changesets to control which changeset will be executed in any migration run. After generating changesets with labels, to deploy specific changes according to these labels, you must run a command that specifies a label filter. For example, |
Optional |
|
Lets you replace the schemas in the output changelog. This is a CSV list. The parameter size must match Example: |
Optional |
|
Determines whether |
Optional |
|
Password to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specifies database schemas you want to include |
Optional |
|
Liquibase 4.27.0+. Specifies how Liquibase sorts a list of objects in your database to generate a changelog. When Note: If you set this parameter to |
Optional |
|
Username to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
Global parameters
Attribute | Definition | Requirement |
---|---|---|
|
Your Liquibase Pro license key |
Required |
Command parameters
Attribute | Definition | Requirement |
---|---|---|
|
The JDBC database connection URL. See Using JDBC URL in Liquibase. |
Required |
|
Specifies the author for changesets in the generated changelog. |
Optional |
|
Changelog file to write results |
Optional |
|
Specifies the context filter to generate and apply to all changesets in your changelog. Useful to set many contexts quickly. Similar to the set-contexts command. Available in Liquibase 4.24.0 and later. Contexts are tags you can add to changesets to control which changesets will be executed in any particular migration run. After generating changesets with contexts, to deploy specific changes according to these contexts, you must run a command that specifies a context filter. For example, |
Optional |
|
Specifies a directory to send the data output of the command as a CSV file. |
Optional |
|
Name of the default catalog to use for the database connection |
Optional |
|
Name of the default schema to use for the database connection. If Tip: In Liquibase v4.23.0+, camelCase for Note: The syntax |
Optional |
|
Specifies the types of objects to compare. Specify multiple values as a comma-separated list (without spaces). Valid values are: If null, default types are Note: The diff types |
Optional |
|
The JDBC driver class |
Optional |
|
The JDBC driver properties file |
Optional |
|
Objects to exclude from diff |
Optional |
|
If |
Optional |
|
Objects to include in diff |
Optional |
|
If |
Optional |
|
Includes the tablespace of tables and indexes in a generated changesets if the value is |
Optional * |
|
Specifies the label filter to generate and apply to all changesets in your changelog. Useful to set many labels quickly. Similar to the set-labels command. Available in Liquibase 4.24.0 and later. Labels are tags you can add to changesets to control which changeset will be executed in any migration run. After generating changesets with labels, to deploy specific changes according to these labels, you must run a command that specifies a label filter. For example, |
Optional |
|
Lets you replace the schemas in the output changelog. This is a CSV list. The parameter size must match Example: |
Optional |
|
Determines whether |
Optional |
|
Password to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specify Change Types you want to target. Liquibase sets |
Optional |
|
Specifies database schemas you want to include |
Optional |
|
Liquibase 4.27.0+. Specifies how Liquibase sorts a list of objects in your database to generate a changelog. When Note: If you set this parameter to |
Optional |
|
Username to connect to the target database. Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro. |
Optional |
Note: The username
and password
attributes are not required for connections and systems which use alternate means of authentication. Also, you can specify database credentials as part of the url
attribute.
* --include-tablespace
only captures the tablespace if it was specified in the create table
statement.
Database objects supported by Liquibase
You can use the following object types in Liquibase:
Object type | --diff-types syntax |
Liquibase edition |
---|---|---|
Catalog | catalogs
|
Liquibase Open Source |
Column | columns
|
Liquibase Open Source |
Data | data
|
Liquibase Open Source |
Foreign key | foreignkeys
|
Liquibase Open Source |
Index | indexes
|
Liquibase Open Source |
NOT NULL constraint | N/A | Liquibase Open Source |
Primary key | primarykeys
|
Liquibase Open Source |
Schema | N/A | Liquibase Open Source |
Sequence | sequences
|
Liquibase Open Source |
Table | tables
|
Liquibase Open Source |
Unique constraint | uniqueconstraints
|
Liquibase Open Source |
View | views
|
Liquibase Open Source |
Check constraint | checkconstraints
|
Liquibase Pro |
Function | functions
|
Liquibase Pro |
Package | databasepackage
|
Liquibase Pro |
Package body | databasepackagebody
|
Liquibase Pro |
Stored procedure | storedprocedures
|
Liquibase Pro |
Trigger | triggers
|
Liquibase Pro |
Liquibase Pro stored logic behavior
While Liquibase Open Source stores all changesets in a changelog, Liquibase Pro creates a directory called Objects
and places the directory at the same level as your changelog.
The Objects
directory contains subdirectories for each of the stored logic types:
package
packagebody
function
stored procedure
trigger
Note: Some database platforms may not support all of these stored logic types.
The generate-changelog
command will not create the Objects
directory if:
- You don't have a valid Liquibase Pro license key.
- Stored logic is not present in the database.
- The target database does not support the
generate-changelog
command and stored logic objects. - The changelog file is written in formatted SQL. The
Objects
folder can only be created when generating XML, JSON, or YAML changelogs. - There is a pre-existing directory called
Objects
that was created outside Liquibase.
If your database contains Stored Logic objects, you may have issues attempting to run the generate-changelog
command more than once, even with a new changelog name, because the stored logic files already exist in the Objects
directory.
To generate a newer version of the changelog file with stored logic objects based on the current database state, you need to delete, rename, or move the Objects
directory that was created by running the generate-changelog
command previously. Then, you can run the generate-changelog
command again.
Note: If there is a pre-existing Objects
directory that is not related to Liquibase, you need to delete, rename, or move it to run the generate-changelog
command.
If you want to track the history of stored logic objects, use the diff-changelog command. The diff-changelog
command structures stored logic files into timestamped directories every time you run the command.