plan: implement DistinctDefaultPlan and modified some tests

This commit is contained in:
Ewan Chou
2015-09-12 20:16:39 +08:00
parent dd557bd1ec
commit 31abb81e5c
7 changed files with 91 additions and 78 deletions

View File

@ -24,6 +24,7 @@ import (
"github.com/pingcap/tidb/plan"
"github.com/pingcap/tidb/util/format"
"github.com/pingcap/tidb/util/types"
"github.com/reborndb/go/errors"
)
var (
@ -33,7 +34,9 @@ var (
// DistinctDefaultPlan e.g. SELECT distinct(id) FROM t;
type DistinctDefaultPlan struct {
*SelectList
Src plan.Plan
Src plan.Plan
rows []*plan.Row
cursor int
}
// Explain implements the plan.Plan Explain interface.
@ -95,10 +98,59 @@ func (r *DistinctDefaultPlan) Do(ctx context.Context, f plan.RowIterFunc) (err e
// Next implements plan.Plan Next interface.
func (r *DistinctDefaultPlan) Next(ctx context.Context) (row *plan.Row, err error) {
if r.rows == nil {
err = r.fetchAll(ctx)
if err != nil {
return nil, errors.Trace(err)
}
}
if r.cursor == len(r.rows) {
return
}
row = r.rows[r.cursor]
r.cursor++
return
}
func (r *DistinctDefaultPlan) fetchAll(ctx context.Context) error {
t, err := memkv.CreateTemp(true)
if err != nil {
return errors.Trace(err)
}
defer func() {
if derr := t.Drop(); derr != nil && err == nil {
err = derr
}
}()
for {
row, err := r.Src.Next(ctx)
if row == nil || err != nil {
return errors.Trace(err)
}
var v []interface{}
// get distinct key
key := row.Data[0:r.HiddenFieldOffset]
v, err = t.Get(key)
if err != nil {
return errors.Trace(err)
}
if len(v) == 0 {
// no group for key, save data for this group
r.rows = append(r.rows, row)
if err := t.Set(key, []interface{}{true}); err != nil {
return errors.Trace(err)
}
}
}
}
// Close implements plan.Plan Close interface.
func (r *DistinctDefaultPlan) Close() error {
return nil
return r.Src.Close()
}
// UseNext implements NextPlan interface
func (r *DistinctDefaultPlan) UseNext() bool {
return plan.UseNext(r.Src)
}

View File

@ -11,34 +11,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package plans
package plans_test
import (
"reflect"
"testing"
. "github.com/pingcap/check"
"github.com/pingcap/tidb/context"
"github.com/pingcap/tidb/expression"
"github.com/pingcap/tidb/field"
"github.com/pingcap/tidb/plan"
"github.com/pingcap/tidb/util/format"
"github.com/pingcap/tidb/plan/plans"
"github.com/pingcap/tidb/rset/rsets"
)
func TestT(t *testing.T) {
TestingT(t)
}
type testRowData struct {
id int64
data []interface{}
}
type testTablePlan struct {
rows []*testRowData
fields []string
}
var distinctTestData = []*testRowData{
{1, []interface{}{10, "hello"}},
{2, []interface{}{10, "hello"}},
@ -47,55 +34,24 @@ var distinctTestData = []*testRowData{
{6, []interface{}{60, "hello"}},
}
func (p *testTablePlan) Do(ctx context.Context, f plan.RowIterFunc) error {
for _, d := range p.rows {
if more, err := f(d.id, d.data); !more || err != nil {
return err
}
}
return nil
}
func (p *testTablePlan) Explain(w format.Formatter) {}
func (p *testTablePlan) GetFields() []*field.ResultField {
var ret []*field.ResultField
for _, fn := range p.fields {
ret = append(ret, &field.ResultField{
Name: fn,
})
}
return ret
}
func (p *testTablePlan) Filter(ctx context.Context, expr expression.Expression) (plan.Plan, bool, error) {
return p, false, nil
}
func (p *testTablePlan) Next(ctx context.Context) (row *plan.Row, err error) {
return
}
func (p *testTablePlan) Close() error {
return nil
}
type testDistinctSuit struct{}
var _ = Suite(&testDistinctSuit{})
func (t *testDistinctSuit) TestDistinct(c *C) {
tblPlan := &testTablePlan{distinctTestData, []string{"id", "name"}}
tblPlan := &testTablePlan{distinctTestData, []string{"id", "name"}, 0}
p := DistinctDefaultPlan{
SelectList: &SelectList{
p := plans.DistinctDefaultPlan{
SelectList: &plans.SelectList{
HiddenFieldOffset: len(tblPlan.GetFields()),
},
Src: tblPlan,
}
rset := rsets.Recordset{
Plan: &p,
}
r := map[int][]interface{}{}
err := p.Do(nil, func(id interface{}, data []interface{}) (bool, error) {
err := rset.Do(func(data []interface{}) (bool, error) {
r[data[0].(int)] = data
return true, nil
})

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package plans
package plans_test
import (
. "github.com/pingcap/check"
@ -19,6 +19,7 @@ import (
"github.com/pingcap/tidb/field"
"github.com/pingcap/tidb/model"
mysql "github.com/pingcap/tidb/mysqldef"
"github.com/pingcap/tidb/plan/plans"
"github.com/pingcap/tidb/util/charset"
)
@ -62,10 +63,10 @@ func (t *testFinalPlan) TestFinalPlan(c *C) {
},
}
tblPlan := &testTablePlan{finalTestData, []string{"id", "name", "ok"}}
tblPlan := &testTablePlan{finalTestData, []string{"id", "name", "ok"}, 0}
p := &SelectFinalPlan{
SelectList: &SelectList{
p := &plans.SelectFinalPlan{
SelectList: &plans.SelectList{
HiddenFieldOffset: len(tblPlan.GetFields()),
ResultFields: []*field.ResultField{
field.ColToResultField(col1, "t"),

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package plans
package plans_test
import (
. "github.com/pingcap/check"
@ -19,6 +19,7 @@ import (
"github.com/pingcap/tidb/expression/expressions"
"github.com/pingcap/tidb/field"
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/plan/plans"
)
type testGroupBySuite struct{}
@ -34,9 +35,9 @@ var groupByTestData = []*testRowData{
}
func (t *testGroupBySuite) TestGroupBy(c *C) {
tblPlan := &testTablePlan{groupByTestData, []string{"id", "name"}}
tblPlan := &testTablePlan{groupByTestData, []string{"id", "name"}, 0}
// test multiple fields
sl := &SelectList{
sl := &plans.SelectList{
Fields: []*field.Field{
{
Expr: &expressions.Ident{
@ -62,7 +63,7 @@ func (t *testGroupBySuite) TestGroupBy(c *C) {
AggFields: map[int]struct{}{2: {}},
}
groupbyPlan := &GroupByDefaultPlan{
groupbyPlan := &plans.GroupByDefaultPlan{
SelectList: sl,
Src: tblPlan,
By: []expression.Expression{

View File

@ -11,13 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package plans
package plans_test
import (
. "github.com/pingcap/check"
"github.com/pingcap/tidb/expression/expressions"
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/parser/opcode"
"github.com/pingcap/tidb/plan/plans"
)
type testHavingPlan struct{}
@ -33,8 +34,8 @@ var havingTestData = []*testRowData{
}
func (t *testHavingPlan) TestHaving(c *C) {
tblPlan := &testTablePlan{groupByTestData, []string{"id", "name"}}
havingPlan := &HavingPlan{
tblPlan := &testTablePlan{groupByTestData, []string{"id", "name"}, 0}
havingPlan := &plans.HavingPlan{
Src: tblPlan,
Expr: &expressions.BinaryOperation{
Op: opcode.GE,

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package plans
package plans_test
import (
. "github.com/pingcap/check"
@ -21,6 +21,7 @@ import (
"github.com/pingcap/tidb/model"
mysql "github.com/pingcap/tidb/mysqldef"
"github.com/pingcap/tidb/parser/opcode"
"github.com/pingcap/tidb/plan/plans"
"github.com/pingcap/tidb/util/types"
)
@ -68,10 +69,10 @@ func (s *testJoinSuit) TestJoin(c *C) {
{6, []interface{}{60, "60"}},
}
tblPlan1 := &testTablePlan{testData1, []string{"id", "name"}}
tblPlan2 := &testTablePlan{testData2, []string{"id", "name"}}
tblPlan1 := &testTablePlan{testData1, []string{"id", "name"}, 0}
tblPlan2 := &testTablePlan{testData2, []string{"id", "name"}, 0}
joinPlan := &JoinPlan{
joinPlan := &plans.JoinPlan{
Left: tblPlan1,
Right: tblPlan2,
Type: "CROSS",
@ -83,7 +84,7 @@ func (s *testJoinSuit) TestJoin(c *C) {
return true, nil
})
joinPlan = &JoinPlan{
joinPlan = &plans.JoinPlan{
Left: tblPlan1,
Right: tblPlan2,
Type: "LEFT",
@ -95,7 +96,7 @@ func (s *testJoinSuit) TestJoin(c *C) {
return true, nil
})
joinPlan = &JoinPlan{
joinPlan = &plans.JoinPlan{
Left: tblPlan1,
Right: tblPlan2,
Type: "RIGHT",
@ -120,7 +121,7 @@ func (s *testJoinSuit) TestJoin(c *C) {
return true, nil
})
joinPlan = &JoinPlan{
joinPlan = &plans.JoinPlan{
Left: tblPlan1,
Right: tblPlan2,
Type: "FULL",

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package plans
package plans_test
import (
. "github.com/pingcap/check"
@ -20,6 +20,7 @@ import (
"github.com/pingcap/tidb/model"
mysql "github.com/pingcap/tidb/mysqldef"
"github.com/pingcap/tidb/plan"
"github.com/pingcap/tidb/plan/plans"
"github.com/pingcap/tidb/util/types"
)
@ -46,8 +47,8 @@ var _ = Suite(&testUnionSuit{
})
func (t *testUnionSuit) TestUnion(c *C) {
tblPlan := &testTablePlan{t.data, []string{"id", "name"}}
tblPlan2 := &testTablePlan{t.data2, []string{"id", "name"}}
tblPlan := &testTablePlan{t.data, []string{"id", "name"}, 0}
tblPlan2 := &testTablePlan{t.data2, []string{"id", "name"}, 0}
cols := []*column.Col{
{
ColumnInfo: model.ColumnInfo{
@ -69,7 +70,7 @@ func (t *testUnionSuit) TestUnion(c *C) {
},
}
pln := &UnionPlan{
pln := &plans.UnionPlan{
Srcs: []plan.Plan{
tblPlan,
tblPlan2,