-
Notifications
You must be signed in to change notification settings - Fork 359
fix: prevent silent overflow when reading Parquet TIMESTAMP_MILLIS values #5177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
peterxcli
wants to merge
21
commits into
apache:main
Choose a base branch
from
peterxcli:refactor/5090-use-arrow-temporal-casts
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
a68a595
refactor: use Arrow casts for temporal conversions
peterxcli 263a61e
fix: preserve Spark temporal cast semantics
peterxcli bd1d243
test: match Spark micros-to-millis cases
peterxcli fbb2a7c
test: link Spark micros-to-millis cases
peterxcli 47211ff
test: use Spark tag in source link
peterxcli 6afef50
Use imported arity kernel for Spark timestamp downscaling
peterxcli e71f480
Merge branch 'main' into refactor/5090-use-arrow-temporal-casts
peterxcli 88685aa
fix: enforce Spark temporal conversion semantics
peterxcli 35920f6
andy's 3rd review
peterxcli 6e256f3
Merge branch 'main' into refactor/5090-use-arrow-temporal-casts
peterxcli 212f990
Merge branch 'main' into refactor/5090-use-arrow-temporal-casts
peterxcli 7c33c92
Merge branch 'main' into refactor/5090-use-arrow-temporal-casts
peterxcli ae0152f
address review: drop temporal.rs refactor, improve adapter error message
peterxcli afa3673
chore: remove unused imports in parquet_support
peterxcli c833b72
test: exercise dictionary-encoded pages in TIMESTAMP_MILLIS overflow …
peterxcli 5c8de42
Merge branch 'main' into refactor/5090-use-arrow-temporal-casts
peterxcli d465192
fix: preserve timestamp pruning by rewriting predicates to the millis…
peterxcli 0d78875
Merge remote branch updates
peterxcli d2b6b14
Merge branch 'main' into refactor/5090-use-arrow-temporal-casts
peterxcli 40b92b7
fix: cover IN, null-safe equality, and nested predicates in the milli…
peterxcli 9172861
Merge remote branch updates
peterxcli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P2] Preserve timestamp pruning before checked conversion
With a
TimestampTypecolumn stored asTIMESTAMP_MILLISand containing9223372036854776milliseconds,WHERE ts < TIMESTAMP '1970-01-01 00:00:00'returns no rows in Spark 4.1.3 and the base native build (c067e4e), but5c8de42throwsOverflow happened on: 9223372036854776 * 1000. I reproduced this with plain/dictionary encoding, ANSI on/off, and Comet row-filter pushdown on/off: all eight Spark/base cases succeed and all eight head cases fail.The existing
CometCastColumnExprprevents DataFusion from recognizing the timestamp statistics predicate, so Comet converts values from row groups Spark skips. This new error turns that pruning limitation into a query failure. Please preserve pruning before the checked conversion and add this filtered case as a regression test, while retaining overflow errors for values actually read.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed and fixed — thanks for the thorough repro. The predicate's column was wrapped in
CometCastColumnExpr, which is opaque to DataFusion's pruning analyzer, so the row group Spark prunes from millisecond statistics was being read and converted. The fix rewrites predicate comparisons over aTIMESTAMP_MILLISfile column into the millisecond domain (exact integer rescaling of the literal, like Spark'sParquetFilterspushing predicates in the file's physical unit), plusIS NULL/IS NOT NULLunwrapping. Pruning works again, predicate evaluation never converts file values, and the scan output conversion stays checked, so values actually read still fail likemillisToMicros.Added your filtered case as a regression test over dictionary × ANSI ×
rowFilterPushdown(8 configs), and native unit tests pinning the rounding table for all six comparison operators, both operand orders, and negative/sub-millisecond literals.One deliberate divergence to note: with row-filter pushdown on and a non-pruned row group, rows the filter discards are no longer converted, so Comet can succeed where Spark (which converts the whole row group during decode) throws — the benign direction of "errors only for values actually read." (d465192)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P2] Preserve pruning for IN, null-safe equality, and nested timestamp predicates
Rechecked
0d78875: the originalts < epochreproducer now passes, but this issue remains for three supported predicate forms. With 32 repeated9223372036854776millisecond values in aTIMESTAMP_MILLIScolumn (and the same value in nesteds.ts), these predicates return zero rows in Spark 4.1.3 and basec067e4e, while the PR head throwsOverflow happened on: 9223372036854776 * 1000:All 24 cases reproduce across plain/dictionary encoding, ANSI on/off, and row-filter pushdown on/off; dictionary encoding was verified from the footer. The eight ordinary
<controls pass on all three builds.The new rewrite skips
InListExpr, does not handleIsNotDistinctFrom, and only matches a directCometCastColumnExpr, so the nested-field predicate also retains the opaque conversion. These row groups are still read and converted even though Spark prunes them.Could we extend pruning to these forms before checked conversion and add regression coverage? This is the failing-query direction of the original issue, separate from the documented case where Comet skips an error on a row discarded by its filter.
Validation: independent native Parquet scans plus focused Spark 4.1.3/JDK17 comparisons. The base control reused a hash-verified
c067e4enative library; production JVM/proto sources are identical. Other Spark versions were not run locally.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verified all three and fixed.
INand<=>now rewrite into the millisecond domain (list elements rescale with IN's null semantics preserved; null-safe equality rescales or folds to a constant, and<=> NULLbecomesIS NULL) — I confirmed DataFusion 54.1's PruningPredicate analyzes bothInListExprandIsNotDistinctFrom, so pruning covers them in every config.The nested case turned out deeper than the rewrite: DataFusion can neither prune nested-field predicates (pruning_predicate.rs — "PruningPredicate does not support pruning on nested fields yet") nor evaluate them as row filters (
can_expr_be_pushed_down_with_schemasclassifies struct columns non-pushable), and the failing conversion was actually the flattscolumn being materialized from row groups nothing could prune. Since Spark only avoids the error via nested statistics pruning we don't have, scans whose data filters reference nested fields now fall back to the safe conversion (overflow → NULL, main's behavior) and the filter discards the rows — matching Spark's zero-row answers across your matrix. Checked conversion stays for all other scans, and is scoped to top-level columns for the same reason.Extended the regression test to your three forms plus the flat control (4 predicates × dictionary × ANSI × rowFilterPushdown), and added native tests for the IN/null-safe rewrites and the top-level/nested/flag-off conversion split. Remaining divergence, documented in the code: a nested-predicate scan Spark fails to prune errors in Spark but NULLs in Comet, as does a direct nested read of overflow — both pre-existing behavior. Filed #5553 to lift both once DataFusion grows nested-field pruning. (9172861)