Index's columns don't get a snapshotId when one of them is marked as DESC

I’m writing this here instead of opening an issue on GitHub because I don’t fully understand the reasoning behind this (intentional) behaviour, nonetheless it prevents liquibase from writing snapshots in particular circumstances.

This behaviour is caused by the method private void includeNestedObjects(DatabaseObject object) in the DatabaseSnapshot class.

There are a couple of if statements that check if the current object is an Index, if the current field is columns and if the first one of those columns has an order. If these conditions match the columns field is skipped before the private Object replaceObject(Object fieldValue) method gets called, leaving the columns without a snapshotId.

Here’s the code that does this:

if ("columns".equals(field) && ((object.getClass() == PrimaryKey.class) || (object.getClass() == Index
    .class) || (object.getClass() == UniqueConstraint.class))) {
    if ((fieldValue != null) && !((Collection) fieldValue).isEmpty()) {
        final Column column = (Column) ((Collection) fieldValue).iterator().next();
        String columnName = column.getName();
        if (BooleanUtils.isTrue(column.getDescending()) || columnName.endsWith(" ASC") || columnName.endsWith(" DESC") || columnName.endsWith(" RANDOM")) {
            continue;
        }
    }
}

The lack of a snapshotId causes an UnexpectedLiquibaseException with the message Found a null snapshotId for column <column> while serializing the snapshot.

I’m using liquibase 3.10.1

If this is actually a bug I’ll open an issue on GitHub.

Hi @deci260! Welcome to the forum.

Do you have reproducible steps to get this error? I don’t dig into the code as much but to determine if this is a bug I would:

  • configure lb and db as needed (I would need help here to repro)
  • attempt to take a snapshot with liquibase
  • if it is a valid config and snapshot fails then it would seem to be a bug.

Ronak

Hello! Thanks for your reply! I already opened an issue on github.

I’ll gladly share the minimal steps to reproduce this issue with you.
(I just tested these steps on liquibase command line 3.10.1 and a brand new installation of Postgresql 12).

  • DB preparation (assuming psql):
CREATE DATABASE test;
\c test
CREATE TABLE test(test1 int, test2 int);
CREATE INDEX ON test(test1 DESC, test2);
  • Liquibase command
./liquibase --url=jdbc:postgresql://postgres:5432/test --username=postgres --password=postgres --classpath=./postgresql.jar --outputFile=snapshot.json  snapshot --snapshotFormat=json

Specifying a snapshotFormat is required, snapshotIds are ignored when using the default serializer.

Liquibase will fail with the following exception:

liquibase.exception.UnexpectedLiquibaseException: Found a null snapshotId for column test.public.test.test2
        at liquibase.serializer.core.yaml.YamlSnapshotSerializer.toMap(YamlSnapshotSerializer.java:77)
        at liquibase.serializer.core.yaml.YamlSerializer.toMap(YamlSerializer.java:112)
        at liquibase.serializer.core.yaml.YamlSnapshotSerializer.toMap(YamlSnapshotSerializer.java:82)
        at liquibase.serializer.core.yaml.YamlSerializer.toMap(YamlSerializer.java:134)
        at liquibase.serializer.core.yaml.YamlSnapshotSerializer.toMap(YamlSnapshotSerializer.java:96)
        at liquibase.serializer.core.yaml.YamlSerializer.serialize(YamlSerializer.java:74)
        at liquibase.command.core.SnapshotCommand$SnapshotCommandResult.print(SnapshotCommand.java:148)
        at liquibase.integration.commandline.Main.doMigration(Main.java:1460)
        at liquibase.integration.commandline.Main.run(Main.java:300)
        at liquibase.integration.commandline.Main.main(Main.java:159)