From 79112f6c0896a243f87cdb643bb13bb40b1667e7 Mon Sep 17 00:00:00 2001 From: Ewan Chou Date: Sun, 13 Sep 2015 09:10:51 +0800 Subject: [PATCH] plan: implement Next for HavingPlan --- plan/plans/having.go | 43 +++++++++++++++++++++++++++++++++++---- plan/plans/having_test.go | 6 +++++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/plan/plans/having.go b/plan/plans/having.go index 154e8a0f31..3b810de911 100644 --- a/plan/plans/having.go +++ b/plan/plans/having.go @@ -14,6 +14,7 @@ package plans import ( + "github.com/juju/errors" "github.com/pingcap/tidb/context" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/expression/expressions" @@ -29,8 +30,9 @@ var ( // HavingPlan executes the HAVING statement, HavingPlan's behavior is almost the // same as FilterDefaultPlan. type HavingPlan struct { - Src plan.Plan - Expr expression.Expression + Src plan.Plan + Expr expression.Expression + evalArgs map[interface{}]interface{} } // Explain implements plan.Plan Explain interface. @@ -81,10 +83,43 @@ func (r *HavingPlan) Do(ctx context.Context, f plan.RowIterFunc) (err error) { // Next implements plan.Plan Next interface. func (r *HavingPlan) Next(ctx context.Context) (row *plan.Row, err error) { - return + if r.evalArgs == nil { + r.evalArgs = map[interface{}]interface{}{} + } + for { + var srcRow *plan.Row + srcRow, err = r.Src.Next(ctx) + if srcRow == nil || err != nil { + return nil, errors.Trace(err) + } + r.evalArgs[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { + return getIdentValue(name, r.Src.GetFields(), srcRow.Data, field.CheckFieldFlag) + } + r.evalArgs[expressions.ExprEvalPositionFunc] = func(position int) (interface{}, error) { + // position is in [1, len(fields)], so we must decrease 1 to get correct index + // TODO: check position invalidation + return srcRow.Data[position-1], nil + } + var v bool + v, err = expressions.EvalBoolExpr(ctx, r.Expr, r.evalArgs) + + if err != nil { + return nil, errors.Trace(err) + } + + if v { + row = srcRow + return + } + } } // Close implements plan.Plan Close interface. func (r *HavingPlan) Close() error { - return nil + return r.Src.Close() +} + +// UseNext implements NextPlan interface +func (r *HavingPlan) UseNext() bool { + return plan.UseNext(r.Src) } diff --git a/plan/plans/having_test.go b/plan/plans/having_test.go index 2928d20428..6d824c28a6 100644 --- a/plan/plans/having_test.go +++ b/plan/plans/having_test.go @@ -19,6 +19,7 @@ import ( "github.com/pingcap/tidb/model" "github.com/pingcap/tidb/parser/opcode" "github.com/pingcap/tidb/plan/plans" + "github.com/pingcap/tidb/rset/rsets" ) type testHavingPlan struct{} @@ -50,7 +51,10 @@ func (t *testHavingPlan) TestHaving(c *C) { // having's behavior just like where cnt := 0 - havingPlan.Do(nil, func(id interface{}, data []interface{}) (bool, error) { + rset := rsets.Recordset{ + Plan: havingPlan, + } + rset.Do(func(data []interface{}) (bool, error) { cnt++ return true, nil })