Skip to content

executor: preserve ParentIdx for correlated index_lookup_pushdown under Apply#67548

Merged
ti-chi-bot[bot] merged 2 commits into
pingcap:masterfrom
lcwangchao:fix_67546
Apr 8, 2026
Merged

executor: preserve ParentIdx for correlated index_lookup_pushdown under Apply#67548
ti-chi-bot[bot] merged 2 commits into
pingcap:masterfrom
lcwangchao:fix_67546

Conversation

@lcwangchao
Copy link
Copy Markdown
Collaborator

@lcwangchao lcwangchao commented Apr 3, 2026

What problem does this PR solve?

Issue Number: close #67546

Problem Summary:

Correlated subqueries under Apply can fail when the inner side uses INDEX_LOOKUP_PUSHDOWN. In that path, IndexLookUpExecutor.open() rebuilds the index-side list DAG when corColInIdxSide is true, but it previously rebuilt the executor list without restoring the non-natural parent relationship needed by LocalIndexLookUp. This can surface as Unexpected non-first executor TypeTableScan from TiKV batch executor.

What changed and how does it work?

This PR preserves the un-natural parent mapping when rebuilding the index-side pushed-down DAG for correlated IndexLookUpExecutors.

  • store IndexPlansUnNatureOrders in IndexLookUpExecutor
  • add a helper to rebuild list-based dist executors while restoring ParentIdx
  • use that helper in IndexLookUpExecutor.open() when indexLookUpPushDown && corColInIdxSide
  • add a targeted real TiKV regression test for correlated INDEX_LOOKUP_PUSHDOWN under Apply
  • add an integration test case with EXPLAIN FORMAT='plan_tree' and deterministic ordering
  • improve the unistore panic message to include the unsupported parent executor type for easier debugging

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
    • I checked and no code files have been changed.

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

Fix correlated subqueries with index lookup pushdown under Apply that could fail with `Unexpected non-first executor TypeTableScan`.

Summary by CodeRabbit

  • Bug Fixes

    • Index lookup pushdown for correlated subqueries now preserves parent/child ordering in execution plans, preventing incorrect plan behavior.
  • Tests

    • Added integration and RealTiKV tests validating correlated index lookup pushdown and resulting plans/results.
  • Chores

    • Improved error message for unsupported executor parent types.

@ti-chi-bot ti-chi-bot Bot added the release-note Denotes a PR that will be considered when it comes time to generate release notes. label Apr 3, 2026
@pantheon-ai
Copy link
Copy Markdown

pantheon-ai Bot commented Apr 3, 2026

@lcwangchao I've received your pull request and will start the review. I'll conduct a thorough review covering code quality, potential issues, and implementation details.

⏳ This process typically takes 10-30 minutes depending on the complexity of the changes.

ℹ️ Learn more details on Pantheon AI.

@ti-chi-bot ti-chi-bot Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Apr 3, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 3, 2026

📝 Walkthrough

Walkthrough

This pull request preserves un‑natural order parent/child index mapping for correlated index‑lookup pushdown: the planner's IndexPlansUnNatureOrders metadata is propagated into executor construction and used when rebuilding list‑based DAG executors for pushed‑down index lookups.

Changes

Cohort / File(s) Summary
Executor construction & DAG building
pkg/executor/builder.go, pkg/executor/distsql.go, pkg/executor/internal/builder/builder_utils.go
Propagate idxPlanUnNatureOrders from physical plans into IndexLookUpExecutor; add ConstructListBasedDistExecForUnNatureOrderPlans(...) to set ParentIdx on list‑based executors when rebuilding index‑side DAGs.
Mockstore panic message
pkg/store/mockstore/unistore/cophandler/cop_handler.go
Improve panic message to include the parent executor type string.
Integration & RealTiKV tests
tests/integrationtest/t/executor/index_lookup_pushdown.test, tests/integrationtest/r/executor/index_lookup_pushdown.result, tests/realtikvtest/pushdowntest/index_lookup_pushdown_test.go
Add regression/integration tests that exercise correlated subqueries with INDEX_LOOKUP_PUSHDOWN, verify plan trees, and assert query results.

Sequence Diagram(s)

sequenceDiagram
    participant Planner
    participant IndexLookupExecutor
    participant Builder
    participant TiKV

    Planner->>IndexLookupExecutor: create with IndexPlansUnNatureOrders
    IndexLookupExecutor->>IndexLookupExecutor: open() checks corColInIdxSide
    alt corColInIdxSide == true
        IndexLookupExecutor->>Builder: ConstructListBasedDistExecForUnNatureOrderPlans(idxPlans, unNatureOrders)
        Builder->>Builder: build list executors
        Builder->>Builder: set ParentIdx on executors per unNatureOrders
        Builder-->>IndexLookupExecutor: return executors with ParentIdx
    else
        IndexLookupExecutor->>Builder: ConstructListBasedDistExec(idxPlans)
        Builder-->>IndexLookupExecutor: return executors
    end
    IndexLookupExecutor->>TiKV: send DAG with ParentIdx relationships
    TiKV-->>IndexLookupExecutor: execute and return rows
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

sig/planner

Suggested reviewers

  • hawkingrei
  • winoros

Poem

🐰 I tunneled through plans with a hop and a hop,
Found ParentIdx lost at the rim of the top,
I stitched indices back where they belong,
Now pushed‑down lookups sing a safe song,
Hooray — the query finishes without a flop! 🎋

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: preserving ParentIdx for correlated index_lookup_pushdown under Apply, which is the core issue being fixed.
Description check ✅ Passed The description comprehensively addresses all required template sections: problem statement with issue reference (#67546), detailed explanation of changes and mechanisms, complete checklist with integration tests marked, and proper release note.
Linked Issues check ✅ Passed All coding objectives from issue #67546 are met: preserving ParentIdx mapping through storing IndexPlansUnNatureOrders in IndexLookUpExecutor, implementing the helper function ConstructListBasedDistExecForUnNatureOrderPlans, using it in the correlated index_lookup_pushdown path, and adding comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the correlated index_lookup_pushdown issue: executor field addition and logic, helper function for ParentIdx restoration, test additions, and a minor unistore error message improvement for debugging clarity.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

Command failed


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@lcwangchao
Copy link
Copy Markdown
Collaborator Author

@pantheon-ai review this PR

@pantheon-ai
Copy link
Copy Markdown

pantheon-ai Bot commented Apr 3, 2026

@lcwangchao I've received your follow-up and will continue on this pull request. I'll update this comment when I have something to share.

ℹ️ Learn more details on Pantheon AI.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/executor/internal/builder/builder_utils.go (1)

56-59: Guard unNatureOrders indices before assigning ParentIdx.

This loop can panic if a malformed mapping slips in (executors[i] out of range). Since the function already returns error, validate indices and fail with context.

Proposed defensive patch
 import (
+	"github.com/pingcap/errors"
 	"github.com/pingcap/tidb/pkg/distsql"
 	"github.com/pingcap/tidb/pkg/kv"
 	plannercore "github.com/pingcap/tidb/pkg/planner/core/base"
@@
 	for i, j := range unNatureOrders {
+		if i < 0 || i >= len(executors) || j < 0 || j >= len(executors) {
+			return nil, errors.Errorf("invalid unNatureOrders mapping child=%d parent=%d, executors=%d", i, j, len(executors))
+		}
 		parentIdx := uint32(j)
 		executors[i].ParentIdx = &parentIdx
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/executor/internal/builder/builder_utils.go` around lines 56 - 59, The
loop assigning ParentIdx from unNatureOrders can panic if indices are out of
range; update the loop that iterates over unNatureOrders to validate bounds
before assigning: for each pair (i, j) ensure i < len(executors) and 0 <= j <
len(executors) (or whatever target slice length is appropriate), and if a check
fails return a descriptive error (include i and j) instead of panicking; keep
using parentIdx as uint32 and only set executors[i].ParentIdx = &parentIdx after
the validations succeed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/executor/builder.go`:
- Line 4568: Add a unit test that exercises IndexLookUpExecutor.open() when
indexLookUpPushDown && corColInIdxSide to validate the rebuild path preserves
ParentIdx mappings after idxPlanUnNatureOrders propagation; locate the
IndexLookUpExecutor type and its open() method and construct a minimal executor
stack (mock/real IndexReader/IndexLookup/IndexPlan variants) where
idxPlanUnNatureOrders differs, call open(), and assert rebuilt index-side
executors' ParentIdx fields equal the originals (and that behavior tied to
idxPlanUnNatureOrders is preserved). Ensure the test lives under pkg/executor,
uses existing test helpers to build indexLookUpPushDown scenarios, and focuses
only on the rebuild/ParentIdx assertions (no integration dependencies).

In `@tests/integrationtest/t/executor/index_lookup_pushdown.test`:
- Around line 204-225: Add a focused unit test in the executor package that
specifically exercises the ParentIdx restoration path used by list-based
distributed execution rebuilds: create a small synthetic plan/operator that
simulates an Apply with a correlated subquery and the index_lookup_pushdown
hint, then force the "unnatural" parent mapping scenario and assert that
RestoreParentIdx (or the method in pkg/executor responsible for restoring parent
index mappings) correctly re-maps parent indices after rebuilding the exec list;
reference the executor code paths that handle ParentIdx, RestoreParentIdx (or
equivalent functions/classes in pkg/executor), and the list-based dist exec
rebuild logic so the new UT isolates and validates the mapping restoration
behavior independent of the larger integration test.

---

Nitpick comments:
In `@pkg/executor/internal/builder/builder_utils.go`:
- Around line 56-59: The loop assigning ParentIdx from unNatureOrders can panic
if indices are out of range; update the loop that iterates over unNatureOrders
to validate bounds before assigning: for each pair (i, j) ensure i <
len(executors) and 0 <= j < len(executors) (or whatever target slice length is
appropriate), and if a check fails return a descriptive error (include i and j)
instead of panicking; keep using parentIdx as uint32 and only set
executors[i].ParentIdx = &parentIdx after the validations succeed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dda119ec-7aa3-411a-ac99-d60c32315eec

📥 Commits

Reviewing files that changed from the base of the PR and between 1fc24d3 and dd4dc93.

📒 Files selected for processing (7)
  • pkg/executor/builder.go
  • pkg/executor/distsql.go
  • pkg/executor/internal/builder/builder_utils.go
  • pkg/store/mockstore/unistore/cophandler/cop_handler.go
  • tests/integrationtest/r/executor/index_lookup_pushdown.result
  • tests/integrationtest/t/executor/index_lookup_pushdown.test
  • tests/realtikvtest/pushdowntest/index_lookup_pushdown_test.go

Comment thread pkg/executor/builder.go
Comment thread tests/integrationtest/t/executor/index_lookup_pushdown.test
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 3, 2026

Codecov Report

❌ Patch coverage is 76.47059% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.7419%. Comparing base (01ddf6c) to head (75e82bf).
⚠️ Report is 29 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #67548        +/-   ##
================================================
+ Coverage   77.7526%   78.7419%   +0.9892%     
================================================
  Files          1959       1973        +14     
  Lines        543378     553466     +10088     
================================================
+ Hits         422491     435810     +13319     
+ Misses       120046     117216      -2830     
+ Partials        841        440       -401     
Flag Coverage Δ
integration 44.1478% <76.4705%> (+7.9730%) ⬆️
unit 77.2898% <29.4117%> (+0.9047%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 61.5065% <ø> (ø)
parser ∅ <ø> (∅)
br 50.6218% <ø> (-10.3921%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/integrationtest/r/executor/index_lookup_pushdown.result`:
- Around line 568-606: Add a focused executor unit test that exercises the
ParentIdx restoration code path used when rebuilding IndexLookUp executors
(specifically target IndexLookUpExecutor.open and the list-based distributed
execution construction / ParentIdx restore logic), rather than only relying on
the integration golden test; create a test under pkg/executor that constructs an
IndexLookUpExecutor in the same way the dist exec rebuild path does (simulate
list-based child construction or call the helper used for distributed rebuild),
invoke open() to trigger ParentIdx restoration, and assert that restored
ParentIdx/state is correct (e.g., index ranges, pushed-down selection, and
aggregate behavior) to prevent regressions during refactors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 920cf8c0-d926-4362-9251-03df3d604bd1

📥 Commits

Reviewing files that changed from the base of the PR and between dd4dc93 and 75e82bf.

📒 Files selected for processing (3)
  • tests/integrationtest/r/executor/index_lookup_pushdown.result
  • tests/integrationtest/t/executor/index_lookup_pushdown.test
  • tests/realtikvtest/pushdowntest/index_lookup_pushdown_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/realtikvtest/pushdowntest/index_lookup_pushdown_test.go
  • tests/integrationtest/t/executor/index_lookup_pushdown.test

Comment thread tests/integrationtest/r/executor/index_lookup_pushdown.result
@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/retest

@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/test unit-test

@tiprow
Copy link
Copy Markdown

tiprow Bot commented Apr 3, 2026

@lcwangchao: The specified target(s) for /test were not found.
The following commands are available to trigger required jobs:

/test fast_test_tiprow
/test tidb_parser_test

Use /test all to run all jobs.

Details

In response to this:

/test unit-test

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/retest

1 similar comment
@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/retest

@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/test unit-test

@tiprow
Copy link
Copy Markdown

tiprow Bot commented Apr 5, 2026

@lcwangchao: The specified target(s) for /test were not found.
The following commands are available to trigger required jobs:

/test fast_test_tiprow
/test tidb_parser_test

Use /test all to run all jobs.

Details

In response to this:

/test unit-test

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@ti-chi-bot ti-chi-bot Bot added approved needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Apr 7, 2026
@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/retest

2 similar comments
@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/retest

@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/retest

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Apr 7, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: cfzjywxk, winoros

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot Bot added lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Apr 7, 2026
@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Apr 7, 2026

[LGTM Timeline notifier]

Timeline:

  • 2026-04-07 03:56:23.029958026 +0000 UTC m=+842188.235318073: ☑️ agreed by winoros.
  • 2026-04-07 13:34:22.123929607 +0000 UTC m=+876867.329289664: ☑️ agreed by cfzjywxk.

@lcwangchao
Copy link
Copy Markdown
Collaborator Author

/retest

@hawkingrei
Copy link
Copy Markdown
Member

/retest

2 similar comments
@hawkingrei
Copy link
Copy Markdown
Member

/retest

@hawkingrei
Copy link
Copy Markdown
Member

/retest

@ti-chi-bot ti-chi-bot Bot merged commit 43a9c91 into pingcap:master Apr 8, 2026
35 checks passed
@lcwangchao lcwangchao deleted the fix_67546 branch April 9, 2026 02:29
@lcwangchao lcwangchao added the needs-cherry-pick-release-8.5 Should cherry pick this PR to release-8.5 branch. label Apr 9, 2026
@ti-chi-bot
Copy link
Copy Markdown
Member

In response to a cherrypick label: new pull request created to branch release-8.5: #67632.

ti-chi-bot Bot pushed a commit that referenced this pull request Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved lgtm needs-cherry-pick-release-8.5 Should cherry pick this PR to release-8.5 branch. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

correlated subquery with INDEX_LOOKUP_PUSHDOWN may fail with Unexpected non-first executor TypeTableScan

5 participants