Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ var DerivedTableOuterScopeVisibilityQueries = []ScriptTest{
},
},
{
Name: "https://github.com/dolthub/go-mysql-server/issues/1282",
Name: "github.com/dolthub/go-mysql-server/issues/1282",
SetUpScript: []string{
"CREATE TABLE `dcim_rackgroup` (`id` char(32) NOT NULL, `lft` int unsigned NOT NULL, `rght` int unsigned NOT NULL, `tree_id` int unsigned NOT NULL, `level` int unsigned NOT NULL, `parent_id` char(32), PRIMARY KEY (`id`), KEY `dcim_rackgroup_tree_id_9c2ad6f4` (`tree_id`), CONSTRAINT `dcim_rackgroup_parent_id_cc315105_fk_dcim_rackgroup_id` FOREIGN KEY (`parent_id`) REFERENCES `dcim_rackgroup` (`id`));",
"CREATE TABLE `dcim_rack` (`id` char(32) NOT NULL, `group_id` char(32), PRIMARY KEY (`id`), KEY `dcim_rack_group_id_44e90ea9` (`group_id`), CONSTRAINT `dcim_rack_group_id_44e90ea9_fk_dcim_rackgroup_id` FOREIGN KEY (`group_id`) REFERENCES `dcim_rackgroup` (`id`));",
Expand Down
79 changes: 79 additions & 0 deletions enginetest/queries/join_queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -1641,4 +1641,83 @@ LATERAL (
},
},
},
{
Name: "nested lateral joins",
SetUpScript: []string{
"CREATE table ab (a int primary key, b int);",
"insert into ab values (0,3), (1,2), (2,1), (3,0);",
"create table three_pk (pk1 tinyint, pk2 tinyint, pk3 tinyint, col tinyint, primary key (pk1, pk2))",
"insert into three_pk values (0,0,0,100), (0,1,1,101), (1,0,1,110), (1,1,0,111)",
},
Assertions: []ScriptTestAssertion{
{
Query: `select * from ab ab1 join lateral (select * from ab ab2 join lateral (select * from three_pk where pk1 = ab1.a and pk2 = ab2.a) inner1) inner2;`,
Expected: []sql.Row{
{0, 3, 0, 3, 0, 0, 0, 100},
{0, 3, 1, 2, 0, 1, 1, 101},
{1, 2, 0, 3, 1, 0, 1, 110},
{1, 2, 1, 2, 1, 1, 0, 111},
},
},
{
Query: `select * from ab ab1 join lateral (select * from ab ab2 join lateral (select * from ab ab3 join lateral (select * from three_pk where pk1 = ab1.a and pk2 = ab2.a and pk3 = ab3.a) inner1) inner2) inner3;`,
Expected: []sql.Row{
{0, 3, 0, 3, 0, 3, 0, 0, 0, 100},
{0, 3, 1, 2, 1, 2, 0, 1, 1, 101},
{1, 2, 0, 3, 1, 2, 1, 0, 1, 110},
{1, 2, 1, 2, 0, 3, 1, 1, 0, 111},
},
},
{
Query: `select * from ab ab1 where exists (select * from ab ab2 where exists (select * from three_pk where pk1 = ab1.a and pk2 = ab2.a));`,
Expected: []sql.Row{
{0, 3},
{1, 2},
},
},
{
Query: `select * from ab ab1 where exists (select * from ab ab2 where exists (select * from ab ab3 where exists (select * from three_pk where pk1 = ab1.a and pk2 = ab2.a and pk3 = ab3.a)));`,
Expected: []sql.Row{
{0, 3},
{1, 2},
},
},
},
},
{
Name: "non-lateral joins inside inside lateral join",
SetUpScript: []string{
"CREATE table ab (a int primary key);",
"insert into ab values (0), (1), (2);",
"create table three_pk (pk1 tinyint, pk2 tinyint, pk3 tinyint, col tinyint, primary key (pk1, pk2))",
"insert into three_pk values (0,0,0,100), (0,1,1,101), (1,0,1,110), (1,1,0,111)",
},
Assertions: []ScriptTestAssertion{
{
Query: `
select *
from three_pk outer_table join lateral (
select /*+ JOIN_ORDER(inner1, inner2, inner3) */ *
from three_pk inner1 join (three_pk inner2 join three_pk inner3
on outer_table.pk2 = inner2.pk1 and outer_table.pk2 = inner2.pk2
and outer_table.pk3 = inner3.pk1 and outer_table.pk3 = inner3.pk2)
on outer_table.pk1 = inner1.pk1 and outer_table.pk1 = inner1.pk2
) inner_join;`,
Expected: []sql.Row{
{0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100},
{0, 1, 1, 101, 0, 0, 0, 100, 1, 1, 0, 111, 1, 1, 0, 111},
{1, 0, 1, 110, 1, 1, 0, 111, 0, 0, 0, 100, 1, 1, 0, 111},
{1, 1, 0, 111, 1, 1, 0, 111, 1, 1, 0, 111, 0, 0, 0, 100},
},
},
{
Query: `select ab1.a, a2 from ab ab1 join lateral (select ab2.a as a2, ab3.a as a3 from ab ab2 full outer join ab ab3 on ab2.a = ab1.a) inner1 where a3 is null;`,
Expected: []sql.Row{
{0, 1}, {0, 2},
{1, 0}, {1, 2},
{2, 0}, {2, 1},
},
},
},
},
}
196 changes: 196 additions & 0 deletions enginetest/queries/query_plans.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions sql/analyzer/apply_indexes_from_outer_scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ func getSubqueryIndexes(
result := make(map[string]sql.Index)
// For every predicate involving a table in the outer scope, see if there's an index lookup possible on its comparands
// (the tables in this scope)
// TODO: As written, this only looks at a single outer scope.
// This prevents optimization when we need to get predicates from multiple outer scopes like:
// select * from ab ab1 where exists
// (select * from ab ab2 join lateral
// (select * from two_pk where pk1 = ab1.a and pk2 = ab2.a) inner1)`
for _, scopeTable := range tablesInScope {
indexCols := exprsByTable[scopeTable]
if indexCols != nil {
Expand Down
7 changes: 0 additions & 7 deletions sql/analyzer/fix_exec_indexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,13 +661,6 @@ func (s *idxScope) finalizeSelf(n sql.Node) (sql.Node, error) {
return n, nil
}
n = jn.WithScopeLen(scopeLen)
n, err = n.WithChildren(
plan.NewStripRowNode(jn.Left(), scopeLen),
plan.NewStripRowNode(jn.Right(), scopeLen),
)
if err != nil {
return nil, err
}
}
return n, nil
}
Expand Down
2 changes: 1 addition & 1 deletion sql/analyzer/resolve_subqueries.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func finalizeSubqueriesHelper(ctx *sql.Context, a *Analyzer, node sql.Node, scop
var subScope *plan.Scope = scope
for _, joinParent := range joinParents {
if sqa.OuterScopeVisibility && joinParent != nil {
if stripChild, ok := joinParent.Right().(*plan.StripRowNode); ok && stripChild.Child == sqa {
if joinParent.Right() == sqa {
subScope = scope.NewScopeInJoin(joinParent.Children()[0])
subScope.SetLateralJoin(joinParent.Op.IsLateral())
} else {
Expand Down
2 changes: 1 addition & 1 deletion sql/analyzer/symbol_resolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func pruneTables(ctx *sql.Context, a *Analyzer, n sql.Node, s *plan.Scope, sel R
}
case *plan.Filter, *plan.Distinct, *plan.GroupBy, *plan.Project, *plan.TableAlias,
*plan.Window, *plan.Sort, *plan.Limit, *plan.RecursiveCte,
*plan.RecursiveTable, *plan.TopN, *plan.Offset, *plan.StripRowNode:
*plan.RecursiveTable, *plan.TopN, *plan.Offset:
default:
return n, transform.SameTree, nil
}
Expand Down
2 changes: 0 additions & 2 deletions sql/memo/join_order_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,6 @@ func (j *joinOrderBuilder) populateSubgraph(n sql.Node) (vertexSet, edgeSet, *Ex
group = j.buildJoinLeaf(n)
case sql.NameableNode:
group = j.buildJoinLeaf(n.(plan.TableIdNode))
case *plan.StripRowNode:
return j.populateSubgraph(n.Child)
case *plan.CachedResults:
return j.populateSubgraph(n.Child)
default:
Expand Down
12 changes: 0 additions & 12 deletions sql/plan/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,6 @@ func (s *Scope) NewScopeFromSubqueryExpression(node sql.Node, corr sql.ColSet) *
// NewScopeFromSubqueryExpression returns a new subscope created from a subquery expression contained by the specified
// node.
func (s *Scope) NewScopeInJoin(node sql.Node) *Scope {
for {
var done bool
switch n := node.(type) {
case *StripRowNode:
node = n.Child
default:
done = true
}
if done {
break
}
}
if s == nil {
return &Scope{joinSiblings: []sql.Node{node}}
}
Expand Down
Loading