expression: rewrite builtin function: CHAR_LENGTH (#4105)

* expression: rewrite builtin funtion 'CHAR_LENGTH'
This commit is contained in:
Du Chuan
2017-08-09 19:29:32 +08:00
committed by Lynn
parent 3cb7728103
commit 2ed02b287d
4 changed files with 45 additions and 20 deletions

View File

@ -1645,33 +1645,29 @@ type charLengthFunctionClass struct {
}
func (c *charLengthFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
sig := &builtinCharLengthSig{newBaseBuiltinFunc(args, ctx)}
return sig.setSelf(sig), errors.Trace(c.verifyArgs(args))
if argsErr := c.verifyArgs(args); argsErr != nil {
return nil, errors.Trace(argsErr)
}
bf, err := newBaseBuiltinFuncWithTp(args, ctx, tpInt, tpString)
if err != nil {
return nil, errors.Trace(err)
}
sig := &builtinCharLengthSig{baseIntBuiltinFunc{bf}}
return sig.setSelf(sig), nil
}
type builtinCharLengthSig struct {
baseBuiltinFunc
baseIntBuiltinFunc
}
// eval evals a builtinCharLengthSig.
// evalInt evals a builtinCharLengthSig.
// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_char-length
func (b *builtinCharLengthSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
switch args[0].Kind() {
case types.KindNull:
return d, nil
default:
s, err := args[0].ToString()
if err != nil {
return d, errors.Trace(err)
}
r := []rune(s)
d.SetInt64(int64(len(r)))
return d, nil
func (b *builtinCharLengthSig) evalInt(row []types.Datum) (int64, bool, error) {
val, isNull, err := b.args[0].EvalString(row, b.ctx.GetSessionVars().StmtCtx)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
return int64(len([]rune(val))), false, nil
}
type findInSetFunctionClass struct {

View File

@ -1211,6 +1211,7 @@ func (s *testEvaluatorSuite) TestCharLength(c *C) {
fc := funcs[ast.CharLength]
f, err := fc.getFunction(datumsToConstants(types.MakeDatums(v.input)), s.ctx)
c.Assert(err, IsNil)
c.Assert(f.isDeterministic(), Equals, true)
r, err := f.eval(nil)
c.Assert(err, IsNil)
c.Assert(r, testutil.DatumEquals, types.NewDatum(v.result))

View File

@ -541,6 +541,18 @@ func (s *testIntegrationSuite) TestStringBuiltin(c *C) {
result = tk.MustQuery(`select bin("中文");`)
result.Check(testkit.Rows("0"))
// for char_length
result = tk.MustQuery(`select char_length(null);`)
result.Check(testkit.Rows("<nil>"))
result = tk.MustQuery(`select char_length("Hello");`)
result.Check(testkit.Rows("5"))
result = tk.MustQuery(`select char_length("a中b文c");`)
result.Check(testkit.Rows("5"))
result = tk.MustQuery(`select char_length(123);`)
result.Check(testkit.Rows("3"))
result = tk.MustQuery(`select char_length(12.3456);`)
result.Check(testkit.Rows("7"))
}
func (s *testIntegrationSuite) TestEncryptionBuiltin(c *C) {

View File

@ -195,6 +195,22 @@ func (s *testPlanSuite) createTestCase4StrFuncs() []typeInferTestCase {
{"bin(c_set )", mysql.TypeVarString, charset.CharsetUTF8, 0, 64, types.UnspecifiedLength},
{"bin(c_enum )", mysql.TypeVarString, charset.CharsetUTF8, 0, 64, types.UnspecifiedLength},
{"char_length(c_int)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_float)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_double)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_decimal)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_datetime)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_time)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_timestamp)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_char)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_varchar)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_text)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_binary)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_varbinary)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_blob)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_set)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char_length(c_enum)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0},
{"char(c_int )", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 4, types.UnspecifiedLength},
{"char(c_bigint )", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 4, types.UnspecifiedLength},
{"char(c_float )", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 4, types.UnspecifiedLength},