question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

loadData inserts NULL when CSV contains function

See original GitHub issue

Environment

Liquibase Version: 4.2.1

Liquibase Integration & Version: SpringLiquibase 4.2.1

Liquibase Extension(s) & Version:

Database Vendor & Version: H2 1.4.200

Operating System Type & Version: Windows 10

Description

When CSV file used for loadData contains a function (for example “CURRENT_TIMESTAMP”), Liquibase tries to insert NULL for that column instead of using that function.

Steps To Reproduce

FOO table:

  <createTable tableName="FOO">
            <column name="CODE" type="VARCHAR(255)">
                <constraints nullable="false"/>
            </column>
            <column name="CHANGE_DATETIME" type="TIMESTAMP">
                <constraints nullable="false"/>
            </column>
   </createTable>

loadData changeset (failing):

        <loadData encoding="UTF-8" file="foo.csv" relativeToChangelogFile="true" quotchar="&quot;" separator="," tableName="FOO">
            <column header="CODE" name="CODE"/>
            <column header="CHANGE_DATETIME" name="CHANGE_DATETIME" type="TIMESTAMP"/>
        </loadData>

foo.csv content:

"CODE","CHANGE_DATETIME"
"ABC","CURRENT_TIMESTAMP"

Actual Behavior

Liquibase tries to insert NULL to “CHANGE_DATETIME” column which fails due to not-null constraint.

NULL not allowed for column "CHANGE_DATETIME"; SQL statement:
INSERT INTO FOO(CODE, CHANGE_DATETIME) VALUES(?, ?) [23502-200]
        at org.h2.jdbc.JdbcPreparedStatement.executeBatch(JdbcPreparedStatement.java:1235)
        at liquibase.statement.BatchDmlExecutablePreparedStatement.executePreparedStatement(BatchDmlExecutablePreparedStatement.java:64)
        at liquibase.statement.ExecutablePreparedStatementBase.execute(ExecutablePreparedStatementBase.java:80)

Expected/Desired Behavior

Liquibase should use “CURRENT_TIMESTAMP” in insert and the current timestamp should be inserted.

Additional Context

It worked fine in the old Liquibase version that I used (3.4.2). As a workaround, a custom load data change can be used that disables prepared statements:

@DatabaseChange(name = "loadData", priority = 100, appliesTo = "table", description = "Loads data from a CSV file into an existing table.")
public class CustomLoadDataChange extends LoadDataChange {
    @Override
    protected boolean hasPreparedStatementsImplemented() {
        return false;
    }
}

and then META-INF/services/liquibase.change.Change file must contain the qualified class name of CustomLoadDataChange.

Please also note that disabling of prepared statements for given change with usePreparedStatements=false currently does not work due to https://github.com/liquibase/liquibase/issues/1091

Some issues that might be related: https://liquibase.jira.com/browse/CORE-3208 https://liquibase.jira.com/browse/CORE-2976

Using different types in loadData instead of type=“TIMESTAMP” does not help. For type=“STRING” the error is: Cannot parse "TIMESTAMP" constant "CURRENT_TIMESTAMP" For type=“COMPUTED” the error is the same as for type=“TIMESTAMP”.

For details for CURRENT_TIMESTAMP function in H2 please see: http://www.h2database.com/html/functions.html#current_timestamp

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
LaurianeDPXcommented, Jan 24, 2022

Hi, thanks for your answer.

I continued my tests this morning and the weirdest thing happened (weirdest = I don’t have an explanation for this, but maybe you do). I just changed the xsd of the databaseChangeLog XML tags from dbchangelog-2.0.xsd to dbchangelog-4.4.xsd, and it worked. The workaround with usePreparedStatements=false is not needed anymore.

If you have an explanation for that behavior, I’d be happy to hear it. But as for this issue, it does not impact me anymore.

0reactions
FBurguercommented, Jul 6, 2022

We seem to be now attempting to load in the value you specified in the CSV file. In this case, it’s not a valid datetime value. If you want to allow functions, you can use type=“COMPUTED” and we’ll pass it as a function, but then all values need to be a valid function or else a database-valid date string that is quoted in the csv file

Read more comments on GitHub >

github_iconTop Results From Across the Web

MySQL load NULL values from CSV data - Stack Overflow
When reading data with LOAD DATA INFILE, empty or missing columns are updated with ''. If you want a NULL value in a...
Read more >
loadData | Liquibase Docs
Loads data from a CSV file into an existing table when you add it to your changelog. Uses. A value of NULL in...
Read more >
23212: allow missing data = NULL in LOAD DATA INFILE
Just setting a DB field to "DEFAULT NULL" should imply the right thing! A missing value in the CSV quite obviously calls for...
Read more >
MySQL Error when importing CSV with empty fields
Something like this, checking every value for '', and inserting NULL instead, may help. Change a,b,c,d for the actual name and number of ......
Read more >
Keep nulls or default values during bulk import - SQL Server
For bulk import in SQL Server, both bcp and BULK INSERT load default values to replace null values. For both, you can choose...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found