Skip to content

planner: skip plan cache for join ON subqueries - #68422

Open
hawkingrei wants to merge 1 commit into
pingcap:masterfrom
hawkingrei:issue-65975-join-on-subquery-cache
Open

planner: skip plan cache for join ON subqueries#68422
hawkingrei wants to merge 1 commit into
pingcap:masterfrom
hawkingrei:issue-65975-join-on-subquery-cache

Conversation

@hawkingrei

@hawkingrei hawkingrei commented May 16, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #65975

Problem Summary:

Prepared statements could fail with ON condition doesn't support subqueries yet when the query used an uncorrelated scalar subquery in a JOIN ... ON condition. The equivalent normal SELECT succeeds because the subquery can be evaluated during plan build, but the prepared plan-cache path kept ? markers as mutable constants long enough for the ON rewriter to build an unsupported Apply.

What changed and how does it work?

When planning a join ON expression that contains subqueries, skip plan cache before rewriting the ON expression. This keeps prepared EXECUTE parameters as concrete constants for the current execution, so the existing build-time subquery evaluation path can handle the uncorrelated subquery instead of producing an unsupported Apply.

A regression test covers the normal query and the prepared EXECUTE form from the issue, and checks that the prepared path skips plan cache.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No code

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

Manual test

Compared with MySQL 9.4.0 in a local temporary container. Both normal and prepared forms return one NULL row; MySQL reports a 1292 Truncated incorrect INTEGER value: '' warning for the prepared form.

Tests

go test -tags=intest,deadlock ./pkg/planner/core/casetest/plancache -run TestPlanCachePreparedJoinOnSubquery -count=1
go test -tags=intest,deadlock ./pkg/planner/core/casetest/plancache -run 'TestPlanCache(PreparedJoinOnSubquery|WithSubquery)$' -count=1
make bazel_prepare
git diff --check

Release note

Fix a prepared statement error when a JOIN ON condition contains an uncorrelated subquery.

Summary by CodeRabbit

  • Bug Fixes
    • Disabled prepared plan caching for JOIN queries containing subqueries in the ON condition to ensure correct query execution.

Review Change Stack

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-tests-checked release-note Denotes a PR that will be considered when it comes time to generate release notes. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. sig/planner SIG: Planner labels May 16, 2026
@ti-chi-bot

ti-chi-bot Bot commented May 16, 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 king-dylan 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

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3c4e76f5-7e30-4b42-b498-4d43d5a4f391

📥 Commits

Reviewing files that changed from the base of the PR and between dd8253c and 7b6a70f.

📒 Files selected for processing (3)
  • pkg/planner/core/casetest/plancache/BUILD.bazel
  • pkg/planner/core/casetest/plancache/plan_cache_suite_test.go
  • pkg/planner/core/logical_plan_builder.go

📝 Walkthrough

Walkthrough

This PR fixes inconsistent behavior between normal and prepared SELECT statements when subqueries appear in JOIN ON conditions. The fix detects such subqueries and disables plan cache to prevent execution errors in prepared statements, with comprehensive test validation.

Changes

Plan cache disabling for JOIN ON subqueries

Layer / File(s) Summary
Plan cache skip implementation
pkg/planner/core/logical_plan_builder.go
buildJoin() now calls skipPlanCacheForJoinOnSubquery() before rewriting the ON expression. The helper function checks whether caching is enabled, scans the ON expression for subquery expressions via subqueryExprExtractor, and if any are found, sets StmtCtx.SetSkipPlanCache() with an un-cacheable reason message.
Regression test and test infrastructure
pkg/planner/core/casetest/plancache/plan_cache_suite_test.go, pkg/planner/core/casetest/plancache/BUILD.bazel
TestPlanCachePreparedJoinOnSubquery creates a table with NULL and boolean data, runs a non-parameterized LEFT JOIN query to assert success, then prepares and executes a parameterized variant with an ON condition subquery that must emit a warning about un-cacheability and result in a plan-cache miss. Test shard count incremented from 46 to 47.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • pingcap/tidb#66869: Modifies pkg/planner/core/logical_plan_builder.go to extend subqueryExprExtractor usage for different subquery contexts.
  • pingcap/tidb#67433: Modifies buildJoin logic in pkg/planner/core/logical_plan_builder.go for join condition handling.

Suggested labels

sig/planner, size/M, ok-to-test

Suggested reviewers

  • qw4990
  • guo-shaoge

Poem

🐰 A curious case where two paths diverge,
The normal and prepared took different urge.
But now with subqueries in JOIN's ON revealed,
Both statements align, their behaviors sealed.
Hop hop, consistency reigns! 🌟

🚥 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 Title 'planner: skip plan cache for join ON subqueries' clearly and concisely describes the main change: skipping plan cache for join ON conditions containing subqueries.
Description check ✅ Passed Description includes all required template sections: issue reference (close #65975), problem summary, explanation of changes, test types marked, manual test notes, and release note.
Linked Issues check ✅ Passed Code changes fully address issue #65975 by skipping plan cache when JOIN ON conditions contain subqueries, enabling prepared statements to handle uncorrelated subqueries correctly.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the issue: modified shard count, added regression test, and implemented plan cache skipping logic for JOIN ON subqueries.

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

@codecov

codecov Bot commented May 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 76.5019%. Comparing base (dd8253c) to head (7b6a70f).
⚠️ Report is 404 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #68422        +/-   ##
================================================
- Coverage   77.2764%   76.5019%   -0.7746%     
================================================
  Files          2010       1992        -18     
  Lines        555481     557543      +2062     
================================================
- Hits         429256     426531      -2725     
- Misses       125305     130969      +5664     
+ Partials        920         43       -877     
Flag Coverage Δ
integration 41.5240% <90.9090%> (+1.7300%) ⬆️

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

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

@hawkingrei

Copy link
Copy Markdown
Contributor Author

/test mysql-test

@tiprow

tiprow Bot commented May 16, 2026

Copy link
Copy Markdown

@hawkingrei: 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 mysql-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.

@hawkingrei

Copy link
Copy Markdown
Contributor Author

/retest

@hawkingrei
hawkingrei requested a review from qw4990 May 19, 2026 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI-Correction Bugfix by AI release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/planner SIG: Planner 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.

Inconsistent behaviour between normal and prepared SELECT when use subquery in ON condition

1 participant