Skip to content

Conversation

@terry1purcell
Copy link
Contributor

@terry1purcell terry1purcell commented Jan 19, 2026

What problem does this PR solve?

Issue Number: ref #40328

Problem Summary:

What changed and how does it work?

Add LATERAL join support to MySQL compatible behavior. Include LATERAL + ORDER BY + LIMIT within a recursive query - where the ORDER BY + LIMIT is within a lateral join.

Claude code review:

LATERAL Join Implementation - Code Review

Overview

The implementation adds MySQL 8.0+ LATERAL join support to TiDB, allowing derived tables to
reference columns from tables to their left in the FROM clause. The approach reuses the
existing LogicalApply infrastructure.

Files Modified

File Changes
pkg/parser/parser.y Grammar rule for LATERAL
pkg/parser/ast/dml.go Lateral field on TableSource
pkg/planner/core/logical_plan_builder.go buildJoin and buildLateralJoin
pkg/planner/core/rule_join_reorder.go Block reordering for Apply
Error definitions MySQL error code 3809
Tests Unit and integration tests

Positive Findings

  1. Sound Architecture

The choice to reuse LogicalApply is appropriate - LATERAL joins are semantically equivalent to
correlated subqueries, and this avoids duplicating execution infrastructure.

  1. Proper Cleanup with Defer (lines 612-617)

defer func() {
b.outerSchemas = b.outerSchemas[:len(b.outerSchemas)-1]
b.outerNames = b.outerNames[:len(b.outerNames)-1]
b.buildingLateralSubquery = saveBuildingLateral
}()
Consolidating all cleanup in a single defer ensures consistent cleanup in both success and
error paths.

  1. Column Index Fix (lines 805-808)

leftLen := leftPlan.Schema().Len()
for i := range rightPlan.Schema().Len() {
ap.Schema().Columns[leftLen+i].Index = leftLen + i
}
Critical fix to update column indices after schema merge - prevents incorrect data reads from
projections.

  1. Proper Error Handling
  • RIGHT JOIN with LATERAL returns MySQL error 3809
  • NATURAL JOIN/USING clause rejected with LATERAL
  • Subqueries in ON condition rejected
  1. FullSchema/FullNames Handling (lines 844-873)

Properly handles FullSchema and FullNames for LogicalJoin compatibility.

  1. Clone All FieldNames (lines 814-839)

Deep cloning output names prevents unintended mutations, including hidden names.

  1. Test Coverage
  • Unit tests for plan building
  • Integration tests with various scenarios
  • Recursive CTE with LATERAL tests

Potential Issues and Suggestions

Issue 1: Missing Join Reorder Block for LogicalApply

Location: rule_join_reorder.go lines 58-67

Observation: The current code disables join reorder flag in buildJoin (line 593-595), but
extractJoinGroup still checks for LogicalJoin only:

join, isJoin := p.(*logicalop.LogicalJoin)
if isJoin && join.PreferJoinOrder { ...

Risk: Low - LogicalApply embeds LogicalJoin, so type assertion may succeed but the subsequent
conditions (e.g., join.StraightJoin, join type checks) should prevent extraction into reorder
groups. However, an explicit check would be safer.

Recommendation: Add explicit check at the beginning:
if _, isApply := p.(*logicalop.LogicalApply); isApply {
return &joinGroupResult{group: []base.LogicalPlan{p}, ...}
}

Issue 2: ON Condition Subquery Check May Be Too Restrictive

Location: logical_plan_builder.go line 883

if newPlan != ap {
return nil, plannererrors.ErrInvalidLateralJoin.GenWithStackByArgs("ON condition contains
subqueries")
}

Risk: Medium - This check prevents ALL subqueries in ON conditions, not just correlated ones.
MySQL allows uncorrelated subqueries in ON clauses with LATERAL.

Recommendation: Consider allowing uncorrelated subqueries in ON conditions in a future
enhancement.

Issue 3: curClause Not Reset After ON Condition Processing

Location: logical_plan_builder.go line 877

The code sets b.curClause = onClause before processing ON condition but doesn't reset it after.
This was addressed in commit 78f1034, but verify it doesn't affect subsequent processing if
buildLateralJoin returns early due to an error.

Observation: Since the function returns after ON condition processing (either success or
error), this is acceptable.

Issue 4: Parser Tests Needed for LATERAL Keyword Restoration

Location: ast/dml.go lines 556-558

if n.Lateral {
ctx.WriteKeyWord("LATERAL ")
}

Recommendation: Ensure there are parser tests that verify SQL with LATERAL is properly
restored/printed (round-trip testing).

Issue 5: buildingLateralSubquery Flag Usage

Location: planbuilder.go and logical_plan_builder.go

The buildingLateralSubquery flag is set but I don't see where it's consumed to change behavior.
If it's used to allow ORDER BY/LIMIT in recursive CTE parts, ensure there are tests covering
this interaction.


Minor Code Quality Observations

  1. Comment Accuracy

Line 750: Good function-level comment explaining LATERAL semantics.

  1. Copyright Year

lateral_join_test.go line 1: Uses "Copyright 2026" which is incorrect (should be 2025 or
current year).

  1. Consistent Error Messages

All error messages use the same format pattern via ErrInvalidLateralJoin.GenWithStackByArgs() -
good consistency.


Security Considerations

No security issues identified. The implementation:

  • Doesn't introduce SQL injection vectors
  • Properly validates input at the parser level
  • Uses existing TiDB error handling infrastructure

Performance Considerations

  1. Nested Loop Execution: LATERAL uses LogicalApply which executes as nested loop. This is
    expected behavior but may be slow for large datasets. The decorrelation optimizer
    (FlagDecorrelate) is enabled to convert to joins when safe.
  2. No Index Hints Support: LATERAL subqueries don't support index hints. This is standard MySQL
    behavior.

Summary

The LATERAL join implementation is well-designed and thoroughly implemented. Key strengths:

  • Leverages existing infrastructure (LogicalApply)
  • Proper cleanup handling with defer
  • Correct column index adjustment
  • Good error handling with MySQL-compatible error codes
  • Comprehensive test coverage

Suggested improvements:

  1. Add explicit LogicalApply check in join reorder extraction
  2. Consider allowing uncorrelated subqueries in ON conditions (future enhancement)
  3. Fix copyright year in test file

Overall Assessment: Ready for merge with minor cleanup.

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

Copilot AI review requested due to automatic review settings January 19, 2026 20:00
@ti-chi-bot ti-chi-bot bot added do-not-merge/needs-linked-issue release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jan 19, 2026
@tiprow
Copy link

tiprow bot commented Jan 19, 2026

Hi @terry1purcell. Thanks for your PR.

PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test all.

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.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds initial support for LATERAL joins in TiDB's query planner. LATERAL allows derived tables (subqueries) to reference columns from tables that appear to their left in the FROM clause, enabling correlated references in join contexts. The PR is marked as "WIP" (Work In Progress).

Changes:

  • Added LATERAL keyword parsing support in the SQL parser
  • Implemented LATERAL join planning using LogicalApply nodes
  • Prevented join reordering for LATERAL joins to preserve execution dependencies
  • Added error handling for invalid LATERAL join usage

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test_lateral_simple.go Basic smoke test for LATERAL parsing and restoration
pkg/parser/parser.y Added LATERAL keyword and grammar rule for LATERAL derived tables
pkg/parser/misc.go Registered LATERAL token in keyword map
pkg/parser/ast/dml.go Added Lateral boolean field to TableSource with Restore support
pkg/parser/mysql/errcode.go Added ErrInvalidLateralJoin error code (3809)
pkg/errno/errcode.go Added ErrInvalidLateralJoin constant
pkg/errno/errname.go Added error message for invalid LATERAL usage
pkg/util/dbterror/plannererrors/planner_terror.go Registered ErrInvalidLateralJoin in planner errors
pkg/planner/core/logical_plan_builder.go Implemented buildLateralJoin using LogicalApply, disabled join reorder for LATERAL
pkg/planner/core/rule_join_reorder.go Prevented reordering of LogicalApply nodes used by LATERAL
DEPS.bzl Dependency updates (not reviewed in detail)
pkg/parser/parser.go Generated parser code (not reviewed)

@codecov
Copy link

codecov bot commented Jan 19, 2026

Codecov Report

❌ Patch coverage is 84.09091% with 49 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.3589%. Comparing base (38fdd1b) to head (9561895).
⚠️ Report is 12 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #65656        +/-   ##
================================================
+ Coverage   77.7655%   79.3589%   +1.5933%     
================================================
  Files          2001       1949        -52     
  Lines        545901     537589      -8312     
================================================
+ Hits         424523     426625      +2102     
+ Misses       119716     109527     -10189     
+ Partials       1662       1437       -225     
Flag Coverage Δ
integration 47.4877% <79.0163%> (-0.6757%) ⬇️
unit 76.7003% <81.4935%> (+0.3066%) ⬆️

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

Components Coverage Δ
dumpling 56.7974% <ø> (ø)
parser ∅ <ø> (∅)
br 65.3671% <ø> (+4.3834%) ⬆️
🚀 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.

This file is auto-generated by genkeyword and needs to be updated
when new keywords are added to misc.go. The change adds LATERAL
to the reserved keywords list.

Also includes formatting changes to logical_plan_builder.go from
go fmt alignment.
Copilot AI review requested due to automatic review settings January 19, 2026 22:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 5 comments.

Copilot AI review requested due to automatic review settings January 20, 2026 16:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 15 out of 16 changed files in this pull request and generated 8 comments.

terry1purcell and others added 3 commits January 20, 2026 09:04
Update keyword counts in tests to reflect the addition of
the LATERAL keyword:
- Total keywords: 673 → 674
- Reserved keywords: 232 → 233

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add comprehensive integration tests covering:
- Basic LATERAL join with comma syntax
- LATERAL with ORDER BY and LIMIT
- LATERAL with aggregates
- LEFT JOIN LATERAL
- LATERAL with recursive CTEs
- Multiple left-side tables
- Nested subqueries in LATERAL
- LATERAL without correlation
- RIGHT JOIN with LATERAL error (3809)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Regenerate errors.toml to include the new ErrInvalidLateralJoin
error code (3809) added for LATERAL join support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Copilot AI review requested due to automatic review settings January 20, 2026 17:24
Change error code validation to use ErrInvalidLateralJoin.Equal(err)
instead of comparing expectedErrorCode against the static error code.
This ensures the test actually validates the returned error rather than
just checking if expectedErrorCode equals 3809.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated 2 comments.

@terry1purcell terry1purcell changed the title planner: lateral join support planner: lateral join support | tidb-test=pr/2664 Jan 21, 2026
Copilot AI review requested due to automatic review settings January 21, 2026 01:44
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 1 comment.

@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 21, 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 benmeadowcroft, d3hunter, qw4990 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

Copilot AI review requested due to automatic review settings January 21, 2026 05:51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated no new comments.

@terry1purcell
Copy link
Contributor Author

@pantheon-bot please review.

@pantheon-ai
Copy link

pantheon-ai bot commented Feb 3, 2026

P1: pruneRedundantApply can incorrectly eliminate LATERAL Apply

The pruneRedundantApply optimization in pkg/planner/core/rule_decorrelate.go:141 removes a LogicalApply when its parent LogicalSelection simplifies to TRUE, but it does not check apply.IsLateral. For LEFT JOIN LATERAL, this can incorrectly drop the entire lateral join when queries have trivial WHERE clauses (e.g., WHERE 1=1 or WHERE TRUE), changing row multiplicity and potentially breaking plans that reference lateral-derived columns.

Evidence: pkg/planner/core/rule_decorrelate.go:152 - no IsLateral guard before returning apply.Children()[0]

Fix: Add && !apply.IsLateral check before eliminating the Apply, similar to the guard in LogicalApply.PruneColumns at pkg/planner/core/operator/logicalop/logical_apply.go:83


P1: Optimizer can mis-decorrelate correlated LATERAL Apply into plain Join

The decorrelation logic in pkg/planner/core/rule_decorrelate.go:228 recomputes apply.CorCols by extracting correlated columns against outerPlan.Schema(). However, when the outer side is a USING/NATURAL join, redundant join-key columns exist only in FullSchema (not Schema). If a LATERAL subquery references these redundant columns, they won't be captured in the recomputed CorCols, causing len(apply.CorCols) == 0 to incorrectly trigger Apply→Join simplification. The correlated references remain in the inner plan but become unbound (evaluate as NULL), producing wrong results.

Evidence:

  • pkg/planner/core/rule_decorrelate.go:228 - recomputes CorCols against outerPlan.Schema()
  • pkg/planner/core/logical_plan_builder.go:621 - LATERAL name resolution uses FullSchema
  • pkg/planner/core/logical_plan_builder.go:793 - CorCols extraction uses leftPlan.Schema() (mismatch)

Fix: Extract correlated columns against the same schema used for name resolution (FullSchema when present), or ensure redundant columns are included in the extraction schema


P2: FullSchema/CorCols extraction mismatch causes NULL values for redundant columns

When building a LATERAL join where the left side is a USING/NATURAL join, buildJoin exposes FullSchema/FullNames for name resolution (including redundant columns), but buildLateralJoin extracts CorCols only against leftPlan.Schema(). Correlated columns referencing redundant columns (e.g., qualified as t2.a in t1 JOIN t2 USING(a)) are created but never wired to the Apply executor, remaining NULL at runtime.

Evidence:

  • pkg/planner/core/logical_plan_builder.go:620 - uses join.FullSchema for outer scope
  • pkg/planner/core/logical_plan_builder.go:793 - extracts CorCols against leftPlan.Schema()
  • pkg/executor/parallel_apply.go:281 - only binds listed correlated columns

Fix: Align CorCols extraction with the outer scope used for name resolution


P2: Nested LATERAL loses visibility of redundant columns when left becomes LogicalApply

When building nested LATERAL joins, if the left plan is a LogicalApply (from a previous LATERAL join), buildJoin at line 618 only checks for *logicalop.LogicalJoin to use FullSchema/FullNames, falling back to Schema()/OutputNames() for Apply. This causes redundant columns from USING/NATURAL joins to disappear from the outer scope for nested LATERAL subqueries, leading to "unknown column" errors for valid SQL.

Evidence: pkg/planner/core/logical_plan_builder.go:618 - type check excludes *logicalop.LogicalApply

Fix: Extend the FullSchema check to also handle *logicalop.LogicalApply with non-nil FullSchema


P2: LogicalApply statistics assume 1 row per outer row

LogicalApply.DeriveStats at pkg/planner/core/operator/logicalop/logical_apply.go:129 hard-codes RowCount to the left child's row count, which is correct for scalar subqueries but not for LATERAL joins where the right side can return 0..N rows per outer row. This can lead to significant cardinality underestimation for LATERAL queries, potentially causing suboptimal plans (cost estimation issue, not correctness).

Evidence: pkg/planner/core/operator/logicalop/logical_apply.go:129 - unconditional RowCount: leftProfile.RowCount

Fix: For IsLateral applies, estimate cardinality based on join multiplicity

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated 3 comments.

@terry1purcell
Copy link
Contributor Author

@pantheon-bot please review

@pantheon-ai
Copy link

pantheon-ai bot commented Feb 3, 2026

Code Review Results

P1 Issues (Correctness - Wrong Results)

Issue 1: Correlated columns dropped during pruning for LATERAL over USING/NATURAL joins

  • Severity: P1
  • Impact: Silent wrong results - correlated values become NULL when LATERAL references redundant USING/NATURAL columns
  • Root Cause: LogicalApply.PruneColumns re-extracts correlation only from Schema() instead of FullSchema, dropping columns that exist only in FullSchema
  • Evidence: la.CorCols = coreusage.ExtractCorColumnsBySchema4LogicalPlan(la.Children()[1], la.Children()[0].Schema()) at pkg/planner/core/operator/logicalop/logical_apply.go:98
  • Example Pattern: SELECT ... FROM t1 JOIN t2 USING(a) JOIN LATERAL (SELECT t2.a) ... - the t2.a reference resolves during planning but gets NULL at runtime
  • Fix: Extract CorCols against outer child's FullSchema when available (for both LogicalJoin and LogicalApply)

Issue 2: Nested LATERAL loses correlation when outer side is LogicalApply

  • Severity: P1
  • Impact: Wrong results in multi-LATERAL chains when referencing redundant USING/NATURAL columns
  • Root Cause: buildLateralJoin() only switches to FullSchema for *LogicalJoin, missing *LogicalApply.FullSchema, causing incomplete CorCols/Data wiring
  • Evidence: outerSchema := leftPlan.Schema(); if join, ok := leftPlan.(*logicalop.LogicalJoin); ok && join.FullSchema != nil { outerSchema = join.FullSchema } at pkg/planner/core/logical_plan_builder.go:802
  • Example Pattern: Nested LATERAL where the left subtree is itself a LogicalApply from a USING/NATURAL join
  • Fix: Also handle *logicalop.LogicalApply in the FullSchema selection logic (mirror buildJoin behavior)

P2 Issues (Quality/Diagnostics)

Issue 3: LATERAL outer-scope resolution breaks with wrapped left side

  • Severity: P2
  • Impact: Valid queries fail with "unknown column" error when left side is wrapped (e.g., JOIN with ON produces LogicalSelection)
  • Root Cause: Outer schema/name selection only checks direct LogicalJoin/LogicalApply types, ignoring wrapper nodes
  • Evidence: if join, ok := leftPlan.(*logicalop.LogicalJoin); ok && join.FullSchema != nil at pkg/planner/core/logical_plan_builder.go:627
  • Fix: Unwrap passthrough nodes (LogicalSelection/LogicalProjection/etc.) before checking for FullSchema

Issue 4: LATERAL LEFT JOIN stats under-estimation

  • Severity: P2
  • Impact: Optimizer cost estimates can be lower than logically possible, potentially causing suboptimal plans
  • Root Cause: Multiplicative row count formula doesn't enforce LEFT OUTER JOIN's minimum (preserved-side rowcount)
  • Evidence: rowCount = leftProfile.RowCount * rightProfile.RowCount at pkg/planner/core/operator/logicalop/logical_apply.go:150 (no max(rowCount, leftProfile.RowCount) clamp)
  • Fix: Add lower bound: rowCount = math.Max(rowCount, leftProfile.RowCount) for LeftOuterJoin

Issue 5: ONLY_FULL_GROUP_BY error formatting regression

  • Severity: P2
  • Impact: Error messages show leading dot for derived-table column refs (e.g., .t1.v2), reducing readability
  • Root Cause: Error path concatenates DBName + "." + TblName + "." + ColName even when DBName is empty
  • Evidence: contains nonaggregated column '.t1.v2' at tests/integrationtest/r/planner/core/integration.result:2350
  • Fix: Conditional dot insertion based on whether DBName is non-empty

Summary: Identified 2 P1 correctness issues and 3 P2 quality issues. The P1 issues involve correlated column handling in LATERAL joins with USING/NATURAL - both can silently produce wrong results (NULLs instead of correlated values) in specific patterns. Recommend fixing these before merge.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 2 comments.

Comment on lines +461 to +487
// Clone output names before modifying to avoid mutating shared structs
if x.AsName.L != "" {
clonedNames := make([]*types.FieldName, len(p.OutputNames()))
for i, name := range p.OutputNames() {
if name.Hidden {
clonedNames[i] = name
continue
}
// Clone the field name and update table name
// For derived tables (subqueries), clear DBName to avoid confusion with actual tables
// For base tables with aliases, preserve DBName for proper metadata and DEFAULT() resolution
dbName := ast.NewCIStr("")
if isTableName {
dbName = name.DBName
}
clonedNames[i] = &types.FieldName{
DBName: dbName,
OrigTblName: name.OrigTblName,
OrigColName: name.OrigColName,
TblName: x.AsName,
ColName: name.ColName,
NotExplicitUsable: name.NotExplicitUsable,
Redundant: name.Redundant,
Hidden: name.Hidden,
}
}
p.SetOutputNames(clonedNames)
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The changes at lines 461-487 introduce a behavior change where derived tables (subqueries with aliases) now have their DBName cleared to an empty string. This affects error messages and potentially other functionality that depends on DBName being set.

Looking at the test result changes in tests/integrationtest/r/planner/core/integration.result (lines 2350, 2352) and tests/integrationtest/r/executor/aggregate.result (line 1519), error messages that previously showed fully qualified column names like planner__core__integration.t1.v2 now show .t1.v2 (with empty database name).

While this change may be intentional to avoid confusion between derived tables and actual database tables, it's a breaking change in error message format. Consider:

  1. Documenting this behavior change in the PR description as it affects user-visible error messages
  2. Verifying that this doesn't break any tooling or scripts that parse these error messages
  3. Ensuring that the empty DBName doesn't cause issues elsewhere in the codebase that might assume DBName is always set

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Claude code response to this is that we should correct the empty DB name separately in another PR.

Comment on lines +4513 to +4514
prevSchema := cte.cteClass.SeedPartLogicalPlan.Schema().Clone()
lp.SetSchema(getResultCTESchema(cte.cteClass.SeedPartLogicalPlan.Schema(), b.ctx.GetSessionVars()))
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The change from cte.seedLP.Schema() to cte.cteClass.SeedPartLogicalPlan.Schema() at lines 4513-4514 appears to be accessing the same value through an indirection, since cte.cteClass.SeedPartLogicalPlan is set to cte.seedLP at line 4500. However, this indirection only exists if cte.cteClass == nil at line 4497.

If cte.cteClass is not nil (i.e., it was already created in a previous call), then cte.seedLP and cte.cteClass.SeedPartLogicalPlan might be different if cte.seedLP was somehow modified after the cteClass was created.

While the change seems functionally correct (using the cached value from cteClass), this subtle change could affect CTE behavior in edge cases. Consider adding a comment explaining why this indirection is used instead of the direct reference, or verify that both values are always identical at this point.

Suggested change
prevSchema := cte.cteClass.SeedPartLogicalPlan.Schema().Clone()
lp.SetSchema(getResultCTESchema(cte.cteClass.SeedPartLogicalPlan.Schema(), b.ctx.GetSessionVars()))
// Use the seed plan stored in cteClass as the canonical source of the schema.
// cteClass.SeedPartLogicalPlan is initialized from cte.seedLP when the CTEClass
// is first created and should remain stable across subsequent uses.
seedSchema := cte.cteClass.SeedPartLogicalPlan.Schema()
prevSchema := seedSchema.Clone()
lp.SetSchema(getResultCTESchema(seedSchema, b.ctx.GetSessionVars()))

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants