Fresh install giving unusual "Unexpected datatype NULL"

Before posting this, I just had an idea… I’m running the OpenJDK:
$ java --version
openjdk 11.0.13 2021-10-19
OpenJDK Runtime Environment 18.9 (build 11.0.13+8)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.13+8, mixed mode, sharing)

I’ve a strong hunch installing the Oracle JDK will fix this problem, so I’ll go try that now, but here’s my problem report anyway…

I’ve had to reinstall a Fedora system (now on F35) but copied my old workspace files so it’s a carbon copy of the Liquibase installation I had previously, but a fresh install of the MariaDB database and JDBC drivers being used. I’m now seeing an unexpected error at what seems to be just after the database lock is released.

INFO: Successfully released change log lock
Unexpected error running Liquibase: Unexpected datatype NULL
For more information, please use the --logLevel flag
Nov 18, 2021 4:13:20 PM liquibase.integration
SEVERE: Unexpected error running Liquibase: Unexpected datatype NULL
liquibase.exception.LiquibaseException: java.lang.IllegalArgumentException: Unexpected datatype NULL
at liquibase.Liquibase.runInScope(Liquibase.java:2409)
at liquibase.Liquibase.update(Liquibase.java:211)
at liquibase.Liquibase.update(Liquibase.java:197)
at liquibase.integration.commandline.Main.doMigration(Main.java:1875)
at liquibase.integration.commandline.Main$1.lambda$run$0(Main.java:397)
at liquibase.Scope.lambda$child$0(Scope.java:177)
at liquibase.Scope.child(Scope.java:186)
at liquibase.Scope.child(Scope.java:176)
at liquibase.Scope.child(Scope.java:155)
at liquibase.integration.commandline.Main$1.run(Main.java:396)
at liquibase.integration.commandline.Main$1.run(Main.java:220)
at liquibase.Scope.child(Scope.java:186)
at liquibase.Scope.child(Scope.java:162)
at liquibase.integration.commandline.Main.run(Main.java:220)
at liquibase.integration.commandline.Main.main(Main.java:163)
Caused by: java.lang.IllegalArgumentException: Unexpected datatype NULL
at org.mariadb.jdbc.message.server.ColumnDefinitionPacket.getDefaultCodec(ColumnDefinitionPacket.java:371)
at org.mariadb.jdbc.client.result.Result.getObject(Result.java:463)
at liquibase.util.JdbcUtil.getResultSetValue(JdbcUtil.java:80)
at liquibase.executor.jvm.ColumnMapRowMapper.getColumnValue(ColumnMapRowMapper.java:72)
at liquibase.snapshot.ResultSetCache$ResultSetExtractor$1.getColumnValue(ResultSetCache.java:320)
at liquibase.executor.jvm.ColumnMapRowMapper.mapRow(ColumnMapRowMapper.java:34)
at liquibase.executor.jvm.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:72)
at liquibase.snapshot.ResultSetCache$ResultSetExtractor.extract(ResultSetCache.java:343)
at liquibase.snapshot.ResultSetCache$ResultSetExtractor.extract(ResultSetCache.java:308)
at liquibase.snapshot.JdbcDatabaseSnapshot$CachingDatabaseMetaData$2.fastFetchQuery(JdbcDatabaseSnapshot.java:1011)
at liquibase.snapshot.ResultSetCache$SingleResultSetExtractor.fastFetch(ResultSetCache.java:367)
at liquibase.snapshot.ResultSetCache.get(ResultSetCache.java:72)
at liquibase.snapshot.JdbcDatabaseSnapshot$CachingDatabaseMetaData.getTables(JdbcDatabaseSnapshot.java:968)
at liquibase.snapshot.jvm.TableSnapshotGenerator.snapshotObject(TableSnapshotGenerator.java:34)
at liquibase.snapshot.jvm.JdbcSnapshotGenerator.snapshot(JdbcSnapshotGenerator.java:65)
at liquibase.snapshot.SnapshotGeneratorChain.snapshot(SnapshotGeneratorChain.java:49)
at liquibase.snapshot.jvm.JdbcSnapshotGenerator.snapshot(JdbcSnapshotGenerator.java:68)
at liquibase.snapshot.SnapshotGeneratorChain.snapshot(SnapshotGeneratorChain.java:49)
at liquibase.snapshot.jvm.JdbcSnapshotGenerator.snapshot(JdbcSnapshotGenerator.java:68)
at liquibase.snapshot.SnapshotGeneratorChain.snapshot(SnapshotGeneratorChain.java:49)
at liquibase.snapshot.jvm.JdbcSnapshotGenerator.snapshot(JdbcSnapshotGenerator.java:68)
at liquibase.snapshot.SnapshotGeneratorChain.snapshot(SnapshotGeneratorChain.java:49)
at liquibase.snapshot.jvm.JdbcSnapshotGenerator.snapshot(JdbcSnapshotGenerator.java:68)
at liquibase.snapshot.SnapshotGeneratorChain.snapshot(SnapshotGeneratorChain.java:49)
at liquibase.snapshot.jvm.JdbcSnapshotGenerator.snapshot(JdbcSnapshotGenerator.java:68)
at liquibase.snapshot.SnapshotGeneratorChain.snapshot(SnapshotGeneratorChain.java:49)
at liquibase.snapshot.jvm.JdbcSnapshotGenerator.snapshot(JdbcSnapshotGenerator.java:68)
at liquibase.snapshot.SnapshotGeneratorChain.snapshot(SnapshotGeneratorChain.java:49)
at liquibase.snapshot.DatabaseSnapshot.include(DatabaseSnapshot.java:314)
at liquibase.snapshot.DatabaseSnapshot.init(DatabaseSnapshot.java:105)
at liquibase.snapshot.DatabaseSnapshot.(DatabaseSnapshot.java:58)
at liquibase.snapshot.JdbcDatabaseSnapshot.(JdbcDatabaseSnapshot.java:38)
at liquibase.snapshot.SnapshotGeneratorFactory.createSnapshot(SnapshotGeneratorFactory.java:215)
at liquibase.snapshot.SnapshotGeneratorFactory.createSnapshot(SnapshotGeneratorFactory.java:244)
at liquibase.snapshot.SnapshotGeneratorFactory.getDatabaseChangeLogTable(SnapshotGeneratorFactory.java:252)
at liquibase.changelog.StandardChangeLogHistoryService.init(StandardChangeLogHistoryService.java:109)
at liquibase.Liquibase.checkLiquibaseTables(Liquibase.java:1913)
at liquibase.Liquibase.lambda$update$1(Liquibase.java:226)
at liquibase.Scope.lambda$child$0(Scope.java:177)
at liquibase.Scope.child(Scope.java:186)
at liquibase.Scope.child(Scope.java:176)
at liquibase.Scope.child(Scope.java:155)
at liquibase.Liquibase.runInScope(Liquibase.java:2404)
… 14 more

A gist of the full output with logLevel=DEBUG: gist:05aedb73729f6ad7451e79d6c59a5571 · GitHub

My changelog.xml is fairly standard:

<?xml version="1.0" encoding="UTF-8"?>

<include file="one-of-100-files.xml"/>

and the properties file used is simple enough:

#liquibase.properties
driver: org.mariadb.jdbc.Driver
classpath: /usr/lib/java/mariadb-java-client.jar
url: jdbc:mariadb://127.0.0.1/premier2
username: uuu
password: ppp
parameter.table_prefix:

I can open an SQL connection to the database and copy/paste the database lock commands to create and release the lock just fine, and the website using the database is functioning normally, so I don’t think there’s a fault with the database.

There are exceptions to do with “Unable to get public no-arg constructor” but according to Puzzling liquibase error after upgrading to traccar 4.13, openjdk-11 - Traccar this is not an issue.

Where can I look for more debugging info please?

The Oracle JDK did not fix the problem. I think I traced it to the use of the mariadb-java-client-3.0.1-1 on my system. When I instead use mysql-connector-java-8.0.25-3 (and adjust the connection string from “jdbc:mariadb://…” to “jdbc:mysql://…”) the error goes away.

I’m running mariadb-server-10.5.12-1 on Fedora, why would the mariadb connector result in an exception when the mysql one does not?

While I was still stuck I tried getting the liquibase source and stepping through it. It seems the error is that the call to “getTables()” to fetch the schema of DATABASECHANGELOG returns a resultset whose first column is a value but all subsequent columns are null, this is given to extract() which ends up using liquibase.util.JdbcUtil.getResultSetValue() to call ResultSet.getObject() for the second field which throws IllegalArgumentException “Unexpected datatype NULL”. Because it’s not an SQLException, it’s not caught in the catch handler of getResultSetValue().

JdbcDatabaseSnapshot() has the lines:

                return extract(databaseMetaData.getTables(catalog, schema, ((table == null) ?
                    SQL_FILTER_MATCH_ALL : table), new String[]{"TABLE"}));

The actual metadata on the table is fetched by a class implemented in the JDBC driver, DatabaseMetaData.getTables(). The MariaDB ResultSet implementation has a ‘data’ member where the first element has a value but others are null, whereas the MySQL ResultSet object clearly has a different implementation.

I saw the actual SQL issued to the database for the “get table schema” call, something like this:

SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, IF(TABLE_TYPE=‘BASE TABLE’ or TABLE_TYPE=‘SYSTEM VERSIONED’, ‘TABLE’, TABLE_TYPE) as TABLE_TYPE, TABLE_COMMENT REMARKS, NULL TYPE_CAT, NULL TYPE_SCHEM, NULL TYPE_NAME, NULL SELF_REFERENCING_COL_NAME, NULL REF_GENERATION FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = ‘DATABASECHANGELOG’

The second result field is clearly hardcoded as a NULL value and I think it’s this that the exception happens on, inside getResultSetValue mentioned above). When I run this against the same database from SquirrelSQL using the same MariaDB connector it gives a sensible resultset.

It doesn’t seem right that a MariaDB connector ResultSet object would throw IllegalArgumentException “Unexpected datatype NULL” when getObject() is called. If the field at the index requested is null it should just return null. So, I’m a bit lost. I’ll stick to the mysql connector for now!

Hi @premierrange Thanks for the alert. Great debug work. Did you create an issue in our github repository.

1 Like

See also MariaDB Connector 3.x results in "Unexpected datatype NULL" · Issue #2431 · liquibase/liquibase · GitHub

1 Like

Cheers @MikeOlivas, no I haven’t done anything further because I’m not sure I’m reporting a real bug, it might be something silly I’m doing. I was hoping someone more familiar with Java and the technologies discussed here could reproduce the problem, or point out what I’m doing wrong. I don’t normally work with Java these days so getting to this point took a lot of time I can’t really justify around my day job.

I’ve given up trying to use the mariadb-java-client and am using mysql-connector-java, as it seems to work against our MariaDB database. I also found that using the mariadb connector with SquirrelSQL causes it to be unable to list the tables in the Objects tree browser, no idea why.

PS I should mention that I ran into this during a rebuild of my workstation after an SSD crashed, so bearing in mind the law of parsimony I was wary that whatever was causing the problem may be due to software misconfiguration on my system rather then an actual fault in the tools.

I see at the linked github issue #2431 they announced the problem appears to be fixed, and I can now build and run the 3.0.4 version of the driver from Release MariaDB Connector/Java 3.0.4 · mariadb-corporation/mariadb-connector-j · GitHub and use it against MariaDB via Liquibase with no NULL error. It has also fixed my problem with browsing the database schema in SquirrelSQL.

FYI to build in Maven I had to disable tests and javadoc generation, both of which failed with weird errors:

$ mvn package -DskipTests -Dmaven.javadoc.skip=true

This produces target/mariadb-java-client-3.0.4.jar

Thanks for everyone’s help!