From b318856d6860690aa860a9196c7f9af82116d522 Mon Sep 17 00:00:00 2001 From: Davide Angelocola Date: Sun, 21 Jun 2026 17:25:45 +0200 Subject: [PATCH] fix(cli): handle IS NULL / IS NOT NULL in FilterCommand switch The sealed RowFilter gained IsNull/IsNotNull arms; FilterCommand's row-level toRowPredicate switch was not updated, breaking compilation on main. Add both arms: a row is null only when the column decodes to a MaskedArray whose validity bit is unset (unmasked arrays are null-free). Co-Authored-By: Claude Opus 4.8 --- .../java/io/github/dfa1/vortex/cli/FilterCommand.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cli/src/main/java/io/github/dfa1/vortex/cli/FilterCommand.java b/cli/src/main/java/io/github/dfa1/vortex/cli/FilterCommand.java index cabb3351..f064e668 100644 --- a/cli/src/main/java/io/github/dfa1/vortex/cli/FilterCommand.java +++ b/cli/src/main/java/io/github/dfa1/vortex/cli/FilterCommand.java @@ -7,6 +7,7 @@ import io.github.dfa1.vortex.reader.array.FloatArray; import io.github.dfa1.vortex.reader.array.IntArray; import io.github.dfa1.vortex.reader.array.LongArray; +import io.github.dfa1.vortex.reader.array.MaskedArray; import io.github.dfa1.vortex.reader.array.ShortArray; import io.github.dfa1.vortex.reader.array.VarBinArray; import io.github.dfa1.vortex.csv.CsvExporter; @@ -158,6 +159,8 @@ private static RowPredicate toRowPredicate(RowFilter filter) { (chunk, rowIdx) -> compareValue(chunk.column(col), rowIdx, (Comparable) val) == 0; case RowFilter.Neq(var col, var val) -> (chunk, rowIdx) -> compareValue(chunk.column(col), rowIdx, (Comparable) val) != 0; + case RowFilter.IsNull(var col) -> (chunk, rowIdx) -> isRowNull(chunk.column(col), rowIdx); + case RowFilter.IsNotNull(var col) -> (chunk, rowIdx) -> !isRowNull(chunk.column(col), rowIdx); case RowFilter.And(var filters) -> { RowPredicate[] preds = filters.stream().map(FilterCommand::toRowPredicate).toArray(RowPredicate[]::new); yield (chunk, rowIdx) -> { @@ -172,6 +175,11 @@ private static RowPredicate toRowPredicate(RowFilter filter) { }; } + // Only a masked column carries nulls; an unmasked array is null-free, so every row is non-null. + private static boolean isRowNull(Array arr, long rowIdx) { + return arr instanceof MaskedArray masked && !masked.isValid(rowIdx); + } + private static int compareValue(Array arr, long rowIdx, Comparable value) { return switch (arr) { case LongArray la -> compareNumeric(la.getLong(rowIdx), value);