You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7dd85fc
Browse filesBrowse the repository at this point in the historyBrowse files
feat(parquet-datasource): always accept pushable filters, run rejected conjuncts post-scan
The parquet scan now always accepts pushable filter conjuncts so the parent
`FilterExec` is removed, and guarantees every accepted conjunct is applied
somewhere:
- `pushdown_filters = true` → row-filterable conjuncts via the parquet
`RowFilter` (during decode); any rejected conjuncts fall through to a
new in-scan post-scan filter applied on decoded batches.
- `pushdown_filters = false` → the whole predicate runs as a post-scan
filter on decoded batches (behaviorally identical to a `FilterExec`).
Also fixes a real correctness bug on main. `build_row_filter` (and its
`RowFilterGenerator` wrapper) silently dropped conjuncts that
`FilterCandidateBuilder::build` rejected (`Ok(None)` was `.flatten()`-ed
away) and swallowed whole-build errors. `ParquetSource::try_pushdown_filters`
had already removed the parent `FilterExec`, so those conjuncts were never
applied anywhere — most commonly when the per-file expr-adapter rewrite
turns a table-schema-pushable predicate into a non-pushable one (schema
evolution / coercion / whole-struct references). `build_row_filter` now
returns `(Option<RowFilter>, Vec<Arc<dyn PhysicalExpr>>)` so the opener
routes rejected conjuncts to the post-scan filter.
Packaging: the projection-widening + rebasing + filter evaluation lives in
a new `post_scan_filter.rs` module exposing `PostScanFilter` and
`DecoderProjection`. The opener calls `DecoderProjection::build(...)` in
place of the prior inline `build_projection_read_plan` /
`reassign_expr_columns` / `make_projector` block — net simplification of
`opener/mod.rs`.
Regression tests:
- `build_row_filter_surfaces_rejected_struct_conjunct` (`row_filter.rs`)
asserts the new API contract — `build_row_filter` no longer drops the
rejected conjunct.
- `rejected_struct_conjunct_runs_post_scan_not_dropped` (`opener/mod.rs`)
is an end-to-end test: a struct file with `s IS NOT NULL` and
`pushdown_filters=true` would return 3 rows on main (conjunct silently
dropped, predicate relaxed); with this fix it correctly returns 2.
Many tests / snapshots / `.slt` explain outputs are updated to reflect the
new plan shape: the parquet scan now owns the predicate, so the
`FilterExec` is gone from plans (clickbench, push_down_filter_parquet,
projection_pushdown, etc.). Row-count assertions in opener/integration
tests that used to assert "row group not pruned ⇒ all rows returned" now
correctly reflect the matching row count, since the scan applies the
predicate row-level via the post-scan filter.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments