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
4 changes: 4 additions & 0 deletions enginetest/queries/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -6937,6 +6937,10 @@ var QueryTests = []QueryTest{
Query: "SELECT CONV(i, 10, 2) FROM mytable",
Expected: []sql.Row{{"1"}, {"10"}, {"11"}},
},
{
Query: `SELECT t1.pk from one_pk join (one_pk t1 join one_pk t2 on t1.pk = t2.pk) on t1.pk = one_pk.pk and one_pk.pk = 1 join (one_pk t3 join one_pk t4 on t3.c1 is not null) on t3.pk = one_pk.pk and one_pk.c1 = 10`,
Expected: []sql.Row{{1}, {1}, {1}, {1}},
},
{
Query: "select i from mytable where i in (select (select i from mytable order by i limit 1) as i)",
Expected: []sql.Row{{1}},
Expand Down
25 changes: 8 additions & 17 deletions sql/analyzer/optimization_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,28 +133,19 @@ func moveJoinConditionsToFilter(ctx *sql.Context, a *Analyzer, n sql.Node, scope
return node, transform.SameTree, nil
}

// Add a new filter node with all removed predicates above the top level InnerJoin. Or, if there is a filter node
// above that, combine into a new filter.
selector := func(c transform.Context) bool {
switch c.Parent.(type) {
case *plan.Filter:
return false
return transform.NodeWithCtx(node, func(transform.Context) bool { return true }, func(c transform.Context) (sql.Node, transform.TreeIdentity, error) {
if c.Node != topJoin {
Copy link
Member

Choose a reason for hiding this comment

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

Does this function run recursively up the tree, so each join node gets a turn to be the top node?

I'm curious how this interacts with pushdown, could use some more plan tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There will always be one topJoin in a single scope. You would need a subquery, union, etc to get a second scope. If we know the joins are all compact in the tree, we could probably have this whole rule just be a single transform. When we hit a node that isn't a join and the topJoin is not nil we combine the conditions turned where filters. The relationship to pushdown is what you were telling me yesterday: this rule only moves filters from join to where clause, pushdown decides how low filters can be pushed.

return c.Node, transform.SameTree, nil
}
return c.Parent != topJoin
}

return transform.NodeWithCtx(node, selector, func(c transform.Context) (sql.Node, transform.TreeIdentity, error) {
switch node := c.Node.(type) {
switch n := c.Parent.(type) {
case *plan.Filter:
return plan.NewFilter(
expression.JoinAnd(append([]sql.Expression{node.Expression}, nonJoinFilters...)...),
node.Child), transform.NewTree, nil
case *plan.InnerJoin, *plan.CrossJoin:
expression.JoinAnd(append([]sql.Expression{n.Expression}, nonJoinFilters...)...),
n.Child), transform.NewTree, nil
default:
return plan.NewFilter(
expression.JoinAnd(nonJoinFilters...),
node), transform.NewTree, nil
default:
return node, transform.SameTree, nil
c.Node), transform.NewTree, nil
}
})
}
Expand Down