You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

335 lines
9.7 KiB

// 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
import (
"math"
. "github.com/pingcap/check"
"github.com/pingcap/parser/ast"
"github.com/pingcap/parser/auth"
"github.com/pingcap/parser/charset"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/types/json"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/mock"
"github.com/pingcap/tidb/util/printer"
"github.com/pingcap/tidb/util/testutil"
)
func (s *testEvaluatorSuite) TestDatabase(c *C) {
fc := funcs[ast.Database]
ctx := mock.NewContext()
f, err := fc.getFunction(ctx, nil)
c.Assert(err, IsNil)
d, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(d.Kind(), Equals, types.KindNull)
ctx.GetSessionVars().CurrentDB = "test"
d, err = evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(d.GetString(), Equals, "test")
c.Assert(f.Clone().PbCode(), Equals, f.PbCode())
// Test case for schema().
fc = funcs[ast.Schema]
c.Assert(fc, NotNil)
f, err = fc.getFunction(ctx, nil)
c.Assert(err, IsNil)
d, err = evalBuiltinFunc(f, chunk.MutRowFromDatums(types.MakeDatums()).ToRow())
c.Assert(err, IsNil)
c.Assert(d.GetString(), Equals, "test")
c.Assert(f.Clone().PbCode(), Equals, f.PbCode())
}
func (s *testEvaluatorSuite) TestFoundRows(c *C) {
ctx := mock.NewContext()
sessionVars := ctx.GetSessionVars()
sessionVars.LastFoundRows = 2
fc := funcs[ast.FoundRows]
f, err := fc.getFunction(ctx, nil)
c.Assert(err, IsNil)
d, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(d.GetUint64(), Equals, uint64(2))
}
func (s *testEvaluatorSuite) TestUser(c *C) {
ctx := mock.NewContext()
sessionVars := ctx.GetSessionVars()
sessionVars.User = &auth.UserIdentity{Username: "root", Hostname: "localhost"}
fc := funcs[ast.User]
f, err := fc.getFunction(ctx, nil)
c.Assert(err, IsNil)
d, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(d.GetString(), Equals, "root@localhost")
c.Assert(f.Clone().PbCode(), Equals, f.PbCode())
}
func (s *testEvaluatorSuite) TestCurrentUser(c *C) {
ctx := mock.NewContext()
sessionVars := ctx.GetSessionVars()
sessionVars.User = &auth.UserIdentity{Username: "root", Hostname: "localhost", AuthUsername: "root", AuthHostname: "localhost"}
fc := funcs[ast.CurrentUser]
f, err := fc.getFunction(ctx, nil)
c.Assert(err, IsNil)
d, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(d.GetString(), Equals, "root@localhost")
c.Assert(f.Clone().PbCode(), Equals, f.PbCode())
}
func (s *testEvaluatorSuite) TestCurrentRole(c *C) {
ctx := mock.NewContext()
sessionVars := ctx.GetSessionVars()
sessionVars.ActiveRoles = make([]*auth.RoleIdentity, 0, 10)
sessionVars.ActiveRoles = append(sessionVars.ActiveRoles, &auth.RoleIdentity{Username: "r_1", Hostname: "%"})
sessionVars.ActiveRoles = append(sessionVars.ActiveRoles, &auth.RoleIdentity{Username: "r_2", Hostname: "localhost"})
fc := funcs[ast.CurrentRole]
f, err := fc.getFunction(ctx, nil)
c.Assert(err, IsNil)
d, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(d.GetString(), Equals, "`r_1`@`%`,`r_2`@`localhost`")
c.Assert(f.Clone().PbCode(), Equals, f.PbCode())
}
func (s *testEvaluatorSuite) TestConnectionID(c *C) {
ctx := mock.NewContext()
sessionVars := ctx.GetSessionVars()
sessionVars.ConnectionID = uint64(1)
fc := funcs[ast.ConnectionID]
f, err := fc.getFunction(ctx, nil)
c.Assert(err, IsNil)
d, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(d.GetUint64(), Equals, uint64(1))
c.Assert(f.Clone().PbCode(), Equals, f.PbCode())
}
func (s *testEvaluatorSuite) TestVersion(c *C) {
fc := funcs[ast.Version]
f, err := fc.getFunction(s.ctx, nil)
c.Assert(err, IsNil)
v, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v.GetString(), Equals, mysql.ServerVersion)
c.Assert(f.Clone().PbCode(), Equals, f.PbCode())
}
func (s *testEvaluatorSuite) TestBenchMark(c *C) {
cases := []struct {
LoopCount int
Expression interface{}
Expected int64
IsNil bool
}{
{-3, 1, 0, true},
{0, 1, 0, false},
{3, 1, 0, false},
{3, 1.234, 0, false},
{3, types.NewDecFromFloatForTest(1.234), 0, false},
{3, "abc", 0, false},
{3, types.CurrentTime(mysql.TypeDatetime), 0, false},
{3, types.CurrentTime(mysql.TypeTimestamp), 0, false},
{3, types.CurrentTime(mysql.TypeDuration), 0, false},
{3, json.CreateBinary("[1]"), 0, false},
}
for _, t := range cases {
f, err := newFunctionForTest(s.ctx, ast.Benchmark, s.primitiveValsToConstants([]interface{}{
t.LoopCount,
t.Expression,
})...)
c.Assert(err, IsNil)
d, err := f.Eval(chunk.Row{})
c.Assert(err, IsNil)
if t.IsNil {
c.Assert(d.IsNull(), IsTrue)
} else {
c.Assert(d.GetInt64(), Equals, t.Expected)
}
// test clone
b1 := f.Clone().(*ScalarFunction).Function.(*builtinBenchmarkSig)
c.Assert(b1.constLoopCount, Equals, int64(t.LoopCount))
}
}
func (s *testEvaluatorSuite) TestCharset(c *C) {
fc := funcs[ast.Charset]
f, err := fc.getFunction(s.ctx, s.datumsToConstants(types.MakeDatums(nil)))
c.Assert(f, IsNil)
c.Assert(err, ErrorMatches, "*FUNCTION CHARSET does not exist")
}
func (s *testEvaluatorSuite) TestCoercibility(c *C) {
fc := funcs[ast.Coercibility]
f, err := fc.getFunction(s.ctx, s.datumsToConstants(types.MakeDatums(nil)))
c.Assert(f, NotNil)
c.Assert(err, IsNil)
}
func (s *testEvaluatorSuite) TestCollation(c *C) {
fc := funcs[ast.Collation]
f, err := fc.getFunction(s.ctx, s.datumsToConstants(types.MakeDatums(nil)))
c.Assert(f, NotNil)
c.Assert(err, IsNil)
}
func (s *testEvaluatorSuite) TestRowCount(c *C) {
ctx := mock.NewContext()
sessionVars := ctx.GetSessionVars()
sessionVars.StmtCtx.PrevAffectedRows = 10
f, err := funcs[ast.RowCount].getFunction(ctx, nil)
c.Assert(err, IsNil)
c.Assert(f, NotNil)
sig, ok := f.(*builtinRowCountSig)
c.Assert(ok, IsTrue)
c.Assert(sig, NotNil)
intResult, isNull, err := sig.evalInt(chunk.Row{})
c.Assert(err, IsNil)
c.Assert(isNull, IsFalse)
c.Assert(intResult, Equals, int64(10))
c.Assert(f.Clone().PbCode(), Equals, f.PbCode())
}
// TestTiDBVersion for tidb_server().
func (s *testEvaluatorSuite) TestTiDBVersion(c *C) {
f, err := newFunctionForTest(s.ctx, ast.TiDBVersion, s.primitiveValsToConstants([]interface{}{})...)
c.Assert(err, IsNil)
v, err := f.Eval(chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v.GetString(), Equals, printer.GetTiDBInfo())
}
func (s *testEvaluatorSuite) TestLastInsertID(c *C) {
maxUint64 := uint64(math.MaxUint64)
cases := []struct {
insertID uint64
args interface{}
expected uint64
isNil bool
getErr bool
}{
{0, 1, 1, false, false},
{0, 1.1, 1, false, false},
{0, maxUint64, maxUint64, false, false},
{0, -1, math.MaxUint64, false, false},
{1, nil, 1, false, false},
{math.MaxUint64, nil, math.MaxUint64, false, false},
}
for _, t := range cases {
var (
f Expression
err error
)
if t.insertID > 0 {
s.ctx.GetSessionVars().StmtCtx.PrevLastInsertID = t.insertID
}
if t.args != nil {
f, err = newFunctionForTest(s.ctx, ast.LastInsertId, s.primitiveValsToConstants([]interface{}{t.args})...)
} else {
f, err = newFunctionForTest(s.ctx, ast.LastInsertId)
}
tp := f.GetType()
c.Assert(err, IsNil)
c.Assert(tp.Tp, Equals, mysql.TypeLonglong)
c.Assert(tp.Charset, Equals, charset.CharsetBin)
c.Assert(tp.Collate, Equals, charset.CollationBin)
c.Assert(tp.Flag&mysql.BinaryFlag, Equals, uint(mysql.BinaryFlag))
c.Assert(tp.Flen, Equals, mysql.MaxIntWidth)
d, err := f.Eval(chunk.Row{})
if t.getErr {
c.Assert(err, NotNil)
} else {
c.Assert(err, IsNil)
if t.isNil {
c.Assert(d.Kind(), Equals, types.KindNull)
} else {
c.Assert(d.GetUint64(), Equals, t.expected)
}
}
}
_, err := funcs[ast.LastInsertId].getFunction(s.ctx, []Expression{NewZero()})
c.Assert(err, IsNil)
}
func (s *testEvaluatorSuite) TestFormatBytes(c *C) {
tbl := []struct {
Arg interface{}
Ret interface{}
}{
{nil, nil},
{float64(0), "0 bytes"},
{float64(2048), "2.00 KiB"},
{float64(75295729), "71.81 MiB"},
{float64(5287242702), "4.92 GiB"},
{float64(5039757204245), "4.58 TiB"},
{float64(890250274520475525), "790.70 PiB"},
{float64(18446644073709551615), "16.00 EiB"},
{float64(287952852482075252752429875), "2.50e+08 EiB"},
{float64(-18446644073709551615), "-16.00 EiB"},
}
Dtbl := tblToDtbl(tbl)
for _, t := range Dtbl {
fc := funcs[ast.FormatBytes]
f, err := fc.getFunction(s.ctx, s.datumsToConstants(t["Arg"]))
c.Assert(err, IsNil)
v, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["Ret"][0])
}
}
func (s *testEvaluatorSuite) TestFormatNanoTime(c *C) {
tbl := []struct {
Arg interface{}
Ret interface{}
}{
{nil, nil},
{float64(0), "0 ns"},
{float64(2000), "2.00 us"},
{float64(898787877), "898.79 ms"},
{float64(9999999991), "10.00 s"},
{float64(898787877424), "14.98 min"},
{float64(5827527520021), "1.62 h"},
{float64(42566623663736353), "492.67 d"},
{float64(4827524825702572425242552), "5.59e+10 d"},
{float64(-9999999991), "-10.00 s"},
}
Dtbl := tblToDtbl(tbl)
for _, t := range Dtbl {
fc := funcs[ast.FormatNanoTime]
f, err := fc.getFunction(s.ctx, s.datumsToConstants(t["Arg"]))
c.Assert(err, IsNil)
v, err := evalBuiltinFunc(f, chunk.Row{})
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["Ret"][0])
}
}