Skip to content

parser: add LATERAL derived table syntax (MySQL WL#8652) (#67076)#68887

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

parser: add LATERAL derived table syntax (MySQL WL#8652) (#67076)#68887
ti-chi-bot wants to merge 1 commit into
pingcap:release-8.5from
ti-chi-bot:cherry-pick-67076-to-release-8.5

Conversation

@ti-chi-bot

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

Copy link
Copy Markdown
Member

This is an automated cherry-pick of #67076

Add parser support for the LATERAL keyword in derived tables, following MySQL 8.0 syntax. This is parser-only; planner support follows in a separate PR. There is a planner change to ensure that LATERAL is correctly rejected until the planner code is delivered.

Grammar: LATERAL SubSelect TableAsName IdentListWithParenOpt

  • Alias is required (TableAsName, not TableAsNameOpt)
  • AS keyword is optional
  • Optional column list: LATERAL (...) AS dt(c1, c2)

AST changes:

  • TableSource.Lateral bool flag
  • TableSource.ColumnNames []CIStr for column aliases
  • Restore() emits LATERAL keyword and column list

What problem does this PR solve?

Issue Number: ref #40328

Problem Summary:

What changed and how does it work?

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

  • New Features

    • Parser now recognizes LATERAL derived tables with optional column alias lists per MySQL 8.0+ specification.
    • Includes AST validation for LATERAL syntax invariants.
  • Tests

    • Added comprehensive test coverage for LATERAL parsing, SQL restoration, nested subqueries, and invalid syntax scenarios.

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/XXL Denotes a PR that changes 1000+ 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
Member Author

@terry1purcell 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

ti-chi-bot Bot commented Jun 2, 2026

Copy link
Copy Markdown

@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

ti-chi-bot Bot commented Jun 2, 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 tangenta, terry1purcell 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 Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces parser support for MySQL 8.0+ LATERAL derived tables with optional column alias lists. The TableSource AST gains Lateral and ColumnNames fields, the grammar recognizes LATERAL syntax, and round-trip restoration is implemented with validation. The planner explicitly rejects LATERAL as unsupported.

Changes

LATERAL Derived Table Parsing

Layer / File(s) Summary
TableSource AST structure and restoration
pkg/parser/ast/dml.go
TableSource struct gains Lateral bool and ColumnNames []CIStr fields. Restore method validates invariants (LATERAL/ColumnNames only for derived tables), conditionally emits LATERAL keyword, and outputs optional column alias lists after the alias clause.
LATERAL keyword and token definition
pkg/parser/keywords.go, pkg/parser/parser.y, pkg/parser/keywords_test.go
LATERAL is registered as a reserved keyword in the Keywords slice, added as a %token in the grammar, and keyword count assertions are updated.
Token map and grammar production
pkg/parser/misc.go, pkg/parser/parser.y
The tokenMap is updated to recognize LATERAL (⚠️ note: unresolved merge conflict marker at line 159 requires attention). A new TableFactor production for LATERAL SubSelect constructs a TableSource with Lateral=true and populates ColumnNames.
Parser round-trip validation testing
pkg/parser/lateral_test.go, pkg/parser/BUILD.bazel
TestLateralParsing validates parsing, restoration, and re-parsing of LATERAL syntax in JOIN variants, nested subqueries, and column list forms. A recursive findLateralTableSource helper searches the AST for LATERAL table sources. Test file is wired into the build.
Planner rejection of unsupported LATERAL syntax
pkg/planner/core/preprocess.go, pkg/planner/core/preprocess_test.go
The preprocessor rejects node.Lateral with ErrNotSupportedYet. Test coverage validates rejection for plain FROM and LEFT JOIN LATERAL ... ON true forms.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • pingcap/tidb#67076: Parallel implementation adding LATERAL parsing by extending ast.TableSource with identical Lateral/ColumnNames fields, similar Restore() logic, and equivalent lateral_test.go and parser grammar wiring.

Suggested labels

cherry-pick-approved

Suggested reviewers

  • terry1purcell
  • hawkingrei
  • benmeadowcroft
  • tangenta

Poem

🐰 A lateral leap through the SQL parse tree,
LATERAL hops where subqueries be,
Restore and re-parse, the round trip is clean,
But the planner says "nope"—not ready yet, seen?
With tests standing guard and keywords in place,
We'll support LATERAL joins... just not this release! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% 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 clearly and specifically describes the main change: adding LATERAL derived table syntax support to the parser, with reference to MySQL WL#8652.
Description check ✅ Passed The description includes issue reference (ref #40328), explains what changed (LATERAL keyword support with grammar/AST details), and has unit test checked, though it lacks detailed explanation of how the feature works.
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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (1)
pkg/parser/misc.go (1)

159-1731: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Unresolved merge conflict markers span the entire tokenMap and will cause compilation failure.

The tokenMap variable contains git conflict markers that must be resolved. The incoming version (after the ======= marker) includes the "LATERAL": lateral mapping at line 1286, which is required for this feature.

Note: The two versions have significant differences beyond just the LATERAL keyword—the target branch appears to have diverged. Careful manual resolution is required to ensure all keywords from both branches are preserved.

As per coding guidelines, after resolving conflicts in parser files, run:

make parser
make parser_unit_test
🤖 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/parser/misc.go` around lines 159 - 1731, The file pkg/parser/misc.go
contains unresolved git conflict markers inside the tokenMap declaration; remove
the conflict markers (<<<<<<<, =======, >>>>>>>) and manually merge both sides
so that tokenMap includes all unique keyword mappings from both versions (ensure
entries like "LATERAL": lateral and "ADD_COLUMNAR_REPLICA_ON_DEMAND":
addColumnarReplicaOnDemand are preserved and no duplicates/conflicting
identifiers remain); after resolving, run make parser and make parser_unit_test
to validate the parser changes.
🤖 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/parser/ast/dml.go`:
- Around line 536-549: Remove the leftover merge conflict markers (<<<<<<<,
=======, >>>>>>>) in the struct declaration and keep the merged fields: AsName
(CIStr), Lateral (bool) with its comment, and ColumnNames ([]CIStr) with its
comment; ensure the struct now declares AsName CIStr followed by the Lateral and
ColumnNames fields and that there are no conflict markers remaining in the
dml.go AST type definition.
- Around line 556-565: The current guards only check for *TableName and miss
other non-derived sources like *Join, so update the validation in the node where
n.Source, n.Lateral, n.ColumnNames and n.AsName.String() are checked to ensure
the source is a derived table rather than just "not a TableName". Replace the
isTableName check with a predicate that verifies the source is a derived table
(e.g., type assert to the DerivedTable node or check a Derived flag on n.Source)
and use that predicate to reject LATERAL or column-alias lists on any
non-derived source (including Join), and keep the column-list-without-alias
check to only allow column lists when the source is a derived table.

In `@pkg/parser/keywords_test.go`:
- Around line 39-43: Resolve the leftover git merge conflict markers in
pkg/parser/keywords_test.go by removing the lines starting with <<<<<<<,
=======, and >>>>>>> and ensure the test assertion uses the updated expected
count require.Equal(t, 677, len(parser.Keywords)) (reflecting the added LATERAL
keyword); keep the incoming change (677) and delete the HEAD variant so the file
compiles cleanly.

In `@pkg/parser/lateral_test.go`:
- Around line 188-205: The helper findLateralTableSource currently returns only
the first LATERAL TableSource and masks regressions when there are multiple
LATERAL nodes; update the test helper so it collects and returns all lateral
TableSource nodes (e.g., rename to findAllLateralTableSources or add a new
helper) by traversing the entire ResultSetNode tree (handling *ast.TableSource
and *ast.Join), then update the "Multiple LATERAL joins" test to assert on both
returned nodes' Lateral==true instead of relying on a single match.

In `@pkg/parser/parser.y`:
- Around line 9933-9939: The action for the "LATERAL SubSelect" production is
using the wrong types for TableAsName and IdentListWithParenOpt; change the type
assertions from ast.CIStr and []ast.CIStr to model.CIStr and []model.CIStr (the
code that sets ts := &ast.TableSource{...}, ts.AsName = $3 and ts.ColumnNames =
$4 should cast $3 to model.CIStr and $4 to []model.CIStr). Update the assertions
for $3 and $4 in that action (the variables resultNode, ts, and TableSource
remain the same) so the code compiles against the model package types.

In `@pkg/planner/core/preprocess_test.go`:
- Around line 283-348: Remove the Git conflict markers (<<<<<<<, =======,
>>>>>>>) in the test case block in preprocess_test.go and keep the intended
added test rows (the VECTOR/COLUMNAR/FULLTEXT index cases, the
CREATE/VECTOR/COLUMNAR variations, and the LATERAL derived table cases) so the
test slice (the test cases variable in the preprocess tests) contains only valid
Go literals; ensure you do not duplicate or drop any of the newly introduced
cases and that the surrounding slice syntax and commas remain correct.

---

Outside diff comments:
In `@pkg/parser/misc.go`:
- Around line 159-1731: The file pkg/parser/misc.go contains unresolved git
conflict markers inside the tokenMap declaration; remove the conflict markers
(<<<<<<<, =======, >>>>>>>) and manually merge both sides so that tokenMap
includes all unique keyword mappings from both versions (ensure entries like
"LATERAL": lateral and "ADD_COLUMNAR_REPLICA_ON_DEMAND":
addColumnarReplicaOnDemand are preserved and no duplicates/conflicting
identifiers remain); after resolving, run make parser and make parser_unit_test
to validate the parser changes.
🪄 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: 89ef9a09-014d-4523-bd01-5d8797b6e1d1

📥 Commits

Reviewing files that changed from the base of the PR and between 4d31b77 and 832cd20.

📒 Files selected for processing (10)
  • pkg/parser/BUILD.bazel
  • pkg/parser/ast/dml.go
  • pkg/parser/keywords.go
  • pkg/parser/keywords_test.go
  • pkg/parser/lateral_test.go
  • pkg/parser/misc.go
  • pkg/parser/parser.go
  • pkg/parser/parser.y
  • pkg/planner/core/preprocess.go
  • pkg/planner/core/preprocess_test.go

Comment thread pkg/parser/ast/dml.go
Comment on lines +536 to +549
<<<<<<< HEAD
AsName model.CIStr
=======
AsName CIStr

// Lateral indicates whether this is a LATERAL derived table.
// MySQL 8.0+ syntax: FROM t1, LATERAL (SELECT ...) AS dt
// LATERAL allows the derived table to reference columns from tables to its left.
Lateral bool

// ColumnNames is the optional column alias list for derived tables.
// e.g. LATERAL (SELECT ...) AS dt(c1, c2)
ColumnNames []CIStr
>>>>>>> 270aa759fc2 (parser: add LATERAL derived table syntax (MySQL WL#8652) (#67076))

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 leftover cherry-pick conflict markers.

This hunk still contains <<<<<<< / ======= / >>>>>>>, so pkg/parser/ast/dml.go will not compile until the conflict is resolved. Keep the merged AsName, Lateral, and ColumnNames fields, but remove the conflict markers themselves.

Suggested resolution
-	// AsName is the alias name of the table source.
-<<<<<<< HEAD
-	AsName model.CIStr
-=======
-	AsName CIStr
-
-	// Lateral indicates whether this is a LATERAL derived table.
-	// MySQL 8.0+ syntax: FROM t1, LATERAL (SELECT ...) AS dt
-	// LATERAL allows the derived table to reference columns from tables to its left.
-	Lateral bool
-
-	// ColumnNames is the optional column alias list for derived tables.
-	// e.g. LATERAL (SELECT ...) AS dt(c1, c2)
-	ColumnNames []CIStr
->>>>>>> 270aa759fc2 (parser: add LATERAL derived table syntax (MySQL WL#8652) (`#67076`))
+	// AsName is the alias name of the table source.
+	AsName CIStr
+
+	// Lateral indicates whether this is a LATERAL derived table.
+	// MySQL 8.0+ syntax: FROM t1, LATERAL (SELECT ...) AS dt
+	// LATERAL allows the derived table to reference columns from tables to its left.
+	Lateral bool
+
+	// ColumnNames is the optional column alias list for derived tables.
+	// e.g. LATERAL (SELECT ...) AS dt(c1, c2)
+	ColumnNames []CIStr
📝 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
<<<<<<< HEAD
AsName model.CIStr
=======
AsName CIStr
// Lateral indicates whether this is a LATERAL derived table.
// MySQL 8.0+ syntax: FROM t1, LATERAL (SELECT ...) AS dt
// LATERAL allows the derived table to reference columns from tables to its left.
Lateral bool
// ColumnNames is the optional column alias list for derived tables.
// e.g. LATERAL (SELECT ...) AS dt(c1, c2)
ColumnNames []CIStr
>>>>>>> 270aa759fc2 (parser: add LATERAL derived table syntax (MySQL WL#8652) (#67076))
// AsName is the alias name of the table source.
AsName CIStr
// Lateral indicates whether this is a LATERAL derived table.
// MySQL 8.0+ syntax: FROM t1, LATERAL (SELECT ...) AS dt
// LATERAL allows the derived table to reference columns from tables to its left.
Lateral bool
// ColumnNames is the optional column alias list for derived tables.
// e.g. LATERAL (SELECT ...) AS dt(c1, c2)
ColumnNames []CIStr
🤖 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/parser/ast/dml.go` around lines 536 - 549, Remove the leftover merge
conflict markers (<<<<<<<, =======, >>>>>>>) in the struct declaration and keep
the merged fields: AsName (CIStr), Lateral (bool) with its comment, and
ColumnNames ([]CIStr) with its comment; ensure the struct now declares AsName
CIStr followed by the Lateral and ColumnNames fields and that there are no
conflict markers remaining in the dml.go AST type definition.

Comment thread pkg/parser/ast/dml.go
Comment on lines +556 to +565
// Validate AST invariants before emitting any SQL.
_, isTableName := n.Source.(*TableName)
if n.Lateral && isTableName {
return errors.New("LATERAL cannot be applied to a table name, only to derived tables")
}
if len(n.ColumnNames) > 0 && isTableName {
return errors.New("column alias list cannot be applied to a table name")
}
if len(n.ColumnNames) > 0 && n.AsName.String() == "" {
return errors.New("column list provided without alias for derived table")

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 | 🟠 Major | ⚡ Quick win

Validate against non-derived sources, not just *TableName.

These guards still allow Lateral or ColumnNames on TableSource{Source: *Join} even though the new invariant is “derived tables only.” That means Restore can still emit invalid SQL for parenthesized joins instead of rejecting the AST up front.

Suggested fix
-	_, isTableName := n.Source.(*TableName)
-	if n.Lateral && isTableName {
-		return errors.New("LATERAL cannot be applied to a table name, only to derived tables")
-	}
-	if len(n.ColumnNames) > 0 && isTableName {
-		return errors.New("column alias list cannot be applied to a table name")
-	}
+	isDerived := false
+	switch n.Source.(type) {
+	case *SelectStmt, *SetOprStmt:
+		isDerived = true
+	}
+	if n.Lateral && !isDerived {
+		return errors.New("LATERAL cannot be applied to a non-derived table source")
+	}
+	if len(n.ColumnNames) > 0 && !isDerived {
+		return errors.New("column alias list cannot be applied to a non-derived table source")
+	}
 	if len(n.ColumnNames) > 0 && n.AsName.String() == "" {
 		return errors.New("column list provided without alias for derived table")
 	}
📝 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
// Validate AST invariants before emitting any SQL.
_, isTableName := n.Source.(*TableName)
if n.Lateral && isTableName {
return errors.New("LATERAL cannot be applied to a table name, only to derived tables")
}
if len(n.ColumnNames) > 0 && isTableName {
return errors.New("column alias list cannot be applied to a table name")
}
if len(n.ColumnNames) > 0 && n.AsName.String() == "" {
return errors.New("column list provided without alias for derived table")
// Validate AST invariants before emitting any SQL.
isDerived := false
switch n.Source.(type) {
case *SelectStmt, *SetOprStmt:
isDerived = true
}
if n.Lateral && !isDerived {
return errors.New("LATERAL cannot be applied to a non-derived table source")
}
if len(n.ColumnNames) > 0 && !isDerived {
return errors.New("column alias list cannot be applied to a non-derived table source")
}
if len(n.ColumnNames) > 0 && n.AsName.String() == "" {
return errors.New("column list provided without alias for derived table")
}
🤖 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/parser/ast/dml.go` around lines 556 - 565, The current guards only check
for *TableName and miss other non-derived sources like *Join, so update the
validation in the node where n.Source, n.Lateral, n.ColumnNames and
n.AsName.String() are checked to ensure the source is a derived table rather
than just "not a TableName". Replace the isTableName check with a predicate that
verifies the source is a derived table (e.g., type assert to the DerivedTable
node or check a Derived flag on n.Source) and use that predicate to reject
LATERAL or column-alias lists on any non-derived source (including Join), and
keep the column-list-without-alias check to only allow column lists when the
source is a derived table.

Comment on lines +39 to +43
<<<<<<< HEAD
require.Equal(t, 661, len(parser.Keywords))
=======
require.Equal(t, 677, len(parser.Keywords))
>>>>>>> 270aa759fc2 (parser: add LATERAL derived table syntax (MySQL WL#8652) (#67076))

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

Unresolved merge conflict markers will cause compilation failure.

The file contains git conflict markers (<<<<<<< HEAD, =======, >>>>>>>) that must be resolved before the code can compile. Based on the PR objectives adding the LATERAL keyword, the incoming version with 677 keywords should be retained.

🐛 Proposed fix to resolve the merge conflict
-<<<<<<< HEAD
-	require.Equal(t, 661, len(parser.Keywords))
-=======
 	require.Equal(t, 677, len(parser.Keywords))
->>>>>>> 270aa759fc2 (parser: add LATERAL derived table syntax (MySQL WL#8652) (`#67076`))
📝 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
<<<<<<< HEAD
require.Equal(t, 661, len(parser.Keywords))
=======
require.Equal(t, 677, len(parser.Keywords))
>>>>>>> 270aa759fc2 (parser: add LATERAL derived table syntax (MySQL WL#8652) (#67076))
require.Equal(t, 677, len(parser.Keywords))
🤖 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/parser/keywords_test.go` around lines 39 - 43, Resolve the leftover git
merge conflict markers in pkg/parser/keywords_test.go by removing the lines
starting with <<<<<<<, =======, and >>>>>>> and ensure the test assertion uses
the updated expected count require.Equal(t, 677, len(parser.Keywords))
(reflecting the added LATERAL keyword); keep the incoming change (677) and
delete the HEAD variant so the file compiles cleanly.

Comment on lines +188 to +205
// findLateralTableSource recursively searches for the first LATERAL TableSource in a ResultSetNode.
func findLateralTableSource(node ast.ResultSetNode) *ast.TableSource {
if node == nil {
return nil
}

switch n := node.(type) {
case *ast.TableSource:
if n.Lateral {
return n
}
return findLateralTableSource(n.Source)
case *ast.Join:
if ts := findLateralTableSource(n.Left); ts != nil {
return ts
}
return findLateralTableSource(n.Right)
}

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

The helper masks regressions in the multiple-LATERAL case.

findLateralTableSource stops at the first match, so the "Multiple LATERAL joins" case never verifies that both derived tables keep Lateral=true after round-trip. A bug affecting the second node would still pass here.

🤖 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/parser/lateral_test.go` around lines 188 - 205, The helper
findLateralTableSource currently returns only the first LATERAL TableSource and
masks regressions when there are multiple LATERAL nodes; update the test helper
so it collects and returns all lateral TableSource nodes (e.g., rename to
findAllLateralTableSources or add a new helper) by traversing the entire
ResultSetNode tree (handling *ast.TableSource and *ast.Join), then update the
"Multiple LATERAL joins" test to assert on both returned nodes' Lateral==true
instead of relying on a single match.

Comment thread pkg/parser/parser.y
Comment on lines +9933 to +9939
| "LATERAL" SubSelect TableAsName IdentListWithParenOpt
{
resultNode := $2.(*ast.SubqueryExpr).Query
ts := &ast.TableSource{Source: resultNode, AsName: $3.(ast.CIStr)}
ts.Lateral = true
ts.ColumnNames = $4.([]ast.CIStr)
$$ = ts

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking whether ast.CIStr exists:"
rg -n --type=go '\btype\s+CIStr\b|\bCIStr\b' pkg/parser/ast pkg/parser/model

echo
echo "Checking the producers used by this rule:"
rg -n -A4 -B2 '^TableAsName:|^IdentListWithParenOpt:' pkg/parser/parser.y

echo
echo "Checking existing CIStr usage in parser.y:"
rg -n '\bmodel\.CIStr\b|\bast\.CIStr\b' pkg/parser/parser.y

Repository: pingcap/tidb

Length of output: 9151


Fix ast.CIStr / []ast.CIStr type assertions to model.CIStr / []model.CIStr in the LATERAL SubSelect action

TableAsName returns model.CIStr and IdentListWithParenOpt returns []model.CIStr, but this action still asserts ast.CIStr and []ast.CIStr (lines 9936 and 9938), which will fail to compile.

Suggested fix
 |	"LATERAL" SubSelect TableAsName IdentListWithParenOpt
 	{
 		resultNode := $2.(*ast.SubqueryExpr).Query
-		ts := &ast.TableSource{Source: resultNode, AsName: $3.(ast.CIStr)}
+		ts := &ast.TableSource{Source: resultNode, AsName: $3.(model.CIStr)}
 		ts.Lateral = true
-		ts.ColumnNames = $4.([]ast.CIStr)
+		ts.ColumnNames = $4.([]model.CIStr)
 		$$ = ts
 	}
📝 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
| "LATERAL" SubSelect TableAsName IdentListWithParenOpt
{
resultNode := $2.(*ast.SubqueryExpr).Query
ts := &ast.TableSource{Source: resultNode, AsName: $3.(ast.CIStr)}
ts.Lateral = true
ts.ColumnNames = $4.([]ast.CIStr)
$$ = ts
| "LATERAL" SubSelect TableAsName IdentListWithParenOpt
{
resultNode := $2.(*ast.SubqueryExpr).Query
ts := &ast.TableSource{Source: resultNode, AsName: $3.(model.CIStr)}
ts.Lateral = true
ts.ColumnNames = $4.([]model.CIStr)
$$ = ts
🤖 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/parser/parser.y` around lines 9933 - 9939, The action for the "LATERAL
SubSelect" production is using the wrong types for TableAsName and
IdentListWithParenOpt; change the type assertions from ast.CIStr and []ast.CIStr
to model.CIStr and []model.CIStr (the code that sets ts :=
&ast.TableSource{...}, ts.AsName = $3 and ts.ColumnNames = $4 should cast $3 to
model.CIStr and $4 to []model.CIStr). Update the assertions for $3 and $4 in
that action (the variables resultNode, ts, and TableSource remain the same) so
the code compiles against the model package types.

Comment on lines +283 to +348
<<<<<<< HEAD
=======

// issue 45674
{"alter table t2 add (b int)", true, nil},
{"alter table t2 add (b int)", false, infoschema.ErrTableNotExists.GenWithStackByArgs("test", "t2")},
{"create index x on t2(x)", true, nil},
{"create index x on t2(x)", false, infoschema.ErrTableNotExists.GenWithStackByArgs("test", "t2")},

// Invalid usages of columnar indexes
// Note: USING VECTOR is currently not introduced yet.
{"ALTER TABLE t ADD VECTOR INDEX (a, (VEC_COSINE_DISTANCE(a))) USING HNSW COMMENT 'a'", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"ALTER TABLE t ADD VECTOR INDEX ((VEC_COSINE_DISTANCE(a))) USING HYPO COMMENT 'a'", false, errors.New(`[ddl:8200]'USING HYPO' is not supported for VECTOR INDEX`)},
{"ALTER TABLE t ADD COLUMNAR INDEX (a)", false, errors.New(`[ddl:8200]COLUMNAR INDEX must specify 'USING <index_type>'`)},
{"ALTER TABLE t ADD COLUMNAR INDEX (a, b) USING INVERTED COMMENT 'a'", false, errors.New(`[ddl:8200]COLUMNAR INDEX of INVERTED type must specify one column name`)},
{"ALTER TABLE t ADD COLUMNAR INDEX (a) USING HYPO COMMENT 'a'", false, errors.New(`[ddl:8200]'USING HYPO' is not supported for COLUMNAR INDEX`)},
{"ALTER TABLE t ADD COLUMNAR INDEX ((a - 1)) USING HYPO COMMENT 'a'", false, errors.New(`[ddl:8200]'USING HYPO' is not supported for COLUMNAR INDEX`)},
{"ALTER TABLE t ADD INDEX (a) USING HNSW", false, errors.New(`[ddl:8200]'USING HNSW' can be only used for VECTOR INDEX`)},
{"ALTER TABLE t ADD INDEX (a) USING INVERTED", false, errors.New(`[ddl:8200]'USING INVERTED' can be only used for COLUMNAR INDEX`)},
// {"ALTER TABLE t ADD INDEX (a) USING VECTOR", false, errors.New(`[ddl:8200]'USING VECTOR' can be only used for COLUMNAR INDEX`)},
{"ALTER TABLE t ADD FULLTEXT INDEX (a) WITH PARSER foo", false, errors.New(`[ddl:8200]Unsupported parser 'foo'`)},
{"ALTER TABLE t ADD FULLTEXT INDEX (a) USING HNSW", false, errors.New(`[ddl:8200]'USING HNSW' is not supported for FULLTEXT INDEX`)},
{"CREATE VECTOR INDEX idx ON t (a) USING HNSW ", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE VECTOR INDEX idx ON t (a, b) USING HNSW", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE VECTOR INDEX idx ON t ((VEC_COSINE_DISTANCE(a))) TYPE BTREE", false, errors.New(`[ddl:8200]'USING BTREE' is not supported for VECTOR INDEX`)},
{"CREATE VECTOR INDEX idx ON t ((VEC_COSINE_DISTANCE(a)), a) USING HNSW", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE VECTOR INDEX idx ON t (a, (VEC_COSINE_DISTANCE(a))) USING HNSW", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE VECTOR INDEX ident ON d_n.t_n ( ident , ident2 ASC ) TYPE HNSW", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE UNIQUE INDEX ident USING HNSW ON d_n.t_n ( ident , ident2 ASC )", false, errors.New(`[ddl:8200]'USING HNSW' can be only used for VECTOR INDEX`)},
{"CREATE INDEX ident USING HNSW ON d_n.t_n ( ident )", false, errors.New(`[ddl:8200]'USING HNSW' can be only used for VECTOR INDEX`)},
{"CREATE INDEX ident USING INVERTED ON d_n.t_n ( ident )", false, errors.New(`[ddl:8200]'USING INVERTED' can be only used for COLUMNAR INDEX`)},
// {"CREATE INDEX ident USING VECTOR ON d_n.t_n ( ident )", false, errors.New(`[ddl:8200]'USING VECTOR' can be only used for COLUMNAR INDEX`)},
{"CREATE COLUMNAR INDEX ident USING HNSW ON d_n.t_n ( ident )", false, errors.New(`[ddl:8200]'USING HNSW' is not supported for COLUMNAR INDEX`)},
{"CREATE VECTOR INDEX ident USING HNSW ON d_n.t_n ( ident )", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
// {"CREATE VECTOR INDEX ident USING VECTOR ON d_n.t_n ((VEC_L2_DISTANCE(ident)))", false, errors.New(`[ddl:8200]'USING VECTOR' is not supported for VECTOR INDEX`)},
{"CREATE COLUMNAR INDEX ident ON d_n.t_n ((VEC_L2_DISTANCE(ident)))", false, errors.New(`[ddl:8200]COLUMNAR INDEX must specify 'USING <index_type>'`)},
{"CREATE COLUMNAR INDEX ident ON d_n.t_n (ident)", false, errors.New(`[ddl:8200]COLUMNAR INDEX must specify 'USING <index_type>'`)},
{"CREATE COLUMNAR INDEX ident USING HNSW ON d_n.t_n ((VEC_L2_DISTANCE(ident)))", false, errors.New(`[ddl:8200]'USING HNSW' is not supported for COLUMNAR INDEX`)},
// {"CREATE COLUMNAR INDEX ident USING VECTOR ON d_n.t_n (ident)", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE COLUMNAR INDEX ident USING INVERTED ON d_n.t_n ((VEC_L2_DISTANCE(ident)))", false, errors.New(`[ddl:8200]COLUMNAR INDEX of INVERTED type must specify one column name`)},
{"CREATE FULLTEXT INDEX ident ON d_n.t_n (ident) WITH PARSER foo", false, errors.New(`[ddl:8200]Unsupported parser 'foo'`)},
{"CREATE FULLTEXT INDEX ident ON d_n.t_n (ident) USING HNSW", false, errors.New(`[ddl:8200]'USING HNSW' is not supported for FULLTEXT INDEX`)},
{"CREATE TABLE t(a int, b vector(3), UNIQUE INDEX(b) USING HNSW)", false, errors.New(`[ddl:8200]'USING HNSW' can be only used for VECTOR INDEX`)},
{"CREATE TABLE t(a int, b vector(3), UNIQUE INDEX(b) USING INVERTED)", false, errors.New(`[ddl:8200]'USING INVERTED' can be only used for COLUMNAR INDEX`)},
// {"CREATE TABLE t(a int, b vector(3), UNIQUE INDEX(b) USING VECTOR)", false, errors.New(`[ddl:8200]'USING VECTOR' can be only used for COLUMNAR INDEX`)},
{"CREATE TABLE t(a int, b vector(3), VECTOR INDEX(b) USING HNSW)", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE TABLE t(a int, b vector(3), VECTOR INDEX(a, b) USING HNSW)", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE TABLE t(a int, b vector(3), VECTOR INDEX((VEC_COSINE_DISTANCE(b))) USING HASH)", false, errors.New(`[ddl:8200]'USING HASH' is not supported for VECTOR INDEX`)},
{"CREATE TABLE t(a int, b vector(3), VECTOR INDEX(a, (VEC_COSINE_DISTANCE(b))) USING HNSW)", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE TABLE t(a int, b vector(3), VECTOR INDEX((VEC_COSINE_DISTANCE(b)), a) USING HNSW)", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE TABLE t(a int, COLUMNAR INDEX(b))", false, errors.New(`[ddl:8200]COLUMNAR INDEX must specify 'USING <index_type>'`)},
{"CREATE TABLE t(a int, COLUMNAR INDEX(b) USING HNSW)", false, errors.New(`[ddl:8200]'USING HNSW' is not supported for COLUMNAR INDEX`)},
// {"CREATE TABLE t(a int, COLUMNAR INDEX(b) USING VECTOR)", false, errors.New(`[ddl:8200]VECTOR INDEX must specify an expression like ((VEC_XX_DISTANCE(<COLUMN>)))`)},
{"CREATE TABLE t(c TEXT, FULLTEXT INDEX (t) WITH PARSER foo)", false, errors.New(`[ddl:8200]Unsupported parser 'foo'`)},
{"CREATE TABLE t(c TEXT, FULLTEXT INDEX (t) USING HNSW)", false, errors.New(`[ddl:8200]'USING HNSW' is not supported for FULLTEXT INDEX`)},

// The following columnar index usages are valid, they only fail due to table not found.
{"CREATE VECTOR INDEX ident USING HNSW ON d_n.t_n ((VEC_L2_DISTANCE(ident)))", false, errors.New(`[schema:1146]Table 'd_n.t_n' doesn't exist`)},
{"CREATE VECTOR INDEX ident ON d_n.t_n ((VEC_L2_DISTANCE(ident)))", false, errors.New(`[schema:1146]Table 'd_n.t_n' doesn't exist`)},
// {"CREATE COLUMNAR INDEX ident USING VECTOR ON d_n.t_n ((VEC_L2_DISTANCE(ident)))", false, errors.New(`[schema:1146]Table 'd_n.t_n' doesn't exist`)},
{"CREATE FULLTEXT INDEX x ON ident (col_x)", false, errors.New(`[schema:1146]Table 'test.ident' doesn't exist`)},

// LATERAL derived tables are not yet supported in the planner.
{"SELECT * FROM t, LATERAL (SELECT t.a) AS dt", false, plannererrors.ErrNotSupportedYet},
{"SELECT * FROM t LEFT JOIN LATERAL (SELECT t.a) AS dt ON true", false, plannererrors.ErrNotSupportedYet},
>>>>>>> 270aa759fc2 (parser: add LATERAL derived table syntax (MySQL WL#8652) (#67076))

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 merge conflict markers in the test table.

This test block still has <<<<<<< / ======= / >>>>>>>, so the file will not compile. Resolve the cherry-pick conflict and keep the intended new cases without the markers.

🤖 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/preprocess_test.go` around lines 283 - 348, Remove the Git
conflict markers (<<<<<<<, =======, >>>>>>>) in the test case block in
preprocess_test.go and keep the intended added test rows (the
VECTOR/COLUMNAR/FULLTEXT index cases, the CREATE/VECTOR/COLUMNAR variations, and
the LATERAL derived table cases) so the test slice (the test cases variable in
the preprocess tests) contains only valid Go literals; ensure you do not
duplicate or drop any of the newly introduced cases and that the surrounding
slice syntax and commas remain correct.

@tiprow

tiprow Bot commented Jun 2, 2026

Copy link
Copy Markdown

@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 832cd20 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.

@ti-chi-bot

ti-chi-bot Bot commented Jun 2, 2026

Copy link
Copy Markdown

@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 832cd20 link true /test check-dev
idc-jenkins-ci-tidb/unit-test 832cd20 link true /test unit-test
idc-jenkins-ci-tidb/mysql-test 832cd20 link true /test mysql-test
idc-jenkins-ci-tidb/build 832cd20 link true /test build
idc-jenkins-ci-tidb/check_dev_2 832cd20 link true /test check-dev2

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.

@ti-chi-bot ti-chi-bot Bot added cherry-pick-approved Cherry pick PR approved by release team. and removed do-not-merge/cherry-pick-not-approved labels Jun 5, 2026
@qw4990

qw4990 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

duplicated with #68886

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

Labels

cherry-pick-approved Cherry pick PR approved by release team. 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/XXL Denotes a PR that changes 1000+ 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.

3 participants