Skip to content

planner: build multi alternative logical plan from shared AST (#66677)#68859

Closed
ti-chi-bot wants to merge 1 commit into
pingcap:release-8.5from
ti-chi-bot:cherry-pick-66677-to-release-8.5
Closed

planner: build multi alternative logical plan from shared AST (#66677)#68859
ti-chi-bot wants to merge 1 commit into
pingcap:release-8.5from
ti-chi-bot:cherry-pick-66677-to-release-8.5

Conversation

@ti-chi-bot
Copy link
Copy Markdown
Member

@ti-chi-bot ti-chi-bot commented Jun 2, 2026

This is an automated cherry-pick of #66677

What problem does this PR solve?

Issue Number: ref #66676

Problem Summary:

This work is split into two steps for shared-AST multi logical plan build support.

This PR is Step 1 only: isolate planner build state so repeated builds from the same AST can be added safely in the follow-up step.

What changed and how does it work?

Main work in this PR (Step 1):

  • Audit remaining planner-held AST references and document the read-only ones.
  • Split QBHintHandler into:
    • shared AST-derived metadata,
    • per-build hint runtime state.
  • Add StatementContext logical-plan-build snapshot/restore support for mutable planning fields used by planner build/optimize paths (including warnings, plan-cache tracker state, and TableStats).

Not included in this PR:

  • The actual optimize-path behavior change for repeated logical-plan builds from the same AST.
  • Candidate winner-selection behavior changes for multi-build (planned in Step 2).

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

  • Refactor
    • Improved hint state management during logical query plan building by decoupling hint tracking from plan builder lifecycle.
    • Enhanced view hint handling with stateful hint resolution and per-view build-state isolation.
    • Added state save/restore mechanisms for plan cache and logical plan build configurations to support multi-candidate plan generation.

Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io>
@ti-chi-bot ti-chi-bot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. ok-to-test Indicates a PR is ready to be tested. release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. type/cherry-pick-for-release-8.5 This PR is cherry-picked to release-8.5 from a source PR. labels Jun 2, 2026
@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Jun 2, 2026

This cherry pick PR is for a release branch and has not yet been approved by triage owners.
Adding the do-not-merge/cherry-pick-not-approved label.

To merge this cherry pick:

  1. It must be LGTMed and approved by the reviewers firstly.
  2. For pull requests to TiDB-x branches, it must have no failed tests.
  3. AFTER it has lgtm and approved labels, please wait for the cherry-pick merging approval from triage owners.
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.

@ti-chi-bot
Copy link
Copy Markdown
Member Author

@AilinKid This PR has conflicts, I have hold it.
Please resolve them or ask others to resolve them, then comment /unhold to remove the hold label.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Jun 2, 2026

@ti-chi-bot: ## If you want to know how to resolve it, please read the guide in TiDB Dev Guide.

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 ti-community-infra/tichi repository.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Jun 2, 2026

[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 0xpoe 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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors QB hint handling to be per-build state rather than globally mutable handler fields. It introduces QBHintBuildState to hold per-traversal hint maps, threads this state through PlanBuilder and logical plan building, adds statement-context save/restore for logical plan build state, and shifts unused view hint cleanup responsibility from the hint processor to the plan builder.

Changes

Per-Build Hint State Infrastructure and Integration

Layer / File(s) Summary
QB Hint Handler Build State and APIs
pkg/util/hint/hint_query_block.go
QBHintBuildState struct holds per-build QBOffsetToHints and ViewQBNameUsed maps; QBHintHandler.NewBuildState() creates this state; GetCurrentStmtHints(), MarkViewQBNameUsed(), and HandleUnusedViewHints() now thread and operate on state instead of mutating handler fields; SetWarns() emits warnings from a list.
PlanCacheTracker State Snapshot Methods
pkg/util/context/plancache.go
PlanCacheTracker.Save() and Restore() snapshot and restore mutable planning-time flags (useCache, cacheType, planCacheUnqualified, forcePlanCache, alwaysWarnSkipCache) under mutex.
Statement Context Logical Plan Build State Save/Restore
pkg/sessionctx/stmtctx/stmtctx.go
LogicalPlanBuildState struct captures statement-scoped planner state; SaveLogicalPlanBuildState() and RestoreLogicalPlanBuildState() snapshot/restore warnings, table metadata, pruning/view state, and plan-cache config via PlanCacheTracker methods.
PlanBuilder QB Hint Build State Tracking
pkg/planner/core/planbuilder.go
Adds hintState field to track per-build hint state; GetHintState() accessor; Init() initializes state via processor.NewBuildState(); HandleUnusedViewHints() computes and applies unused view hint warnings.
Optimize Function Unused Hint Handling
pkg/planner/optimize.go
Shifts deferred unused view hint cleanup from hintProcessor.HandleUnusedViewHints() to builder.HandleUnusedViewHints() after builder.Init().
Logical Plan Builder Hint State Usage
pkg/planner/core/logical_plan_builder.go
pushTableHints() passes b.hintState to GetCurrentStmtHints(); view QBName hint marking uses MarkViewQBNameUsed(qbName, b.hintState); BuildDataSourceFromView() creates per-view hint state, temporarily swaps builder state, and restores with SetWarns().
Tests and Build Configuration
pkg/sessionctx/stmtctx/stmtctx_test.go, pkg/sessionctx/stmtctx/BUILD.bazel
TestLogicalPlanBuildStateRestore validates save/restore of logical plan state; TestQBHintHandlerBuildState validates build-state accumulation; bazel config increases shard count and adds test dependencies.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • pingcap/tidb#66676: Implements the Step 1 state-isolation refactor for per-build QB hint handling and logical plan build state save/restore described in the issue.

Possibly related PRs

  • pingcap/tidb#66677: Parallels this PR in refactoring QB hint handling to use per-build state and adding statement-scoped build state save/restore with related test coverage.

Suggested labels

cherry-pick-approved

Suggested reviewers

  • AilinKid
  • qw4990
  • guo-shaoge
  • winoros
  • terry1purcell

Poem

🐰 Per-build hints now take the stage,
No more state mutates on page.
Thread it through each logical plan,
Save and restore with steady hand.
Query blocks flow with grace so keen,
Cleanest hint state ever seen!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: enabling multi-alternative logical plan building from a shared AST in the planner package.
Description check ✅ Passed The description includes an issue reference (ref #66676), clear problem statement, detailed explanation of changes across multiple sections, and completed checklist with unit test marked as done.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ 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.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Jun 2, 2026

@ti-chi-bot: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
idc-jenkins-ci-tidb/check_dev dc79ec2 link true /test check-dev
idc-jenkins-ci-tidb/unit-test dc79ec2 link true /test unit-test
idc-jenkins-ci-tidb/mysql-test dc79ec2 link true /test mysql-test
idc-jenkins-ci-tidb/check_dev_2 dc79ec2 link true /test check-dev2
idc-jenkins-ci-tidb/build dc79ec2 link true /test build

Full PR test history. Your PR dashboard.

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. I understand the commands that are listed here.

@tiprow
Copy link
Copy Markdown

tiprow Bot commented Jun 2, 2026

@ti-chi-bot: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
fast_test_tiprow_for_release dc79ec2 link true /test fast_test_tiprow_for_release

Full PR test history. Your PR dashboard.

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. I understand the commands that are listed here.

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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/planner/core/logical_plan_builder.go (1)

5082-5111: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix unused locals in view-hint filtering (won’t compile)

pkg/planner/core/logical_plan_builder.go:5082-5111: currentQbNameMap4View and currentQbHints4View are only declared/assigned, but the final wiring sets hintProcessor.ViewQBNameToTable = qbNameMap4View and hintProcessor.ViewQBNameToHints = viewHints, leaving the new locals unused → Go will fail with “declared and not used”.

Suggested safe fix: remove the dead locals
-	currentQbNameMap4View := make(map[string][]ast.HintTable)
-	currentQbHints4View := make(map[string][]*ast.TableOptimizerHint)
 	currentQbHints := make(map[int][]*ast.TableOptimizerHint)
 	currentQbNameMap := make(map[string]int)
@@
-			currentQbNameMap4View[qbName] = viewQbNameHint
-			currentQbHints4View[qbName] = viewHints[qbName]
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/planner/core/logical_plan_builder.go` around lines 5082 - 5111, The
temporary maps currentQbNameMap4View and currentQbHints4View are declared and
populated but never used, causing a compile error; remove both declarations and
any assignments to currentQbNameMap4View/currentQbHints4View inside the loop and
simply continue using qbNameMap4View and viewHints (which are later assigned to
hintProcessor.ViewQBNameToTable and hintProcessor.ViewQBNameToHints); ensure
only currentQbHints and currentQbNameMap (and deletions of
qbNameMap4View/viewHints) remain as needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/sessionctx/stmtctx/BUILD.bazel`:
- Around line 48-52: Remove the leftover merge conflict markers in BUILD.bazel
around the shard_count attribute (delete the <<<<<<<, =======, and >>>>>>>
lines) and leave a single shard_count = <correct_value> entry (e.g., shard_count
= 14 or shard_count = 17 as intended) so the Bazel rule parses cleanly; ensure
only one shard_count line remains in the rule.

In `@pkg/sessionctx/stmtctx/stmtctx.go`:
- Around line 68-93: There is an unresolved git conflict block left in
stmtctx.go; remove the conflict markers (<<<<<<<, =======, >>>>>>>) and
reconcile the two definitions so the file parses: either restore the jsonSQLWarn
type if needed or keep LogicalPlanBuildState (or combine them appropriately),
ensuring only valid Go types remain and references to jsonSQLWarn and
LogicalPlanBuildState are correctly defined and compiled; update imports if
required and run go build to verify the file parses.
- Around line 607-609: The code references sc.ViewDepth but StatementContext
lacks a ViewDepth field; add a ViewDepth field to the StatementContext struct
(matching the original type used elsewhere in the project), and update any
constructors/copy/snapshot/restore logic so ViewDepth is properly preserved and
copied (ensure sc.ViewDepth is set/returned where StatementContext is
initialized and that the snapshot/Restore/Copy methods include ViewDepth
alongside useDynamicPruneMode, viewDepth, and colRefFromUpdatePlan). Use the
existing symbols StatementContext, sc.ViewDepth, Copy(), snapshot/restore (or
the struct's constructor functions) to locate where to add and wire this field.

---

Outside diff comments:
In `@pkg/planner/core/logical_plan_builder.go`:
- Around line 5082-5111: The temporary maps currentQbNameMap4View and
currentQbHints4View are declared and populated but never used, causing a compile
error; remove both declarations and any assignments to
currentQbNameMap4View/currentQbHints4View inside the loop and simply continue
using qbNameMap4View and viewHints (which are later assigned to
hintProcessor.ViewQBNameToTable and hintProcessor.ViewQBNameToHints); ensure
only currentQbHints and currentQbNameMap (and deletions of
qbNameMap4View/viewHints) remain as needed.
🪄 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: d4653a90-f1e4-428b-8276-6e34087b6fed

📥 Commits

Reviewing files that changed from the base of the PR and between d9e323f and dc79ec2.

📒 Files selected for processing (8)
  • pkg/planner/core/logical_plan_builder.go
  • pkg/planner/core/planbuilder.go
  • pkg/planner/optimize.go
  • pkg/sessionctx/stmtctx/BUILD.bazel
  • pkg/sessionctx/stmtctx/stmtctx.go
  • pkg/sessionctx/stmtctx/stmtctx_test.go
  • pkg/util/context/plancache.go
  • pkg/util/hint/hint_query_block.go

Comment on lines +48 to +52
<<<<<<< HEAD
shard_count = 14,
=======
shard_count = 17,
>>>>>>> d59e531fe61 (planner: build multi alternative logical plan from shared AST (#66677))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Remove the leftover conflict markers from the Bazel rule.

Line 48 still contains merge-conflict markers, so Bazel cannot parse this file. Keep only the intended shard_count entry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/sessionctx/stmtctx/BUILD.bazel` around lines 48 - 52, Remove the leftover
merge conflict markers in BUILD.bazel around the shard_count attribute (delete
the <<<<<<<, =======, and >>>>>>> lines) and leave a single shard_count =
<correct_value> entry (e.g., shard_count = 14 or shard_count = 17 as intended)
so the Bazel rule parses cleanly; ensure only one shard_count line remains in
the rule.

Comment on lines +68 to 93
<<<<<<< HEAD
type jsonSQLWarn struct {
Level string `json:"level"`
SQLErr *terror.Error `json:"err,omitempty"`
Msg string `json:"msg,omitempty"`
=======
// LogicalPlanBuildState stores the statement-scoped planner state that is mutated while
// building a logical plan from AST.
type LogicalPlanBuildState struct {
warnings []SQLWarn
extraWarnings []SQLWarn
tables []TableEntry
tableStats map[int64]any
lockTableIDs map[int64]struct{}
tblInfo2UnionScan map[*model.TableInfo]bool
useDynamicPruneMode bool
viewDepth int32
colRefFromUpdatePlan intset.FastIntSet
// plan cache related stuff
planCacheUseCache bool
planCacheType contextutil.PlanCacheType
planCacheUnqualified string
planCacheForce bool
planCacheAlwaysWarn bool
>>>>>>> d59e531fe61 (planner: build multi alternative logical plan from shared AST (#66677))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Resolve the cherry-pick conflict before merge.

Line 68 still starts a <<<<<<< / ======= / >>>>>>> block, so this file does not parse. It also leaves jsonSQLWarn and LogicalPlanBuildState in an unresolved state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/sessionctx/stmtctx/stmtctx.go` around lines 68 - 93, There is an
unresolved git conflict block left in stmtctx.go; remove the conflict markers
(<<<<<<<, =======, >>>>>>>) and reconcile the two definitions so the file
parses: either restore the jsonSQLWarn type if needed or keep
LogicalPlanBuildState (or combine them appropriately), ensuring only valid Go
types remain and references to jsonSQLWarn and LogicalPlanBuildState are
correctly defined and compiled; update imports if required and run go build to
verify the file parses.

Comment on lines +607 to +609
useDynamicPruneMode: sc.UseDynamicPruneMode,
viewDepth: sc.ViewDepth,
colRefFromUpdatePlan: sc.ColRefFromUpdatePlan.Copy(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

ViewDepth is snapshotted/restored but not declared on StatementContext.

Lines 608 and 628 reference sc.ViewDepth, but there is no ViewDepth field on StatementContext anywhere in this file. This cherry-pick will still fail to compile after the conflict markers are fixed unless that field addition is brought over too.

Also applies to: 627-629

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/sessionctx/stmtctx/stmtctx.go` around lines 607 - 609, The code
references sc.ViewDepth but StatementContext lacks a ViewDepth field; add a
ViewDepth field to the StatementContext struct (matching the original type used
elsewhere in the project), and update any constructors/copy/snapshot/restore
logic so ViewDepth is properly preserved and copied (ensure sc.ViewDepth is
set/returned where StatementContext is initialized and that the
snapshot/Restore/Copy methods include ViewDepth alongside useDynamicPruneMode,
viewDepth, and colRefFromUpdatePlan). Use the existing symbols StatementContext,
sc.ViewDepth, Copy(), snapshot/restore (or the struct's constructor functions)
to locate where to add and wire this field.

@AilinKid
Copy link
Copy Markdown
Contributor

AilinKid commented Jun 2, 2026

done in #68646

@AilinKid AilinKid closed this Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/cherry-pick-not-approved do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. ok-to-test Indicates a PR is ready to be tested. release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. type/cherry-pick-for-release-8.5 This PR is cherry-picked to release-8.5 from a source PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants