Skip to content

refactor: share leaf-level parquet read plan assembly with the row filter#23427

Closed
adriangb wants to merge 2 commits into
apache:mainfrom
pydantic:projection-read-plan-assemble
Closed

refactor: share leaf-level parquet read plan assembly with the row filter#23427
adriangb wants to merge 2 commits into
apache:mainfrom
pydantic:projection-read-plan-assemble

Conversation

@adriangb

@adriangb adriangb commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Stacked on #23426. Please merge that one first; until it lands this PR's diff also contains its commit. The change reviewable here is the last commit, assemble_read_plan.

Rationale for this change

projection_read_plan::build_projection_read_plan and row_filter::build_parquet_read_plan both end in the same chain to build a leaf-level plan:

leaf_indices_for_roots → resolve_struct_field_leaves → extend/sort/dedup
    → ProjectionMask::leaves → build_filter_schema → ParquetReadPlan

They differ only in that the row filter also sizes the resulting leaves (required_bytes) and returns an Option. As @mbutrovich noted in review, a shared helper collapses both.

What changes are included in this PR?

  • New assemble_read_plan(root_indices, struct_field_accesses, file_schema, schema_descr) in projection_read_plan.rs. It returns the ParquetReadPlan plus the resolved leaf indices, which is what lets the row filter keep computing required_bytes without duplicating the leaf resolution.
  • Both call sites delegate to it. build_parquet_read_plan shrinks from ~30 lines to ~10.
  • leaf_indices_for_roots, resolve_struct_field_leaves and build_filter_schema are now private to projection_read_plan rather than pub(crate), since assemble_read_plan is the only remaining caller.

No behavior change.

Are these changes tested?

Yes, by existing tests: datafusion-datasource-parquet unit tests (158 pass) and the parquet_integration suite in datafusion (213 pass), both unchanged. The row-filter path is covered by parquet::filter_pushdown and the struct-field pushdown tests in row_filter.rs.

Are there any user-facing changes?

No.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BsRGsN18YBCji5iFTQmWpr

@github-actions github-actions Bot added the datasource Changes to the datasource crate label Jul 9, 2026
adriangb and others added 2 commits July 9, 2026 12:25
`build_projection_read_plan` had three copies of the same
`ProjectionMask::roots` + `Schema::project` + `ParquetReadPlan`
sequence, one per early-return path. Extract `root_level_plan`.

No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsRGsN18YBCji5iFTQmWpr
`build_projection_read_plan` and `row_filter::build_parquet_read_plan`
ran the same chain to build a leaf-level plan: leaf_indices_for_roots,
resolve_struct_field_leaves, sort/dedup, ProjectionMask::leaves,
build_filter_schema. They differed only in the row filter also sizing
the leaves and returning an Option.

Extract `assemble_read_plan`, which returns the plan plus the resolved
leaf indices so the row filter can compute `required_bytes` from them.
The three helpers it subsumes are now private to the module.

No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsRGsN18YBCji5iFTQmWpr
@adriangb

adriangb commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Folding this into #23426 — both cleanups came out of the same review thread on #23396, touch the same function, and are small enough to review as two commits in one PR. The assemble_read_plan commit is now the second commit there, unchanged.

@adriangb adriangb closed this Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

datasource Changes to the datasource crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant