Skip to content

Conversation

@robertream
Copy link

Summary

Fixes #16998: SortExec shares DynamicFilterPhysicalExpr across multiple executions

This PR addresses an issue where SortExec was sharing the same DynamicFilterPhysicalExpr across multiple invocations of with_new_children (e.g., from reset_plan_states), causing recursive queries to fail.

Changes

  • Fixed SortExec::with_new_children: Now properly clones the DynamicFilterPhysicalExpr instead of sharing the same instance across multiple executions
  • Added comprehensive unit test: test_sort_exec_filter_cloning_issue_16998 that reproduces the issue and verifies the fix

Problem Description

The issue occurred when recursive queries would repeatedly execute the same SortExec plan. The shared DynamicFilterPhysicalExpr would maintain state across executions, leading to incorrect results. For example:

with recursive r as (
  select 0 as k, 0 as v
    union all
    (
      select *
      from r
      order by v
      limit 1
    )
)
select *
from r
limit 5;

This query would return only 2 rows instead of the expected 5 rows.

Solution

The fix ensures each SortExec instance gets its own copy of the dynamic filter by:

  1. Creating a new DynamicFilterPhysicalExpr instance with the same children expressions
  2. Preserving the current expression state or falling back to a true literal
  3. Ensuring independent state management across multiple executions

Test Verification

  • Added test_sort_exec_filter_cloning_issue_16998 that specifically tests the recursive query scenario
  • All existing sort tests continue to pass
  • The test fails when the fix is reverted, confirming it properly detects the issue

🤖 Generated with Claude Code

@github-actions github-actions bot added sqllogictest SQL Logic Tests (.slt) physical-plan Changes to the physical-plan crate labels Aug 2, 2025
Copy link
Member

@xudong963 xudong963 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @robertream , I enabled the CI process, will have a look later. /cc @adriangb

@xudong963 xudong963 requested a review from adriangb August 2, 2025 04:20
@adriangb
Copy link
Contributor

adriangb commented Aug 2, 2025

As you can see the current behavior was intentional and necessary for this functionality. IMO we should add a .cloned() or with_new_state() method to ExecutionPlan that defaults to with_new_children() and we call that from places that don't want to preserve state.

@github-actions github-actions bot added the physical-expr Changes to the physical-expr crates label Aug 2, 2025
@robertream
Copy link
Author

robertream commented Aug 2, 2025 via email

@adriangb
Copy link
Contributor

adriangb commented Aug 3, 2025

I am unfortunately AFK until Monday at which point I'll have a pileup of work stuff. So Monday evening or Tuesday I'll try something. My suggestion would be a new method that explicitly copies an ExecutionPlan resetting any state.

adriangb added a commit to pydantic/datafusion that referenced this pull request Aug 4, 2025
adriangb added a commit to pydantic/datafusion that referenced this pull request Aug 4, 2025
@adriangb
Copy link
Contributor

adriangb commented Aug 4, 2025

@robertream I don't think I can push to your branch so I opened #17028 with my change / suggestions. Could you take a look? We should either incorporate feedback here or proceed with my PR. Either way I'll give you attribution in the commits there.

@robertream
Copy link
Author

@robertream I don't think I can push to your branch so I opened #17028 with my change / suggestions. Could you take a look? We should either incorporate feedback here or proceed with my PR. Either way I'll give you attribution in the commits there.

Go with your PR, mine was part of an experiment

@alamb alamb closed this in #17028 Aug 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

physical-expr Changes to the physical-expr crates physical-plan Changes to the physical-plan crate sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shared DynamicFilterPhysicalExpr causes recursive queries to fail

3 participants