diff --git a/expression/bench_test.go b/expression/bench_test.go index 4c1a5c11a4e02..0ddb6237a04fc 100644 --- a/expression/bench_test.go +++ b/expression/bench_test.go @@ -541,6 +541,54 @@ func (g *randDurInt) gen() interface{} { return int64(rand.Intn(types.TimeMaxHour)*10000 + rand.Intn(60)*100 + rand.Intn(60)) } +// locationGener is used to generate location for the built-in function GetFormat. +type locationGener struct { + nullRation float64 +} + +func (g *locationGener) gen() interface{} { + if rand.Float64() < g.nullRation { + return nil + } + switch rand.Uint32() % 5 { + case 0: + return usaLocation + case 1: + return jisLocation + case 2: + return isoLocation + case 3: + return eurLocation + case 4: + return internalLocation + default: + return nil + } +} + +// formatGener is used to generate a format for the built-in function GetFormat. +type formatGener struct { + nullRation float64 +} + +func (g *formatGener) gen() interface{} { + if rand.Float64() < g.nullRation { + return nil + } + switch rand.Uint32() % 4 { + case 0: + return dateFormat + case 1: + return datetimeFormat + case 2: + return timestampFormat + case 3: + return timeFormat + default: + return nil + } +} + type vecExprBenchCase struct { // retEvalType is the EvalType of the expression result. // This field is required. diff --git a/expression/builtin_time.go b/expression/builtin_time.go index da7330a25ea73..121d34fb7b7f3 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -1747,49 +1747,7 @@ func (b *builtinGetFormatSig) evalString(row chunk.Row) (string, bool, error) { return "", isNull, err } - var res string - switch t { - case dateFormat: - switch l { - case usaLocation: - res = "%m.%d.%Y" - case jisLocation: - res = "%Y-%m-%d" - case isoLocation: - res = "%Y-%m-%d" - case eurLocation: - res = "%d.%m.%Y" - case internalLocation: - res = "%Y%m%d" - } - case datetimeFormat, timestampFormat: - switch l { - case usaLocation: - res = "%Y-%m-%d %H.%i.%s" - case jisLocation: - res = "%Y-%m-%d %H:%i:%s" - case isoLocation: - res = "%Y-%m-%d %H:%i:%s" - case eurLocation: - res = "%Y-%m-%d %H.%i.%s" - case internalLocation: - res = "%Y%m%d%H%i%s" - } - case timeFormat: - switch l { - case usaLocation: - res = "%h:%i:%s %p" - case jisLocation: - res = "%H:%i:%s" - case isoLocation: - res = "%H:%i:%s" - case eurLocation: - res = "%H.%i.%s" - case internalLocation: - res = "%H%i%s" - } - } - + res := b.getFormat(t, l) return res, false, nil } diff --git a/expression/builtin_time_vec.go b/expression/builtin_time_vec.go index 19e714e8e3d04..5a839b22a324c 100644 --- a/expression/builtin_time_vec.go +++ b/expression/builtin_time_vec.go @@ -545,11 +545,88 @@ func (b *builtinNullTimeDiffSig) vecEvalDuration(input *chunk.Chunk, result *chu } func (b *builtinGetFormatSig) vectorized() bool { - return false + return true } +// vecEvalString evals a builtinGetFormatSig. +// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_get-format func (b *builtinGetFormatSig) vecEvalString(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") + n := input.NumRows() + buf0, err := b.bufAllocator.get(types.ETString, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf0) + if err = b.args[0].VecEvalString(b.ctx, input, buf0); err != nil { + return err + } + buf1, err := b.bufAllocator.get(types.ETString, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf1) + if err = b.args[1].VecEvalString(b.ctx, input, buf1); err != nil { + return err + } + + result.ReserveString(n) + for i := 0; i < n; i++ { + if buf0.IsNull(i) || buf1.IsNull(i) { + result.AppendNull() + continue + } + format := buf0.GetString(i) + location := buf1.GetString(i) + res := b.getFormat(format, location) + result.AppendString(res) + } + return nil +} + +func (b *builtinGetFormatSig) getFormat(format, location string) string { + res := "" + switch format { + case dateFormat: + switch location { + case usaLocation: + res = "%m.%d.%Y" + case jisLocation: + res = "%Y-%m-%d" + case isoLocation: + res = "%Y-%m-%d" + case eurLocation: + res = "%d.%m.%Y" + case internalLocation: + res = "%Y%m%d" + } + case datetimeFormat, timestampFormat: + switch location { + case usaLocation: + res = "%Y-%m-%d %H.%i.%s" + case jisLocation: + res = "%Y-%m-%d %H:%i:%s" + case isoLocation: + res = "%Y-%m-%d %H:%i:%s" + case eurLocation: + res = "%Y-%m-%d %H.%i.%s" + case internalLocation: + res = "%Y%m%d%H%i%s" + } + case timeFormat: + switch location { + case usaLocation: + res = "%h:%i:%s %p" + case jisLocation: + res = "%H:%i:%s" + case isoLocation: + res = "%H:%i:%s" + case eurLocation: + res = "%H.%i.%s" + case internalLocation: + res = "%H%i%s" + } + } + return res } func (b *builtinLastDaySig) vectorized() bool { diff --git a/expression/builtin_time_vec_test.go b/expression/builtin_time_vec_test.go index 0a7def873677b..4e3f466d90f8c 100644 --- a/expression/builtin_time_vec_test.go +++ b/expression/builtin_time_vec_test.go @@ -202,6 +202,13 @@ var vecBuiltinTimeCases = map[string][]vecExprBenchCase{ geners: []dataGenerator{&timeStrGener{}, &constStrGener{"%y-%m-%d"}}, }, }, + ast.GetFormat: { + { + retEvalType: types.ETString, + childrenTypes: []types.EvalType{types.ETString, types.ETString}, + geners: []dataGenerator{&formatGener{0.2}, &locationGener{0.2}}, + }, + }, } func (s *testEvaluatorSuite) TestVectorizedBuiltinTimeEvalOneVec(c *C) {