// Next implements Executor Next interface. func (e *IndexRangeExec) Next() (*Row, error) { if e.iter == nil { seekVals := make([]interface{}, len(e.scan.idx.Columns)) for i := 0; i < len(e.lowVals); i++ { var err error if e.lowVals[i] == plan.MinNotNullVal { seekVals[i] = []byte{} } else { seekVals[i], err = types.Convert(e.lowVals[i], e.scan.valueTypes[i]) if err != nil { return nil, errors.Trace(err) } } } txn, err := e.scan.ctx.GetTxn(false) if err != nil { return nil, errors.Trace(err) } e.iter, _, err = e.scan.idx.X.Seek(txn, seekVals) if err != nil { return nil, types.EOFAsNil(err) } } for { if e.finished { return nil, nil } idxKey, h, err := e.iter.Next() if err != nil { return nil, types.EOFAsNil(err) } if !e.skipLowCmp { var cmp int cmp, err = indexCompare(idxKey, e.lowVals) if err != nil { return nil, errors.Trace(err) } if cmp < 0 || (cmp == 0 && e.lowExclude) { continue } e.skipLowCmp = true } cmp, err := indexCompare(idxKey, e.highVals) if err != nil { return nil, errors.Trace(err) } if cmp > 0 || (cmp == 0 && e.highExclude) { // This span has finished iteration. e.finished = true continue } var row *Row row, err = e.lookupRow(h) if err != nil { return nil, errors.Trace(err) } return row, nil } }
// Do implements plan.Plan Do interface. func (r *selectIndexDefaultPlan) Do(ctx context.Context, f plan.RowIterFunc) (err error) { var x kv.Index switch ix := r.x.(type) { case *column.IndexedCol: x = ix.X default: panic("should never happen") } txn, err := ctx.GetTxn(false) if err != nil { return err } en, err := x.SeekFirst(txn) if err != nil { return types.EOFAsNil(err) } defer en.Close() var id int64 for { k, _, err := en.Next() if err != nil { return types.EOFAsNil(err) } id++ if more, err := f(id, k); !more || err != nil { return err } } }
// Next implements plan.Plan Next interface. func (r *indexPlan) Next(ctx context.Context) (row *plan.Row, err error) { for { if r.cursor == len(r.spans) { return } span := r.spans[r.cursor] if r.iter == nil { seekVal := span.seekVal 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 { cmp := indexCompare(val, span.lowVal) if cmp < 0 || (cmp == 0 && span.lowExclude) { 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 } }
// Do implements plan.Plan Do interface, all records are added into an // in-memory array, and sorted in ASC/DESC order. func (r *OrderByDefaultPlan) Do(ctx context.Context, f plan.RowIterFunc) error { t := &orderByTable{Ascs: r.Ascs} m := map[interface{}]interface{}{} err := r.Src.Do(ctx, func(rid interface{}, in []interface{}) (bool, error) { m[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return getIdentValue(name, r.ResultFields, in, field.CheckFieldFlag) } m[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 in[position-1], nil } row := &orderByRow{ Row: in, Key: make([]interface{}, 0, len(r.By)), } for _, by := range r.By { // err1 is used for passing `go tool vet --shadow` check. val, err1 := by.Eval(ctx, m) if err1 != nil { return false, err1 } if val != nil { var ordered bool val, ordered, err1 = types.IsOrderedType(val) if err1 != nil { return false, err1 } if !ordered { return false, errors.Errorf("cannot order by %v (type %T)", val, val) } } row.Key = append(row.Key, val) } t.Rows = append(t.Rows, row) return true, nil }) if err != nil { return err } sort.Sort(t) var more bool for _, row := range t.Rows { if more, err = f(nil, row.Row); !more || err != nil { break } } return types.EOFAsNil(err) }
func (r *indexPlan) doSpan(ctx context.Context, txn kv.Transaction, span *indexSpan, f plan.RowIterFunc) error { seekVal := span.lowVal if span.lowVal == minNotNullVal { seekVal = []byte{} } it, _, err := r.idx.Seek(txn, []interface{}{seekVal}) if err != nil { return types.EOFAsNil(err) } defer it.Close() var skipLowCompare bool for { k, h, err := it.Next() if err != nil { return types.EOFAsNil(err) } val := k[0] if !skipLowCompare { if span.lowExclude && indexCompare(span.lowVal, val) == 0 { continue } skipLowCompare = true } cmp := indexCompare(span.highVal, val) if cmp < 0 || (cmp == 0 && span.highExclude) { return nil } data, err := r.src.Row(ctx, h) if err != nil { return err } if more, err := f(h, data); err != nil || !more { return err } } }
// Do : Distinct plan use an in-memory temp table for storing items that has same // key, the value in temp table is an array of record handles. func (r *DistinctDefaultPlan) Do(ctx context.Context, f plan.RowIterFunc) (err error) { t, err := memkv.CreateTemp(true) if err != nil { return } defer func() { if derr := t.Drop(); derr != nil && err == nil { err = derr } }() var rows [][]interface{} if err = r.Src.Do(ctx, func(id interface{}, in []interface{}) (bool, error) { var v []interface{} // get distinct key key := in[0:r.HiddenFieldOffset] v, err = t.Get(key) if err != nil { return false, err } if len(v) == 0 { // no group for key, save data for this group rows = append(rows, in) if err := t.Set(key, []interface{}{true}); err != nil { return false, err } } return true, nil }); err != nil { return } var more bool for _, row := range rows { if more, err = f(nil, row); !more || err != nil { break } } return types.EOFAsNil(err) }
// Do implements plan.Plan Do interface. // Table: Subject_Selection // Subject Semester Attendee // --------------------------------- // ITB001 1 John // ITB001 1 Bob // ITB001 1 Mickey // ITB001 2 Jenny // ITB001 2 James // MKB114 1 John // MKB114 1 Erica // refs: http://stackoverflow.com/questions/2421388/using-group-by-on-multiple-columns func (r *GroupByDefaultPlan) Do(ctx context.Context, f plan.RowIterFunc) (err error) { // TODO: now we have to use this to save group key -> row index // later we will serialize group by items into a string key and then use a map instead. t, err := memkv.CreateTemp(true) if err != nil { return err } defer func() { if derr := t.Drop(); derr != nil && err == nil { err = derr } }() k := make([]interface{}, len(r.By)) // save output group by result var outRows []*groupRow err = r.Src.Do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { out := make([]interface{}, len(r.Fields)) // TODO: later order by will use the same mechanism, so we may use another plan to do this m := map[interface{}]interface{}{} // must first eval none aggregate fields, because alias group by will use this. if err := r.evalNoneAggFields(ctx, out, m, in); err != nil { return false, err } if err := r.evalGroupKey(ctx, k, out, in); err != nil { return false, err } // get row index with k. v, err := t.Get(k) if err != nil { return false, err } index := 0 if len(v) == 0 { // no group for key, save data for this group index = len(outRows) outRows = append(outRows, &groupRow{Row: out, Args: m}) if err := t.Set(k, []interface{}{index}); err != nil { return false, err } } else { // we have already saved data in the group by key, use this index = v[0].(int) // we will use this context args to evaluate aggregate fields. m = outRows[index].Args } // eval aggregate fields if err := r.evalAggFields(ctx, out, m, in); err != nil { return false, err } return true, nil }) if err != nil { return err } if len(outRows) == 0 { // empty table var out []interface{} out, err = r.evalEmptyTable(ctx) if err != nil || out == nil { return err } _, err = f(nil, out) return err } // we don't consider implicit GROUP BY sorting now. // Relying on implicit GROUP BY sorting in MySQL 5.7 is deprecated. // To achieve a specific sort order of grouped results, // it is preferable to use an explicit ORDER BY clause. // GROUP BY sorting is a MySQL extension that may change in a future release var more bool for _, row := range outRows { // eval aggregate done if err := r.evalAggDone(ctx, row.Row, row.Args); err != nil { return err } if more, err = f(nil, row.Row); !more || err != nil { break } } return types.EOFAsNil(err) }
func (r *TableDefaultPlan) rangeNext(ctx context.Context) (*plan.Row, error) { for { if r.cursor == len(r.spans) { return nil, nil } span := r.spans[r.cursor] if r.seekKey == nil { seekVal := span.seekVal var err error r.seekKey, err = r.toSeekKey(seekVal) if err != nil { return nil, errors.Trace(err) } } txn, err := ctx.GetTxn(false) if err != nil { return nil, errors.Trace(err) } if r.iter != nil { r.iter.Close() } r.iter, err = txn.Seek(r.seekKey) if err != nil { return nil, types.EOFAsNil(err) } if !r.iter.Valid() || !r.iter.Key().HasPrefix(r.T.RecordPrefix()) { r.seekKey = nil r.cursor++ r.skipLowCmp = false continue } rowKey := r.iter.Key() handle, err := tables.DecodeRecordKeyHandle(rowKey) if err != nil { return nil, errors.Trace(err) } r.seekKey, err = r.toSeekKey(handle + 1) if err != nil { return nil, errors.Trace(err) } if !r.skipLowCmp { cmp := indexCompare(handle, span.lowVal) if cmp < 0 || (cmp == 0 && span.lowExclude) { continue } r.skipLowCmp = true } cmp := indexCompare(handle, span.highVal) if cmp > 0 || (cmp == 0 && span.highExclude) { // This span has finished iteration. // Move to the next span. r.seekKey = nil r.cursor++ r.skipLowCmp = false continue } row := &plan.Row{} row.Data, err = r.T.Row(ctx, handle) if err != nil { return nil, errors.Trace(err) } // Put rowKey to the tail of record row rke := &plan.RowKeyEntry{ Tbl: r.T, Key: string(rowKey), } row.RowKeys = append(row.RowKeys, rke) return row, nil } }
// Next implements plan.Plan Next interface. func (r *indexPlan) Next(ctx context.Context) (*plan.Row, error) { for { if r.cursor == len(r.spans) { return nil, nil } span := r.spans[r.cursor] if r.isPointLookup(span) { // Do point lookup on index will prevent prefetch cost. row, err := r.pointLookup(ctx, span.seekVal) if err != nil { return nil, errors.Trace(err) } r.cursor++ if row != nil { return row, nil } continue } if r.iter == nil { seekVal := span.seekVal 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) } } idxKey, h, err := r.iter.Next() if err != nil { return nil, types.EOFAsNil(err) } val := idxKey[0] if !r.skipLowCmp { cmp := indexCompare(val, span.lowVal) if cmp < 0 || (cmp == 0 && span.lowExclude) { 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 } var row *plan.Row row, err = r.lookupRow(ctx, h) if err != nil { return nil, errors.Trace(err) } return row, nil } }