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
1,932 changes: 1,023 additions & 909 deletions enginetest/queries/integration_plans.go

Large diffs are not rendered by default.

297 changes: 148 additions & 149 deletions enginetest/queries/query_plans.go

Large diffs are not rendered by default.

17 changes: 9 additions & 8 deletions enginetest/queries/tpch_plans.go

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

11 changes: 8 additions & 3 deletions sql/analyzer/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ func (f filtersByTable) size() int {

// getFiltersByTable returns a map of table name to filter expressions on that table for the node provided. Any
// predicates that contain no table or more than one table are not included in the result.
func getFiltersByTable(n sql.Node) filtersByTable {
func getFiltersByTable(n sql.Node, scope *plan.Scope) filtersByTable {
filters := newFiltersByTable()
transform.Inspect(n, func(node sql.Node) bool {
switch node := node.(type) {
case *plan.Filter:
fs := exprToTableFilters(node.Expression)
fs := exprToTableFilters(node.Expression, scope)
filters.merge(fs)
}
if o, ok := node.(sql.OpaqueNode); ok {
Expand All @@ -62,7 +62,7 @@ func getFiltersByTable(n sql.Node) filtersByTable {
// exprToTableFilters returns a map of table name to filter expressions on that table for all parts of the expression
// given, split at AND. Any expressions that contain subquerys, or refer to more than one table, are not included in
// the result.
func exprToTableFilters(expr sql.Expression) filtersByTable {
func exprToTableFilters(expr sql.Expression, scope *plan.Scope) filtersByTable {
filters := newFiltersByTable()
for _, expr := range expression.SplitConjunction(expr) {
var seenTables = make(map[string]bool)
Expand All @@ -71,6 +71,11 @@ func exprToTableFilters(expr sql.Expression) filtersByTable {
sql.Inspect(expr, func(e sql.Expression) bool {
f, ok := e.(*expression.GetField)
if ok {
// A GetField that resolves to an outer scope or lateral scope
// is effectively constant and can be skipped.
if scope.Correlated().Contains(f.Id()) {
return true
}
if !seenTables[f.Table()] {
seenTables[f.Table()] = true
lastTable = f.Table()
Expand Down
12 changes: 6 additions & 6 deletions sql/analyzer/filters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,14 @@ func TestExprToTableFilters(t *testing.T) {
},
}

filters := exprToTableFilters(expr)
filters := exprToTableFilters(expr, nil)
assert.Equal(t, expected, filters)

// Test various complex conditions -- anytime we can't neatly split the expressions into tables
filters = exprToTableFilters(expression.NewAnd(
lit(0),
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable", "f", false),
))
), nil)
expected = filtersByTable{
"mytable": []sql.Expression{
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable", "f", false),
Expand All @@ -197,7 +197,7 @@ func TestExprToTableFilters(t *testing.T) {
filters = exprToTableFilters(expression.NewAnd(
expression.NewLiteral(nil, types.Null),
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable", "f", false),
))
), nil)
expected = filtersByTable{
"mytable": []sql.Expression{
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable", "f", false),
Expand All @@ -208,7 +208,7 @@ func TestExprToTableFilters(t *testing.T) {
filters = exprToTableFilters(expression.NewAnd(
expression.NewEquals(lit(1), mustExpr(function.NewRand())),
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable", "f", false),
))
), nil)
expected = filtersByTable{
"mytable": []sql.Expression{
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable", "f", false),
Expand All @@ -219,7 +219,7 @@ func TestExprToTableFilters(t *testing.T) {
filters = exprToTableFilters(expression.NewOr(
expression.NewLiteral(nil, types.Null),
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable", "f", false),
))
), nil)
expected = filtersByTable{
"mytable": []sql.Expression{
expression.NewOr(
Expand All @@ -239,7 +239,7 @@ func TestExprToTableFilters(t *testing.T) {
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable", "f", false),
expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "mytable2", "i", false),
),
))
), nil)
expected = filtersByTable{
"mytable": []sql.Expression{
eq(
Expand Down
12 changes: 9 additions & 3 deletions sql/analyzer/pushdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func pushFilters(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope, s
}
// Find all col exprs and group them by the table they mention so that we can keep track of which ones
// have been pushed down and need to be removed from the parent filter
filtersByTable := getFiltersByTable(n)
filtersByTable := getFiltersByTable(n, scope)
filters := newFilterSet(n.Expression, filtersByTable, tableAliases)

// move filter predicates directly above their respective tables in joins
Expand Down Expand Up @@ -220,7 +220,7 @@ func transformPushdownSubqueryAliasFilters(ctx *sql.Context, a *Analyzer, n sql.
switch n := n.(type) {
case *plan.Filter:
// First step is to find all col exprs and group them by the table they mention.
filtersByTable := getFiltersByTable(n)
filtersByTable := getFiltersByTable(n, scope)
filters = newFilterSet(n.Expression, filtersByTable, tableAliases)
return transformFilterNode(n)
default:
Expand Down Expand Up @@ -293,7 +293,13 @@ func pushdownFiltersUnderSubqueryAlias(ctx *sql.Context, a *Analyzer, sa *plan.S
if gt, ok := e.(*expression.GetField); ok {
gf, ok := sa.ScopeMapping[gt.Id()]
if !ok {
return e, transform.SameTree, fmt.Errorf("unable to find child with id: %d", gt.Index())
// The GetField must be referencing an outer or lateral scope.
// We need to add this to the subquery alias's list of correlated columns
sa.Correlated.Add(gt.Id())
// There now may be a reference to a lateral scope, so we mark the alias as lateral just in case.
// This shouldn't break anything, but it might inhibit optimizations that check this.
sa.IsLateral = true
return e, transform.NewTree, nil
}
return gf, transform.NewTree, nil
}
Expand Down
13 changes: 7 additions & 6 deletions sql/plan/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,13 @@ func (s *Scope) NewScopeInJoin(node sql.Node) *Scope {
newNodes = append(newNodes, node)
newNodes = append(newNodes, s.joinSiblings...)
return &Scope{
nodes: s.nodes,
Memos: s.Memos,
recursionDepth: s.recursionDepth + 1,
Procedures: s.Procedures,
joinSiblings: newNodes,
corr: s.corr,
nodes: s.nodes,
Memos: s.Memos,
recursionDepth: s.recursionDepth + 1,
Procedures: s.Procedures,
joinSiblings: newNodes,
corr: s.corr,
CurrentNodeIsFromSubqueryExpression: s.CurrentNodeIsFromSubqueryExpression,
}
}

Expand Down