Skip to content

pkg/planner, pkg/sessionctx: keep native TiCI FTS plan when LIKE fallback rejects syntax (#68525)#68572

Merged
ti-chi-bot[bot] merged 7 commits into
pingcap:release-fts-202602from
ti-chi-bot:cherry-pick-68525-to-release-fts-202602
May 22, 2026
Merged

pkg/planner, pkg/sessionctx: keep native TiCI FTS plan when LIKE fallback rejects syntax (#68525)#68572
ti-chi-bot[bot] merged 7 commits into
pingcap:release-fts-202602from
ti-chi-bot:cherry-pick-68525-to-release-fts-202602

Conversation

@ti-chi-bot
Copy link
Copy Markdown
Member

@ti-chi-bot ti-chi-bot commented May 21, 2026

This is an automated cherry-pick of #68525

What problem does this PR solve?

Issue Number: close #68489

Problem Summary:

With @@tidb_opt_enable_alternative_logical_plans = 1, the planner could discard a valid native TiCI FTS plan before native planning actually ran. When the LIKE fallback then rejected boolean prefix syntax such as stainles*, the query failed even though the native FTS path was executable.

What changed and how does it work?

  • Remove the nonViableFTSMatch heuristic invalidation path from round-1 build state.
  • Keep the predicate-context MATCH signal only for scheduling the fallback round.
  • Let the real native planning path decide whether fallback should take over by returning FTSLikeFallbackError.
  • Add a regression test showing that alternative logical plans keep the native multi-column TiCI prefix plan for boolean MATCH ... AGAINST.
  • Record the planner note under docs/note/planner/rule/rule_ai_notes.md.

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.

Test command:

make failpoint-enable && (GOCACHE=/private/tmp/index-join-refactor-go-build go test ./pkg/planner/core/casetest/tici -run TestTiCIAlternativeLogicalPlansKeepNativePrefixPlan --tags=intest; rc=$?; make failpoint-disable; exit $rc)

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.

Fix an alternative logical plan bug where a valid native TiCI full-text query could be discarded and replaced by an unsupported LIKE fallback for boolean prefix MATCH AGAINST syntax.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added tidb_enable_tici_estimate system variable to control search index row-count estimation behavior.
  • Bug Fixes

    • Improved fallback behavior for full-text search queries when native search paths are unavailable.
    • Enhanced IGNORE INDEX hint support for native search queries.
  • Tests

    • Added regression tests for full-text search alternative query plan selection.

Review Change Stack

@ti-chi-bot ti-chi-bot added ok-to-test Indicates a PR is ready to be tested. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/planner SIG: Planner size/L Denotes a PR that changes 100-499 lines, ignoring generated files. type/cherry-pick-for-release-fts-202602 labels May 21, 2026
@winoros winoros changed the title pkg/planner, pkg/sessionctx: keep native TiCI FTS plan when LIKE fallback rejects syntax | tidb-test=feature/fts tiflash=feature/fts tikv=feature/fts (#68525) pkg/planner, pkg/sessionctx: keep native TiCI FTS plan when LIKE fallback rejects syntax (#68525) May 21, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

This PR fixes a bug where FTS alternative-plan heuristics incorrectly invalidated native TiCI plans. It removes the problematic nonViableFTSMatch flag, gates TiCI search-path estimation behind a new system variable, adds IGNORE INDEX support for TiCI indexes, and includes regression tests documenting the fix.

Changes

FTS Fallback and TiCI Estimation

Layer / File(s) Summary
TiDB System Variable for TiCI Estimation
pkg/sessionctx/vardef/tidb_vars.go, pkg/sessionctx/variable/sysvar.go, pkg/planner/core/casetest/tici/BUILD.bazel
Introduces TiDBEnableTiCIEstimate global system variable with default enabled state and atomic-boolean holder. Registered as a GLOBAL system variable with ON/OFF get/set handlers. BUILD dependency added to enable test access.
TiCI Search-Path Estimation Gating
pkg/planner/core/stats.go, pkg/planner/core/casetest/tici/stats_test.go
deriveTiCISearchPathStats early-returns when vardef.EnableTiCIEstimate.Load() is false, preventing estimate-driven cardinality adjustments for search paths. Test verifies plan differences when estimate flag is disabled.
FTS Alternative-Plan Fallback Signaling Fix
pkg/planner/core/planbuilder.go, pkg/planner/core/expression_rewriter.go, pkg/planner/optimize.go, pkg/sessionctx/stmtctx/stmtctx.go
Removes nonViableFTSMatch build-time invalidation flag and replaces with predicateMatchSeen to track direct-boolean-context MATCH...AGAINST. Expression rewriter now only calls MarkPredicateMatch() without checking native viability. Optimizer no longer performs early round discard; fallback is driven by native optimization error handling.
TiCI Index Hint Support for IGNORE INDEX
pkg/planner/core/operator/logicalop/logical_datasource.go
Adds isTiCIIndexIgnoredByHint and isIgnoredByIndexHint helpers to check scan-scoped IGNORE/USE INDEX hints. chooseTiCIIndex now skips TiCI access paths when the candidate index is explicitly ignored.
Regression Tests
pkg/planner/core/casetest/tici/tici_test.go
Three new integration tests: prefix search on fulltext index routes to TiCI plan; word search prefers native FTS over LIKE fallback; IGNORE INDEX hint routes to LIKE fallback instead of TiCI path.
Issue Documentation
docs/note/planner/rule/rule_ai_notes.md
Records the issue (FTS heuristic invalidating native plans), implementation changes (removing nonViableFTSMatch, restricting predicate-match signaling), and regression test coverage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The changes span planner logic, system variables, and test infrastructure across 10+ files, but follow a coherent narrative: fix the FTS fallback signaling (planbuilder, expression_rewriter, optimize), gate estimation (stats), add hint support (datasource), and test comprehensively. No deep semantic complexity; straightforward flag/method replacements and conditional logic adjustments. Moderate spread requires reviewing the interconnected signaling changes across multiple files.

Possibly related issues

  • #68489: Core issue being fixed — FTS LIKE fallback rejects boolean MATCH...AGAINST syntax that native FTS can handle, causing planning errors when alternative logical plans are enabled.

Possibly related PRs

  • pingcap/tidb#68525: Makes the same core planner change by removing nonViableFTSMatch invalidation and routing FTS LIKE fallback trigger via HasPredicateMatch/native error handling, with matching updates in expression_rewriter, planbuilder, optimize, and alternative-logical-plan tests.

  • pingcap/tidb#68298: Modifies TiCI search-path count estimation in deriveTiCISearchPathStats by restricting estimates to multi-table queries, complementing this PR's addition of the TiDBEnableTiCIEstimate flag-gating mechanism.

  • pingcap/tidb#66583: Refactors TiCI index analysis and selection in logical_datasource.go, directly connected to this PR's changes to chooseTiCIIndex and TiCI path eligibility under index-skip hints.

Suggested labels

approved, lgtm

Suggested reviewers

  • qw4990
  • winoros
  • hawkingrei

Poem

A planner once wrongly discarded,
The native FTS path departed,
Till predicate marks took the place,
Of viability's embrace—
Now fallback hints keep plans charted! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 accurately summarizes the main fix: preventing native TiCI FTS plans from being discarded when LIKE fallback rejects boolean syntax.
Description check ✅ Passed The PR description includes the issue number (close #68489), problem summary, changes overview, test confirmation, and release notes; all required template sections are present.
Linked Issues check ✅ Passed All code changes directly address issue #68489 by removing nonViableFTSMatch heuristic, preserving native FTS plans, and adding regression tests for boolean MATCH AGAINST syntax.
Out of Scope Changes check ✅ Passed All changes are in-scope: FTS plan preservation logic, predicate match signaling, TiCI index hint handling, regression tests, and supporting variable configuration.

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

✨ 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 and usage tips.

@ti-chi-bot ti-chi-bot Bot added the needs-1-more-lgtm Indicates a PR needs 1 more LGTM. label May 21, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

❌ Patch coverage is 38.29787% with 29 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (release-fts-202602@fc2e1e9). Learn more about missing BASE report.

Additional details and impacted files
@@                   Coverage Diff                   @@
##             release-fts-202602     #68572   +/-   ##
=======================================================
  Coverage                      ?   39.4147%           
=======================================================
  Files                         ?       1725           
  Lines                         ?     478098           
  Branches                      ?          0           
=======================================================
  Hits                          ?     188441           
  Misses                        ?     272673           
  Partials                      ?      16984           
Flag Coverage Δ
integration 39.4147% <38.2978%> (?)

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

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

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

🧹 Nitpick comments (1)
docs/note/planner/rule/rule_ai_notes.md (1)

64-64: 💤 Low value

Optional: Standardize flag style for Go idiom.

The command uses --tags=intest (double-dash), while Go convention is -tags=intest (single-dash). Both work, but single-dash is more idiomatic for Go tooling. Note that this file already has inconsistency between line 21 (single-dash) and line 46 (double-dash).

♻️ Optional flag style adjustment
-  `make failpoint-enable && (go test ./pkg/planner/core/casetest/tici -run TestTiCIAlternativeLogicalPlansKeepNativePrefixPlan --tags=intest; rc=$?; make failpoint-disable; exit $rc)`
+  `make failpoint-enable && (go test ./pkg/planner/core/casetest/tici -run TestTiCIAlternativeLogicalPlansKeepNativePrefixPlan -tags=intest; rc=$?; make failpoint-disable; exit $rc)`
🤖 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 `@docs/note/planner/rule/rule_ai_notes.md` at line 64, Replace the double-dash
Go flag in the command snippet so it uses the idiomatic single-dash form: change
`--tags=intest` to `-tags=intest` in the command that runs `go test` for
`TestTiCIAlternativeLogicalPlansKeepNativePrefixPlan`; ensure similar
consistency elsewhere in this file (e.g., line with single-dash at the earlier
example) so all `go test` invocations use `-tags=...`.
🤖 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/planner/core/casetest/tici/stats_test.go`:
- Around line 47-49: The test currently forces the global TiCI-estimate var back
to ON in the defer which can leak state; before calling
tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))
capture the current global value (e.g. via tk.MustQuery(fmt.Sprintf("select
@@global.%s", vardef.TiDBEnableTiCIEstimate)) into a local variable origVal) and
in the defer restore that original value with tk.MustExec(fmt.Sprintf("set
global %s = %s", vardef.TiDBEnableTiCIEstimate, origVal)); update the code
around the tk.MustExec calls so the test always restores the prior setting
instead of hardcoding "on".

---

Nitpick comments:
In `@docs/note/planner/rule/rule_ai_notes.md`:
- Line 64: Replace the double-dash Go flag in the command snippet so it uses the
idiomatic single-dash form: change `--tags=intest` to `-tags=intest` in the
command that runs `go test` for
`TestTiCIAlternativeLogicalPlansKeepNativePrefixPlan`; ensure similar
consistency elsewhere in this file (e.g., line with single-dash at the earlier
example) so all `go test` invocations use `-tags=...`.
🪄 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: 9a9f066d-2656-4603-85cd-091fa2de47bf

📥 Commits

Reviewing files that changed from the base of the PR and between fc2e1e9 and 36dc249.

📒 Files selected for processing (12)
  • docs/note/planner/rule/rule_ai_notes.md
  • pkg/planner/core/casetest/tici/BUILD.bazel
  • pkg/planner/core/casetest/tici/stats_test.go
  • pkg/planner/core/casetest/tici/tici_test.go
  • pkg/planner/core/expression_rewriter.go
  • pkg/planner/core/operator/logicalop/logical_datasource.go
  • pkg/planner/core/planbuilder.go
  • pkg/planner/core/stats.go
  • pkg/planner/optimize.go
  • pkg/sessionctx/stmtctx/stmtctx.go
  • pkg/sessionctx/vardef/tidb_vars.go
  • pkg/sessionctx/variable/sysvar.go
💤 Files with no reviewable changes (1)
  • pkg/planner/core/planbuilder.go

Comment on lines +47 to 49
tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))
defer tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))

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 | 🟡 Minor | ⚡ Quick win

Restore the original global TiCI-estimate value after the test.

The deferred reset hardcodes ON, so this test can leak global state when the previous value was OFF, which makes later tests order-dependent.

Suggested fix
 tk := testkit.NewTestKit(t, store)
-tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))
-defer tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))
+origTiCIEstimate := tk.MustQuery(
+	fmt.Sprintf("select @@global.%s", vardef.TiDBEnableTiCIEstimate),
+).Rows()[0][0]
+tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))
+defer tk.MustExec(fmt.Sprintf("set global %s = %v", vardef.TiDBEnableTiCIEstimate, origTiCIEstimate))

As per coding guidelines, "Keep test changes minimal and deterministic; avoid broad golden/testdata churn unless required."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))
defer tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))
tk := testkit.NewTestKit(t, store)
origTiCIEstimate := tk.MustQuery(
fmt.Sprintf("select @@global.%s", vardef.TiDBEnableTiCIEstimate),
).Rows()[0][0]
tk.MustExec(fmt.Sprintf("set global %s = on", vardef.TiDBEnableTiCIEstimate))
defer tk.MustExec(fmt.Sprintf("set global %s = %v", vardef.TiDBEnableTiCIEstimate, origTiCIEstimate))
🤖 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/casetest/tici/stats_test.go` around lines 47 - 49, The test
currently forces the global TiCI-estimate var back to ON in the defer which can
leak state; before calling tk.MustExec(fmt.Sprintf("set global %s = on",
vardef.TiDBEnableTiCIEstimate)) capture the current global value (e.g. via
tk.MustQuery(fmt.Sprintf("select @@global.%s", vardef.TiDBEnableTiCIEstimate))
into a local variable origVal) and in the defer restore that original value with
tk.MustExec(fmt.Sprintf("set global %s = %s", vardef.TiDBEnableTiCIEstimate,
origVal)); update the code around the tk.MustExec calls so the test always
restores the prior setting instead of hardcoding "on".

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented May 22, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: qw4990, winoros
Once this PR has been reviewed and has the lgtm label, please assign yudongusa 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 lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels May 22, 2026
@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented May 22, 2026

[LGTM Timeline notifier]

Timeline:

  • 2026-05-21 19:44:03.92411361 +0000 UTC m=+66174.564970423: ☑️ agreed by winoros.
  • 2026-05-22 01:56:26.55063003 +0000 UTC m=+88517.191486833: ☑️ agreed by qw4990.

@ti-chi-bot ti-chi-bot Bot merged commit f66233d into pingcap:release-fts-202602 May 22, 2026
23 checks passed
@ti-chi-bot ti-chi-bot Bot deleted the cherry-pick-68525-to-release-fts-202602 branch May 22, 2026 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm ok-to-test Indicates a PR is ready to be tested. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/planner SIG: Planner size/L Denotes a PR that changes 100-499 lines, ignoring generated files. type/cherry-pick-for-release-fts-202602

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants