Liquibase - validation failed checksum changed - liquibase

This is the first version of my changelog.sql:
-- liquibase formatted sql
-- changeset kh:1
CREATE TABLE test_table (test_id INT, test_column VARCHAR(256), PRIMARY KEY (test_id))
--changeset kh:2
INSERT INTO test_table (test_id, test_column) VALUES(3,'saket');
This is an update of my changelog.sql (Added a column in the first changeset):
-- liquibase formatted sql
-- changeset kh:1
CREATE TABLE test_table (test_id INT, test_column VARCHAR(256), test_column2 VARCHAR(256), PRIMARY KEY (test_id))
--changeset kh:2
INSERT INTO test_table (test_id, test_column) VALUES(3,'saket');
I execute a liquibase update with the following command:
docker run --rm -v /changelog:/liquibase/changelog liquibase/liquibase \
--url=jdbc:postgresql://xxxxxxxxxx:5432/postgres \
--changelog-file=changelog.sql --username=xxxx \
--password=xxxx update
I get this error:
Caused by: liquibase.exception.ValidationFailedException: Validation Failed:
1 changesets check sum
changelog.sql::1::kh was: 8:46ea95d67274343c559a1c5ddc8ee33 but is now: 8:ab7361c532323a6a32bc79d230a46574
I understand that when running it in a productive environment, it should fail in order not to launch scripts again by mistake, but, in a non-productive environment, how should it work?
I imagine three solutions in a DevOps (NonProd) scenario:
Restore database as the first step and execute changelog for specific version.
For nonprod, ignore the checksum validation
Modify the changelog and add a new changeset with the change.- For my taste, this is the least correct
In a non-production environment, it may be necessary to make changes to SQL until the new functionality is validated. What is the best practice, and is there any other solution?

The checksum error indicates that you are modifying a changeset that has already been executed in the particular database target. Therefore, Liquibase does not understand why you are doing this modification.
The sql statement "CREATE TABLE test_table" cannot be executed again, so adding the additional column does not make sense.
If you want to add a column to a table that has already been created, you really only have 2 options:
Drop and recreate the table to include the new column
Alter the table to add the new column
Option 1 can be acomplished by using Liquibase rollback, followed by modifying the changeset, and then Liquibase update.
Option 2 can be accomplished by adding a new changeset.
Both are 100% valid options.

Related

Liquibase Update Command doesn't drop elements (tables, functions, procedure...) from my database despite SQL script absent from my solution

I use liquibase tool to manage a postgres database. I work as the following :
I have a solution composed of different folders containing SQL scripts responsible for schema creation, tables creations, types creation, procedures creation, etc... Then, I have a ChangeLog file in xml format, containing the following informations :
includeAll path="#{Server.WorkingDirectory}#/02 - Schema" relativeToChangelogFile="false"
includeAll path="#{Server.WorkingDirectory}#/03 - Types" relativeToChangelogFile="false
includeAll path="#{Server.WorkingDirectory}#/04 - Tables" relativeToChangelogFile="false"
includeAll path="#{Server.WorkingDirectory}#/05 - Fonctions" relativeToChangelogFile="false"
includeAll path="#{Server.WorkingDirectory}#/06 - Stored Procedures" relativeToChangelogFile="false"
I run liquibase via command line :
liquibase --changeLogFile=$(Changelog.File.Name) --driver=$(Driver.Name) --classpath=$(Driver.Classpath) --url=$(BDD.URL) --username=$(BDD.Login) --password=$(BDD.Password) update
This enable Liquibase to take all the SQL scripts in the different folders listed in the changelogFile, compare it with the current database at url $(BDD.URL), and generate a delta script containing all the SQL queries to be executed to have a database corresponding to my solution.
This works well when I add new scripts (new tables or procedures) or modify existing scripts, my database is correctly updated by the command line, as expected. BUT it does not do anything when I delete a script from my solution.
To be more factual, here is what I want :
I have a SQL file containing the query "CREATE TABLE my_table" located in the folder "04 - Tables".
I execute the update command above, and it creates the table "my_table" in my database.
I finally do not want this table in my database any more. Thus I would like to simply remove the corresponding SQL script from my solution, and then run again the "update" command to simply remove my table in my database, generating automatically a "DROP TABLE my_table" by the liquibase "update" command. But this is not working as Liquibase doesn't record any change when I remove a sql file (whereas it does when I add or modify a file).
Does anyone know a solution to this ? Is there a specific command to drop an element when there is no "CREATE" query for this element, in a SQL solution ?
Many thanks in advance for you help :)
You will need to explicitly write a script to drop the table.
Other option is to rollback the change IF YOU HAVE Specified the Rollback SQL as part of your original SQL script.
There is a Pro Version option to rollback a single update , with free / community version, you can rollback last few changes in sequence
ex; I did "liquibase rollbackCount 5" will rollback the last 5 changes that were applied ONLY IF I HAD Coded the rollback sql needed as part of my script.
My Sql script sample that included the code to rollback is
--rollback drop TABLE test.user1 ; drop table test.cd_activity;
CREATE TABLE test.user1 (
user_type_id int NOT NULL
);
CREATE TABLE test.cd_activity (
activity_id Integer NOT NULL
userid int);

How to tag several changeset in sqlfile mode

I use sqlfile mode.
in a sql file I wrote severals changeset :
--liquibase formatted sql
--changeset chs:31
create table tab_tst3(
id int primary key,
name varchar(255)
);
--rollback drop table tab_tst3;
--changeset chs:32
insert into tab_tst3 (id, name) values (1, 'tab 1');
insert into tab_tst3 (id, name) values (2, 'tab 2');
--changeset chs:33
create sequence tab_seq3;
--rollback drop sequence tab_seq3;
when i execute that file like :
liquibase --driver=oracle.jdbc.OracleDriver --url=jdbc:oracle:thin:#xxxxxx--username=xxx--
password=xxx --changeLogFile=myfile.sql
Starting Liquibase at jeu., 08 ao¹t 2019 15:48:14 CEST (version 3.7.0 built at 2019-07-16 02:26:39)
Successfully tagged 'xxxx'
And when I do
liquibase --driver=oracle.jdbc.OracleDriver --url=jdbc:oracle:thin:#xxxxxx--username=xxx--
password=xxx --tag=myTAG
Only the last ligne is tagged (chs:33)
How to tag all the 3 lines with the same tag ?
thanks
What the tag command does is mark a particular set of changes that have been deployed already as "this set of changes is in a good state that I might want to get back to". So the idea is that you ran liquibase update and the three changesets in the changelog at that time get deployed to the database. You do some testing, and you decide that everything is good, so you run liquibase tag to mark that spot. You continue development, and add some new changesets, and use liquibase update to deploy those to the database. During your testing, you discover a problem, so you want to go back to the last known good state, so you use the liquibase rollback command with the tag you applied and it rolls back the newer changes that were problematic, getting you back to a known good state.

Script out insert script with dependency in SQL server

we want Script out insert script with dependency in multiple table.
For example – TABLEA is Master table- here I want to insert 1 record from old version of table script out earlier (SSMS-TASK-Generate script), but due to dependency in another table it will not work.
Regards,
Manish
If you have the real foreign key between your tables, SMSS Generate Scripts Task takes care of the dependencies and the master table insert script will be generated before the detail tables.

Does liquibase recognize if table is already up to date before executing changeSet?

In our case liquibase is used to update databses for existing installation. New installations are already up to date.
Assuming we have got a new installation. Starting the application will force to execute liquibase changesets (e.g. change type of a column) but as I mentioned before there is nothing to update as the column already was created with the correct type.
Does liquibase recognize that the table column is already up to date or does it try to execute the changeset as there is no entry within the databasechangelog table for it?
Liquibase uses an alternative approach that avoids a need to analyze the target database's data dictionary. This makes DB operations simpler and more cross platform.
A special table "DATABASECHANGELOG" keeps a record of the changesets applied to the target database instance. This table also contains a checksum (calculated at runtime) to determine if changsets are altered between runs of liquibase.
So if you altered the type of a table column, liquibase can detect this and can throw an error, when run against an existing database. (Obviously, on a new DB, the table would be created as expected).
Finally, the changeset documentation describes two optional attributes ("runAlways" and "runOnChange") which could tell lqiuibase to reapply a changeset more than once to a database. There is also a "clearCheckSums" command that can be used to reset the checksums on an existing database. Obviously you need to know what you're doing when using such an option :-)
Liquibase will not recognize anything automatically.
But you can use <preConditions/> in your changeSet to check if your changeSet must be applied or not.

liquibase does not add script to history when changeset fails

When a changeset is marked as failOnError:false, does liquibase record it as having been applied when it fails?
For example, we have a script that performs a pre-emptive drop table in one changeset and then creates the table in the next changeset. When the script is first run, the drop table statement fails as expected and then the table is created successfully. However, the changeset that attempted the drop table is not added to the databasechangelog table.
Is that expected behavior?
That is the current behavior currently. Depending on the reason for the failure, it can make sense to either continue to retry it or to not.
I created https://liquibase.jira.com/browse/CORE-1766 to add the feature to mark it as failed and not try again.
Currently, your best option would be to add a precondition to the dropTable changeSet with onFail="MARK_RAN"