Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression: vectorized builtinDateFormatSig #14934

Merged
merged 15 commits into from
Mar 11, 2020
Merged
85 changes: 73 additions & 12 deletions expression/builtin_time_vec.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func (b *builtinDayNameSig) vecEvalIndex(input *chunk.Chunk, apply func(i, res i
return nil
}

// evalString evals a builtinDayNameSig.
// vecEvalString evals a builtinDayNameSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayname
func (b *builtinDayNameSig) vecEvalString(input *chunk.Chunk, result *chunk.Column) error {
n := input.NumRows()
Expand Down Expand Up @@ -478,7 +478,7 @@ func (b *builtinYearWeekWithoutModeSig) vectorized() bool {
return true
}

// evalInt evals YEARWEEK(date).
// vecEvalInt evals YEARWEEK(date).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_yearweek
func (b *builtinYearWeekWithoutModeSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
n := input.NumRows()
Expand Down Expand Up @@ -520,7 +520,7 @@ func (b *builtinPeriodDiffSig) vectorized() bool {
return true
}

// evalInt evals PERIOD_DIFF(P1,P2).
// vecEvalInt evals PERIOD_DIFF(P1,P2).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_period-diff
func (b *builtinPeriodDiffSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
if err := b.args[0].VecEvalInt(b.ctx, input, result); err != nil {
Expand Down Expand Up @@ -898,7 +898,7 @@ func (b *builtinQuarterSig) vectorized() bool {
return true
}

// evalInt evals QUARTER(date).
// vecEvalInt evals QUARTER(date).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_quarter
func (b *builtinQuarterSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
n := input.NumRows()
Expand Down Expand Up @@ -1089,7 +1089,7 @@ func (b *builtinToSecondsSig) vectorized() bool {
return true
}

// evalInt evals a builtinToSecondsSig.
// vecEvalInt evals a builtinToSecondsSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_to-seconds
func (b *builtinToSecondsSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
n := input.NumRows()
Expand Down Expand Up @@ -1360,7 +1360,7 @@ func (b *builtinTimeToSecSig) vectorized() bool {
return true
}

// evalInt evals TIME_TO_SEC(time).
// vecEvalInt evals TIME_TO_SEC(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time-to-sec
func (b *builtinTimeToSecSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
n := input.NumRows()
Expand Down Expand Up @@ -1568,7 +1568,7 @@ func (b *builtinPeriodAddSig) vectorized() bool {
return true
}

// evalInt evals PERIOD_ADD(P,N).
// vecEvalInt evals PERIOD_ADD(P,N).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_period-add
func (b *builtinPeriodAddSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
if err := b.args[0].VecEvalInt(b.ctx, input, result); err != nil {
Expand Down Expand Up @@ -1606,7 +1606,7 @@ func (b *builtinTimestampAddSig) vectorized() bool {
return true
}

// evalString evals a builtinTimestampAddSig.
// vecEvalString evals a builtinTimestampAddSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestampadd
func (b *builtinTimestampAddSig) vecEvalString(input *chunk.Chunk, result *chunk.Column) error {
n := input.NumRows()
Expand Down Expand Up @@ -1696,7 +1696,7 @@ func (b *builtinToDaysSig) vectorized() bool {
return true
}

// evalInt evals a builtinToDaysSig.
// vecEvalInt evals a builtinToDaysSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_to-days
func (b *builtinToDaysSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
n := input.NumRows()
Expand Down Expand Up @@ -1732,11 +1732,72 @@ func (b *builtinToDaysSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column)
}

func (b *builtinDateFormatSig) vectorized() bool {
return false
return true
}

func (b *builtinDateFormatSig) vecEvalString(input *chunk.Chunk, result *chunk.Column) error {
return errors.Errorf("not implemented")
n := input.NumRows()

dateBuf, err := b.bufAllocator.get(types.ETDatetime, n)
if err != nil {
return err
}
defer b.bufAllocator.put(dateBuf)
if err := b.args[0].VecEvalTime(b.ctx, input, dateBuf); err != nil {
return err
}
times := dateBuf.Times()

formatBuf, err := b.bufAllocator.get(types.ETString, n)
if err != nil {
return err
}
defer b.bufAllocator.put(formatBuf)
if err := b.args[1].VecEvalString(b.ctx, input, formatBuf); err != nil {
return err
}

result.ReserveString(n)

for i := range times {
t := times[i]
if dateBuf.IsNull(i) || formatBuf.IsNull(i) {
result.AppendNull()
continue
}

formatMask := formatBuf.GetString(i)
// MySQL compatibility, #11203
// If format mask is 0 then return 0 without warnings
if formatMask == "0" {
result.AppendString("0")
continue
}

if t.InvalidZero() {
lance6716 marked this conversation as resolved.
Show resolved Hide resolved
// MySQL compatibility, #11203
// 0 | 0.0 should be converted to null without warnings
n, err := t.ToNumber().ToInt()
isOriginalIntOrDecimalZero := err == nil && n == 0
// Args like "0000-00-00", "0000-00-00 00:00:00" set Fsp to 6
isOriginalStringZero := t.Fsp() > 0

result.AppendNull()

if isOriginalIntOrDecimalZero && !isOriginalStringZero {
continue
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result.AppendNull() should be in this branch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vector based DATE_FORMAT will exit when encountered first handleInvalidTimeError, is this the same behaviour with row based DATE_FORMAT?

if errHandled := handleInvalidTimeError(b.ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, t.String())); errHandled != nil {
return errHandled
}
}
res, err := t.DateFormat(formatMask)
if err != nil {
return err
}
result.AppendString(res)
}
return nil
}

func (b *builtinHourSig) vectorized() bool {
Expand Down Expand Up @@ -2169,7 +2230,7 @@ func (b *builtinUnixTimestampIntSig) vectorized() bool {
return true
}

// evalInt evals a UNIX_TIMESTAMP(time).
// vecEvalInt evals a UNIX_TIMESTAMP(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_unix-timestamp
func (b *builtinUnixTimestampIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {
n := input.NumRows()
Expand Down
8 changes: 7 additions & 1 deletion expression/builtin_time_vec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,13 @@ var vecBuiltinTimeCases = map[string][]vecExprBenchCase{
ast.DateDiff: {
{retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETDatetime, types.ETDatetime}},
},
ast.DateFormat: {},
ast.DateFormat: {
{
retEvalType: types.ETString,
childrenTypes: []types.EvalType{types.ETString, types.ETString},
geners: []dataGenerator{&dateTimeStrGener{randGen: newDefaultRandGen()}, newTimeFormatGener(0.5)},
},
},
ast.Hour: {
{retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETDuration}, geners: []dataGenerator{newRangeDurationGener(0.2)}},
},
Expand Down