172 lines
6.1 KiB
Go
172 lines
6.1 KiB
Go
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package expression_test
|
|
|
|
import (
|
|
. "github.com/pingcap/check"
|
|
"github.com/pingcap/tidb/expression"
|
|
"github.com/pingcap/tidb/parser/opcode"
|
|
"github.com/pingcap/tidb/util/mock"
|
|
"github.com/pingcap/tidb/util/types"
|
|
)
|
|
|
|
var _ = Suite(&testCompSubQuerySuite{})
|
|
|
|
type testCompSubQuerySuite struct {
|
|
}
|
|
|
|
func (s *testCompSubQuerySuite) TestCompSubQuery(c *C) {
|
|
tbl := []struct {
|
|
lhs interface{}
|
|
op opcode.Op
|
|
rhs []interface{}
|
|
all bool
|
|
result interface{} // 0 for false, 1 for true, nil for nil.
|
|
}{
|
|
// Test any subquery.
|
|
{nil, opcode.EQ, []interface{}{1, 2}, false, nil},
|
|
{0, opcode.EQ, []interface{}{1, 2}, false, 0},
|
|
{0, opcode.EQ, []interface{}{1, 2, nil}, false, nil},
|
|
{1, opcode.EQ, []interface{}{1, 1}, false, 1},
|
|
{1, opcode.EQ, []interface{}{1, 1, nil}, false, 1},
|
|
{nil, opcode.NE, []interface{}{1, 2}, false, nil},
|
|
{1, opcode.NE, []interface{}{1, 2}, false, 1},
|
|
{1, opcode.NE, []interface{}{1, 2, nil}, false, 1},
|
|
{1, opcode.NE, []interface{}{1, 1}, false, 0},
|
|
{1, opcode.NE, []interface{}{1, 1, nil}, false, nil},
|
|
{nil, opcode.GT, []interface{}{1, 2}, false, nil},
|
|
{1, opcode.GT, []interface{}{1, 2}, false, 0},
|
|
{1, opcode.GT, []interface{}{1, 2, nil}, false, nil},
|
|
{2, opcode.GT, []interface{}{1, 2}, false, 1},
|
|
{2, opcode.GT, []interface{}{1, 2, nil}, false, 1},
|
|
{3, opcode.GT, []interface{}{1, 2}, false, 1},
|
|
{3, opcode.GT, []interface{}{1, 2, nil}, false, 1},
|
|
{nil, opcode.GE, []interface{}{1, 2}, false, nil},
|
|
{0, opcode.GE, []interface{}{1, 2}, false, 0},
|
|
{0, opcode.GE, []interface{}{1, 2, nil}, false, nil},
|
|
{1, opcode.GE, []interface{}{1, 2}, false, 1},
|
|
{1, opcode.GE, []interface{}{1, 2, nil}, false, 1},
|
|
{2, opcode.GE, []interface{}{1, 2}, false, 1},
|
|
{3, opcode.GE, []interface{}{1, 2}, false, 1},
|
|
{nil, opcode.LT, []interface{}{1, 2}, false, nil},
|
|
{0, opcode.LT, []interface{}{1, 2}, false, 1},
|
|
{0, opcode.LT, []interface{}{1, 2, nil}, false, 1},
|
|
{1, opcode.LT, []interface{}{1, 2}, false, 1},
|
|
{2, opcode.LT, []interface{}{1, 2}, false, 0},
|
|
{2, opcode.LT, []interface{}{1, 2, nil}, false, nil},
|
|
{3, opcode.LT, []interface{}{1, 2}, false, 0},
|
|
{nil, opcode.LE, []interface{}{1, 2}, false, nil},
|
|
{0, opcode.LE, []interface{}{1, 2}, false, 1},
|
|
{0, opcode.LE, []interface{}{1, 2, nil}, false, 1},
|
|
{1, opcode.LE, []interface{}{1, 2}, false, 1},
|
|
{2, opcode.LE, []interface{}{1, 2}, false, 1},
|
|
{3, opcode.LE, []interface{}{1, 2}, false, 0},
|
|
{3, opcode.LE, []interface{}{1, 2, nil}, false, nil},
|
|
|
|
// Test all subquery.
|
|
{nil, opcode.EQ, []interface{}{1, 2}, true, nil},
|
|
{0, opcode.EQ, []interface{}{1, 2}, true, 0},
|
|
{0, opcode.EQ, []interface{}{1, 2, nil}, true, 0},
|
|
{1, opcode.EQ, []interface{}{1, 2}, true, 0},
|
|
{1, opcode.EQ, []interface{}{1, 2, nil}, true, 0},
|
|
{1, opcode.EQ, []interface{}{1, 1}, true, 1},
|
|
{1, opcode.EQ, []interface{}{1, 1, nil}, true, nil},
|
|
{nil, opcode.NE, []interface{}{1, 2}, true, nil},
|
|
{0, opcode.NE, []interface{}{1, 2}, true, 1},
|
|
{1, opcode.NE, []interface{}{1, 2, nil}, true, 0},
|
|
{1, opcode.NE, []interface{}{1, 1}, true, 0},
|
|
{1, opcode.NE, []interface{}{1, 1, nil}, true, 0},
|
|
{nil, opcode.GT, []interface{}{1, 2}, true, nil},
|
|
{1, opcode.GT, []interface{}{1, 2}, true, 0},
|
|
{1, opcode.GT, []interface{}{1, 2, nil}, true, 0},
|
|
{2, opcode.GT, []interface{}{1, 2}, true, 0},
|
|
{2, opcode.GT, []interface{}{1, 2, nil}, true, 0},
|
|
{3, opcode.GT, []interface{}{1, 2}, true, 1},
|
|
{3, opcode.GT, []interface{}{1, 2, nil}, true, nil},
|
|
{nil, opcode.GE, []interface{}{1, 2}, true, nil},
|
|
{0, opcode.GE, []interface{}{1, 2}, true, 0},
|
|
{0, opcode.GE, []interface{}{1, 2, nil}, true, 0},
|
|
{1, opcode.GE, []interface{}{1, 2}, true, 0},
|
|
{1, opcode.GE, []interface{}{1, 2, nil}, true, 0},
|
|
{2, opcode.GE, []interface{}{1, 2}, true, 1},
|
|
{3, opcode.GE, []interface{}{1, 2}, true, 1},
|
|
{3, opcode.GE, []interface{}{1, 2, nil}, true, nil},
|
|
{nil, opcode.LT, []interface{}{1, 2}, true, nil},
|
|
{0, opcode.LT, []interface{}{1, 2}, true, 1},
|
|
{0, opcode.LT, []interface{}{1, 2, nil}, true, nil},
|
|
{1, opcode.LT, []interface{}{1, 2}, true, 0},
|
|
{2, opcode.LT, []interface{}{1, 2}, true, 0},
|
|
{2, opcode.LT, []interface{}{1, 2, nil}, true, 0},
|
|
{3, opcode.LT, []interface{}{1, 2}, true, 0},
|
|
{nil, opcode.LE, []interface{}{1, 2}, true, nil},
|
|
{0, opcode.LE, []interface{}{1, 2}, true, 1},
|
|
{0, opcode.LE, []interface{}{1, 2, nil}, true, nil},
|
|
{1, opcode.LE, []interface{}{1, 2}, true, 1},
|
|
{2, opcode.LE, []interface{}{1, 2}, true, 0},
|
|
{3, opcode.LE, []interface{}{1, 2}, true, 0},
|
|
{3, opcode.LE, []interface{}{1, 2, nil}, true, 0},
|
|
}
|
|
|
|
ctx := mock.NewContext()
|
|
for _, t := range tbl {
|
|
lhs := convert(t.lhs)
|
|
|
|
rhs := make([][]interface{}, 0, len(t.rhs))
|
|
for _, v := range t.rhs {
|
|
rhs = append(rhs, []interface{}{convert(v)})
|
|
}
|
|
|
|
sq := newMockSubQuery(rhs, []string{"c"})
|
|
expr := expression.NewCompareSubQuery(t.op, expression.Value{Val: lhs}, sq, t.all)
|
|
|
|
c.Assert(expr.IsStatic(), IsFalse)
|
|
|
|
str := expr.String()
|
|
c.Assert(len(str), Greater, 0)
|
|
|
|
v, err := expr.Eval(ctx, nil)
|
|
c.Assert(err, IsNil)
|
|
|
|
switch x := t.result.(type) {
|
|
case nil:
|
|
c.Assert(v, IsNil)
|
|
case int:
|
|
val, err := types.ToBool(v)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(val, Equals, int64(x))
|
|
}
|
|
}
|
|
|
|
// Test error.
|
|
sq := newMockSubQuery([][]interface{}{{1, 2}}, []string{"c1", "c2"})
|
|
expr := expression.NewCompareSubQuery(opcode.EQ, expression.Value{Val: 1}, sq, true)
|
|
|
|
_, err := expr.Eval(ctx, nil)
|
|
c.Assert(err, NotNil)
|
|
|
|
expr = expression.NewCompareSubQuery(opcode.EQ, expression.Value{Val: 1}, sq, false)
|
|
|
|
_, err = expr.Eval(ctx, nil)
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
func convert(v interface{}) interface{} {
|
|
switch x := v.(type) {
|
|
case int:
|
|
return int64(x)
|
|
}
|
|
|
|
return v
|
|
}
|