Skip to content

planner: fix partial index pruning due to shared Range pointer mutation#70002

Open
yy782 wants to merge 2 commits into
pingcap:masterfrom
yy782:fix/union-ranges-avoid-mutating-input
Open

planner: fix partial index pruning due to shared Range pointer mutation#70002
yy782 wants to merge 2 commits into
pingcap:masterfrom
yy782:fix/union-ranges-avoid-mutating-input

Conversation

@yy782

@yy782 yy782 commented Jul 23, 2026

Copy link
Copy Markdown

What problem does this PR solve?

Issue Number: ref #69779

Problem Summary:

What changed and how does it work?

When query condition is a < 3 and partial index condition is a >= 0, CheckPartialIndexes wrongly prunes the index. The root cause is UnionRanges mutating shared Range pointers, corrupting the caller's input. The fix deep copies the original value when initializing lastRange to isolate merge side effects.See issue #69779 for details.

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

Please refer to Release Notes Language Style Guide to write a quality release note.

None

Summary by CodeRabbit

  • Bug Fixes

    • Improved range processing to preserve metadata correctly when combining or separating encoded intervals.
    • Improved query planning behavior for partial indexes when filter conditions do not match the index predicate.
  • Tests

    • Added coverage for partial-index selection and explicit index bypass scenarios, including ordered and limited queries.

yy782 added 2 commits July 23, 2026 14:48
…ointer

UnionRanges builds sortRange objects holding pointers to the original
Range. When merging adjacent or overlapping ranges, it mutates the
pointed Range directly, corrupting the caller's input because the
pointer is shared across all sortRange items.

This causes CheckPartialIndexes to incorrectly determine that partial
index conditions are implied by query conditions, leading to wrong
index pruning.

Ref pingcap#69779
…p#69779)

Verify that a >= 0 does NOT imply a < 3 for partial index pruning,
which is the regression case from the shared pointer bug in UnionRanges.
@ti-chi-bot ti-chi-bot Bot added release-note-none Denotes a PR that doesn't merit a release note. do-not-merge/needs-triage-completed labels Jul 23, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign jackysp for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found 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 contribution This PR is from a community contributor. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. needs-ok-to-test Indicates a PR created by contributors and need ORG member send '/ok-to-test' to start testing. labels Jul 23, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

Hi @yy782. Thanks for your PR.

I'm waiting for a pingcap member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

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.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c80fa0f0-df10-452a-a269-a1290d5322c7

📥 Commits

Reviewing files that changed from the base of the PR and between e09d2bd and c1c14ed.

📒 Files selected for processing (3)
  • pkg/util/ranger/ranger.go
  • tests/integrationtest/r/planner/core/casetest/index/partialindex.result
  • tests/integrationtest/t/planner/core/casetest/index/partialindex.test

📝 Walkthrough

Walkthrough

UnionRanges now clones range metadata instead of reusing range object references. Partial-index integration coverage adds queries whose predicates do not imply the index predicate and records results with and without explicit index usage.

Changes

Range metadata and partial-index validation

Layer / File(s) Summary
Clone metadata in UnionRanges
pkg/util/ranger/ranger.go
UnionRanges clones originalValue when initializing and replacing lastRange, while preserving encoded boundaries.
Partial-index implication coverage
tests/integrationtest/t/planner/core/casetest/index/partialindex.test, tests/integrationtest/r/planner/core/casetest/index/partialindex.result
Adds table t3, a partial index on a < 3, ordered limited queries using a >= 0, an IGNORE INDEX variant, and recorded results.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: sig/planner

Suggested reviewers: d3hunter, hawkingrei

Poem

I’m a rabbit guarding ranges bright,
Cloning each datum snug and right.
Partial indexes hop in line,
Queries test each boundary sign.
No shared pointers nibble the hay!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title matches the main fix: partial-index pruning caused by shared Range pointer mutation.
Description check ✅ Passed Description follows the template closely and includes the issue ref, problem, change summary, and integration test.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@terry1purcell

Copy link
Copy Markdown
Contributor

/ok-to-test

@ti-chi-bot ti-chi-bot Bot added ok-to-test Indicates a PR is ready to be tested. and removed needs-ok-to-test Indicates a PR created by contributors and need ORG member send '/ok-to-test' to start testing. labels Jul 23, 2026
@terry1purcell
terry1purcell requested a review from Copilot July 23, 2026 15:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Not ready to approve

The UnionRanges merge path still assigns HighVal by reference (slice aliasing), which can reintroduce shared-state behavior and undermine the intended isolation fix.

Pull request overview

This PR addresses a planner correctness bug where partial indexes could be incorrectly accepted/pruned due to UnionRanges mutating shared *Range inputs, leading to wrong implication checks and potentially incorrect query results (ref #69779).

Changes:

  • Prevents UnionRanges from mutating caller-owned *Range instances by cloning the active merge range.
  • Adds an integration test case that reproduces and guards against the “partial index chosen when predicate doesn’t imply index predicate” wrong-result scenario.
  • Updates the corresponding integration test result file.
File summaries
File Description
pkg/util/ranger/ranger.go Clones the working range in UnionRanges to avoid mutating shared *Range pointers during merges.
tests/integrationtest/t/planner/core/casetest/index/partialindex.test Adds a regression query case ensuring a >= 0 does not incorrectly allow using a partial index defined with a < 3.
tests/integrationtest/r/planner/core/casetest/index/partialindex.result Records expected results for the new regression case (ensuring full rowset is returned).

Review details

  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Low

Note

Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/util/ranger/ranger.go
Comment on lines +699 to +701
lastRange.encodedStart = objects[i].encodedStart
lastRange.encodedEnd = objects[i].encodedEnd
lastRange.originalValue = objects[i].originalValue.Clone()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

After Clone(), lastRange.originalValue is already an independent Range object. The HighVal assignment on line 694 only changes where this cloned object's HighVal field points — it does not mutate the caller's original Range in any way.

While the cloned HighVal and objects[i].HighVal do share the same underlying array, the returned ranges' HighVal is only ever read (for range endpoint comparison), never mutated in-place by downstream consumers. So this slice aliasing is safe in practice.

I'm leaning toward keeping the current approach — it avoids an unnecessary copy and the semantics are correct for this use case. That said, if you feel a deep copy here adds more confidence, I'm open to it.

@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.9288%. Comparing base (e35ad93) to head (c1c14ed).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #70002        +/-   ##
================================================
- Coverage   76.3239%   73.9288%   -2.3951%     
================================================
  Files          2041       2058        +17     
  Lines        559772     579166     +19394     
================================================
+ Hits         427240     428171       +931     
- Misses       131631     150634     +19003     
+ Partials        901        361       -540     
Flag Coverage Δ
integration 40.9387% <100.0000%> (+1.2334%) ⬆️

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

Components Coverage Δ
dumpling 60.4471% <ø> (ø)
parser ∅ <ø> (∅)
br 47.4060% <ø> (-15.3154%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@yy782

yy782 commented Jul 24, 2026

Copy link
Copy Markdown
Author

/retest

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

Labels

contribution This PR is from a community contributor. ok-to-test Indicates a PR is ready to be tested. release-note-none Denotes a PR that doesn't merit a release note. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants