UnexpectedLiquibaseException: Don't know how to find table and column names - liquibase

While trying to execute a changeset that should add a column to a table :
<changeSet id="2013.06.25_2" author="ama">
<preConditions onFail="MARK_RAN">
<not>
<columnExists tableName="T_FORCED_DATA" columnName="TRADE_KEY_ID"/>
</not>
</preConditions>
<comment>Add column T_FORCED_DATA.TRADE_KEY_ID</comment>
<addColumn tableName="T_FORCED_DATA">
<column name="TRADE_KEY_ID" type="numeric(10,0)" defaultValue="NULL">
<constraints nullable="true" references="T_TRADE_KEY" foreignKeyName="TRADE_KEY_ID" />
</column>
</addColumn>
</changeSet>
I get the following error :
SEVERE 6/25/13 5:35 PM:liquibase: Change Set db/changelog/_2013/_06/_05/update_T_FORCED_DATA.xml::2013.06.25_2::ama failed. Error: Don't know how to find table and column names from T_TRADE_KEY liquibase.exception.UnexpectedLiquibaseException: Don't know how to find table and column names from T_TRADE_KEY
at liquibase.sqlgenerator.core.AddColumnGenerator.addForeignKeyStatements(AddColumnGenerator.java:93)
at liquibase.sqlgenerator.core.AddColumnGeneratorDefaultClauseBeforeNotNull.generateSql(AddColumnGeneratorDefaultClauseBeforeNotNull.java:91)
at liquibase.sqlgenerator.core.AddColumnGeneratorDefaultClauseBeforeNotNull.generateSql(AddColumnGeneratorDefaultClauseBeforeNotNull.java:26)
at liquibase.sqlgenerator.SqlGeneratorChain.generateSql(SqlGeneratorChain.java:30)
at liquibase.sqlgenerator.SqlGeneratorFactory.generateSql(SqlGeneratorFactory.java:150)
at liquibase.executor.AbstractExecutor.applyVisitors(AbstractExecutor.java:22)
at liquibase.executor.jvm.JdbcExecutor.access$000(JdbcExecutor.java:36)
at liquibase.executor.jvm.JdbcExecutor$1ExecuteStatementCallback.doInStatement(JdbcExecutor.java:82)
at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:55)
at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:104)
at liquibase.database.AbstractDatabase.execute(AbstractDatabase.java:1091)
at liquibase.database.AbstractDatabase.executeStatements(AbstractDatabase.java:1075)
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:317)
at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:27)
at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:58)
at liquibase.Liquibase.update(Liquibase.java:114)
at org.liquibase.maven.plugins.LiquibaseUpdate.doUpdate(LiquibaseUpdate.java:31)
at org.liquibase.maven.plugins.AbstractLiquibaseUpdateMojo.performLiquibaseTask(AbstractLiquibaseUpdateMojo.java:24)
at org.liquibase.maven.plugins.AbstractLiquibaseMojo.execute(AbstractLiquibaseMojo.java:305)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
Does anyone know why am I getting this exception ?
For info : I have a Table called T_TRADE_KEY with a column TRADE_KEY_ID.
Thanks

Looking at the liquibase code and according to the stack trace you provided liquibase is checking on the references="T_TRADE_KEY" with a regex of:
([\\w\\._]+)\\(([\\w_]+)\\).
While this does not match, the error you get is thrown.
The regex expects something with brackets.
So I guess something like:
references="T_TRADE_KEY(TRADE_KEY_ID)"
should work.
The attribute foreignKeyName is not the column name of the foreign key but just a name for the foreign key.
Maybe the documentation on the <constraint> tag also helps.

Related

Add new column via liquibase only if not already exists

I want to use liquibase on spring boot startup to add a new column to an existing table.
But in the particular schema I'm working with I have already added it manually.
So I get an error on startup indicating the column already exists (because it does):
Error creating bean with name 'liquibase' defined in class path resource
[...LiquibaseConfiguration.class]: LiquibaseException:
liquibase.exception.MigrationFailedException: Migration failed for
change set db/changelog/AlterTable_MyTable_AddNewCol.xml::1::me (manual):
Reason: liquibase.exception.DatabaseException:
Duplicate column name 'new_col' [Failed SQL: (1060)
ALTER TABLE my_schema.my_table ADD new_col INT NULL]
Is there a liquibase precondition option to add the column only if it does not already exist; and if it already exists, don't error out?
I tried the following and the process errors out with the above error:
<databaseChangeLog ... >
<changeSet author="me (manual)" id="1">
<preConditions onFail="WARN">
<columnExists tableName="my_table" columnName="new_col" />
</preConditions>
<addColumn tableName="my_table">
<column name="new_col" type="integer"/>
</addColumn>
</changeSet>
</databaseChangeLog>

How to get PreConditions working from Java applied changelogs?

I am trying to use PreConditions to skip CreateTable changesets and MARK_RAN if the table exists. The PreConditions seem to be ignored as Liquibase logs a table exists error as it tries to create an existing table in MYSQL (in AWS Aurora).
<?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.10.xsd">
<changeSet author="xxx" id="1231">
<preConditions onFail="MARK_RAN">
<not>
<tableExists tableName="tenant"/>
</not>
</preConditions>
<createTable tableName="tenant">
<column autoIncrement="true" name="tenantId" type="int(11)">
<constraints primaryKey="true" nullable="false"
unique="false" />
</column>
...
The changelogs are being applied using the following Java code:
final Database dataBase = DatabaseFactory.getInstance()
.findCorrectDatabaseImplementation(new JdbcConnection(connection));
final Liquibase liquiBase = new liquibase.Liquibase(CHANGE_LOG_FILE, RESOURCE_ACCESSOR, dataBase);
liquiBase.update(CONTEXTS, LABEL_EXPRESSION);
The error:
Response: {"errorMessage":"Failed to connect to Liquibase due to Migration failed for change set db.changelog-1.1.xml::1231::xxx:\n Reason: liquibase.exception.DatabaseException: Table 'tenant' already exists [Failed SQL: CREATE TABLE xxx_global.tenant (tenantId INT AUTO_INCREMENT NOT NULL, region VARCHAR(255) NULL, tenantName VARCHAR(255) NULL, CONSTRAINT PK_TENANT PRIMARY KEY (tenantId))]"}
My only other thought would be to try to use a custom context on the CreateTable changesets for clean installations
I found the issue and it was not a Liquibase issue. The AWS stack containing the Lambda code to call Liquibase was not updating. I deleted and recreated the stack and it started working.

Liquibase loadData as string, not CLOB resource

The Problem
I recently upgraded Liquibase to 3.6.2 from 3.4.2.
Loading seed data from a CSV into text fields now results in a CLOB resource error. Before it would simply insert the text as a value.
The Setup
I'm using Liquibase to manage migrations of my data.
I have a table with an code and description column. description is of type TEXT.
<changeSet author="" id="create-table-degrees">
<createTable tableName="degrees">
<column name="code"
type="varchar(2)">
<constraints primaryKey="true"/>
</column>
<column name="description"
type="text">
<constraints unique="true"/>
</column>
</createTable>
<rollback>
<dropTable tableName="degrees"/>
</rollback>
</changeSet>
I have seed data in a CSV:
code,description
"D1","MASTERS"
"D2","DOCTORATE"
I load it using loadData:
<changeSet author="" id="seed-degrees">
<loadData file="seeds/degrees.csv"
tableName="degrees" />
</changeSet>
The Error
Unexpected error running Liquibase: CLOB resource not found: MASTERS
The Question
Is there a way to keep Liquibase from interpreting seed values as file paths instead of strings, or do I need to manually define the column types as String in loadData.
e.g. I would like to avoid having to modify the old changeSet to:
<changeSet author="" id="seed-degrees">
<loadData file="seeds/degrees.csv"
tableName="roles">
<column name="description" type="string" />
</loadData>
</changeSet>
The workaround listed in CORE-3287: Anver S December 3, 2018, 3:07 PM
While adding an explicit column type definition as defined in original
stackoverflow post
<column name="description" type="string" />
does the trick - for me it effectively requires to update already
applied changesets which ideally I'd try to avoid.

Liquibase: changeLogPropertyDefined doesn't work

I'm trying to execute one of two insert depending on value of Java system property 'type'. But when I run updateSQL, it generates both insert entries despite of value and even presence of variable 'type'. This are my change sets:
<!--changes for CS only-->
<changeSet id="57" author="mborodin">
<preConditions onFail="CONTINUE">
<changeLogPropertyDefined property="type" value="cs"/>
</preConditions>
<sql>INSERT INTO cs.config(key, value) values('autochecks.findProfilesInDb', 'true'),
('web.type', 'cs'), ('globalFailureDetectorEnabled', 'true');
</sql>
</changeSet>
<!--changes for LCS only-->
<changeSet id="58" author="mborodin">
<preConditions onFail="CONTINUE">
<and>
<changeLogPropertyDefined property="type" value="lcs"/>
<not>
<changeSetExecuted
id="57"
author="mborodin"
changeLogFile="${changeLogFile}"
/>
</not>
</and>
</preConditions>
<sql>INSERT INTO cs.config(key, value) values('autochecks.findProfilesInDb', 'false'),
('web.type', 'local-cs'), ('globalFailureDetectorEnabled', 'false');
</sql>
</changeSet>
What's wrong? Is there a better way to work it?
From the first nvoxland's answer at liquibase forum:
… we added the onSqlOutput tag. IGNORE just assumes that the
precondition cannot be applied, but you should continue to "run" the
changeLog. TEST means to actually run the precondition. FAIL mean to
stop the execution of the changelog, alerting you that you cannot run
in updateSql mode because a correct execution of the precondtion is
required to continue.
The problem has been solved by adding onSqlOutput="TEST" tag.

no declaration can be found for element 'constructor-arg'

The error when running:
Caused by: org.xml.sax.SAXParseException; lineNumber: 34; columnNumber: 30; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'constructor-arg'.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
The source:
<spring:bean id="HandlerA_id" name="HandlerA" class="Handler">
<constructor-arg>
<ref bean="BeanA"></ref>
</constructor-arg>
</spring:bean>
The editor recognizes the constructor-arg tag and gives a summary upon roll-over.
In the config file, xsi:schemaLocation value contains (among others):
"...http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd..."
If you examine the xsd at that URL, you can see that the constructor-arg tag is valid for group beanElements which is one of the complex types allowed in 'bean'
Does the runtime not properly validate XML under some conditions?
Include the spring: prefix in the tag. Same for the ref tag.