From 278c0846ee3b79e53fae038859dd6a92c0268069 Mon Sep 17 00:00:00 2001 From: AerysNan Date: Wed, 20 Nov 2019 14:04:58 +0800 Subject: [PATCH 1/2] vectorize builtinCastStringAsIntSig Signed-off-by: AerysNan --- expression/builtin_cast_vec.go | 52 +++++++++++++++++++++++++++-- expression/builtin_cast_vec_test.go | 11 ++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/expression/builtin_cast_vec.go b/expression/builtin_cast_vec.go index 6f45047108e0c..ff08316ce73fe 100644 --- a/expression/builtin_cast_vec.go +++ b/expression/builtin_cast_vec.go @@ -14,7 +14,9 @@ package expression import ( + "math" "strconv" + "strings" "github.com/pingcap/errors" "github.com/pingcap/parser/mysql" @@ -810,11 +812,57 @@ func (b *builtinCastRealAsDecimalSig) vecEvalDecimal(input *chunk.Chunk, result } func (b *builtinCastStringAsIntSig) vectorized() bool { - return false + return true } func (b *builtinCastStringAsIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") + n := input.NumRows() + result.ResizeInt64(n, false) + if b.args[0].GetType().Hybrid() || IsBinaryLiteral(b.args[0]) { + return b.args[0].VecEvalInt(b.ctx, input, result) + } + buf, err := b.bufAllocator.get(types.ETString, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf) + if err := b.args[0].VecEvalString(b.ctx, input, buf); err != nil { + return err + } + result.MergeNulls(buf) + sc := b.ctx.GetSessionVars().StmtCtx + i64s := result.Int64s() + for i := 0; i < n; i++ { + if result.IsNull(i) { + continue + } + var ( + res int64 + ures uint64 + ) + val := strings.TrimSpace(buf.GetString(i)) + isNegative := len(val) > 1 && val[0] == '-' + if !isNegative { + ures, err = types.StrToUint(sc, val) + if err == nil && !mysql.HasUnsignedFlag(b.tp.Flag) && ures > uint64(math.MaxInt64) { + sc.AppendWarning(types.ErrCastAsSignedOverflow) + } + res = int64(ures) + } else if b.inUnion && mysql.HasUnsignedFlag(b.tp.Flag) { + res = 0 + } else { + res, err = types.StrToInt(sc, val) + if err == nil && mysql.HasUnsignedFlag(b.tp.Flag) { + sc.AppendWarning(types.ErrCastNegIntAsUnsigned) + } + } + res, err = b.handleOverflow(res, val, err, isNegative) + i64s[i] = res + if err != nil { + return err + } + } + return nil } func (b *builtinCastStringAsDurationSig) vectorized() bool { diff --git a/expression/builtin_cast_vec_test.go b/expression/builtin_cast_vec_test.go index 14a9df1bdf6e6..0e2a8028a37d8 100644 --- a/expression/builtin_cast_vec_test.go +++ b/expression/builtin_cast_vec_test.go @@ -14,6 +14,7 @@ package expression import ( + "math" "math/rand" "testing" "time" @@ -33,6 +34,16 @@ var vecBuiltinCastCases = map[string][]vecExprBenchCase{ {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETJson}}, {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETDatetime}}, {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETDuration}}, + { + retEvalType: types.ETInt, + childrenTypes: []types.EvalType{types.ETString}, + geners: []dataGenerator{&numStrGener{rangeInt64Gener{math.MinInt64 + 1, 0}}}, + }, + { + retEvalType: types.ETInt, + childrenTypes: []types.EvalType{types.ETString}, + geners: []dataGenerator{&numStrGener{rangeInt64Gener{0, math.MaxInt64}}}, + }, {retEvalType: types.ETReal, childrenTypes: []types.EvalType{types.ETInt}}, {retEvalType: types.ETDuration, childrenTypes: []types.EvalType{types.ETInt}, geners: []dataGenerator{new(randDurInt)}}, {retEvalType: types.ETReal, childrenTypes: []types.EvalType{types.ETReal}}, From 096cc14d370534603f01159a64b3c1d4f2043539 Mon Sep 17 00:00:00 2001 From: AerysNan Date: Wed, 20 Nov 2019 14:41:11 +0800 Subject: [PATCH 2/2] fix Signed-off-by: AerysNan --- expression/builtin_cast_vec.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/expression/builtin_cast_vec.go b/expression/builtin_cast_vec.go index ff08316ce73fe..029e7b0b63c25 100644 --- a/expression/builtin_cast_vec.go +++ b/expression/builtin_cast_vec.go @@ -817,10 +817,10 @@ func (b *builtinCastStringAsIntSig) vectorized() bool { func (b *builtinCastStringAsIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error { n := input.NumRows() - result.ResizeInt64(n, false) if b.args[0].GetType().Hybrid() || IsBinaryLiteral(b.args[0]) { return b.args[0].VecEvalInt(b.ctx, input, result) } + result.ResizeInt64(n, false) buf, err := b.bufAllocator.get(types.ETString, n) if err != nil { return err @@ -832,6 +832,8 @@ func (b *builtinCastStringAsIntSig) vecEvalInt(input *chunk.Chunk, result *chunk result.MergeNulls(buf) sc := b.ctx.GetSessionVars().StmtCtx i64s := result.Int64s() + isUnsigned := mysql.HasUnsignedFlag(b.tp.Flag) + unionUnsigned := isUnsigned && b.inUnion for i := 0; i < n; i++ { if result.IsNull(i) { continue @@ -844,23 +846,24 @@ func (b *builtinCastStringAsIntSig) vecEvalInt(input *chunk.Chunk, result *chunk isNegative := len(val) > 1 && val[0] == '-' if !isNegative { ures, err = types.StrToUint(sc, val) - if err == nil && !mysql.HasUnsignedFlag(b.tp.Flag) && ures > uint64(math.MaxInt64) { + if !isUnsigned && err == nil && ures > uint64(math.MaxInt64) { sc.AppendWarning(types.ErrCastAsSignedOverflow) } res = int64(ures) - } else if b.inUnion && mysql.HasUnsignedFlag(b.tp.Flag) { + } else if unionUnsigned { res = 0 } else { res, err = types.StrToInt(sc, val) - if err == nil && mysql.HasUnsignedFlag(b.tp.Flag) { + if err == nil && isUnsigned { + // If overflow, don't append this warnings sc.AppendWarning(types.ErrCastNegIntAsUnsigned) } } res, err = b.handleOverflow(res, val, err, isNegative) - i64s[i] = res if err != nil { return err } + i64s[i] = res } return nil }