From 7e55f308feeed6f233ce4b23fe5ececd48e1f26d Mon Sep 17 00:00:00 2001 From: Ewan Chou Date: Sat, 12 Sep 2015 21:16:22 +0800 Subject: [PATCH] plan: implement Next for index plan --- plan/plans/index.go | 78 ++++++++++++++++++++++++++++++++++++---- plan/plans/index_test.go | 7 +++- 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/plan/plans/index.go b/plan/plans/index.go index dc06e1c866..be5328995b 100644 --- a/plan/plans/index.go +++ b/plan/plans/index.go @@ -16,6 +16,7 @@ package plans import ( "fmt" + "github.com/juju/errors" "github.com/pingcap/tidb/column" "github.com/pingcap/tidb/context" "github.com/pingcap/tidb/expression" @@ -119,11 +120,14 @@ func (span *indexSpan) cutOffHigh(val interface{}, exclude bool) *indexSpan { } type indexPlan struct { - src table.Table - colName string - idxName string - idx kv.Index - spans []*indexSpan // multiple spans are ordered by their values and without overlapping. + src table.Table + colName string + idxName string + idx kv.Index + spans []*indexSpan // multiple spans are ordered by their values and without overlapping. + cursor int + skipLowCmp bool + iter kv.IndexIterator } // comparison function that takes minNotNullVal and maxVal into account. @@ -362,10 +366,72 @@ func toSpans(op opcode.Op, val interface{}) []*indexSpan { // Next implements plan.Plan Next interface. func (r *indexPlan) Next(ctx context.Context) (row *plan.Row, err error) { - return + for { + if r.cursor == len(r.spans) { + return + } + span := r.spans[r.cursor] + if r.iter == nil { + seekVal := span.lowVal + if span.lowVal == minNotNullVal { + seekVal = []byte{} + } + var txn kv.Transaction + txn, err = ctx.GetTxn(false) + if err != nil { + return nil, errors.Trace(err) + } + r.iter, _, err = r.idx.Seek(txn, []interface{}{seekVal}) + if err != nil { + return nil, types.EOFAsNil(err) + } + } + var idxKey []interface{} + var h int64 + idxKey, h, err = r.iter.Next() + if err != nil { + return nil, types.EOFAsNil(err) + } + val := idxKey[0] + if !r.skipLowCmp { + if span.lowExclude && indexCompare(span.lowVal, val) == 0 { + continue + } + r.skipLowCmp = true + } + cmp := indexCompare(val, span.highVal) + if cmp > 0 || (cmp == 0 && span.highExclude) { + // This span has finished iteration. + // Move to the next span. + r.iter.Close() + r.iter = nil + r.cursor++ + r.skipLowCmp = false + continue + } + row = &plan.Row{} + row.Data, err = r.src.Row(ctx, h) + if err != nil { + return nil, errors.Trace(err) + } + rowKey := &plan.RowKeyEntry{ + Tbl: r.src, + Key: string(r.src.RecordKey(h, nil)), + } + row.RowKeys = append(row.RowKeys, rowKey) + return + } } // Close implements plan.Plan Close interface. func (r *indexPlan) Close() error { + if r.iter != nil { + r.iter.Close() + } return nil } + +// UseNext implements NextPlan interface +func (r *indexPlan) UseNext() bool { + return true +} diff --git a/plan/plans/index_test.go b/plan/plans/index_test.go index 46ee2179c1..588d4d70ae 100644 --- a/plan/plans/index_test.go +++ b/plan/plans/index_test.go @@ -26,6 +26,7 @@ import ( mysql "github.com/pingcap/tidb/mysqldef" "github.com/pingcap/tidb/parser/opcode" "github.com/pingcap/tidb/plan/plans" + "github.com/pingcap/tidb/rset/rsets" "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/table/tables" @@ -197,7 +198,11 @@ func (p *testIndexSuit) TestIndexPlan(c *C) { c.Assert(np, NotNil) ret := map[int64]string{} - np.Do(p, func(id interface{}, data []interface{}) (bool, error) { + rset := rsets.Recordset{ + Plan: np, + Ctx: p, + } + rset.Do(func(data []interface{}) (bool, error) { ret[data[0].(int64)] = data[1].(string) return true, nil })