diff --git a/executor/executor_test.go b/executor/executor_test.go index bb1e214941923..e627601a7dfef 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -1,4 +1,4 @@ -// Copyright 2016 PingCAP, Inc. +// Copyright 2015 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -719,6 +719,8 @@ func (s *testSuite) TestSelectHaving(c *C) { r.Check(testkit.Rows(rowStr)) tk.MustExec("commit") + r = tk.MustQuery("select * from select_having_test group by id having null is not null;") + tk.MustExec("drop table select_having_test") } @@ -926,7 +928,6 @@ func (s *testSuite) TestUnion(c *C) { defer testleak.AfterTest(c)() tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") - testSQL := `select 1 union select 0;` tk.MustExec(testSQL) @@ -1156,6 +1157,13 @@ func (s *testSuite) TestNewJoin(c *C) { result = tk.MustQuery("select * from t1 left join t2 on t1.c1 = t2.c1 right join t3 on t2.c1 = t3.c1 order by t1.c1, t1.c2, t2.c1, t2.c2, t3.c1, t3.c2;") result.Check(testkit.Rows(" 5 5", " 9 9", "1 1 1 1 1 1")) + + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1 (c1 int)") + tk.MustExec("insert into t1 values (1), (1), (1)") + result = tk.MustQuery("select * from t1 a join t1 b on a.c1 = b.c1;") + result.Check(testkit.Rows("1 1", "1 1", "1 1", "1 1", "1 1", "1 1", "1 1", "1 1", "1 1")) + plan.UseNewPlanner = false } diff --git a/executor/new_executor.go b/executor/new_executor.go index 35d44cfa3b2f2..1d5f104b31ae3 100644 --- a/executor/new_executor.go +++ b/executor/new_executor.go @@ -37,10 +37,20 @@ type HashJoinExec struct { otherFilter ast.ExprNode outter bool leftSmall bool + matchedRows []*Row + cursor int } func joinTwoRow(a *Row, b *Row) *Row { - return &Row{RowKeys: append(a.RowKeys, b.RowKeys...), Data: append(a.Data, b.Data...)} + ret := &Row{ + RowKeys: make([]*RowKeyEntry, 0, len(a.RowKeys)+len(b.RowKeys)), + Data: make([]types.Datum, 0, len(a.Data)+len(b.Data)), + } + ret.RowKeys = append(ret.RowKeys, a.RowKeys...) + ret.RowKeys = append(ret.RowKeys, b.RowKeys...) + ret.Data = append(ret.Data, a.Data...) + ret.Data = append(ret.Data, b.Data...) + return ret } func (e *HashJoinExec) getHashKey(exprs []ast.ExprNode) ([]byte, error) { @@ -62,19 +72,21 @@ func (e *HashJoinExec) getHashKey(exprs []ast.ExprNode) ([]byte, error) { return result, err } -// Fields implements Executor Fields interface +// Fields implements Executor Fields interface. func (e *HashJoinExec) Fields() []*ast.ResultField { return e.fields } -// Close implements Executor Close interface +// Close implements Executor Close interface. func (e *HashJoinExec) Close() error { e.hashTable = nil + e.matchedRows = nil return nil } func (e *HashJoinExec) prepare() error { e.hashTable = make(map[string][]*Row) + e.cursor = 0 for { row, err := e.smallExec.Next() if err != nil { @@ -82,7 +94,6 @@ func (e *HashJoinExec) prepare() error { } if row == nil { e.smallExec.Close() - e.prepared = true break } matched := true @@ -109,7 +120,7 @@ func (e *HashJoinExec) prepare() error { return nil } -func (e *HashJoinExec) constructMatchedRow(bigRow *Row) (matchedRows []*Row, err error) { +func (e *HashJoinExec) constructMatchedRows(bigRow *Row) (matchedRows []*Row, err error) { hashcode, err := e.getHashKey(e.bigHashKey) if err != nil { return nil, errors.Trace(err) @@ -118,15 +129,15 @@ func (e *HashJoinExec) constructMatchedRow(bigRow *Row) (matchedRows []*Row, err if rows, ok := e.hashTable[string(hashcode)]; ok { for _, smallRow := range rows { //TODO: remove result fields in order to reduce memory copy cost. - startKey := 0 - if !e.leftSmall { - startKey = len(bigRow.Data) - } - for i, data := range smallRow.Data { - e.fields[i+startKey].Expr.SetValue(data.GetValue()) - } otherMatched := true if e.otherFilter != nil { + startKey := 0 + if !e.leftSmall { + startKey = len(bigRow.Data) + } + for i, data := range smallRow.Data { + e.fields[i+startKey].Expr.SetValue(data.GetValue()) + } otherMatched, err = evaluator.EvalBool(e.ctx, e.otherFilter) } if err != nil { @@ -163,7 +174,18 @@ func (e *HashJoinExec) fillNullRow(bigRow *Row) (returnRow *Row, err error) { return returnRow, nil } -// Next implements Executor Next interface +func (e *HashJoinExec) returnRecord() (ret *Row, ok bool) { + if e.cursor >= len(e.matchedRows) { + return nil, false + } + for i, data := range e.matchedRows[e.cursor].Data { + e.fields[i].Expr.SetValue(data.GetValue()) + } + e.cursor++ + return e.matchedRows[e.cursor-1], true +} + +// Next implements Executor Next interface. func (e *HashJoinExec) Next() (*Row, error) { if !e.prepared { err := e.prepare() @@ -171,6 +193,10 @@ func (e *HashJoinExec) Next() (*Row, error) { return nil, err } } + row, ok := e.returnRecord() + if ok { + return row, nil + } for { bigRow, err := e.bigExec.Next() if err != nil { @@ -189,18 +215,17 @@ func (e *HashJoinExec) Next() (*Row, error) { } } if bigMatched { - matchedRows, err = e.constructMatchedRow(bigRow) + matchedRows, err = e.constructMatchedRows(bigRow) if err != nil { return nil, errors.Trace(err) } } - for _, row := range matchedRows { - for i, data := range row.Data { - e.fields[i].Expr.SetValue(data.GetValue()) - } + e.matchedRows = matchedRows + e.cursor = 0 + row, ok := e.returnRecord() + if ok { return row, nil - } - if e.outter && len(matchedRows) == 0 { + } else if e.outter { return e.fillNullRow(bigRow) } } diff --git a/optimizer/plan/new_plans.go b/optimizer/plan/new_plans.go index 9d60f82a2080e..a594bb47cfefe 100644 --- a/optimizer/plan/new_plans.go +++ b/optimizer/plan/new_plans.go @@ -46,7 +46,7 @@ type Join struct { } // AddChild for parent. -func AddChild(parent Plan, child Plan) { +func addChild(parent Plan, child Plan) { if child == nil || parent == nil { return } diff --git a/optimizer/plan/newplanbuilder.go b/optimizer/plan/newplanbuilder.go index 2a673e981088a..f9a8c5a54106d 100644 --- a/optimizer/plan/newplanbuilder.go +++ b/optimizer/plan/newplanbuilder.go @@ -115,8 +115,11 @@ func (b *planBuilder) buildNewJoin(join *ast.Join) Plan { } leftPlan := b.buildNewSinglePathPlan(join.Left) rightPlan := b.buildNewSinglePathPlan(join.Right) - onCondition := splitWhere(join.On.Expr) - eqCond, leftCond, rightCond, otherCond := extractOnCondition(onCondition, leftPlan, rightPlan) + var eqCond, leftCond, rightCond, otherCond []ast.ExprNode + if join.On != nil { + onCondition := splitWhere(join.On.Expr) + eqCond, leftCond, rightCond, otherCond = extractOnCondition(onCondition, leftPlan, rightPlan) + } joinPlan := &Join{EqualConditions: eqCond, LeftConditions: leftCond, RightConditions: rightCond, OtherConditions: otherCond} if join.Tp == ast.LeftJoin { joinPlan.JoinType = LeftOuterJoin @@ -125,8 +128,8 @@ func (b *planBuilder) buildNewJoin(join *ast.Join) Plan { } else { joinPlan.JoinType = InnerJoin } - AddChild(joinPlan, leftPlan) - AddChild(joinPlan, rightPlan) + addChild(joinPlan, leftPlan) + addChild(joinPlan, rightPlan) joinPlan.SetFields(append(leftPlan.Fields(), rightPlan.Fields()...)) return joinPlan } @@ -134,7 +137,7 @@ func (b *planBuilder) buildNewJoin(join *ast.Join) Plan { func (b *planBuilder) buildFilter(p Plan, where ast.ExprNode) Plan { conditions := splitWhere(where) filter := &Filter{Conditions: conditions} - AddChild(filter, p) + addChild(filter, p) filter.SetFields(p.Fields()) return filter } diff --git a/optimizer/plan/plan.go b/optimizer/plan/plan.go index b660ba51359e0..69091de7fe43a 100644 --- a/optimizer/plan/plan.go +++ b/optimizer/plan/plan.go @@ -39,7 +39,7 @@ type Plan interface { AddParent(parent Plan) // AddChild means append a child for plan. AddChild(children Plan) - // ReplaceParent means replace a parent for another one. + // ReplaceParent means replace a parent with another one. ReplaceParent(parent, newPar Plan) error // ReplaceChild means replace a child with another one. ReplaceChild(children, newChild Plan) error diff --git a/optimizer/plan/planbuilder.go b/optimizer/plan/planbuilder.go index cbad23bdc0e69..037c27b0c85a7 100644 --- a/optimizer/plan/planbuilder.go +++ b/optimizer/plan/planbuilder.go @@ -38,7 +38,7 @@ var ( // Error codes. const ( CodeUnsupportedType terror.ErrCode = 1 - SystemInternalError terror.ErrCode = 1 + SystemInternalError terror.ErrCode = 2 ) // BuildPlan builds a plan from a node. @@ -541,12 +541,12 @@ func (b *planBuilder) buildPseudoSelectPlan(p Plan, sel *ast.SelectStmt) Plan { x.NoLimit = true } np := &Sort{ByItems: sel.OrderBy.Items} - AddChild(np, p) + addChild(np, p) p = np } if sel.Limit != nil { np := &Limit{Offset: sel.Limit.Offset, Count: sel.Limit.Count} - AddChild(np, p) + addChild(np, p) np.SetLimit(0) p = np } else { @@ -562,14 +562,14 @@ func (b *planBuilder) buildSelectLock(src Plan, lock ast.SelectLockType) *Select selectLock := &SelectLock{ Lock: lock, } - AddChild(selectLock, src) + addChild(selectLock, src) selectLock.SetFields(src.Fields()) return selectLock } func (b *planBuilder) buildSelectFields(src Plan, fields []*ast.ResultField) Plan { selectFields := &SelectFields{} - AddChild(selectFields, src) + addChild(selectFields, src) selectFields.SetFields(fields) return selectFields } @@ -579,7 +579,7 @@ func (b *planBuilder) buildAggregate(src Plan, aggFuncs []*ast.AggregateFuncExpr aggPlan := &Aggregate{ AggFuncs: aggFuncs, } - AddChild(aggPlan, src) + addChild(aggPlan, src) if src != nil { aggPlan.SetFields(src.Fields()) } @@ -593,7 +593,7 @@ func (b *planBuilder) buildHaving(src Plan, having *ast.HavingClause) Plan { p := &Having{ Conditions: splitWhere(having.Expr), } - AddChild(p, src) + addChild(p, src) p.SetFields(src.Fields()) return p } @@ -602,7 +602,7 @@ func (b *planBuilder) buildSort(src Plan, byItems []*ast.ByItem) Plan { sort := &Sort{ ByItems: byItems, } - AddChild(sort, src) + addChild(sort, src) sort.SetFields(src.Fields()) return sort } @@ -616,7 +616,7 @@ func (b *planBuilder) buildLimit(src Plan, limit *ast.Limit) Plan { s.ExecLimit = li return s } - AddChild(li, src) + addChild(li, src) li.SetFields(src.Fields()) return li } @@ -840,7 +840,11 @@ func (se *subqueryVisitor) Leave(in ast.Node) (out ast.Node, ok bool) { func (b *planBuilder) buildUnion(union *ast.UnionStmt) Plan { sels := make([]Plan, len(union.SelectList.Selects)) for i, sel := range union.SelectList.Selects { - sels[i] = b.buildSelect(sel) + if UseNewPlanner { + sels[i] = b.buildNewSelect(sel) + } else { + sels[i] = b.buildSelect(sel) + } } var p Plan p = &Union{ @@ -876,6 +880,7 @@ func (b *planBuilder) buildUnion(union *ast.UnionStmt) Plan { uField.Column.Tp = f.Column.Tp } } + addChild(p, sel) } for _, v := range unionFields { v.Expr.SetType(&v.Column.FieldType) @@ -896,7 +901,7 @@ func (b *planBuilder) buildUnion(union *ast.UnionStmt) Plan { func (b *planBuilder) buildDistinct(src Plan) Plan { d := &Distinct{} - AddChild(d, src) + addChild(d, src) d.SetFields(src.Fields()) return d } @@ -1039,7 +1044,7 @@ func (b *planBuilder) buildShow(show *ast.ShowStmt) Plan { } if len(conditions) != 0 { filter := &Filter{Conditions: conditions} - AddChild(filter, p) + addChild(filter, p) p = filter } return p @@ -1061,7 +1066,7 @@ func (b *planBuilder) buildInsert(insert *ast.InsertStmt) Plan { } if insert.Select != nil { insertPlan.SelectPlan = b.build(insert.Select) - AddChild(insertPlan, insertPlan.SelectPlan) + addChild(insertPlan, insertPlan.SelectPlan) if b.err != nil { return nil } @@ -1082,7 +1087,7 @@ func (b *planBuilder) buildExplain(explain *ast.ExplainStmt) Plan { return nil } p := &Explain{StmtPlan: targetPlan} - AddChild(p, targetPlan) + addChild(p, targetPlan) p.SetFields(buildExplainFields()) return p } diff --git a/optimizer/plan/planbuilder_join.go b/optimizer/plan/planbuilder_join.go index 9f1a8ef30f594..14c7aaa974885 100644 --- a/optimizer/plan/planbuilder_join.go +++ b/optimizer/plan/planbuilder_join.go @@ -619,7 +619,7 @@ func (b *planBuilder) buildJoin(sel *ast.SelectStmt) Plan { p.SetFields(rfs) if filterConditions != nil { filterPlan := &Filter{Conditions: filterConditions} - AddChild(filterPlan, p) + addChild(filterPlan, p) filterPlan.SetFields(p.Fields()) return filterPlan } @@ -737,8 +737,8 @@ func (b *planBuilder) buildPlanFromJoinPath(path *joinPath) Plan { Outer: b.buildPlanFromJoinPath(path.outer), Inner: b.buildPlanFromJoinPath(path.inner), } - AddChild(join, join.Outer) - AddChild(join, join.Inner) + addChild(join, join.Outer) + addChild(join, join.Inner) if path.rightJoin { join.SetFields(append(join.Inner.Fields(), join.Outer.Fields()...)) } else { @@ -751,7 +751,7 @@ func (b *planBuilder) buildPlanFromJoinPath(path *joinPath) Plan { inPlan := b.buildPlanFromJoinPath(in) join.Inners = append(join.Inners, inPlan) join.fields = append(join.fields, in.resultFields()...) - AddChild(join, inPlan) + addChild(join, inPlan) } join.Conditions = path.conditions for _, equiv := range path.eqConds { @@ -817,7 +817,7 @@ func (b *planBuilder) buildSubqueryJoinPath(path *joinPath) Plan { return p } filterPlan := &Filter{Conditions: path.conditions} - AddChild(filterPlan, p) + addChild(filterPlan, p) filterPlan.SetFields(p.Fields()) return filterPlan } diff --git a/optimizer/plan/predicate_push_down.go b/optimizer/plan/predicate_push_down.go index 5438391dece52..2f8c498322299 100644 --- a/optimizer/plan/predicate_push_down.go +++ b/optimizer/plan/predicate_push_down.go @@ -42,7 +42,7 @@ func (cl *columnSubstitutor) Leave(inNode ast.Node) (node ast.Node, ok bool) { } } } - return inNode, false + return inNode, true } // PredicatePushDown applies predicate push down to all kinds of plans, except aggregation and union. @@ -60,6 +60,9 @@ func PredicatePushDown(p Plan, predicates []ast.ExprNode) (ret []ast.ExprNode, e if len(retConditions) > 0 { v.Conditions = retConditions } else { + if len(p.GetParents()) == 0 { + return ret, nil + } err1 = RemovePlan(p) if err1 != nil { return nil, errors.Trace(err1) @@ -112,6 +115,9 @@ func PredicatePushDown(p Plan, predicates []ast.ExprNode) (ret []ast.ExprNode, e } return ret, nil case *SelectFields: + if len(v.GetChildren()) == 0 { + return predicates, nil + } cs := &columnSubstitutor{fields: v.Fields()} var push []ast.ExprNode for _, cond := range predicates { @@ -166,6 +172,9 @@ func PredicatePushDown(p Plan, predicates []ast.ExprNode) (ret []ast.ExprNode, e } return ret, nil default: + if len(v.GetChildren()) == 0 { + return predicates, nil + } //TODO: support union and sub queries when abandon result field. for _, child := range v.GetChildren() { _, err = PredicatePushDown(child, []ast.ExprNode{}) diff --git a/optimizer/resolver.go b/optimizer/resolver.go index 371903f79dfc6..6434edf7da097 100644 --- a/optimizer/resolver.go +++ b/optimizer/resolver.go @@ -220,8 +220,6 @@ func (nr *nameResolver) Enter(inNode ast.Node) (outNode ast.Node, skipChildren b nr.pushContext() case *ast.UpdateStmt: nr.pushContext() - // case *ast. - case *ast.TableName: } return inNode, false }