Skip to content

Commit a459a45

Browse files
committed
Add regression coverage for null identity comparisons
1 parent db4f1e2 commit a459a45

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

tests/table/test_init.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
And,
3333
EqualTo,
3434
In,
35+
LessThan,
36+
Or,
3537
)
3638
from pyiceberg.expressions.visitors import bind
3739
from pyiceberg.io import PY_IO_IMPL, FileIO, load_file_io
@@ -356,6 +358,44 @@ def test_data_scan_plan_files_no_current_snapshot(example_table_metadata_no_snap
356358
assert len(scan.to_arrow()) == 0
357359

358360

361+
def test_data_scan_count_with_less_than_on_null_identity_partition(catalog: Catalog) -> None:
362+
import pyarrow as pa
363+
364+
catalog.create_namespace("default")
365+
schema = Schema(
366+
NestedField(1, "x", IntegerType(), required=False),
367+
NestedField(2, "y", IntegerType(), required=False),
368+
)
369+
spec = PartitionSpec(PartitionField(1, 1000, IdentityTransform(), "x"))
370+
table = catalog.create_table("default.null_identity_partition", schema=schema, partition_spec=spec)
371+
table.append(
372+
pa.table(
373+
{
374+
"x": pa.array([None, None], type=pa.int32()),
375+
"y": pa.array([0, 2], type=pa.int32()),
376+
}
377+
)
378+
)
379+
380+
# To exercise the residual evaluator code path, include y == 2 so partition pruning keeps the file.
381+
#
382+
# Partition pruning:
383+
# x < 1 -> false for the null x partition
384+
# y == 2 -> unknown because y is not partitioned
385+
# false OR unknown -> keep the file
386+
#
387+
# Residual evaluation:
388+
# x < 1 -> false for the null x partition
389+
# y == 2 -> retained because no partition value is available for y
390+
# false OR y == 2 -> residual is y == 2
391+
scan = table.scan(row_filter=Or(LessThan("x", 1), EqualTo("y", 2)))
392+
tasks = list(scan.plan_files())
393+
394+
assert len(tasks) == 1
395+
assert tasks[0].residual == EqualTo("y", 2)
396+
assert scan.count() == 1 # Only the y == 2 row matches.
397+
398+
359399
def test_incremental_append_scan_default(table_v2: Table) -> None:
360400
scan = table_v2.incremental_append_scan()
361401
assert scan.row_filter == AlwaysTrue()

0 commit comments

Comments
 (0)