Skip to content

Commit

Permalink
add ut
Browse files Browse the repository at this point in the history
  • Loading branch information
zz-jason committed Oct 26, 2018
1 parent 143435f commit a49eeb4
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 12 deletions.
33 changes: 24 additions & 9 deletions planner/cascades/expr_iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ func (iter *ExprIter) Next() (found bool) {
}

// Otherwise, iterate itself to find more matched equivalent expressions.
for iter.element.Next(); iter.element != nil; iter.element.Next() {
expr := iter.element.Value.(*GroupExpr)
for elem := iter.element.Next(); elem != nil; elem = elem.Next() {
expr := elem.Value.(*GroupExpr)
exprOperand := GetOperand(expr.exprNode)

if !iter.operand.match(exprOperand) {
Expand All @@ -85,6 +85,7 @@ func (iter *ExprIter) Next() (found bool) {
}

if allMatched {
iter.element = elem
return true
}
}
Expand All @@ -100,18 +101,32 @@ func (iter *ExprIter) Matched() bool {
// Reset resets the iterator to the first matched group expression.
func (iter *ExprIter) Reset() (findMatch bool) {
iter.element = iter.group.GetFirstElem(iter.operand)
return iter.element != nil
iter.matched = iter.element != nil
return iter.matched
}

// NewExprIterFromGroupElem creates the iterator on the group element.
func NewExprIterFromGroupElem(elem *list.Element, p *Pattern) *ExprIter {
expr := elem.Value.(*GroupExpr)
if !p.operand.match(GetOperand(expr.exprNode)) {
return nil
}
iter := newExprIterFromGroupExpr(expr, p)
if iter != nil {
iter.element = elem
}
return iter
}

// NewExprIterFromGroupExpr creates the iterator on the group expression.
func NewExprIterFromGroupExpr(expr *GroupExpr, p *Pattern) *ExprIter {
// newExprIterFromGroupExpr creates the iterator on the group expression.
func newExprIterFromGroupExpr(expr *GroupExpr, p *Pattern) *ExprIter {
if len(p.children) != len(expr.children) {
return nil
}

iter := &ExprIter{operand: p.operand, matched: true}
for i := range p.children {
childIter := NewExprIterFromGroup(expr.children[i], p.children[i])
childIter := newExprIterFromGroup(expr.children[i], p.children[i])
if childIter == nil {
return nil
}
Expand All @@ -120,14 +135,14 @@ func NewExprIterFromGroupExpr(expr *GroupExpr, p *Pattern) *ExprIter {
return iter
}

// NewExprIterFromGroup creates the iterator on the group.
func NewExprIterFromGroup(g *Group, p *Pattern) *ExprIter {
// newExprIterFromGroup creates the iterator on the group.
func newExprIterFromGroup(g *Group, p *Pattern) *ExprIter {
for elem := g.GetFirstElem(p.operand); elem != nil; elem = elem.Next() {
expr := elem.Value.(*GroupExpr)
if !p.operand.match(GetOperand(expr.exprNode)) {
return nil
}
iter := NewExprIterFromGroupExpr(expr, p)
iter := newExprIterFromGroupExpr(expr, p)
if iter != nil {
iter.group, iter.element = g, elem
return iter
Expand Down
102 changes: 102 additions & 0 deletions planner/cascades/expr_iterator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2018 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package cascades

import (
. "github.com/pingcap/check"
plannercore "github.com/pingcap/tidb/planner/core"
)

func (s *testCascadesSuite) TestNewExprIterFromGroupElem(c *C) {
g0 := NewGroup(NewGroupExpr(plannercore.LogicalSelection{}.Init(s.sctx)))
g0.Insert(NewGroupExpr(plannercore.LogicalLimit{}.Init(s.sctx)))
g0.Insert(NewGroupExpr(plannercore.LogicalProjection{}.Init(s.sctx)))
g0.Insert(NewGroupExpr(plannercore.LogicalLimit{}.Init(s.sctx)))

g1 := NewGroup(NewGroupExpr(plannercore.LogicalSelection{}.Init(s.sctx)))
g1.Insert(NewGroupExpr(plannercore.LogicalLimit{}.Init(s.sctx)))
g1.Insert(NewGroupExpr(plannercore.LogicalProjection{}.Init(s.sctx)))
g1.Insert(NewGroupExpr(plannercore.LogicalLimit{}.Init(s.sctx)))

expr := NewGroupExpr(plannercore.LogicalJoin{}.Init(s.sctx))
expr.children = append(expr.children, g0)
expr.children = append(expr.children, g1)
g2 := NewGroup(expr)

pattern := BuildPattern(OperandJoin, BuildPattern(OperandProjection), BuildPattern(OperandSelection))
iter := NewExprIterFromGroupElem(g2.equivalents.Front(), pattern)

c.Assert(iter, NotNil)
c.Assert(iter.group, IsNil)
c.Assert(iter.element, Equals, g2.equivalents.Front())
c.Assert(iter.matched, Equals, true)
c.Assert(iter.operand, Equals, OperandJoin)
c.Assert(len(iter.children), Equals, 2)

c.Assert(iter.children[0].group, Equals, g0)
c.Assert(iter.children[0].element, Equals, g0.GetFirstElem(OperandProjection))
c.Assert(iter.children[0].matched, Equals, true)
c.Assert(iter.children[0].operand, Equals, OperandProjection)
c.Assert(len(iter.children[0].children), Equals, 0)

c.Assert(iter.children[1].group, Equals, g1)
c.Assert(iter.children[1].element, Equals, g1.GetFirstElem(OperandSelection))
c.Assert(iter.children[1].matched, Equals, true)
c.Assert(iter.children[1].operand, Equals, OperandSelection)
c.Assert(len(iter.children[0].children), Equals, 0)
}

func (s *testCascadesSuite) TestExprIterNext(c *C) {
g0 := NewGroup(NewGroupExpr(plannercore.LogicalProjection{}.Init(s.sctx)))
g0.Insert(NewGroupExpr(plannercore.LogicalLimit{}.Init(s.sctx)))
g0.Insert(NewGroupExpr(plannercore.LogicalProjection{}.Init(s.sctx)))
g0.Insert(NewGroupExpr(plannercore.LogicalLimit{}.Init(s.sctx)))
g0.Insert(NewGroupExpr(plannercore.LogicalProjection{}.Init(s.sctx)))

g1 := NewGroup(NewGroupExpr(plannercore.LogicalSelection{}.Init(s.sctx)))
g1.Insert(NewGroupExpr(plannercore.LogicalLimit{}.Init(s.sctx)))
g1.Insert(NewGroupExpr(plannercore.LogicalSelection{}.Init(s.sctx)))
g1.Insert(NewGroupExpr(plannercore.LogicalLimit{}.Init(s.sctx)))
g1.Insert(NewGroupExpr(plannercore.LogicalSelection{}.Init(s.sctx)))

expr := NewGroupExpr(plannercore.LogicalJoin{}.Init(s.sctx))
expr.children = append(expr.children, g0)
expr.children = append(expr.children, g1)
g2 := NewGroup(expr)

pattern := BuildPattern(OperandJoin, BuildPattern(OperandProjection), BuildPattern(OperandSelection))
iter := NewExprIterFromGroupElem(g2.equivalents.Front(), pattern)
c.Assert(iter, NotNil)

count := 0
for ; iter.Matched(); iter.Next() {
count++
c.Assert(iter.group, IsNil)
c.Assert(iter.matched, Equals, true)
c.Assert(iter.operand, Equals, OperandJoin)
c.Assert(len(iter.children), Equals, 2)

c.Assert(iter.children[0].group, Equals, g0)
c.Assert(iter.children[0].matched, Equals, true)
c.Assert(iter.children[0].operand, Equals, OperandProjection)
c.Assert(len(iter.children[0].children), Equals, 0)

c.Assert(iter.children[1].group, Equals, g1)
c.Assert(iter.children[1].matched, Equals, true)
c.Assert(iter.children[1].operand, Equals, OperandSelection)
c.Assert(len(iter.children[0].children), Equals, 0)
}

c.Assert(count, Equals, 9)
}
9 changes: 6 additions & 3 deletions planner/cascades/optimize.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
package cascades

import (
"container/list"

plannercore "github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/sessionctx"
"github.com/pkg/errors"
Expand Down Expand Up @@ -73,7 +75,7 @@ func exploreGroup(g *Group) error {
curExpr.explored = curExpr.explored && childGroup.explored
}

eraseCur, err := findMoreEquiv(curExpr, g)
eraseCur, err := findMoreEquiv(g, elem)
if err != nil {
return err
}
Expand All @@ -87,15 +89,16 @@ func exploreGroup(g *Group) error {
}

// findMoreEquiv finds and applies the matched transformation rules.
func findMoreEquiv(expr *GroupExpr, g *Group) (eraseCur bool, err error) {
func findMoreEquiv(g *Group, elem *list.Element) (eraseCur bool, err error) {
expr := elem.Value.(*GroupExpr)
for _, rule := range GetTransformationRules(expr.exprNode) {
pattern := rule.GetPattern()
if !pattern.operand.match(GetOperand(expr.exprNode)) {
continue
}
// Create a binding of the current group expression and the pattern of
// the transformation rule to enumerate all the possible expressions.
iter := NewExprIterFromGroupExpr(expr, pattern)
iter := NewExprIterFromGroupElem(elem, pattern)
for ; iter != nil && iter.Matched(); iter.Next() {
if !rule.Match(iter) {
continue
Expand Down
86 changes: 86 additions & 0 deletions planner/cascades/pattern_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2018 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package cascades

import (
. "github.com/pingcap/check"
plannercore "github.com/pingcap/tidb/planner/core"
)

func (s *testCascadesSuite) TestGetOperand(c *C) {
c.Assert(GetOperand(&plannercore.LogicalJoin{}), Equals, OperandJoin)
c.Assert(GetOperand(&plannercore.LogicalAggregation{}), Equals, OperandAggregation)
c.Assert(GetOperand(&plannercore.LogicalProjection{}), Equals, OperandProjection)
c.Assert(GetOperand(&plannercore.LogicalSelection{}), Equals, OperandSelection)
c.Assert(GetOperand(&plannercore.LogicalApply{}), Equals, OperandApply)
c.Assert(GetOperand(&plannercore.LogicalMaxOneRow{}), Equals, OperandMaxOneRow)
c.Assert(GetOperand(&plannercore.LogicalTableDual{}), Equals, OperandTableDual)
c.Assert(GetOperand(&plannercore.DataSource{}), Equals, OperandDataSource)
c.Assert(GetOperand(&plannercore.LogicalUnionScan{}), Equals, OperandUnionScan)
c.Assert(GetOperand(&plannercore.LogicalUnionAll{}), Equals, OperandUnionAll)
c.Assert(GetOperand(&plannercore.LogicalSort{}), Equals, OperandSort)
c.Assert(GetOperand(&plannercore.LogicalTopN{}), Equals, OperandTopN)
c.Assert(GetOperand(&plannercore.LogicalLock{}), Equals, OperandLock)
c.Assert(GetOperand(&plannercore.LogicalLimit{}), Equals, OperandLimit)
}

func (s *testCascadesSuite) TestOperandMatch(c *C) {
c.Assert(OperandAny.match(OperandLimit), IsTrue)
c.Assert(OperandAny.match(OperandSelection), IsTrue)
c.Assert(OperandAny.match(OperandJoin), IsTrue)
c.Assert(OperandAny.match(OperandMaxOneRow), IsTrue)
c.Assert(OperandAny.match(OperandAny), IsTrue)

c.Assert(OperandLimit.match(OperandAny), IsTrue)
c.Assert(OperandSelection.match(OperandAny), IsTrue)
c.Assert(OperandJoin.match(OperandAny), IsTrue)
c.Assert(OperandMaxOneRow.match(OperandAny), IsTrue)
c.Assert(OperandAny.match(OperandAny), IsTrue)

c.Assert(OperandLimit.match(OperandLimit), IsTrue)
c.Assert(OperandSelection.match(OperandSelection), IsTrue)
c.Assert(OperandJoin.match(OperandJoin), IsTrue)
c.Assert(OperandMaxOneRow.match(OperandMaxOneRow), IsTrue)
c.Assert(OperandAny.match(OperandAny), IsTrue)

c.Assert(OperandLimit.match(OperandSelection), IsFalse)
c.Assert(OperandLimit.match(OperandJoin), IsFalse)
c.Assert(OperandLimit.match(OperandMaxOneRow), IsFalse)
}

func (s *testCascadesSuite) TestNewPattern(c *C) {
p := NewPattern(OperandAny)
c.Assert(p.operand, Equals, OperandAny)
c.Assert(p.children, IsNil)

p = NewPattern(OperandJoin)
c.Assert(p.operand, Equals, OperandJoin)
c.Assert(p.children, IsNil)
}

func (s *testCascadesSuite) TestPatternSetChildren(c *C) {
p := NewPattern(OperandAny)
p.SetChildren(NewPattern(OperandLimit))
c.Assert(len(p.children), Equals, 1)
c.Assert(p.children[0].operand, Equals, OperandLimit)
c.Assert(p.children[0].children, IsNil)

p = NewPattern(OperandJoin)
p.SetChildren(NewPattern(OperandProjection), NewPattern(OperandSelection))
c.Assert(len(p.children), Equals, 2)
c.Assert(p.children[0].operand, Equals, OperandProjection)
c.Assert(p.children[0].children, IsNil)
c.Assert(p.children[1].operand, Equals, OperandSelection)
c.Assert(p.children[1].children, IsNil)
}

0 comments on commit a49eeb4

Please sign in to comment.