Skip to content

fix: [branch-1.1] keep unconverted DPP filters in a scan's canonical form (#6270) - #7338

Open
andygrove wants to merge 1 commit into
apache:branch-1.1from
andygrove:backport-6270-branch-1.1
Open

andygrove wants to merge 1 commit into
apache:branch-1.1from
andygrove:backport-6270-branch-1.1

Conversation

@andygrove

@andygrove andygrove commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Which issue does this PR close?

Backport of #6270 to branch-1.1. #6270 closed #6264 on main; the issue stays closed.

branch-1.2 already has the fix, because #6270 merged before that branch was cut, so no branch-1.2 backport is needed (git merge-base --is-ancestor e242944ec4 apache/branch-1.2 is true).

Rationale for this change

With AQE on, two exchanges that differ only in the dynamic partition pruning filter of a scan below them compare equal, and AQE replaces the second with a ReusedExchange of the first. The consumer of the second exchange then reads the other branch's rows, and the rows it should have read are silently lost. branch-1.1 has the bug: CometScanUtils.filterUnusedDynamicPruningExpressions drops any DPP filter whose subquery is still the adaptive placeholder. It does not affect only an opt-in path, since it needs only AQE, DPP and a native scan.

This is not a 1.1.0 regression. The bug is in every release that has the filter helper. It is a silent wrong-result bug with priority:critical, so it is a candidate under the backporting guide's "wrong results" rule.

What changes are included in this PR?

Cherry-pick of e242944 with -x. The shared helper now drops only DynamicPruningExpression(TrueLiteral), as FileSourceScanExec does, and CometNativeScanExec.doCanonicalize drops every DPP filter from the stale originalPlan copy so an unused DPP scan still matches its twin.

Adaptations, all recorded in the commit message:

  • contrib/delta-spark is not on branch-1.1, so the changes to CometDeltaNativeScanExec and CometDeltaNativeScanSuite are dropped.
  • The adding_a_new_operator.md change is dropped. Only docs/source/user-guide/latest/ is published from a release branch.
  • CometScanUtils keeps only the FileSourceScanExec import. The FilePartition and NativeConfig imports in the source commit belong to fix: read each native scan partition through the object store its files live in #6753, which is not on this branch.

The rest of the diff (CometNativeScanExec, CometTestBase, CometExecSuite, CometIcebergNativeSuite) applied without changes.

How are these changes tested?

The source PR's tests: two AQE DPP ... not reused across branches (#6264) tests in CometExecSuite and one in CometIcebergNativeSuite, plus a control in CometExecSuite that scans with the same DPP filter are still reused.

Run locally on this branch with Spark 3.5 and a libcomet built from this branch (CometExecSuite, CometIcebergNativeSuite): 263 passed, 0 failed, 10 canceled. The canceled tests are unrelated version-gated ones (variant, TIME type, V3 deletion vectors).

With spark/src/main reverted to branch-1.1, the three not reused across branches tests fail and the control passes. So the branch has the bug and the tests catch it. spotless:check is clean.

…6270)

* fix: keep unconverted DPP filters in a scan's canonical form

AQE canonicalizes a query stage from its exchange before the stage rules
convert DPP placeholders. Comet dropped a DPP filter from the scan's
canonical form while it was still a placeholder, so exchanges over scans
with different DPP filters compared equal and AQE reused one for both,
losing the other branch's rows.

The shared helper now drops only DynamicPruningExpression(TrueLiteral), as
FileSourceScanExec does. CometNativeScanExec.doCanonicalize drops every DPP
filter from originalPlan, a stale copy no DPP rule rewrites, so an unused
DPP scan still matches its twin.

Closes apache#6264. Part of apache#6133.

* docs: describe how a native scan keeps its DPP identity when canonicalized

The plan identity section still said CometNativeScanExec canonicalizes
originalPlan while removing unused dynamic pruning filters. It now strips
every DPP filter from that stale copy, and the scan's DPP identity comes
from the top-level partitionFilters, where only
DynamicPruningExpression(TrueLiteral) is dropped. Say both, and point a
new scan at the second rule with the reason it matters for AQE reuse.

* fix: strip every DPP filter from the Delta scan's originalPlan when canonicalizing

CometDeltaNativeScanExec kept a stale DPP placeholder in its originalPlan
copy once filterUnusedDynamicPruningExpressions stopped dropping
placeholders, so after AQE turned the live filter into TrueLiteral the
scan no longer matched its twin and lost SPARK-32509 exchange reuse.
Drop every DPP filter from originalPlan, as CometNativeScanExec does;
runtimeFilters still carry the scan's DPP identity. Adds a Delta version
of the SPARK-32509 reuse test.

* test: check that DPP scan stages on a Delta table are not reused across branches

Ports the apache#6264 UNION ALL test to the native Delta scan, so a Delta scan
whose live DPP filter differs from its twin's keeps its own shuffle
stage and its own rows.

* refactor: share the scan originalPlan canonicalization and DPP reuse check

CometNativeScanExec and CometDeltaNativeScanExec now call
CometScanUtils.canonicalizeOriginalPlan instead of each stripping DPP
filters from originalPlan inline, and the operator guide points new
scans at it. The no-reuse-over-a-DPP-scan assertion lives once in
CometTestBase and the Comet, Iceberg and Delta suites use it.

The CometExecSuite test that passed on main is replaced by one where
both branches use the same DPP filter: the shuffles must still be
reused as in Spark, which fails if the canonical form keeps too much.

* test: share the reused exchange helpers in CometTestBase

assertExchangeReuseOver and assertNoReusedExchangeOverDppScan now call one
reusedExchangesOver, and assertSameExchangeReuseAsSpark replaces the reuse
count comparison written out in CometExecSuite and CometDeltaNativeScanSuite.

---------

Co-authored-by: Andy Grove <agrove@apache.org>
(cherry picked from commit e242944)

Adapted for branch-1.1: the Delta contrib (CometDeltaNativeScanExec and its
suite) is not on this branch, so those two files are dropped, and so is the
contributor guide change. CometScanUtils keeps only the FileSourceScanExec
import, since apache#6753's FilePartition and NativeConfig code is not here.
@github-actions github-actions Bot added bug Something isn't working area:scan Parquet scan / data reading area:Iceberg labels Oct 30, 2026
@andygrove

Copy link
Copy Markdown
Member Author

@laxmanmamididd you may want this one too

Is it helpful for us to pubish a 1.1.x patch release or are you doing your own builds?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Iceberg area:scan Parquet scan / data reading bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants