*: parser support crc32 conv bit_xor (#2347)

*: parser support crc32 conv bit_xor
This commit is contained in:
ShuNing
2016-12-29 20:49:12 +08:00
committed by GitHub
parent c00a1c3af0
commit c99cdaaa30
9 changed files with 74 additions and 1 deletions

View File

@ -79,6 +79,8 @@ const (
Abs = "abs"
Ceil = "ceil"
Ceiling = "ceiling"
Conv = "conv"
CRC32 = "crc32"
Ln = "ln"
Log = "log"
Log2 = "log2"

View File

@ -138,6 +138,8 @@ var Funcs = map[string]Func{
ast.Power: {builtinPow, 2, 2},
ast.Rand: {builtinRand, 0, 1},
ast.Round: {builtinRound, 1, 2},
ast.Conv: {builtinConv, 3, 3},
ast.CRC32: {builtinCRC32, 1, 1},
// time functions
ast.Curdate: {builtinCurrentDate, 0, 0},

View File

@ -18,6 +18,7 @@
package expression
import (
"hash/crc32"
"math"
"math/rand"
@ -185,3 +186,23 @@ func builtinRound(args []types.Datum, ctx context.Context) (d types.Datum, err e
d.SetFloat64(types.Round(x, dec))
return d, nil
}
// See http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_conv
func builtinConv(args []types.Datum, ctx context.Context) (d types.Datum, err error) {
//TODO implement
return d, errors.New("Function unimplement")
}
// See http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_crc32
func builtinCRC32(args []types.Datum, ctx context.Context) (d types.Datum, err error) {
if args[0].IsNull() {
return d, nil
}
x, err := args[0].ToString()
if err != nil {
return d, errors.Trace(err)
}
r := crc32.ChecksumIEEE([]byte(x))
d.SetUint64(uint64(r))
return d, nil
}

View File

@ -171,3 +171,23 @@ func (s *testEvaluatorSuite) TestRound(c *C) {
c.Assert(v, testutil.DatumEquals, t["Ret"][0])
}
}
func (s *testEvaluatorSuite) TestCRC32(c *C) {
defer testleak.AfterTest(c)()
tbl := []struct {
Arg []interface{}
Ret uint64
}{
{[]interface{}{"mysql"}, 2501908538},
{[]interface{}{"MySQL"}, 3259397556},
{[]interface{}{"hello"}, 907060870},
}
Dtbl := tblToDtbl(tbl)
for _, t := range Dtbl {
v, err := builtinCRC32(t["Arg"], s.ctx)
c.Assert(err, IsNil)
c.Assert(v, testutil.DatumEquals, t["Ret"][0])
}
}

View File

@ -484,6 +484,9 @@ var tokenMap = map[string]int{
"CHAR_FUNC": charFunc,
"CHAR_LENGTH": charLength,
"CHARACTER_LENGTH": charLength,
"CONV": conv,
"BIT_XOR": bitXor,
"CRC32": crc32,
}
func isTokenIdentifier(s string, buf *bytes.Buffer) int {

View File

@ -291,6 +291,9 @@ import (
charFunc "CHAR_FUNC"
charLength "CHAR_LENGTH"
characterLength "CHARACTER_LENGTH"
conv "CONV"
bitXor "BIT_XOR"
crc32 "CRC32"
/* the following tokens belong to UnReservedKeyword*/
action "ACTION"
@ -3021,6 +3024,21 @@ FunctionCallNonKeyword:
Args: []ast.ExprNode{$3.(ast.ExprNode)},
}
}
| "CONV" '(' Expression ',' Expression ',' Expression ')'
{
$$ = &ast.FuncCallExpr{
FnName: model.NewCIStr($1),
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
}
}
| "CRC32" '(' Expression ')'
{
$$ = &ast.FuncCallExpr{
FnName: model.NewCIStr($1),
Args: []ast.ExprNode{$3.(ast.ExprNode)},
}
}
DateArithOpt:
"DATE_ADD"
@ -3099,6 +3117,10 @@ FunctionCallAgg:
{
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
}
| "BIT_XOR" '(' DistinctOpt Expression ')'
{
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
}
FuncDatetimePrec:
{

View File

@ -511,6 +511,8 @@ func (s *testParserSuite) TestBuiltin(c *C) {
{"SELECT LOG(2, 65536);", true},
{"SELECT LOG2(2);", true},
{"SELECT LOG10(10);", true},
{"SELECT CONV(10+'10'+'10'+X'0a',10,10);", true},
{"SELECT CRC32('MySQL');", true},
{"SELECT SUBSTR('Quadratically',5);", true},
{"SELECT SUBSTR('Quadratically',5, 3);", true},

View File

@ -314,7 +314,7 @@ func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) {
"substring_index", "trim", "ltrim", "rtrim", "reverse", "hex", "unhex", "date_format", "rpad", "char_func":
tp = types.NewFieldType(mysql.TypeVarString)
chs = v.defaultCharset
case "strcmp", "isnull", "bit_length", "char_length", "character_length":
case "strcmp", "isnull", "bit_length", "char_length", "character_length", "crc32":
tp = types.NewFieldType(mysql.TypeLonglong)
case "connection_id":
tp = types.NewFieldType(mysql.TypeLonglong)

View File

@ -158,6 +158,7 @@ func (ts *testTypeInferrerSuite) TestInferType(c *C) {
{"char(66)", mysql.TypeVarString, charset.CharsetUTF8},
{"char_length('TiDB')", mysql.TypeLonglong, charset.CharsetBin},
{"character_length('TiDB')", mysql.TypeLonglong, charset.CharsetBin},
{"crc32('TiDB')", mysql.TypeLonglong, charset.CharsetBin},
}
for _, ca := range cases {
ctx := testKit.Se.(context.Context)