Giter VIP home page Giter VIP logo

liquibase / liquibase Goto Github PK

View Code? Open in Web Editor NEW
4.4K 136.0 1.8K 205.95 MB

Main Liquibase Source

Home Page: https://www.liquibase.org

License: Apache License 2.0

Java 77.58% Shell 0.14% HTML 0.03% CSS 0.02% Groovy 21.71% PLpgSQL 0.01% Inno Setup 0.03% Batchfile 0.02% TSQL 0.41% XSLT 0.03% SQLPL 0.04%
java liquibase database-migrations java-library continuous-delivery devops sql continuous-deployment database database-management

liquibase's Introduction

Liquibase Build and Test Quality Gate Status

Liquibase helps millions of developers track, version, and deploy database schema changes. It will help you to:

  • Control database schema changes for specific versions
  • Eliminate errors and delays when releasing databases
  • Automatically order scripts for deployment
  • Easily rollback changes
  • Collaborate with tools you already use

This repository contains the main source code for Liquibase Open Source. For more information about the product, see the Liquibase website.

Liquibase Automation and Integrations

Liquibase Open Source has built-in support for a variety of databases. Databases that are not part of Liquibase Open Source require extensions that you can download for free. Here is the full list of supported databases.

Liquibase can be integrated with Maven, Ant, Gradle, Spring Boot, and other CI/CD tools. For a full list, see Liquibase Tools & Integrations. You can use Liquibase with GitHub Actions, Spinnaker, and many different workflows.

Install and Run Liquibase

System Requirements

Liquibase system requirements can be found on the Download Liquibase page.

An H2 in-memory database example for CLI

  1. Download and run the appropriate installer.
  2. Make sure to add Liquibase to your PATH.
  3. Copy the included examples directory to the needed location.
  4. Open your CLI and navigate to your examples/sql or examples/xml directory.
  5. Start the included H2 database with the liquibase init start-h2 command.
  6. Run the liquibase update command.
  7. Run the liquibase history command to see what has executed!

See also how to get started with Liquibase in minutes or refer to our Installing Liquibase documentation page for more details.

Documentation

Visit the Liquibase Documentation website to find the information on how Liquibase works.

Courses

Learn all about Liquibase by taking our free online courses at Liquibase University.

Want to help?

Want to file a bug or improve documentation? Excellent! Read up on our guidelines for contributing!

Contribute code

Use our step-by-step instructions for contributing code to the Liquibase open source project.

Join the Liquibase Community

Earn points for your achievements and contributions, collect and show off your badges, add accreditations to your LinkedIn. Learn more about the pathway to Legend and benefits. Enjoy being part of the community!

Liquibase Extensions

Provide more database support and features for Liquibase.

License

Liquibase Open Source is licensed under the Apache 2.0 License.

Liquibase Pro has additional features and support and is commercially licensed.

LIQUIBASE is a registered trademark of Liquibase Inc.

Liquibase Forum

Liquibase Blog

Get Support & Advanced Features

Publish Release Manual Trigger to Sonatype

  1. When a PO (Product Owner) or a Team Leader navigates to Publish a release from here -> https://github.com/liquibase/liquibase/releases/, the workflow from /workflow/release-published.yml job is triggered.
  2. When a release is triggered, the workflow file will stop after Setup step and an email will be sent out to the list of approvers mentioned in job manual_trigger_deployment. You can click on the link and perform anyone of the options mentioned in description.
  3. A minimum of 2 approvers are needed in order for the other jobs such as deploy_maven, deploy_javadocs, publish_to_github_packages, etc to be executed.
  4. When you view the GitHub PR, make sure to verify the version which is being published. It should say something like Deploying v4.20.0 to sonatype

liquibase's People

Contributors

abrackx avatar adangel avatar ap-liquibase avatar arturobernalg avatar bbrown-at-datical avatar damienbiggs avatar dependabot[bot] avatar feoktant avatar filipelautert avatar jandroav avatar jnewton03 avatar mallod12 avatar mattbertolini avatar mches avatar mkarg avatar molivasdat avatar neupsh avatar nvoxland avatar odemk avatar riakivets avatar sayalim0412 avatar sleepy-manul avatar stevedonie avatar stevenmassaro avatar stpn-husak avatar suryaaki avatar suryaaki2 avatar vampire avatar vitaliimak avatar wwillard7800 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

liquibase's Issues

Regression: Unique constraint name is ignored when adding a column

Description
There's a regression on an old bug: CORE-1313.

To Reproduce

  1. Clone denarced/uniquetest (Spring Boot project)
  2. Change database information in src/main/resources/application.properties
  3. Create the Postgres database (on Linux CLI: createdb nameOfDb)
  4. Build (mvn clean install) and run (java -jar target/*.jar) the project

The main table should have two unique columns (name and sigi) and both of them should have custom unique constraint names (UQ_name and UQ_sigi) but only the one that was created with the table (UQ_name) has it. The details of the table (using psql):

uniquetest=> \d t_main
                                  Table "public.t_main"
 Column |         Type          | Collation | Nullable |             Default              
--------+-----------------------+-----------+----------+----------------------------------
 id     | bigint                |           | not null | generated by default as identity
 name   | character varying(32) |           |          | 
 sigi   | character varying(32) |           |          | 
Indexes:
    "t_main_pkey" PRIMARY KEY, btree (id)
    "UQ_name" UNIQUE CONSTRAINT, btree (name)
    "t_main_sigi_key" UNIQUE CONSTRAINT, btree (sigi)

Expected behavior
Both columns should have the defined unique constraint names.

MMMA: XSD validation not happening for attributes on createProcedure.

My Ant Liquibase update task fails because of an error locating SQL files referenced in my changelog. The problem is a malformed relativeToChangelogFile attribute. Instead of failing during update, XSD validation should catch this earlier.

The Ant build fails in both 3.8.7 and 4.0.0.
This is NOT Ant related; I just found it with Ant.

Customer Impact

I cannot run Liquibase update from an Ant build if a createProcedure has a malformed relativeToChangelogFile attribute but I cannot tell that is the problem becasue the error message tells me the sql file cannot be located.

3.8.7 Log Message

{CODE}
BUILD FAILED
C:\dev\DaticalDB-testing\liquibase-ant\build.xml:25: liquibase.exception.UnexpectedLiquibaseException: java.io.IOException: File does not exist: sql/lbpro_master_proc.sql
at liquibase.change.core.CreateProcedureChange.generateStatements(CreateProcedureChange.java:303)
at liquibase.change.AbstractChange.warn(AbstractChange.java:362)
at liquibase.changelog.visitor.ValidatingVisitor.visit(ValidatingVisitor.java:110)
at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:83)
at liquibase.changelog.DatabaseChangeLog.validate(DatabaseChangeLog.java:281)
at liquibase.Liquibase.update(Liquibase.java:198)
at liquibase.Liquibase.update(Liquibase.java:179)
at liquibase.Liquibase.update(Liquibase.java:334)
at liquibase.integration.ant.DatabaseUpdateTask.executeWithLiquibaseClassloader(DatabaseUpdateTask.java:34)
at liquibase.integration.ant.BaseLiquibaseTask.execute(BaseLiquibaseTask.java:88)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:293)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:352)
at org.apache.tools.ant.Target.execute(Target.java:437)
at org.apache.tools.ant.Target.performTasks(Target.java:458)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1406)
at org.apache.tools.ant.Project.executeTarget(Project.java:1377)
at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
at org.apache.tools.ant.Project.executeTargets(Project.java:1261)
at org.apache.tools.ant.Main.runBuild(Main.java:857)
at org.apache.tools.ant.Main.startAnt(Main.java:236)
at org.apache.tools.ant.launch.Launcher.run(Launcher.java:287)
at org.apache.tools.ant.launch.Launcher.main(Launcher.java:112)
Caused by: java.io.IOException: File does not exist: sql/lbpro_master_proc.sql
at liquibase.change.core.CreateProcedureChange.generateStatements(CreateProcedureChange.java:293)
... 26 more
{CODE}

4.0 Message Displayed in Console
I cannot figure out how to set the log level in Ant.

{CODE}
prepare:

update:
[liquibase:updateDatabase] Starting Liquibase.
[liquibase:updateDatabase] Mar 16, 2020 1:26:12 PM liquibase.resource
[liquibase:updateDatabase] INFO: Found non-URL ClassLoader classloader AntClassLoader[C:\dev\DaticalDB-testing\liquibase-ant\changelog;C:\dev\DaticalDB-testing\liquibase-ant\lib\liquibase.jar;C:\dev\DaticalDB-testing\liquibase-ant\lib\mssql-jdbc-8.1.0.jre8-preview.jar;C:\dev\DaticalDB-testing\liquibase-ant\lib\snakeyaml-1.24.jar]. Liquibase will try to figure out now to load resources from it, some may be missed. Consider using a custom ClassLoaderResourceAccessor subclass.
[liquibase:updateDatabase] Mar 16, 2020 1:26:17 PM liquibase.lockservice
[liquibase:updateDatabase] INFO: Successfully acquired change log lock
[liquibase:updateDatabase] Mar 16, 2020 1:26:17 PM liquibase.resource
[liquibase:updateDatabase] INFO: Found non-URL ClassLoader classloader AntClassLoader[C:\dev\DaticalDB-testing\liquibase-ant\changelog;C:\dev\DaticalDB-testing\liquibase-ant\lib\liquibase.jar;C:\dev\DaticalDB-testing\liquibase-ant\lib\mssql-jdbc-8.1.0.jre8-preview.jar;C:\dev\DaticalDB-testing\liquibase-ant\lib\snakeyaml-1.24.jar]. Liquibase will try to figure out now to load resources from it, some may be missed. Consider using a custom ClassLoaderResourceAccessor subclass.
[liquibase:updateDatabase] Mar 16, 2020 1:26:18 PM liquibase.resource
[liquibase:updateDatabase] INFO: Found non-URL ClassLoader classloader AntClassLoader[C:\dev\DaticalDB-testing\liquibase-ant\changelog;C:\dev\DaticalDB-testing\liquibase-ant\lib\liquibase.jar;C:\dev\DaticalDB-testing\liquibase-ant\lib\mssql-jdbc-8.1.0.jre8-preview.jar;C:\dev\DaticalDB-testing\liquibase-ant\lib\snakeyaml-1.24.jar]. Liquibase will try to figure out now to load resources from it, some may be missed. Consider using a custom ClassLoaderResourceAccessor subclass.
[liquibase:updateDatabase] Mar 16, 2020 1:26:21 PM liquibase.changelog
[liquibase:updateDatabase] INFO: Reading from DATABASECHANGELOG
[liquibase:updateDatabase] Mar 16, 2020 1:26:22 PM liquibase.lockservice
[liquibase:updateDatabase] INFO: Successfully released change log lock

BUILD FAILED
C:\dev\DaticalDB-testing\liquibase-ant\build.xml:26: Unable to initialize Liquibase: Unable to update database: liquibase.exception.UnexpectedLiquibaseException: java.io.IOException: File does not exist: sql/lbpro_master_proc.sql
{CODE}

Steps to Reproduce

  1. Make sure you have Ant in your path!
  2. Unzip the attached archive: [^liquibase-ant.7z]
  • Update the build.xml global properties to provide a connection to your SQL Server instance.
  • Note that the createProcedure has relativeToChangelog NOT relativeToChangelogFile.
  1. Drop the liquibase jar into ant/lib.
  2. Run the Ant task.
  • ant update

Expected Results

The Liquibase update is successful.
Tables and a procedure are created on the database.

Actual Results

The build fails.
The Liquibase update fails.
It cannot find the SQL file referenced in the changelog.

Feature: Implement "revert" (or "reverse") block

The Active Record Migrations have this nifty revert method. I'll directly give examples of how it would like in Liquibase. dropColumn doesn't have auto-rollback so current Liquibase migration would look like:

    <changSet id="5" author="john">
        <dropColumn tableName="MY_TABLE">
            <column name="COLUMN_NAME" />
        </dropColumn>
        <rollback>
            <addColumn tableName="MY_TABLE">
                <column name="COLUMN_NAME" type="VARCHAR(255)" />
            </addColumn>
        </rollback>
    </changeSet>

Having a revert (or reverse?) change/refactoring (or more likely built-in syntax like rollback), the above would look like:

    <changSet id="5" author="john">
        <revert>
            <addColumn tableName="MY_TABLE">
                <column name="COLUMN_NAME" type="VARCHAR(255)" />
            </addColumn>
        </revert>
    </changeSet>

meaning, while normally applying the migration do the reverse change of addColumn which auto-rollback is dropColumn. When doing a rollback do just the revert instruction.

If the addColumn has been previously done in a single changeSet it could look like:

    <changSet id="2" author="sali">
        <addColumn tableName="MY_TABLE">
            <column name="COLUMN_NAME" type="VARCHAR(255)" />
        </addColumn>
    </changeSet>

    ...

    <changSet id="5" author="john">
        <revert id="2" author="sali" />
    </changeSet>

Now, dropColumn could be made so it has an auto-rollback on its own if all necessary column info (most notably type) is provided – also a feature of Active Record Migrations, but revert is not limited just to this example. Here's another one – currently trying to redefine a constraint:

    <changSet id="8" author="peter">
        <dropUniqueConstraint tableName="MY_TABLE"
                              constraintName="UNIQUE_IDENTITY" />
        <addUniqueConstraint tableName="MY_TABLE"
                             constraintName="UNIQUE_IDENTITY"
                             columnNames="COLUMN_1, COLUMN_2, COLUMN_3" />
        <rollback>
            <dropUniqueConstraint tableName="MY_TABLE"
                                  constraintName="UNIQUE_IDENTITY" />
            <addUniqueConstraint tableName="MY_TABLE"
                                 constraintName="UNIQUE_IDENTITY"
                                 columnNames="COLUMN_1, COLUMN_2" />
        </rollback>
    </changeSet>

Having revert it would look like:

    <changSet id="8" author="peter">
        <revert>
            <addUniqueConstraint tableName="MY_TABLE"
                                 constraintName="UNIQUE_IDENTITY"
                                 columnNames="COLUMN_1, COLUMN_2" />
        </revert>
        <addUniqueConstraint tableName="MY_TABLE"
                             constraintName="UNIQUE_IDENTITY"
                             columnNames="COLUMN_1, COLUMN_2, COLUMN_3" />
    </changeSet>

Again, it could refer just to previous changeSet which has introduced the original constraint:

    <changSet id="6" author="peter">
        <addUniqueConstraint tableName="MY_TABLE"
                             constraintName="UNIQUE_IDENTITY"
                             columnNames="COLUMN_1, COLUMN_2" />
    </changeSet>

    ...

    <changSet id="8" author="peter">
        <revert id="6" author="peter" /><!-- May need logicalFilePath="..." if in another change log file. -->
        <addUniqueConstraint tableName="MY_TABLE"
                             constraintName="UNIQUE_IDENTITY"
                             columnNames="COLUMN_1, COLUMN_2, COLUMN_3" />
    </changeSet>

Postgres: Incorrect dependency ordering of trigger, function, and table in generated changelog.

In order for changes to deploy to a database, the changes must be organized in a particular order. For example, if a table has a trigger defined and that trigger invokes a function, the objects need to be created on the database in this order:

  1. Table
  2. Function
  3. Trigger
    OR
  4. Function
  5. Table
  6. Trigger
    However, the generated changelog of an Aurora Postgres database containing those three objects returns them in the order:
  7. Table
  8. Trigger
  9. Function
    This causes an update operation using the generated changelog to fail because trigger is trying to deploy prior to function. As long as the function is defined prior to the trigger, the changelog can deploy.

Customer Impact

A Datical DB customer would likely feel this quite a bit more than a Liquibase user. Deploying from a generated changelog is not a recommended or common practice outside of Datical DB. That is the answer I got from [~accountid:557058:c8f0b24d-f02f-431c-8842-fd9c929dfbf2] when I asked how common of a workflow deploying from a generated changelog is.

Error Message

{CODE}
liquibase --changeLogFile=gcl3.xml update
Liquibase Pro 3.8.2 by Datical licensed to Liquibase Pro Customer until Tue Nov 03 19:00:00 CST 2020
Unexpected error running Liquibase: ERROR: function canned_spam() does not exist [Failed SQL: (0) CREATE TRIGGER dinner_time BEFORE DELETE ON public.primary_table FOR EACH ROW EXECUTE PROCEDURE canned
_spam()]
{CODE}

Steps to Reproduce

  1. Unzip the postgres_lbpro_master.zip file. [^postgres_lbpro_master.7z]
  2. Update the liquibase.properties to connect to your Postgres databases.
  3. Execute update to deploy changes to your primary database (url connection):
    {CODE}
    liquibase --changeLogFile=postgres_lbpro_master_changelog.xml --labels="setup,createFunction,createTrigger" update
    {CODE}
  4. Execute a generateChangeLog of your primary database (url connection):
    {CODE}
    liquibase --changeLogFile=gcl.xml generateChangeLog
    {CODE}
  5. Execute an update to your secondary database (referenceUrl connection):
    {CODE}
    liquibase --changeLogFile=gcl.xml update
    {CODE}

Expected Results

The update operation is successful.
The change sets in the changelog are in the order: createTable, createFunction, createTrigger OR createFunction, createTable, createTrigger.

Actual Results

The update operation fails with the error listed above.
The change sets in the changelog are in the order: createTable, createTrigger, createFunction.

Derby reserved keywords is incorrect

Description
Derby reserved keywords includes more words than necessary according to https://db.apache.org/derby/docs/10.2/ref/rrefkeywords29722.html.
I am trying to add a column named data it gets quoted.

To Reproduce
Add this to a changeSet:

<createTable  tableName="data_test">
    <column name="data" type="CLOB"/>
</createTable>

And this to another changeSet:

 <insert tableName="data_test">
     <column name="data" value="this is a test"/>
 </insert>

Currently it the insert statement will raise a exception with message "'DATA' is not a column in table or VTI"

Expected behavior
It should be possible to add a column with name data.

Feature Request: Add option to apply changelog to source database before diff/diffChangeLog

Environment

Liquibase Version:
org.liquibase:liquibase-core:3.8.9
Liquibase Integration & Version:
Gradle
Liquibase Extension(s) & Version:
org.liquibase.ext:liquibase-hibernate5:3.+
Database Vendor & Version:
Source: H2 (in-memory)
Target: Hibernate JPA

Description

The issue I'm facing is basically the same as the following Stack Overflow questions:

I would like to request an improvement of the diff / diffChangeLog tasks where an option is provided to apply the changelog to the source database first before comparing.
This would allow comparing current state (by changelog) against target state (in this case, by hibernate entities). Using a H2 in-memory database, which would be a pretty clean solution IMO.

Actual Behavior

  • H2 in-memory server is started (which is always empty)
  • Diff runs between empty database and hibernate entities
  • Liquibase always adds a full changeset since it compares an empty database against target state.

Expected/Desired Behavior

  • H2 in-memory server is started (which is always empty)
  • Liquibase runs changelog against (source) H2 database, applying ddl
  • Diff runs between database and hibernate entities
  • Liquibase adds changeset if necessary, with the appropriate diff between original state and target state.

addNotNullConstraint causes "Data too long" Exception for BIT(1) fields

Description
We forgot to add a not null constraint to a column that was added to a table in a previous changeset, so now we wanted to add that not-null constraint to said new column.
The data type of that column is BIT(1) (so basically a boolean).

Sidenote: We are using MySQL/MariaDB.

I used the following XML-changeset to add the constraint:

<changeSet id="XXX" author="XXX">
    <addNotNullConstraint tableName="XX" columnName="XX" defaultNullValue="1" columnDataType="BIT(1)"/>
</changeSet>

When we run the changeset, the following Exception is thrown:

Error setting up or running Liquibase: Migration failed for change set xxx.xml::xxxx::XXX:
[ERROR]      Reason: liquibase.exception.DatabaseException: (conn=28) Data too long for column 

I saw that a similar issue was already brought up in 2010 (!) on the Liquibase JIRA board here, but was apparently never fixed.

To Reproduce
Use a changeset like this:

<addColumn tableName="xxx">
   <column name="col_name" type="BIT(1)" defaultValue="1"></column>
</addColumn> 

After that, add a second changeset like this:

<changeSet id="XXX" author="XXX">
    <addNotNullConstraint tableName="xxx" columnName="col_name" defaultNullValue="1" columnDataType="BIT(1)"/>
</changeSet>

Then run the liquibase changeset and the mentioned Exception should be thrown.
Please specify the exact commands used, from CLI, from maven, etc.

Describe the actual problematic behavior. Include console outout if relevant, log files if available. Ensure private information is redacted.

Expected behavior
I expect the changeset to run through without issues, adding the not null constraint to the specified table and setting all NULL entries to the specified default in defaultNullValue.
As mentioned in the comment on the linked JIRA post above, adding attributes like defaultNullValueBoolean would also be helpful.

Screenshots
None

Additional context
None

generateChangelog with CockroachDB: createTable should also create PrimaryKey columns

Description
This is fairly easy to reproduce using sample code provided by the folks at CoackroachDB. The issue is that when using the generateChangeLog command against a table that has primary keys, the generated changelog has a changeset to create the table, followed by a second changeset to add the primary key to the table. This changelog is not able to be deployed to a new clean database without errors.

To Reproduce
Follow the instruction in the readme file at https://github.com/timveil-cockroach/liquibase-example

The steps under "Test 2" show the failing condition.
The generated changeset looks like this - see the next section for the expected changeset:

    <changeSet author="steve (generated)" id="1582906076997-1">
        <createTable tableName="customer">
            <column name="c_id" type="BIGINT">
                <constraints nullable="false"/>
            </column>
            <column name="c_d_id" type="BIGINT">
                <constraints nullable="false"/>
            </column>
            <column name="c_w_id" type="BIGINT">
                <constraints nullable="false"/>
            </column>
            <column name="c_first" type="VARCHAR(16)"/>
            <column name="c_middle" type="CHAR(2)"/>
            <column name="c_last" type="VARCHAR(16)"/>
            <column name="c_street_1" type="VARCHAR(20)"/>
            <column name="c_street_2" type="VARCHAR(20)"/>
            <column name="c_city" type="VARCHAR(20)"/>
            <column name="c_state" type="CHAR(2)"/>
            <column name="c_zip" type="CHAR(9)"/>
            <column name="c_phone" type="CHAR(16)"/>
            <column name="c_since" type="TIMESTAMP WITHOUT TIME ZONE"/>
            <column name="c_credit" type="CHAR(2)"/>
            <column name="c_credit_lim" type="numeric(12, 2)"/>
            <column name="c_discount" type="numeric(4, 4)"/>
            <column name="c_balance" type="numeric(12, 2)"/>
            <column name="c_ytd_payment" type="numeric(12, 2)"/>
            <column name="c_payment_cnt" type="BIGINT"/>
            <column name="c_delivery_cnt" type="BIGINT"/>
            <column name="c_data" type="VARCHAR(500)"/>
        </createTable>
    </changeSet>

    <changeSet author="steve (generated)" id="1582906076997-10">
        <addPrimaryKey columnNames="c_w_id, c_d_id, c_id" constraintName="primary" tableName="customer"/>
    </changeSet>

Expected behavior
The generated changeset for the table "customer" should look like the following. Note that the <constraints> tags for the three primary key columns have additional attributes that do not exist on the currently generated changeset.

    <changeSet author="steve (generated)" id="1582906076997-1">
        <createTable tableName="customer">
            <column name="c_id" type="BIGINT">
                <constraints nullable="false" primaryKey="true" primaryKeyName="primary" referencedColumnNames="c_w_id, c_d_id, c_id" />
            </column>
            <column name="c_d_id" type="BIGINT">
                <constraints nullable="false" primaryKey="true" primaryKeyName="primary" referencedColumnNames="c_w_id, c_d_id, c_id" />
            </column>
            <column name="c_w_id" type="BIGINT">
                <constraints nullable="false" primaryKey="true" primaryKeyName="primary" referencedColumnNames="c_w_id, c_d_id, c_id" />
            </column>
            <column name="c_first" type="VARCHAR(16)"/>
            <column name="c_middle" type="CHAR(2)"/>
            <column name="c_last" type="VARCHAR(16)"/>
            <column name="c_street_1" type="VARCHAR(20)"/>
            <column name="c_street_2" type="VARCHAR(20)"/>
            <column name="c_city" type="VARCHAR(20)"/>
            <column name="c_state" type="CHAR(2)"/>
            <column name="c_zip" type="CHAR(9)"/>
            <column name="c_phone" type="CHAR(16)"/>
            <column name="c_since" type="TIMESTAMP WITHOUT TIME ZONE"/>
            <column name="c_credit" type="CHAR(2)"/>
            <column name="c_credit_lim" type="numeric(12, 2)"/>
            <column name="c_discount" type="numeric(4, 4)"/>
            <column name="c_balance" type="numeric(12, 2)"/>
            <column name="c_ytd_payment" type="numeric(12, 2)"/>
            <column name="c_payment_cnt" type="BIGINT"/>
            <column name="c_delivery_cnt" type="BIGINT"/>
            <column name="c_data" type="VARCHAR(500)"/>
        </createTable>
    </changeSet>    

Additional context
The repro steps require the ability to run a docker container and maven. I used maven 3.6.

tagExists command not available with Maven Plugin

Description
It's not possible to call tagExists method rfom maven plugin

Expected behavior
It shoud be possible to run this kind of command : mvn liquibase:tagexists that returns the existance of a tag

TEST - create an issue in Jira

I am creating an issue in Jira to see if it will sync to github issues.

In the future, I think we want to make it so that issues created in jira do not sync, but issues created in github do sync. I'm not 100% sure how to do that, or if that is in fact what we want.

┆Issue is synchronized with this Jira Bug by Unito

diffChangeLog not considering order of operations correctly

Description
This came in from a Liquibase Pro trial, and was a key factor in them not using the tool.

The issue is that they are making changes to the database 'manually' and then using the liquibase diffChangeLog command to add changesets to the changelog. After adding those, the changesets in the changelog are not usable when running liquibase update because liquibase doesn't consider the order of things properly - in the example given, it is trying to create an index on a column before the column itself is created, and a foreign key constraint is also attempted before the column is added.

To Reproduce
Full repro steps needed. Reporter showed a fragment of a yaml changelog that was generated:

- changeSet:
  id: 1583302794177-4
  author: colin (generated)
  changes:
    - createIndex:
      columns:
      - column:
        name: workflowRunId
        indexName: dataFile_workflowRun_ix
        tableName: dataFile
  
- changeSet:
  id: 1583302794177-5
  author: colin (generated)
  changes:
    - addForeignKeyConstraint:
      baseColumnNames: workflowToolId
      baseTableName: dataFile
      constraintName: dataFile_workflowTool_fk
      deferrable: false
      initiallyDeferred: false
      onDelete: CASCADE
      onUpdate: NO ACTION
      referencedColumnNames: id
      referencedTableName: workflowTool
      validate: true

- changeSet:
  id: 1583302794177-6
  author: colin (generated)
  changes:
    - createIndex:
      columns:
      - column:
        name: workflowToolId
        indexName: dataFile_workflowTool_ix
        tableName: dataFile

- changeSet:
  id: 1583302794177-7
  author: colin (generated)
  changes:
    - addColumn:
      columns:
        - column:
          name: workflowToolId
          type: int4
          tableName: dataFile

- changeSet:
  id: 1583302794177-8
  author: colin (generated)
  changes:
    - addColumn:
      columns:
        - column:
          name: workflowRunId
          type: int4
          tableName: dataFile

When using this changelog:

  • changeset with id 1583302794177-5 attempts to create a foreign key constraint that uses column workflowToolId as the baseColumnName, but that column is not added until a later changeset id 1583302794177-7
  • changeset with id 1583302794177-6 attempts to create an index on the column workflowToolId, but that column is not added until a later changeset id 1583302794177-7

Expected behavior
Liquibase should generate the changesets in an order that is deployable - creating the column first, then adding the index and foreign key constraint.

liquibase-core.jar contains ServiceLoader files

Description
Moving this over from Jira (https://liquibase.jira.com/browse/CORE-3522) as it seems like it should be fixed soon.

Starting with version 3.8.1 (observed with 3.8.2 as well), the liquibase-core.jar contains files in META-INF/services that belong to Jackson. This leads to runtime errors when Liquibase and Jackson are used in the same project. I've built a minimal example project at https://github.com/MenschNestor/liquibase-bug that exposes the issue, which revolves around the ServiceLoader mechanism in Java.

Acceptance Criteria

  1. Please make sure that the JAR file does not contain foreign service provider configuration files.
  2. Users who work with both Liquibase and Jackson in the same project can do so without errors

┆Issue is synchronized with this Jira Bug by Unito
┆fixVersions: Liquibase 3.10.1

addNotNullConstraint / dropNotNullConstraint not supported on Firebird

Description
The change addNotNullConstraint and dropNotNullConstraint are not available for Firebird databases.

To Reproduce
Add the commands to a change set and run it against a Firebird database. As a result there will be the following error messages:
addNotNullConstraint is not supported on firebird
dropNotNullConstraint is not supported on firebird

Expected behavior
The commands should be available for Firebird databases as well.

ChangeLog properties interpolation in sql file not working

Hi,

I have 2 levels of hierarchy in my changelogs as shown below and I need to define a property in the second level to be used in the included SQL files.

Expectation :
When I define the property in two changelog files at the second level the SQL files included in each changelog gets the value from the changelog

Actual behavior:
The variables are getting replaced in the sql file

I tried to define the property as local (global: false) but this didn't work as well.

Directory structure:

  • schema.yml
  • scripts
    • feat1
      • changelog.yml
      • change1.sql
    • feat2
      • changelog.yml
      • change2-1.sql

schema.yml:

databaseChangeLog:
  - include:
      file: scripts/feat1/changelog.yml
  - include:
      file: scripts/feat2/changelog.yml   

scripts/feat1/changelog.yml:

databaseChangeLog:
  - property:
      name: MyProp
      value: feat1

  - include:
      file: change1.sql
      relativeToChangelogFile: true

scripts/feat2/changelog.yml:

databaseChangeLog:
  - property:
      name: MyProp
      value: feat2

  - include:
      file: change2-1.sql
      relativeToChangelogFile: true

scripts/feat1/change1.sql:

--liquibase formatted sql

--changeset bash:test-4512 splitStatements:true endDelimiter:\nGO
UPDATE User
SET FirstName='${MyProp}'

scripts/feat2/change2-1.sql:

--liquibase formatted sql

--changeset bash:test-4512 splitStatements:true endDelimiter:\nGO
UPDATE User
SET FirstName='${MyProp}'

Can you please help.

Thanks
Bash

Liquibase falsely deploy sqlFile changeSets when specifying an unrecognized DB name in the "dbms" attribute

Background

When setting a sqlFile changeSet, the attribute "dbms" can be set to a specific database name.
https://www.liquibase.org/documentation/changes/sql_file.html

However, if the dbms name value is not recognized by Liquibase, then the changeSet will be considered as “deployed” and will be added to the DATABASECHANGELOG BUT will not be deployed to the database after running the “liquibase update” command.

STR

  1. Create a sqlFile changeSet in MSSQL Liquibase project with a dbms name that is not recognized by Liquibase. In the following example dbms="sqlserver"

For example:

  <changeSet author="SteveTheZ" id="lmcs765" context="DEV" labels="staging,hotfix">
      <sql dbms="sqlserver" endDelimiter="GO">
          CREATE PROCEDURE [dbo].[CustOrderHist2] @CustomerID nchar(5)
          AS
          SELECT ProductName, Total=SUM(Quantity)
          FROM Products P, [Order Details] OD, Orders O, Customers C
          WHERE C.CustomerID = @CustomerID
          AND C.CustomerID = O.CustomerID AND O.OrderID = OD.OrderID AND OD.ProductID = P.ProductID
          GROUP BY ProductName;
      </sql>
      <rollback>
        DROP PROCEDURE [dbo].[CustOrderHist2];
      </rollback>
    </changeSet>
  1. Run:

Liquibase update

  1. Run:

Liquibase rollbackCount 1

Actual results

After running the the update command in step 1 and 2 the corresponding row to the changeSet shows up in DATABASECHANGELOG. However, the Object CustOrderHist2 procedure is missing in the database.

After running the rollback command on step 3 the following error will occur:

Rolling Back Changeset:../changelog_version2.xml::lmcs765::SteveTheZ
Unexpected error running Liquibase: Cannot drop the procedure 'dbo.CustOrderHist2', because it does not exist or you do not have permission. [Failed SQL: (3701) DROP PROCEDURE [dbo].[CustOrderHist2]]

Expected results

Liquibase should fail to execute the changeSet if the dbms value is not recognized as a valid name and print to the console output a clear message that explains the problem with suggested solutions.

For example:

The following changeSet ../changelog_version2.xml::lmcs765::SteveTheZ has an unknown database type: sqlserver
Available database short names for dbms values:
  oracle
  firebird
  sybase
  sqlite
  hsqldb
  db2z
  h2
  informix
  mariadb
  unsupported
  postgresql
  db2
  ingres
  asany
  derby
  mysql
  mssql

Note

Removing the attribute “dbms” from the changeSet appears to fix the problem. Is this a problem/bug as well [~accountid:557058:c8f0b24d-f02f-431c-8842-fd9c929dfbf2] ? 🧐

Periodically can't parse precondition onFail property

Description

liquibase.precondition.core.PreconditionContainer has two methods:
public void setOnFail(String onFail)
public void setOnFail(FailOption onFail)

But when there is going changeset parsing it uses reflection for getting write method (in liquibase.util.ObjectUtil). And it doesn't check argument type. As a result it takes method with wrong argument for onFail property. So it generates such error:

liquibase.parser.core.ParsedNodeException: Error setting property at liquibase.serializer.AbstractLiquibaseSerializable.load(AbstractLiquibaseSerializable.java:107) ... Caused by: liquibase.exception.UnexpectedLiquibaseException: Cannot call public void liquibase.precondition.core.PreconditionContainer.setOnFail(liquibase.precondition.core.PreconditionContainer$FailOption) with value of type java.lang.String at liquibase.util.ObjectUtil.setProperty(ObjectUtil.java:177) at liquibase.serializer.AbstractLiquibaseSerializable.load(AbstractLiquibaseSerializable.java:68) ... 37 more

It doesn't fail application. But it ignores all preconditions.

To Reproduce
I don't know exactly how to reproduce it. I just get this error periodically on restart my application. Next restart usually works fine without any changes from me.

Expected behavior
Every restart of application doesn't produce such error and handle onFail property for preconditions correctly

Don't use v$session in Oracle as the SELECT grant on this view is not usually available to any user

Description
In Oracle multiuser and multitenant environments the SELECT grant on v$session is usually not available for any user. To do a SELECT from this view is usually enabled by granting SELECT_CATALOG_ROLE to the user. However, in more restricted environments this is not done due to security and privacy concerns.

There is a solution, to call DBMS_UTILITY.DB_VERSION stored procedure. The DBMS_UTILITY package, by default, can be executed by PUBLIC.

To Reproduce

  • Create an Oracle user without SELECT_CATALOG_ROLE
  • Execute a Liquibase migration for this user and its schema
  • Observe in the logs that
2020-04-05 21:26:00 [main] [INFO ] [l.database.core.OracleDatabase] Could not set check compatibility mode on OracleDatabase, assuming not running in any sort of compatibility mode: Cannot read from v$parameter: ORA-00942: table or view does not exist

Liquibase.listUnrunChangeSets is executing DDL statement

Description
Liquibase.listUnrunChangeSets wants to create DATABASECHANGELOG if it does not exist. The method should throw an exception if the DATABASECHANGELOG and/or the DATABASECHANGELOGLOCK table does not exist. Its is unexpected to see a DDL or a modification being executed while collecting unrun changesets.

To Reproduce
Execute the Liquibase.listUnrunChangeSets on an empty database.

Stacktrace

Wrapped by: java.sql.SQLSyntaxErrorException: ORA-01031: insufficient privileges
	at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:509)
	at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:461)
	at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1104)
	at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:550)
	at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:268)
	at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:655)
	at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:229)
	at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:41)
	at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:928)
	at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1205)
	at oracle.jdbc.driver.OracleStatement.executeInternal(OracleStatement.java:1823)
	at oracle.jdbc.driver.OracleStatement.execute(OracleStatement.java:1778)
	at oracle.jdbc.driver.OracleStatementWrapper.execute(OracleStatementWrapper.java:303)
	at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:398)
	... 61 common frames omitted
Wrapped by: liquibase.exception.DatabaseException: ORA-01031: insufficient privileges
 [Failed SQL: (1031) CREATE TABLE DML_USER.DATABASECHANGELOG (ID VARCHAR2(255) NOT NULL, AUTHOR VARCHAR2(255) NOT NULL, FILENAME VARCHAR2(255) NOT NULL, DATEEXECUTED TIMESTAMP NOT NULL, ORDEREXECUTED INTEGER NOT NULL, EXECTYPE VARCHAR2(10) NOT NULL, MD5SUM VARCHAR2(35), DESCRIPTION VARCHAR2(255), COMMENTS VARCHAR2(255), TAG VARCHAR2(255), LIQUIBASE VARCHAR2(20), CONTEXTS VARCHAR2(255), LABELS VARCHAR2(255), DEPLOYMENT_ID VARCHAR2(10))]
	at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:402)
	at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:59)
	at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:131)
	at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:111)
	at liquibase.changelog.StandardChangeLogHistoryService.init(StandardChangeLogHistoryService.java:284)
	at liquibase.Liquibase.checkLiquibaseTables(Liquibase.java:1226)
	at liquibase.Liquibase.listUnrunChangeSets(Liquibase.java:1291)
	at liquibase.Liquibase.listUnrunChangeSets(Liquibase.java:1281)

Expected behavior
I would expect that an exception is thrown stating that the DATABASECHANGELOG or the DATABASECHANGELOGLOCK does not exist.

Additional context
I execute the changelogs in a separate container with a user (DDLDML_USER) having both DDL and DML privileges. To make sure that the application is started on a compatible database I check at startup if there are any unrun changeSets with a user (DML_USER) having no DDL, but only DML privileges (changing the current schema "ALTER SESSION SET CURRENT_SCHEMA=DDLDML_USER"). The above exception appeared when the alter schema was skipped for some reason. I caught the listUnrunChangeSets red handed trying to create the DATABASECHANGELOG table. I use "Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production" and Liquibase 3.8.7.

RFC: syntax validation

When creating liquibase changesets as part of software development, the changeset naturally becomes part of a PR workflow and thus is subject to a PR pipeline.

It would be interesting if it was possible to validate a given changeset for syntax errors without actually connecting to any database. This would allow for basic validation of the changeset description as part of a CI pipeline.

liquibase generateChangeLog creates SMALLINT(5) column instead of SMALLINT on PostgreSQL

Environment section:
liquibase 3.8.6,3.8.7
Description section:

Overview

When using Liquibase to export your schema out of PostgreSQL, if a column uses a SMALLINT, liquibase exports that as SMALLINT(5) instead of SMALLINT

Customer Impact

Customers that are using liquibase to export and import their schemas into another database will not be able to use SMALLINT columns

Steps to Reproduce

Create a table that has a smallint based column on a postgresql based database.
I used the attached dvdrental database as an example.
A simpler example might be

CREATE TABLE public.mike
(
    small smallint
);

and then use
liquibase generateChangeLog to export the table into a change log file
The changelog file will contain

<column name="small" type="SMALLINT(5)"/>
                

Actual Results

A changelog that contains

<column name="small" type="SMALLINT(5)"/>
                

Expected Results

A changelog that contains

<column name="small" type="SMALLINT"/>
                

Workaround

After generating the changelog file, open it up in a text editor and do a global find and replace SMALLINT(5) with SMALLINT

Automated Test Criteria

  • Write a regression test for this bug.
  • The test should be in a database-specific test suite.

Manual Test Criteria

  • Test the fix manually after a desk check.

Documentation Criteria

None.

Attachment section:

[^dvdrental.tar]

DatabaseChangeLogLock race condition exists if two nodes both try to create the table on ORACLE

Description

See the description for CORE-2596(https://liquibase.jira.com/browse/CORE-2596). The issue mentioned in CORE-2596 still arises when working with Oracle database.

While the fix for CORE-2596 checks for the message to contain the keyword exists, Oracle responds with the following error message:

_ora-00955 name is already used by an existing object _. Given that the keyword exists is not present in Oracle's description the code to resolve the deadlock is not executed, resulting in the described problem.

The solution is to adapt the if clause in the code implemented to fix the referenced issue.

} catch (DatabaseException e) {
                if ((e.getMessage() != null) && e.getMessage().contains("exists")) {	                if ((e.getMessage() != null) && e.getMessage().contains("exists")) {
                    //hit a race condition where the table got created by another node.	                    //hit a race condition where the table got created by another

To Reproduce
See the linked ticket. The application still ends up in a race condition.

Expected behavior
See the linked ticket.

Screenshots
N/A
Additional context
N/A

[3.8.x] CreateSequence fails on Postgres <9.4 due to IF NOT PRESENT

Description
Due to recent changes in liquibase 3.8.x, the statement to create a sequence is as follows:
CREATE SEQUENCE IF NOT EXISTS <schema>.<sequenceName> <further configuration>.

This is fine for versions >= 9.5. In versions below that, the IF NOT EXISTS syntax is not supported.

To Reproduce
Add changelog to create a sequence and execute it.

<changeSet author="jpmaas" id="identifier">
        <preConditions onFail="MARK_RAN">
            <not>
                <sequenceExists sequenceName="sequence"/>
            </not>
        </preConditions>
        <createSequence sequenceName="sequence" startValue="1"/>
    </changeSet>

In my case, this changeset is executed via application startup using spring boot 2.

During startup, the following exception is thrown (starting from cause because spring exception is not necessary):

Caused by: liquibase.exception.MigrationFailedException: Migration failed for change set db/changelog.xml::identifier::jpmaas:
     Reason: liquibase.exception.DatabaseException: ERROR: syntax error at or near "NOT"
  Position: 21 [Failed SQL: (0) CREATE SEQUENCE  IF NOT EXISTS schema.sequence START WITH 1]
        at liquibase.changelog.ChangeSet.execute(ChangeSet.java:646)
        at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:53)
        at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:83)
        at liquibase.Liquibase.update(Liquibase.java:202)
        at liquibase.Liquibase.update(Liquibase.java:179)
        at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:366)
        at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:314)
        at liquibase.integration.spring.MultiTenantSpringLiquibase.runOnAllSchemas(MultiTenantSpringLiquibase.java:147)
        at liquibase.integration.spring.MultiTenantSpringLiquibase.afterPropertiesSet(MultiTenantSpringLiquibase.java:94)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792)
        ... 24 common frames omitted
Caused by: liquibase.exception.DatabaseException: ERROR: syntax error at or near "NOT"
  Position: 21 [Failed SQL: (0) CREATE SEQUENCE  IF NOT EXISTS schema.sequence START WITH 1]
        at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:402)
        at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:59)
        at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:131)
        at liquibase.database.AbstractJdbcDatabase.execute(AbstractJdbcDatabase.java:1274)
        at liquibase.database.AbstractJdbcDatabase.executeStatements(AbstractJdbcDatabase.java:1256)
        at liquibase.changelog.ChangeSet.execute(ChangeSet.java:609)
        ... 34 common frames omitted
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "NOT"
  Position: 21
        at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2497)
        at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2233)
        at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:310)
        at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:446)
        at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:370)
        at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:311)
        at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:297)
        at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:274)
        at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:269)
        at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:95)
        at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java)
        at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:398)
        ... 39 common frames omitted

Expected behavior
The sequence can be created without exception on postgres versions below 9.5.

Additional context
The code in question is located at this position:
https://github.com/liquibase/liquibase/blob/master/liquibase-core/src/main/java/liquibase/sqlgenerator/core/CreateSequenceGenerator.java#L50

Security issue in Liquibase Runner plugin is preventing it from being used by Jenkins

Background:

Due to JEP-200, plugins that load classes into master aren't allowed: https://jenkins.io/blog/2018/01/13/jep-200/

The one work around I tried was to update the whitelist.txt. But that got shot down: https://groups.google.com/forum/?nomobile=true#!searchin/jenkinsci-dev/reeves%7Csort:date/jenkinsci-dev/OoUgF2V_kas/BZ5HYL_vAAAJ

To replicate:

git clone https://github.com/jenkinsci/liquibase-runner-plugin.git
mvn hpi:run

Take the pom.xml from the PR listed below. You'll start to see error messages in the log file about classes not being allowed to load

Requirements to fix:

You can try the whitelist method listed below...but that's a non-starter for Jenkins CI dev. What really needs to happen is the Liquibase initializer in Util.java needs to be refactored to create a Liquibase object without classloading.

PR is here: jenkinsci/liquibase-runner-plugin#16

The PR also includes the an update pom.xml. This is way dated and should be updated along with the fix.

Acceptance Criteria

This ticket will be successfully resolved when:

  1. The jenkins runner plugin works
  2. the Liquibase initializer in Util.java needs to be refactored to create a Liquibase object without classloading.
  3. and other refactoring as needed
  4. the pom.xml included in the PR is updated
  5. Our updated code is accepted to the liquibase-runner-plugin repo and available to the general public

┆Issue is synchronized with this Jira Bug by Unito
┆Fix Versions: Liquibase 3.10.1, Jenkins Runner

usePreparedStatements attribute in loadData elements has no effect

Environment

Liquibase Version: 3.8.9

Liquibase Integration & Version: maven liquibase plugin, also version 3.8.9; maven version 3.6.3

Liquibase Extension(s) & Version:

Database Vendor & Version: SQLServer 2012

Operating System Type & Version: Ubuntu running Docker 19.0.3

Description

Regardless of whether the attribute 'usePreparedStatements' is set to 'true' or 'false' in 'loadData' elements, Liquibase always uses prepared statements (so it behaves as if it were harcoded to 'true')

This is the cause why when we try to load a CSV file where a 'DATE' column is set to 'NULL' we get the following error:

Error setting up or running Liquibase:
[ERROR] Migration failed for change set liquibase/xxx:
[ERROR]      Reason: liquibase.exception.DatabaseException: java.sql.BatchUpdateException: Implicit conversion from data type varbinary to datetime2 is not allowed. Use the CONVERT function to run this query.

This was already reported in https://liquibase.jira.com/browse/CORE-3399
As a workaround to overcome this problem, I've tried to set the 'usePreparedStatements' (in order to force the creation of liquibase's InsertStatements) to 'false' but it has no effect.

It all seems to be in Liquibase's 'LoadDataChange' class, in the condition that starts in line 464 from the liquibase codebase, GIT tag 3.8.9:

                // end of: iterate through all the columns of a CSV line

                // Try to use prepared statements if any of the two following conditions apply:
                // 1. There is no other option than using a prepared statement (e.g. in cases of LOBs)
                // 2. The database supports batched statements (for improved performance) AND we are not in an
                //    "SQL" mode (i.e. we generate an SQL file instead of actually modifying the database).
                if
                (
                    (needsPreparedStatement ||
                        (databaseSupportsBatchUpdates &&
                                !(ExecutorService.getInstance().getExecutor(database) instanceof LoggingExecutor)
                        )
                    )
                    && hasPreparedStatementsImplemented()
                ) {
                    anyPreparedStatements = true;
                    ExecutablePreparedStatementBase stmt =
                        this.createPreparedStatement(
                            database, getCatalogName(), getSchemaName(), getTableName(), columnsFromCsv,
                            getChangeSet(), getResourceAccessor()
                        );
                    batchedStatements.add(stmt);
                } else {
                    InsertStatement insertStatement =
                        this.createStatement(getCatalogName(), getSchemaName(), getTableName());

                    for (ColumnConfig column : columnsFromCsv) {
                        String columnName = column.getName();
                        Object value = column.getValueObject();

                        if (value == null) {
                            value = "NULL";
                        }

                        insertStatement.addColumnValue(columnName, value);
                    }

                    statements.add(insertStatement);
                }
                // end of: will we use a PreparedStatement?
            }
            // end of: loop for every input line from the CSV file

The value of the flag 'needsPreparedStatement' is not taken into account in that condition, because:

  1. It is part of an OR condition where the second term is TRUE as long as the database supports batch updates (SQLServer does -as stated in the JDBC driver-) and
  2. the liquibase command run does not generate LOGs (liquibase:update does not generate logs)

So 'needsPreparedStatement' will have no effect.

Steps To Reproduce

  • Given a running instance of SQL Server 2012
  • And a JDK version 11 or above (e.g. openjdk 11)
  • And the following POM.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.liquibase</groupId>
  <artifactId>test.database.problem</artifactId>
  <version>1.0.0</version>
  <name>Problem Dates in SQLServer</name>
  <packaging>jar</packaging>

  <properties>
    <database.port>YOUR SQL SERVER PORT HERE</database.port>
    <database.host>YOUR SQL SERVER HOST HERE</database.host>
    <database.username>YOUR DATABASE USERNAME HERE</database.username>
    <database.password>YOUR DATBASE PASSWORD HERE</database.password>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.microsoft.sqlserver</groupId>
      <artifactId>mssql-jdbc</artifactId>
      <version>8.3.0.jre11-preview</version>
    </dependency>
    <dependency>
      <groupId>org.liquibase</groupId>
      <artifactId>liquibase-core</artifactId>
      <version>3.8.9</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-maven-plugin</artifactId>
        <version>3.8.9</version>
        <configuration>
          <dropFirst>true</dropFirst>
          <verbose>true</verbose>
          <driver>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver>
          <url>jdbc:sqlserver://${database.host}:${database.port}</url>
          <username>${database.username}</username>
          <password>${database.password}</password>
          <changeLogFile>changelog-master.xml</changeLogFile>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
  • And the following changelog-master.xml under src/main/resources
<?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.8.xsd">

    <changeSet author="jdhmoreno" id="testProblemSqlServer">

        <createTable remarks="Contains the column with a DATE" tableName="TABLE_WITH_DATE_COLUMN">
            <column name="ID" type="bigint">
                <constraints primaryKey="true" primaryKeyName="PK_TABLE"/>
            </column>
            <column name="DATE_COLUMN" remarks="The date column" type="DATETIME2"/>
        </createTable>

        <loadData relativeToChangelogFile="true" file="test_date.csv" tableName="TABLE_WITH_DATE_COLUMN" usePreparedStatements="false">
            <column header="ID" name="ID" type="NUMERIC"/>
            <column header="DATE_COLUMN" name="DATE_COLUMN" type="DATETIME2"/>
        </loadData>

    </changeSet>
    
</databaseChangeLog>
  • And the following file test_date.csv under src/main/resources
"ID","DATE_COLUMN"
"1","NULL"
"2","NULL"
"3","NULL"
  • When I run the following maven command
mvn clean resources:resources liquibase:update 
  • Then I got the following error:
[ERROR] Failed to execute goal org.liquibase:liquibase-maven-plugin:3.8.9:update (default-cli) on project test.database.problem:
[ERROR] Error setting up or running Liquibase:
[ERROR] Migration failed for change set liquibase/changelog-master.xml::testProblemSqlServer::jdhmoreno:
[ERROR]      Reason: liquibase.exception.DatabaseException: java.sql.BatchUpdateException: Implicit conversion from data type varbinary to datetime2 is not allowed. Use the CONVERT function to run this query.
[ERROR] -> [Help 1]        

Expected/Desired Behavior

The idea would be that, when usePreparedStatements="false" is set in the loadData element, no PreparedStatements are used.

Proposed solution / idea

A solution might be to have the following condition in the class 'LoadDataChange', line 455

                if
                (
                    (needsPreparedStatement &&
                        (databaseSupportsBatchUpdates &&
                                !(ExecutorService.getInstance().getExecutor(database) instanceof LoggingExecutor)
                        )
                    )
                    && hasPreparedStatementsImplemented()
                )

This way, needsPreparedStatement (which in turns depends on the 'usePreparedStatement' attribute) will drive the creation of PreparedStatements or InsertStatements.
This should help solving the 'date' issue shown above, leaving to the developer the option of enabling them or not.

Notes

A more detailed look on why SQLServer 2012 behaves that way when a SQL NULL is sent for a DATE column can be found in the following StackOverflow thread:
https://stackoverflow.com/questions/43935316/error-inserting-null-or-empty-value-in-date-column-mapped-to-localdate-type-in-j

Out of memory when launching liquibase command “dropAllForeignKey”

Description
I'm running the liquibase command "dropAllForeignKey" on Sybase database with more than 12000 tables and more than 380000 columns. I'm getting an out of memory exception since liquibase code is trying to query all the columns in the data base.

The JVM is launched with : -Xms64M -Xmx512M (if I increase it to 5GO it'll work but I don't see why we have to query all the columns in the data base)

The script I'm using :

When I checked liquibase code I found that:

In DropAllForeignKeyConstraintsChange: we create a snapshot for the table mentioned in the xml
Table target = SnapshotGeneratorFactory.getInstance().createSnapshot( new Table(catalogAndSchema.getCatalogName(), catalogAndSchema.getSchemaName(), database.correctObjectName(getBaseTableName(), Table.class)) , database);

In JdbcDatabaseSnapshot: when we call getColumns, we call the bulkFetchQuery() instead of fastFetchQuery() because the table is neither "DatabaseChangeLogTableName" nor "DatabaseChangeLogLockTableName". In this case, the bulkFetchQuery does not filter on the table given in the dropAllForeignKey xml. Instead, it uses SQL_FILTER_MATCH_ALL, so it'll retrieve all the columns in the database. (It already takes time to query all the columns)

In ColumnMapRowMapper: for each table, we create a LinkedHashMap with size aqual to the number of columns. And here, I'm getting the out of memory

Is it normal that we query all the column when dropping all the foreign keys for a given table? If it's the case, why we need to do it and is there a solution for my problem without increasing the size of the JVM?

PS: There is another command called dropForeignKey to drop the forign key but it needs the name of the foreign key as an input and I don't have it. In fact, I can find the name of the foreign key for a given data base, but I'm running this command on different data bases and the name of the foreign key changes from one to another and I need to have a generic liquibase change. So, I can't use dropForeignKey and I need to use dropAllForeignKey.

Here the stack:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.LinkedHashMap.newNode(LinkedHashMap.java:256)
at java.base/java.util.HashMap.putVal(HashMap.java:637)
at java.base/java.util.HashMap.put(HashMap.java:607)
at liquibase.executor.jvm.ColumnMapRowMapper.mapRow(ColumnMapRowMapper.java:35)
at liquibase.executor.jvm.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:72)
at liquibase.snapshot.ResultSetCache$ResultSetExtractor.extract(ResultSetCache.java:297)
at liquibase.snapshot.JdbcDatabaseSnapshot$CachingDatabaseMetaData$3.extract(JdbcDatabaseSnapshot.java:774)
at liquibase.snapshot.ResultSetCache$ResultSetExtractor.extract(ResultSetCache.java:288)
at liquibase.snapshot.JdbcDatabaseSnapshot$CachingDatabaseMetaData$3.bulkFetchQuery(JdbcDatabaseSnapshot.java:606)
at liquibase.snapshot.ResultSetCache$SingleResultSetExtractor.bulkFetch(ResultSetCache.java:353)
at liquibase.snapshot.ResultSetCache.get(ResultSetCache.java:59)
at liquibase.snapshot.JdbcDatabaseSnapshot$CachingDatabaseMetaData.getColumns(JdbcDatabaseSnapshot.java:539)
at liquibase.snapshot.jvm.ColumnSnapshotGenerator.addTo(ColumnSnapshotGenerator.java:106)
at liquibase.snapshot.jvm.JdbcSnapshotGenerator.snapshot(JdbcSnapshotGenerator.java:79)
at liquibase.snapshot.SnapshotGeneratorChain.snapshot(SnapshotGeneratorChain.java:49)
at liquibase.snapshot.DatabaseSnapshot.include(DatabaseSnapshot.java:286)
at liquibase.snapshot.DatabaseSnapshot.init(DatabaseSnapshot.java:102)
at liquibase.snapshot.DatabaseSnapshot.(DatabaseSnapshot.java:59)
at liquibase.snapshot.JdbcDatabaseSnapshot.(JdbcDatabaseSnapshot.java:38)
at liquibase.snapshot.SnapshotGeneratorFactory.createSnapshot(SnapshotGeneratorFactory.java:217)
at liquibase.snapshot.SnapshotGeneratorFactory.createSnapshot(SnapshotGeneratorFactory.java:246)
at liquibase.snapshot.SnapshotGeneratorFactory.createSnapshot(SnapshotGeneratorFactory.java:230)
at liquibase.change.core.DropAllForeignKeyConstraintsChange.generateChildren(DropAllForeignKeyConstraintsChange.java:90)
at liquibase.change.core.DropAllForeignKeyConstraintsChange.generateStatements(DropAllForeignKeyConstraintsChange.java:59)

To Reproduce
To reproduce you need a huge database. Then uses dropAllForeignKey command on a given table

Expected behavior
DropAllForeignKey should be executed quickly and without any need to too much memory on the JVM

Could I separate sql statements in DDL and DML?

Description
I would like to separate sql statements in DDL type and DML type from the same file .xml. I checked the documentation and I didn't find a feature for this. I checked the extensions too.
I would like know whether liquibase could do it or if I would have to do it ad-hoc. Thanks for your support!

To Reproduce

  • mvn clean liquibase:updateSQL
  • separate statements DML or DDL
  • migrate.sql is generated

Expected behavior
Example migrate1DML.sql

INSERT ....

UPDATE ....

DELETE

Example migrate2DDL.sql

CREATE

DROP

Postgres jsonb default is not quoted

Description
When creating a default for jsonb columns as an empty set '[]' it is not being generated with the quotes but simply square brackets [] causing a syntax error.

To Reproduce
Generate a changelog of a database with a jsonb column with default '[]'
Apply and update to an empty database.

Expected behavior
Column should be created with a default empty set.

Screenshots

Unexpected error running Liquibase: ERROR: syntax error at or near "["
Position: 442 [Failed SQL: (0) CREATE TABLE public.xyz (....JSONB DEFAULT [] NOT NULL...)

Additional context
Currently only ran into this error for jsonb columns. Haven't tried it with json or text fields with a default value which would also need to be quoted.

liquibase:update is dropping databasechangeloglock

Description
Since commit c4f7f7e, a liquibase:update tries to drop the table databasechangeloglock on db2.

To Reproduce
I'm using a DB2 server v11.1.4.4, and a driver 4.23.42. (liquibase 3.8.4)
Also (I don't kown if it is relevant), the DB was intially created with an older liquibase version.

** Stacktrace **

Caused by: com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-551, SQLSTATE=42501, SQLERRMC=M999GST;DROP TABLE;REFVAL.DATABASECHANGELOGLOCK, DRIVER=4.23.42
    at com.ibm.db2.jcc.am.ld.a (ld.java:810)
    at com.ibm.db2.jcc.am.ld.a (ld.java:66)
    at com.ibm.db2.jcc.am.ld.a (ld.java:140)
    at com.ibm.db2.jcc.am.aq.c (aq.java:2807)
    at com.ibm.db2.jcc.am.aq.d (aq.java:2791)
    at com.ibm.db2.jcc.am.aq.b (aq.java:2151)
    at com.ibm.db2.jcc.t4.bb.k (bb.java:432)
    at com.ibm.db2.jcc.t4.bb.c (bb.java:91)
    at com.ibm.db2.jcc.t4.p.b (p.java:38)
    at com.ibm.db2.jcc.t4.vb.h (vb.java:124)
    at com.ibm.db2.jcc.am.aq.kb (aq.java:2146)
    at com.ibm.db2.jcc.am.aq.a (aq.java:3348)
    at com.ibm.db2.jcc.am.aq.e (aq.java:1116)
    at com.ibm.db2.jcc.am.aq.execute (aq.java:1095)
    at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement (JdbcExecutor.java:398)
    at liquibase.executor.jvm.JdbcExecutor.execute (JdbcExecutor.java:59)
    at liquibase.executor.jvm.JdbcExecutor.execute (JdbcExecutor.java:131)
    at liquibase.executor.jvm.JdbcExecutor.execute (JdbcExecutor.java:111)
    at liquibase.lockservice.StandardLockService.init (StandardLockService.java:147)
    at liquibase.lockservice.StandardLockService.acquireLock (StandardLockService.java:252)
    at liquibase.lockservice.StandardLockService.waitForLock (StandardLockService.java:213)
    at liquibase.Liquibase.update (Liquibase.java:184)
    at liquibase.Liquibase.update (Liquibase.java:179)
    at liquibase.Liquibase.update (Liquibase.java:334)

Additional context
From the doc I read, the server is indeed supporting BOOLEAN since v11.1.4.4, but I didn't find any doc saying the the datatype for a BOOLEAN is a java Boolean. The only jdbc doc of 11.1 that I found still mention that java Boolean are mapped to SMALLINT.

Postgres smallint syntax error

Describe the bug
Creating a smallint column in postgres incorrectly specifies the length as smallint(5) which generates a syntax error. It just needs to be smallint.

To Reproduce
Steps to reproduce the behavior:
liquibase generateChangeLog against a database that has a smallint column.
liquibase update against an empty database to recreate the schema.

Expected behavior
Create a smallint without error

Screenshots
Unexpected error running Liquibase: ERROR: syntax error at or near "("
Position: 268 [Failed SQL: (0) CREATE TABLE public.xyz (.....SMALLINT(5)....)

Additional context
This was run inside the published docker container although that should be irrelevant for this error.

Liquibase should have an option/flag to generate an empty changeLog

Description
As a user I would like to have an option to have Liquibase generate an empty changeLog even if my database has some existing Objects.

For example: liquibase generateChangelog --template

Where the flag --template will ensure that the changeLog will not have any changeSets.
Here are some suggestions about how the generated changeLog should look like after the generation:

  1. It should have a general template of a changeLog for the formats XML,JSON,YAML and Formatted SQL
  2. Don't generate any changeSets but instead output a pre-defined string with example placeholder changeSets commented out.

dataOutputDirectory will not be generated if the flag diffTypes is not used

Context

This ticket will need to be assigned to an epic or possibly initiative in which we will re-write or replace the CLI main library/codebase. At the same time we will standardize and smarten how we handle CLI interactions, such as removing case-senstivity where there is no possible collision with another command, providing better messaging, standardizing placement of Global V Command parameters (if we decide to care about that) and generally squashing inconsistencies and making the tool easier and friendlier.

If the diffTypes is not used when running a liquibase command like generateChangeLog or diffChangeLog with the dataOutputDirectory flag, then the dataOutputDirectory will not be created.

Requirements

  • As a user who wants to export ALL the data from my db when i run generatechangelog, i want to use the
    --dataOutputDirectory= flag and by default have all the data in csv files in the dir named "mydatadir"

    • the default behavior of the command, if no diffTypes is present is as if diffTypes was passed with all the object types specified, rather than as if NO object types wer passed (or desired).
  • As a user who wants to export SOME the data from my db when i run generatechangelog, i want to use the
    --dataOutputDirectory= flag and the --diffTypes= flag by default have all the specific data in csv files in the dir named "mydatadir"

Steps to reproduce

Run:

liquibase generateChangeLog --dataOutputDirectory=mydata

Expected Result

  • When diffTypes flag is null (not used), the generated changeLog should includes all Objects and the corresponding changeSets.
  • This is the expected behavior documented in the help command when diffTypes is null.
  • The folder mydata should be created and should contain all data from the database in csv files.

Actual Result

  • The generated ChangeLog contains all objects but has no changeSets.
  • The folder mydata is missing.

Workaround

Run:

liquibase --diffTypes=tables,functions,views,columns,indexes,foreignkeys,primarykeys,uniqueconstraints,data generateChangeLog --dataOutputDirectory=mydata

Notes

  • The example for “Export Data from Database” from https://www.liquibase.org/documentation/command_line.html is incorrect and can be replaced with the command mentioned in the Workaround example in this ticket.
  • Also, we should mention in our doc page that Exporting data from the Database with a corresponding changeLog cannot be done with a Formatted SQL changeLog. For example, if the command in the Workaround will be ran with the Formatted SQL changeLog File, then the results are, a “mydata” folder is created containing the csv files with the DB data as expected. However, the SQL changeLog will be empty (no changeSets).

Acceptance Criteria

This ticket will be successfully resolved when:

liquibase generateChangeLog --dataOutputDirectory=mydata
  1. As a user generating a changelog with the --outputDataDirectory=mydata flag and
  2. the --diffTypes flag is null (not used) , the generated changeLog should includes all Objects and the corresponding changeSets.
  3. a datadirectory subfolder named "mydata" is created and contains all the data from the database in CSV files.
liquibase --diffTypes=<some object types> generateChangeLog --dataOutputDirectory=mydata
  1. As a user generating a changelog with the --outputDataDirectory=mydata flag and a --diffTypes flag specifying the types of objects to diff, a datadirectory name "mydata" will be created and populated which includes specified Objects and the corresponding changeSets.

┆Issue is synchronized with this Jira Bug by Unito
┆Fix Versions: 3.8.9

Liquibase: standardize --schemas usage for snapshot command to either side of command

Background

This ticket could be attached to an epic to re-write or replace the CLI main library/codebase. But, as this issues affects people now, we should resolve it as a bug, knowing we might re-work it later in a CLI re-build epic.

Overall: --schemas will only work for snapshot when to the right of the command, but for other liquibase commands, like generatechangelog, it works and is documented as working to the left (in the "global commands" space). we need to make sure --schemas works to the standard usage (to the left of the command).

Context

A Liquibase client was having issue running a diff between a snapshot and multiple schemas.
The user workflow was as follows:

  1. Snapshot the target database with multiple schemas using the flags: "--schema=<schema1,schema2,schema3>"
  2. The user conducts a few changes to the target database.
  3. The user then runs a diffChangeLog between the snapshot and the target database.
    Unfortunately the resulting diffChangeLog did not carry all the changes that were made in all of the schemas specified while doing the original snapshot.
    After support conducted a few tests, it appears that when running the snapshot command, Liquibase does NOT include all the schemas specified with the "--schema<schema1,schema2,schema3>" flag in the snapshot file.
    Instead, it only contains the default schema.

Steps to reproduce

  1. Create a liquibase project with the following liquibase.properties
changeLogFile: <changeLogName>
url: jdbc:postgresql://localhost:5432/mydb
driver: org.postgresql.Driver
username: <username>
password: <password>
classpath: ../path/to/postgresql-42.2.8.jar
includeSchema: true
schemas: lookup,public
  1. Create a postgreSQL database "mydb" with schemas "lookup, public" (schema public should be created by default as the default schema).
  2. Add some objects to schemas "lookup" and "public"
  3. Run:
liquibase --outputFile=mysnapshot.json snapshot

Expected results

The file mysnapshot.json should contain all objects from both "public" and "lookup".

Actual results

The file_only_ contains objects from "public" schema, which is the default schema.

Notes

Liquibase has the ability to work with multiple schemas with one command.

This ability needs to be specified somewhere on our Liquibase website https://datical.atlassian.net/browse/PD-237
For example:

liquibase --schemas=prod,public,dev --includeSchema=true generateChangeLog

The resulting generated changeLog will contain all the schemas in the proper change sets' attributes.
This will work well with diffChangeLog and diff commands as well.

Acceptance Criteria

This ticket will be successfully resolved when a user with multiple schemas whose CLI

  1. includes the --schemas flag to list their schema
  2. includes the --outputFile=.json flag
  3. to run a snapshot command, like so
liquibase --schemas=<one>,<two> --outputFile=<mysnapshot>.json snapshot 

or

liquibase  --outputFile=<mysnapshot>.json snapshot --schemas=<one>,<two>

should have a file generated for them which captures all the objects from all the listed schemas

Ant task and CLI produce different changeset digests

Description
If you run <liquibase:updateDatabase .../> using Ant, and subsequently run liquibase update using the CLI, the CLI command will fail ("table already exists") since it'll try to run changesets that have already been applied.

To Reproduce

I've been using the changeset from the tutorial here and running it against an Aurora PostgreSQL database from a Linux host.

On the Ant side, I have something like this:

<property name="db.changelog" location="schema/db.changelog-master.xml" />

<taskdef resource="liquibase/integration/ant/antlib.xml" uri="antlib:liquibase.integration.ant">
    <classpath><snip/></classpath>
</taskdef>

<liquibase:database id="db"
                    driver="org.postgresql.Driver"
                    url="jdbc:postgresql://localhost:5432/<db>"
                    user="master"
                    password="${db.password}"/>

<target name="db:update" description="Runs all pending database migrations.">
    <liquibase:updateDatabase changeLogFile="${db.changelog}" databaseref="db" />
</target>

Then on the CLI side, this:

java -cp "..." liquibase.integration.commandline.Main \
    --classpath "..." \
    --defaultsFile="devscripts/liquibase.properties" \
    "$@"

liquibase.properties is

driver: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/<db>
changeLogFile: schema/db.changelog-master.xml

Version is LiquiBase 3.8.8.

Expected behavior
If I have an unapplied changeset, I would expect that running the Ant update task or the liquibase CLI update task in sequence, in either order, to work without throwing errors.

Screenshots
N/A

Additional context
Realistically I don't expect to be using the CLI for updates some of the time and Ant for updates the rest of the time. But it does call into question whether the CLI's reflective operations will be able to correctly identify which changesets have run. We might use the CLI sometimes because the functionality it offers is a superset of what the Ant tasks offer, so I'd like to be assured that it'll actually work when we need it.

Invalid type generated for SMALLINT type column in Postgresql 11

Description
I'm using Postgresql 11 and Liquibase v3.8.8 (I had the same issue in v3.8.2).

For a column with type smallint:
action_id smallint NOT NULL
when running liquibase.generateChangeLog(..) the following change set will be generated.
<changeSet author="xxx (generated)" id="1586384554298-1"> <createTable tableName="usage_log"> <column name="action_id" type="SMALLINT(5)"> <constraints nullable="false"/> </column> </createTable> </changeSet>
When updating an empty schema with a database change log that contains the above mentioned change set, I'm getting the following error:
Reason: liquibase.exception.DatabaseException: ERROR: syntax error at or near "(" Position: 63 [Failed SQL: (0) CREATE TABLE dest_schema.usage_log (action_id SMALLINT(5) NOT NULL)] at liquibase.changelog.ChangeSet.execute(ChangeSet.java:646) ~[liquibase-core-3.8.8.jar:?] at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:53) ~[liquibase-core-3.8.8.jar:?] at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:83) ~[liquibase-core-3.8.8.jar:?] at liquibase.Liquibase.update(Liquibase.java:202) ~[liquibase-core-3.8.8.jar:?] at liquibase.Liquibase.update(Liquibase.java:179) ~[liquibase-core-3.8.8.jar:?] at liquibase.Liquibase.update(Liquibase.java:175) ~[liquibase-core-3.8.8.jar:?] at liquibase.Liquibase.update(Liquibase.java:168) ~[liquibase-core-3.8.8.jar:?]

The problem is with the SMALLINT(5) type that is not valid.

Expected behavior
I was expecting the type for the column to be SMALLINT.
`

`

[regression] Liquibase has started to produce debug logs

Description
Recently I updated my application from Liquibase 3.5.5 to 3.8.7 and I noticed that now there more messages being printed to logs during application startup:

2020-03-14 23:54:29.324 INFO 15925 --- [main] liquibase.executor.jvm.JdbcExecutor : SELECT COUNT(*) FROM mystamps.DATABASECHANGELOGLOCK
2020-03-14 23:54:29.354 INFO 15925 --- [main] liquibase.executor.jvm.JdbcExecutor : SELECT COUNT(*) FROM mystamps.DATABASECHANGELOGLOCK
2020-03-14 23:54:29.368 INFO 15925 --- [main] liquibase.executor.jvm.JdbcExecutor : SELECT LOCKED FROM mystamps.DATABASECHANGELOGLOCK WHERE ID=1
2020-03-14 23:54:29.423 INFO 15925 --- [main] l.lockservice.StandardLockService : Successfully acquired change log lock
2020-03-14 23:54:29.438 INFO 15925 --- [main] l.s.CustomResolverServiceLocator : Can not use class liquibase.parser.core.json.JsonChangeLogParser as a Liquibase service because org.yaml
.snakeyaml.constructor.BaseConstructor is not in the classpath
2020-03-14 23:54:29.442 INFO 15925 --- [main] l.s.CustomResolverServiceLocator : Can not use class liquibase.parser.core.yaml.YamlChangeLogParser as a Liquibase service because org.yaml
.snakeyaml.constructor.BaseConstructor is not in the classpath
2020-03-14 23:54:36.476 INFO 15925 --- [main] liquibase.executor.jvm.JdbcExecutor : SELECT MD5SUM FROM mystamps.DATABASECHANGELOG WHERE MD5SUM IS NOT NULL LIMIT 1
2020-03-14 23:54:36.479 INFO 15925 --- [main] liquibase.executor.jvm.JdbcExecutor : SELECT COUNT(*) FROM mystamps.DATABASECHANGELOG
2020-03-14 23:54:36.483 INFO 15925 --- [main] l.c.StandardChangeLogHistoryService : Reading from mystamps.DATABASECHANGELOG
2020-03-14 23:54:36.485 INFO 15925 --- [main] liquibase.executor.jvm.JdbcExecutor : SELECT * FROM mystamps.DATABASECHANGELOG ORDER BY DATEEXECUTED ASC, ORDEREXECUTED ASC
2020-03-14 23:54:36.943 INFO 15925 --- [main] l.lockservice.StandardLockService : Successfully released change log lock

An example of how it was before update:

2020-03-10 17:48:21.025 INFO 17645 --- [ main] liquibase : Successfully acquired change log lock
2020-03-10 17:48:26.364 INFO 17645 --- [ main] liquibase : Reading from mystamps.DATABASECHANGELOG
2020-03-10 17:48:26.709 INFO 17645 --- [ main] liquibase : Successfully released change log lock

Expected behavior
I'd expect to see only messages that are really useful to me. The SQL queries that Liquibase executes under the hood (highlighted in bold) don't seem useful to me. Note that here I'm talking about Liquibase internal logic, the queries from my changesets are actually useful.

Additional observation: I see that Liquibase changed logger names from "liquibase" to names of the classes. I like this change but it would be nice to mention that in changelogs (I read all of them and I don't remember that it was mentioned). I see this as breaking behavior because now the existing logging configuration might need to be adjusted.

Additional context
My application uses Spring Boot.

Postgres SERIAL and BIGSERIAL are created as INT / BIGINT without auto increment

The following liquibase changeset does not work as expected

        <createTable tableName="test">
            <column name="id" type="SERIAL">
                <constraints nullable="false" primaryKey="true"/>
            </column>
        </createTable>

This changeset results in sql

CREATE TABLE test (id INTEGER NOT NULL, CONSTRAINT TEST_PKEY PRIMARY KEY (id));

In liquibase 3.6.3 and earlier the type SERIAL was used for the column which means that a sequence is automatically included.

This issue seems to be caused by #874
It appears that SERIAL columns are replaced by INT, however liquibase does reconize that this column type is an auto increment column.

It would be acceptible if the generated sql would be

CREATE TABLE test (id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, CONSTRAINT TEST_PKEY PRIMARY KEY (id));

For the includeAll tag, "Not a valid resource entry" is written

Description
If resources are added via includeAll, then we get an invalid resource error.
If the file is specified explicitly, then it is processed correctly

To Reproduce
Liquibase: 3.8.7

db.changelog-master.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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.8.xsd">
<!--	<include file="2020/03/08_1034.xml" relativeToChangelogFile="true"/>-->
	<includeAll path="2020/**" relativeToChangelogFile="true"/>
</databaseChangeLog>
2020-03-09 11:38:14.766  INFO 80831 --- [           main] l.lockservice.StandardLockService        : Successfully acquired change log lock
2020-03-09 11:38:24.883  WARN 80831 --- [           main] i.s.SpringLiquibase$SpringResourceOpener : Not a valid resource entry: jar:file:/CUT_PATH/db.jar!/db/changelog/2020/
2020-03-09 11:38:24.895  WARN 80831 --- [           main] i.s.SpringLiquibase$SpringResourceOpener : Not a valid resource entry: jar:file:/CUT_PATH/db.jar!/db/changelog/2020/03/
2020-03-09 11:38:24.902  WARN 80831 --- [           main] i.s.SpringLiquibase$SpringResourceOpener : Not a valid resource entry: jar:file:/CUT_PATH/db.jar!/db/changelog/2020/03/08_1034.xml

The problem is reproduced only on JDK 13 - there is no problem on JDK 1.8

JDK 1.8:

2020-03-09 12:12:44.987  INFO 80889 --- [           main] l.lockservice.StandardLockService        : Successfully acquired change log lock
2020-03-09 12:12:47.979  INFO 80889 --- [           main] liquibase.changelog.DatabaseChangeLog    : Reading resource: db/changelog/2020/
2020-03-09 12:12:47.980  INFO 80889 --- [           main] liquibase.changelog.DatabaseChangeLog    : Reading resource: db/changelog/2020/03/
2020-03-09 12:12:47.980  INFO 80889 --- [           main] liquibase.changelog.DatabaseChangeLog    : Reading resource: db/changelog/2020/03/08_1034.xml

Databasechangelog is not created with PostgreSQL two schemas

Version of Liquibase
Apache License
Version 2.0, January 2004
Liquibase Integration & Version: <Pick one: CLI, maven, gradle, spring boot, servlet, etc.>
CLI
Database Vendor & Version:

PostgreSQL version 12.2
##Description
I'm trying to automate deployment to PostgreSQL using liquibase, basically I have a database "my_db" with two schemas "myschema1", "myschema2". I have two targets that I execute:

install.bat install-myschema1-db with a url pointing to myschema1 schema

install.bat install-myschema2-db with a url pointing to myschema2 schema

the first target executes correctly and creates all the needed tables, it also automatically creates the myschema1.databasechangelog table used by liquibase for logging.
However, when I try to execute the install-myschema2-db target it fails with ERROR:

Error executing SQL SELECT MD5SUM FROM myschema2.databasechangelog WHERE MD5SUM IS NOT NULL LIMIT 1: ERROR: relation "myschema2.databasechangelog" does not exist

Basically, the installer scans for databasechangelog table and it find it in the database so it doesn't create, but when it tries to search in it , it tries to look in myschema2.databasechangelog but doesn't find it since it's created under myschema1

##Steps to Reproduce
"%ANT_HOME%\bin\ant.bat" -f install.xml -Denv.file=install.properties %CMD_LINE_ARGS%

%CMD_LINE_ARGS% is the target to execute which in this case is install-myschema2-db

I shouldnt need a db connection to run <command>--help

Note: For now, only PRO commands have command specific help. so only "rollbackonechangset" and "rollbackoneupdate".

Context

We should make it easier to learn liquibase, in part by making it easier to read the help. while only PRO commands will be affected, this should be coded so that we can add command specific help (as part of the upcoming Usability Epic) and it should function without further coding work.

Requirements

As a user, i want to open a terminal/command line, fire up liquibase and hit the command's help, without having to fire up a database as well.

When learning liquibase i often check the --help, but this will not work without a specified url which actually connects to a database. for example, rollbackonechangeset --help will tell you.

mmc-mbp:opt mariochampion$ liquibase rollbackonechangeset --help
Liquibase Community 3.8.6 by Datical
Errors:
  The option --url is required.
  The option --changeLogFile is required.

Acceptance Criteria

This ticket will be successfully resolved when:

  1. A user with or without a PRO license should be able to see command --help, without required command options.
  2. A user typing "liquibase rollbackonechangeset --help" will see the help for that command in their console
  3. A user typing "liquibase rollbackoneupdate --help" will see the help for that command in their console

generateChangelog with CockroachDB: addForeignKeyConstraint must have correct column order

Description
This is fairly easy to reproduce using sample code provided by the folks at CoackroachDB. The issue is that when using the generateChangeLog command against a table that has primary keys, the generated changelog has a changeset to create the table, followed by a second changeset to add the primary key to the table. This changelog is not able to be deployed to a new clean database without errors.

To Reproduce
Follow the instruction in the readme file at https://github.com/timveil-cockroach/liquibase-example

The steps under "Test 2" show the failing condition. Note that this bug is somewhat "masked" in the example by the existence of #1021

The issue with the <addForeignKeyConstraint> changes generated is that the order of column names in the referencedColumnNames attribute needs to match the actual order of the columns in the table.

For example, in the current code, a 'bad' changeset looks like this:

    <changeSet author="steve (generated)" id="1582906076997-23">
        <addForeignKeyConstraint baseColumnNames="c_w_id,c_d_id" baseTableName="customer" constraintName="fk_c_w_id_ref_district" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="d_w_id,d_id" referencedTableName="district" validate="true"/>
    </changeSet>

Note that the order of the columns in referencedColumnNames is d_w_id,d_id. If we look at the generated <createTable> statement for the referenced table, we see that the actual order of the columns is d_id,d_w_id as seen below:

    <changeSet author="steve (generated)" id="1582906076997-2">
        <createTable tableName="district">
            <column name="d_id" type="BIGINT">
                <constraints nullable="false"/>
            </column>
            <column name="d_w_id" type="BIGINT">
                <constraints nullable="false"/>
            </column>
            <column name="d_name" type="VARCHAR(10)"/>
            <column name="d_street_1" type="VARCHAR(20)"/>
            <column name="d_street_2" type="VARCHAR(20)"/>
            <column name="d_city" type="VARCHAR(20)"/>
            <column name="d_state" type="CHAR(2)"/>
            <column name="d_zip" type="CHAR(9)"/>
            <column name="d_tax" type="numeric(4, 4)"/>
            <column name="d_ytd" type="numeric(12, 2)"/>
            <column name="d_next_o_id" type="BIGINT"/>
        </createTable>
    </changeSet>

Expected behavior
The generated changeset should look like this:

    <changeSet author="steve (generated)" id="1582906076997-23">
        <addForeignKeyConstraint baseColumnNames="c_w_id,c_d_id" baseTableName="customer" constraintName="fk_c_w_id_ref_district" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="d_id,d_w_id" referencedTableName="district" validate="true"/>
    </changeSet>

Additional context
The repro steps require the ability to run a docker container and maven. I used maven 3.6.

constraint_name for PostgreSQL is not quoted

+ " EXECUTE 'alter table %3$s.%4$s drop constraint ' || constraint_name;\n"

I use PostgreSQL 12.2, liquibase 3.8.8 and I have a changeset with objectQuotingStrategy="QUOTE_ALL_OBJECTS" and <dropPrimaryKey tableName="CardToken"/> command (without constraintName). But when I run liquibase update, I get the following error:

Error: ERROR: constraint "cardtoken_pkey" of relation "CardToken" does not exist Where: SQL statement "alter table "public"."CardToken" drop constraint CARDTOKEN_PKEY" PL/pgSQL function inline_code_block line 7 at EXECUTE [Failed SQL: (0) DO $$ DECLARE constraint_name varchar; BEGIN SELECT tc.CONSTRAINT_NAME into strict constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = 'CardToken' AND TABLE_SCHEMA = 'public'; EXECUTE 'alter table "public"."CardToken" drop constraint ' || constraint_name; END $$;] ;]

Constraint CARDTOKEN_PKEY really exists. But in the code, it is substituted without quotes. I think this is the problem.

CreateViewGenerator generates incorrect SQL for PostgreSQL

Description
CORE-2377 removed the DROP statement generation for PostgreSQL in CreateViewGenerator (commit).

The ticket states that DROP + CREATE can be substituted for a "CREATE OR REPLACE" statement in PostgreSQL in all cases. However, this assumption proved to be incorrect. Quoting PostgreSQL docs for CREATE VIEW:

CREATE OR REPLACE VIEW is similar, but if a view of the same name already exists, it is replaced. The new query must generate the same columns that were generated by the existing view query (that is, the same column names in the same order and with the same data types), but it may add additional columns to the end of the list. The calculations giving rise to the output columns may be completely different.

Changesets that were created for versions < 3.7.0 containing createView are now broken because of this change.

To Reproduce
See here: https://github.com/abelk2/liquibase-postgres-createview/blob/master/README.md

Expected behavior
For PostgreSQL, createView change withreplaceIfExists = "true" should replace existing database views even when field names / data types are changed just like it did before 3.7.0

Liquibase schema XSD 3.5 not working since the last hour

Hi guys,

We are using liquibase and suddenly our ci/cd process stopped working within the last hour.

Checking at the logs, the error displayed is:

Caused by: liquibase.exception.SetupException: Error parsing line 2 column 35 of liquibase/v-1.10/2017-07-26--01-metadata-tables-legacy.xml: s4s-elt-character: Non-whitespace characters are not allowed in schema elements other than 'xs:appinfo' and 'xs:documentation'. Saw '301 Moved Permanently'.
....
SEVERE 3/16/20 4:52 PM: liquibase: s4s-elt-character: Non-whitespace characters are not allowed in schema elements other than 'xs:appinfo' and 'xs:documentation'. Saw '301 Moved Permanently'.
liquibase.exception.ChangeLogParseException: Error parsing line 2 column 35 of liquibase/changelog-test.xml: s4s-elt-character: Non-whitespace characters are not allowed in schema elements other than 'xs:appinfo' and 'xs:documentation'. Saw '301 Moved Permanently'.

All the files we have older than 2 years that are using below schemas are failing:

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
                   xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
                   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/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">

However, when we change dbchangelog-3.5.xsd to dbchangelog-3.1.xsd in above files everything works fine.

This looks like something has changed on your end for the xsd 3.5.

We could change all our migration scripts to use 3.1 schemas, but this will make us to re-update all hashes in our db manually.

Can you please provide any feedback?

validate exit code should be 1 on error

liquibase validate exits with return code 0 even on validation error. To allow integration into scripts and development process tooling, it would be helpful if the best practice from unix was followed:

  • return 0 on success
  • return an int greater 0 on error. Having specific error codes for say xml validation error and a different one for syntactically sound but changed changesets would be a plus.

$ liquibase --changeLogFile master.xml validate
Starte Liquibase am Di, 25 Feb 2020 17:02:05 MEZ (Version 3.8.0, kompiliert am 2019-08-15T20:38:06Z)
echLiquibase Community 3.8.0 by Datical
o $?
Validation Error:
1 change sets have changed since they were ran against the database
change_88.xml::#BSLB-XXY: addColumn: departments::christof was: 8:28984dcd4c2a48cadab9994e8e40fc05 but is now: 8:2676116ef19fedfe8ba62352c10885e1
Liquibase: Der Befehl 'validate' wurde erfolgreich ausgeführt.
$ echo $?
0

How to disable dynamic substitution of parameters in a changelog?

Because our sql contains string literals like '${someFreemarkerParam}'

Environment

Liquibase Version:

Liquibase Integration & Version: <Pick one: CLI, maven, gradle, spring boot, servlet, etc.>

Liquibase Extension(s) & Version:

Database Vendor & Version:

Operating System Type & Version:

Description

A clear and concise description of the issue being addressed.

  • Describe the actual problematic behavior.
  • Ensure private information is redacted.

Steps To Reproduce

List the steps to reproduce the behavior.

  • Please be precise and ensure private information is redacted
  • Include things like
    • Files used - sql scripts, changelog file(s), property file(s), config files, POM Files
    • Exact commands used - CLI, maven, gradle, spring boot, servlet, etc.

Allow adding multiple unique column constraints on table creation.

Hi!

Currently I am working on porting an existing project to SQLite. SQLite does not allow adding constraints to a table later. Adding foreign key constraints work really well on table creation, liquibase does a wonderful job there.

I run into a problem when I try to add a unique constraint across multiple columns.
The XML

        <createTable tableName="MY_EXAMPLE_TABLE">
            <column autoIncrement="true" name="MY_EXAMPLE_TABLE_ENTRY_ID" type="INTEGER">
                <constraints primaryKey="true" primaryKeyName="PK_MY_EXAMPLE_TABLE_ENTRY"/>
            </column>
            <column name="TABLE_KEY" type="TEXT">
                <constraints nullable="false"
                             uniqueConstraintName="UC_MY_EXAMPLE_TABLE_ENTRY_CCEI_DK" unique="true"/>
            </column>
            <column name="TABLE_VALUE" type="CLOB"/>
            <column name="SOME_OTHER_TABLE_ENTRY_ID" type="INTEGER">
                <constraints nullable="false"
                             foreignKeyName="FK_MY_EXAMPLE_TABLE_SOME_OTHER_TABLE_ENTRY_ID"
                             referencedColumnNames="OTHER_TABLE_ENTRY_ID"
                             referencedTableName="OTHER_TABLE_ENTRY"
                             uniqueConstraintName="UC_MY_EXAMPLE_TABLE_ENTRY_CCEI_DK"
                             unique="true"/>
            </column>
        </createTable>

Note that the uniqueConstraintName for the columns SOME_OTHER_TABLE_ENTRY_ID and PK_MY_EXAMPLE_TABLE_ENTRY is the same.

expected sql

CREATE TABLE "MY_EXAMPLE_TABLE" (
	"MY_EXAMPLE_TABLE_ENTRY_ID"	INTEGER NOT NULL,
	"TABLE_KEY"	TEXT NOT NULL,
	"TABLE_VALUE"	TEXT,
	"SOME_OTHER_TABLE_ENTRY_ID"	INTEGER NOT NULL,
	CONSTRAINT "UC_MY_EXAMPLE_TABLE_ENTRY_CCEI_DK" UNIQUE("TABLE_KEY","SOME_OTHER_TABLE_ENTRY_ID"),
	CONSTRAINT "FK_MY_EXAMPLE_TABLE_SOME_OTHER_TABLE_ENTRY_ID" FOREIGN KEY("CALL_CACHING_ENTRY_ID") REFERENCES "OTHER_TABLE_ENTRY"("OTHER_TABLE_ENTRY_ID"),
	CONSTRAINT "PK_MY_EXAMPLE_TABLE_ENTRY KEY("MY_EXAMPLE_TABLE_ENTRY_ID" AUTOINCREMENT)
);

result sql

CREATE TABLE "MY_EXAMPLE_TABLE" (
	"MY_EXAMPLE_TABLE_ENTRY_ID"	INTEGER NOT NULL,
	"TABLE_KEY"	TEXT NOT NULL,
	"TABLE_VALUE"	TEXT,
	"SOME_OTHER_TABLE_ENTRY_ID"	INTEGER NOT NULL,
	CONSTRAINT "UC_MY_EXAMPLE_TABLE_ENTRY_CCEI_DK" UNIQUE("TABLE_KEY"),
	CONSTRAINT "UC_MY_EXAMPLE_TABLE_ENTRY_CCEI_DK" UNIQUE("SOME_OTHER_TABLE_ENTRY_ID"),
	CONSTRAINT "FK_MY_EXAMPLE_TABLE_SOME_OTHER_TABLE_ENTRY_ID" FOREIGN KEY("CALL_CACHING_ENTRY_ID") REFERENCES "OTHER_TABLE_ENTRY"("OTHER_TABLE_ENTRY_ID"),
	CONSTRAINT "PK_MY_EXAMPLE_TABLE_ENTRY KEY("MY_EXAMPLE_TABLE_ENTRY_ID" AUTOINCREMENT)
);

Currently two unique constraints with the same name are created that each have one column, instead of one constraint with both columns.

Is there currently a way to provide a multi-column unique constraint upon table creation? (except for plain SQL). Would it be an idea to join any UNIQUE constraints that share the exact same name?

Liquibase-core - dbDoc fails generating of documents

Prerequisites:

  • Oracle DB(with at least one table with minimum necessary column(id, first_name));
  • Windows 10;
  • liquibase.properties
    driver=oracle.jdbc.driver.OracleDriver
    changeLogFile=test_changelog.xml
    username=liquibase_user
    password=root
    url=jdbc:oracle:thin:@localhost:1521:ORCL
  • test_changelog.xml
    <?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.0.xsd">
    <changeSet runAlways="true" author="testuser" id="3">
    <sql>CREATE INDEX TEST_INDEX ON PERSON (CASE WHEN (FIRST_NAME IS NOT NULL AND (FIRST_NAME='1' OR FIRST_NAME='2' OR FIRST_NAME='3' OR FIRST_NAME='4' OR FIRST_NAME='5'
    OR FIRST_NAME='6' OR FIRST_NAME='7' OR FIRST_NAME='8' OR FIRST_NAME='9' OR FIRST_NAME='10' OR FIRST_NAME='11'
    OR FIRST_NAME='12' OR FIRST_NAME='13' OR FIRST_NAME='14' OR FIRST_NAME='15' OR FIRST_NAME='16' OR FIRST_NAME='17' OR FIRST_NAME='18')) THEN 1 ELSE 0 END)</sql>
    </changeSet>

</databaseChangeLog>

Steps to reproduce:

  1. Execute the next command in cmd:
    java -jar liquibase-core-3.5.5.jar --driver=oracle.jdbc.driver.OracleDriver --classpath=<path_to_jdbc_driver> --changeLogFile=<path_to_test_changelog.xml> --url="jdbc:oracle:thin:@localhost:1521:ORCL" --username=<user_name> --password=<password> update
  2. java -jar liquibase-core-3.5.5.jar --driver=oracle.jdbc.driver.OracleDriver --classpath=<path_to_jdbc_driver> --changeLogFile=<path_to_test_changelog.xml> --url="jdbc:oracle:thin:@localhost:1521:ORCL" --username=<user_name> --password=<password> dbDoc folder_to_out_docs

Expected result: dbDoc generates html files for each table column as well as other attributes.
Actual result: Unexpected error running Liquibase: dbDoc_out\columns\liquibase_user.person.case__when___first_name__is_not_null_and___first_name___1__or__first_name___2__or__first_name___3__or__first_name___4__or__first_name___5__or__first_name___6__or__first_name___7__or__first_name___8__or__first_name___9__or__first_name___10__or__first_name___11__or__first_name___12__or__first_name___13__or__first_name___14__or__first_name___15__or__first_name___16__or__first_name___17__or__first_name___18____then_1_else_0_end.html (The filename, directory name, or volume label syntax is incorrect).

RCA:
The reason of this error is dbDoc tries to create html doc with index body in filename for table column folder. As we can see the index body is too long and file system doesn't allow to create files with such too long file name(255 characters constraint). So, from my perspective, dbDoc identifies index body as column and generates doc for it.

Please fix it.

Separate Firebird v3 from earlier Firebird versions

Description
Firebird 3 has some differences with respect to the created SQL statements. Currently there is no way to distinguish versions prio v3 from v3 and onwards

Expected behavior
The Firebird 3 behaviour should get explictily available by using its own short name "firebird3" and by creating the necessary test cases.

Additional context
The Firebird3Database class should be extended and all test cases should be implemented for it as well.

Rollback is broken

Description
Rollback does not work, with tags or with count, doesn't respect rollback sql file.

To Reproduce

    <changeSet id="5" author="ale">
        <tagDatabase tag="before_provisioning_1"/>
    </changeSet>

    <changeSet id="6" author="ale">
        <sqlFile path="add_two_columns_to_table_a_create_two_new_tables_add_foreign_key.sql" relativeToChangelogFile="true"/>

        <!-- this rollback is for reference only, liquibase rollback is broken , doesn't jump to previous changeset,
         doesn't undo changes  -->
        <rollback>
            <sqlFile path="some_rollback_script_which_works_against_db.sql" relativeToChangelogFile="true"/>
        </rollback>
    </changeSet>

liquibase rollbackSQL before_provisioning_1  --changeLogFile liquibase.xml --url="jdbc:mysql://localhost:3306/credentials" --classpath="/home/ale/liquibase/src/java/mysql-connector-java-5.1.47.jar" --password=some --username=root 
Liquibase Community 3.8.7 by Datical
--  *********************************************************************
--  Rollback to 'before_provisioning_1' Script
--  *********************************************************************
--  Change Log: liquibase.xml
--  Ran at: 11/03/20 16:23
--  Against: [email protected]@jdbc:mysql://localhost:3306/credentials
--  Liquibase version: 3.8.7
--  *********************************************************************

--  Lock Database
UPDATE credentials.DATABASECHANGELOGLOCK SET `LOCKED` = 1, LOCKEDBY = '172.17.0.1 (172.17.0.1)', LOCKGRANTED = '2020-03-11 16:23:18.432' WHERE ID = 1 AND `LOCKED` = 0;

--  Release Database Lock
UPDATE credentials.DATABASECHANGELOGLOCK SET `LOCKED` = 0, LOCKEDBY = NULL, LOCKGRANTED = NULL WHERE ID = 1;
As you can see the above is empty, it refuses to execute contents of mysql file.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.