Repository navigation
Conversation
A residual of AlwaysTrue on a file whose partition value is NULL does not mean every row matches, because the row filter applied by to_arrow() drops NULL rows for predicates such as != or NotNaN. count() added record_count for those files and returned more rows than to_arrow(). count() now reads such a file when a field of the file's partition spec has a source column that the row filter references outside IsNull/NotNull. With such a reference, a file whose spec the table metadata lacks is read too. Other files keep the existing behavior. Closes apache#4276
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Omitted REST partition values can trigger an IndexError during filtered server-planned scans; missing values need a safe fallback to reading the file and regression coverage.
1 open issue
What changed in this PR
This PR addresses #4276 by making count() follow to_arrow() for filters involving NULL partition values, without changing residual evaluation or Arrow’s NULL semantics.
Changes:
- Reads affected files instead of relying on metadata counts, while preserving eligible metadata-only counts.
- Adds regression coverage for identity, bucket, and evolved partition specs, plus checks that unaffected files are not read.
| File | Description |
|---|---|
tests/catalog/test_catalog_behaviors.py |
Adds count-consistency and metadata-only regression tests. |
pyiceberg/table/__init__.py |
Detects relevant NULL partition values and routes affected count tasks through Arrow. |
Review effort: Balanced
A server-planned file can arrive without partition values. The partition-position check raised IndexError for these files. Before, count() used their record-count metadata. When the partition values do not match the spec's field count, count() now reads the file, as it does for an unknown spec.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Closes #4276
Rationale for this change
count()includes NULL rows thatto_arrow()drops in the issue's example:p != 'a'givescount() == 9versuslen(to_arrow()) == 4. I madecount()followto_arrow()without changing residual evaluation orto_arrow(). The NULL convention question in #3918 stays open.count()now reads a file instead of usingrecord_countwhen one of its partition fields is NULL and the row filter references that field's source column outsideIsNullorNotNull. Null checks are ignored because they are exact on a NULL partition value.If the file's spec is missing from table metadata,
count()reads the file when the filter has any such reference. Other files keep the existing behavior. Deletes are unchanged.Are these changes tested?
I added two regression tests to
tests/catalog/test_catalog_behaviors.py. Both run on the memory and SQL catalogs, and both fail on main.count()equalslen(to_arrow())across identity partitions, bucket partitions and an evolved spec with files written before and after removing a partition field.count(), so an unexpected read fails.make testgives 4478 passed, 4 failed and 5 skipped. The same four Hive Kerberos tests fail on main because thehive-kerberosextra cannot be installed in the test environment.prek run -apassed.The tests use locally planned scans. I did not add a REST test, because the REST planning response rejects a NULL partition value.
RESTContentFile.partitionaccepts onlyPrimitiveTypeValue, which excludesNone. The new check uses only the task's partition data and spec ID, so REST-planned tasks take the same path.Are there any user-facing changes?
Yes. For these scans
count()now returns the same number asto_arrow(), for example 4 instead of 9 in the issue's example. It reads the affected files instead of counting them from metadata, including some files whose count does not change. There is no API change. Please add thechangeloglabel.