Repository navigation
Conversation
Writers truncate string and binary bounds (the default metrics mode is truncate(16)): the lower bound is a prefix of the minimum and the upper bound an incremented prefix of the maximum. The table statistics marked them exact, so DataFusion answered MIN/MAX over such a column from the bounds without scanning and returned the truncated prefixes. They are now inexact: still usable for pruning and estimates, never for answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bound arrays downcast float bounds to f32 / f64, but into_any boxed the OrderedFloat wrapper, so every float bound became null and float columns never pruned files or manifests at planning time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Iceberg bounds exclude NaN, while NaN sorts above every number. A file holding 1.0 and NaN has upper bound 1.0, so trusting it pruned the file for k > 2, answered MAX(k) with 1.0 and read the column as the constant 1.0. Use a float column's upper bound only when the file's NaN count is recorded as zero, and a float partition's only when contains_nan is false. Lower bounds stay usable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Parquet row-group pruning keeps a row group whose bounds the predicate cannot evaluate; Iceberg manifest and data-file pruning failed the query instead. Float bounds now reach these predicates, so a cast that cannot take a file's bound must not fail a query whose rows evaluate fine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Parquet writers record a zero minimum as -0.0 and a zero maximum as +0.0
whatever the stored zeros' sign, so MIN over {0.0, 1.0} came back as -0
from statistics (Snowflake: 0). Keep such bounds for pruning only. Test
that a NaN-free file keeps its float maximum and that into_any boxes
plain floats.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Stacked on #138 (base
fix/cleanup-failed-writes); retarget tomainonce #138 merges.Manifest bounds were turned into column statistics and pruning arrays as if they were exact extremes of the column. Four cases broke that assumption, and two of them give wrong results.
String and binary bounds are truncated. Under the default
truncate(16)metrics mode, the lower bound is a prefix of the smallest value and the upper bound an incremented prefix. As exact statistics, DataFusion answeredMIN/MAXwith the truncated prefixes. They are nowInexact.Float upper bounds exclude NaN (Iceberg spec), while Snowflake orders NaN above every number. Over
{1.0, NaN, 1.0}Snowflake givesCOUNT_IF(k > 2)= 1,MAX= NaN and order1, 1, NaN. Trusting the upper bound broke all three:k > 2pruned the file;MAXcame from statistics as1.0;1.0.A float column's upper bound is now used only when the file's
nan_value_countsentry is recorded as 0, in both the statistics and planning-time data-file pruning. A float partition's upper bound is used only whencontains_nanisSome(false). Lower bounds stay usable.Value::into_anyboxed theOrderedFloatwrapper. The bound arrays downcast tof32/f64, so every float bound was null and float columns never pruned files or manifests at planning time. It now boxes the plain float, which enables that pruning. Item 2 keeps it NaN-safe.Zero float bounds are not exact extremes. Parquet writers record a zero minimum as
-0.0and a zero maximum as+0.0whatever the sign of the stored zeros.MINover{0.0, 1.0}came back as-0(Snowflake:0). Such bounds are nowInexact.Since float bounds now reach the planning-time predicates, manifest and data-file pruning keeps every container when the predicate fails to evaluate on the bounds (as Parquet row-group pruning does), instead of failing the query.
Cost:
MAXfrom statistics.MIN/MAXnow scan.Not changed: a NaN with the sign bit set (
-'NaN',inf - inf) sorts below every number in arrow's total order, unlike Snowflake. That is a separate, pre-existing execution difference.Tests:
into_any. The NaN pruning tests fail with the guards removed.cargo test -p datafusion_iceberg -p iceberg-rustpasses, exceptintegration_trino_rest, which fails starting its Trino container in this environment.🤖 Generated with Claude Code