Merge pull request #113 from pingcap/siddontang/in-with-subquery
expressions,parser: IN expression uses subquery
This commit is contained in:
@ -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) {
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user