From 6ce10d1a4d917e44dc6d6972f538da060654312d Mon Sep 17 00:00:00 2001 From: siddontang Date: Fri, 11 Sep 2015 13:45:47 +0800 Subject: [PATCH] expressions,parser: IN expression uses subquery --- expression/expressions/in.go | 22 ++++++++-------------- expression/expressions/in_test.go | 9 ++++----- parser/parser.y | 4 ++-- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/expression/expressions/in.go b/expression/expressions/in.go index 4f30c76b49..74aa16af7f 100644 --- a/expression/expressions/in.go +++ b/expression/expressions/in.go @@ -24,7 +24,6 @@ import ( "github.com/juju/errors" "github.com/pingcap/tidb/context" "github.com/pingcap/tidb/expression" - "github.com/pingcap/tidb/plan" "github.com/pingcap/tidb/util/types" ) @@ -40,8 +39,8 @@ type PatternIn struct { List []expression.Expression // Not is true, the expression is "not in". Not bool - // Sel is the select statement. - Sel plan.Planner + // Sel is the sub query. + Sel *SubQuery } // Clone implements the Expression Clone interface. @@ -93,10 +92,10 @@ func (n *PatternIn) String() string { } if n.Not { - return fmt.Sprintf("%s NOT IN (%s)", n.Expr, n.Sel) + return fmt.Sprintf("%s NOT IN %s", n.Expr, n.Sel) } - return fmt.Sprintf("%s IN (%s)", n.Expr, n.Sel) + return fmt.Sprintf("%s IN %s", n.Expr, n.Sel) } func (n *PatternIn) checkInList(in interface{}, list []interface{}) (interface{}, error) { @@ -166,21 +165,16 @@ func (n *PatternIn) Eval(ctx context.Context, args map[interface{}]interface{}) var res []interface{} if ev, ok := args[n]; !ok { + if err := hasSameColumnCount(ctx, n.Expr, n.Sel); err != nil { + return nil, errors.Trace(err) + } + // select not yet evaluated r, err := n.Sel.Plan(ctx) if err != nil { return nil, err } - count, countErr := columnCount(ctx, n.Expr) - if countErr != nil { - return nil, errors.Trace(countErr) - } - - if g, e := len(r.GetFields()), count; g != e { - return false, errors.Errorf("IN (%s): mismatched field count, have %d, need %d", n.Sel, g, e) - } - res = []interface{}{} // evaluate select and save its result for later in expression check err = r.Do(ctx, func(id interface{}, data []interface{}) (more bool, err error) { diff --git a/expression/expressions/in_test.go b/expression/expressions/in_test.go index 0613755382..077aace3d8 100644 --- a/expression/expressions/in_test.go +++ b/expression/expressions/in_test.go @@ -84,7 +84,7 @@ func (t *testPatternInSuite) TestPatternIn(c *C) { c.Assert(err, IsNil) c.Assert(vvv, IsNil) - sel := newMockStatement() + sel := newMockSubQuery([][]interface{}{{1, 2}}, []string{"id", "name"}) e2.Sel = sel str = e2.String() @@ -101,8 +101,7 @@ func (t *testPatternInSuite) TestPatternIn(c *C) { _, err = e2.Eval(nil, args) c.Assert(err, NotNil) - sel.SetFieldOffset(1) - e2.Sel = sel + e2.Sel = newMockSubQuery([][]interface{}{{1}, {2}}, []string{"id"}) vv, err = e2.Eval(nil, args) c.Assert(err, IsNil) @@ -116,12 +115,12 @@ func (t *testPatternInSuite) TestPatternIn(c *C) { delete(args, e2) e2.Expr = newTestRow(1, 2) - sel.SetFieldOffset(2) + e2.Sel = newMockSubQuery([][]interface{}{{1, 2}}, []string{"id", "name"}) _, err = e2.Eval(nil, args) c.Assert(err, IsNil) e2.Expr = newTestRow(1, 2, 3) - sel.SetFieldOffset(2) + _, err = e2.Eval(nil, args) c.Assert(err, NotNil) diff --git a/parser/parser.y b/parser/parser.y index b7702da165..0f7e4ef5ee 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -1375,9 +1375,9 @@ Factor1: { $$ = &expressions.PatternIn{Expr: $1.(expression.Expression), Not: $2.(bool), List: $5.([]expression.Expression)} } -| PrimaryFactor NotOpt "IN" '(' SelectStmt semiOpt ')' +| PrimaryFactor NotOpt "IN" SubSelect { - $$ = &expressions.PatternIn{Expr: $1.(expression.Expression), Not: $2.(bool), Sel: $5.(*stmts.SelectStmt)} + $$ = &expressions.PatternIn{Expr: $1.(expression.Expression), Not: $2.(bool), Sel: $4.(*expressions.SubQuery)} } | PrimaryFactor NotOpt "BETWEEN" PrimaryFactor "AND" Factor1 {