Merge pull request #113 from pingcap/siddontang/in-with-subquery

expressions,parser: IN expression uses subquery
This commit is contained in:
qiuyesuifeng
2015-09-11 13:54:47 +08:00
3 changed files with 14 additions and 21 deletions

View File

@ -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) {

View File

@ -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)

View File

@ -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
{