Skip to content

Commit a83fcdb

Browse files
authored
expression: return null for empty time format (#67538)
close #59445
1 parent 5aa4aa8 commit a83fcdb

4 files changed

Lines changed: 43 additions & 0 deletions

File tree

pkg/expression/builtin_time.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6477,6 +6477,9 @@ func (b *builtinTimeFormatSig) evalString(ctx EvalContext, row chunk.Row) (strin
64776477
if err != nil || isNull {
64786478
return "", isNull, err
64796479
}
6480+
if len(formatMask) == 0 {
6481+
return "", true, nil
6482+
}
64806483
res, err := b.formatTime(dur, formatMask)
64816484
return res, isNull, err
64826485
}

pkg/expression/builtin_time_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3069,6 +3069,14 @@ func TestTimeFormat(t *testing.T) {
30693069
require.NoError(t, err)
30703070
require.Equal(t, true, v.IsNull())
30713071

3072+
// issue:59445
3073+
args = []types.Datum{types.NewStringDatum("12:34:56"), types.NewStringDatum("")}
3074+
f, err = fc.getFunction(ctx, datumsToConstants(args))
3075+
require.NoError(t, err)
3076+
v, err = evalBuiltinFunc(f, ctx, chunk.Row{})
3077+
require.NoError(t, err)
3078+
require.True(t, v.IsNull())
3079+
30723080
tblDate := []struct {
30733081
Input []string
30743082
Expect any

pkg/expression/builtin_time_vec.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,10 @@ func (b *builtinTimeFormatSig) vecEvalString(ctx EvalContext, input *chunk.Chunk
374374
result.AppendNull()
375375
continue
376376
}
377+
if len(buf1.GetString(i)) == 0 {
378+
result.AppendNull()
379+
continue
380+
}
377381
res, err := b.formatTime(buf.GetDuration(i, 0), buf1.GetString(i))
378382
if err != nil {
379383
return err

pkg/expression/builtin_time_vec_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"math"
1919
"math/rand"
2020
"testing"
21+
"time"
2122

2223
"github.com/pingcap/tidb/pkg/parser/ast"
2324
"github.com/pingcap/tidb/pkg/parser/mysql"
@@ -569,6 +570,33 @@ func TestVectorizedBuiltinTimeFunc(t *testing.T) {
569570
testVectorizedBuiltinFunc(t, vecBuiltinTimeCases)
570571
}
571572

573+
func TestVectorizedTimeFormatEmptyFormatReturnsNull(t *testing.T) {
574+
ctx := createContext(t)
575+
576+
durationType := types.NewFieldType(mysql.TypeDuration)
577+
durationType.SetDecimal(types.DefaultFsp)
578+
formatType := types.NewFieldType(mysql.TypeString)
579+
580+
col0 := &Column{RetType: durationType, Index: 0}
581+
col1 := &Column{RetType: formatType, Index: 1}
582+
f, err := funcs[ast.TimeFormat].getFunction(ctx, []Expression{col0, col1})
583+
require.NoError(t, err)
584+
require.True(t, f.vectorized() && f.isChildrenVectorized())
585+
586+
input := chunk.NewChunkWithCapacity([]*types.FieldType{durationType, formatType}, 2)
587+
input.AppendDuration(0, types.Duration{Duration: 12*time.Hour + 34*time.Minute + 56*time.Second, Fsp: types.DefaultFsp})
588+
input.AppendString(1, "")
589+
input.AppendDuration(0, types.Duration{Duration: time.Hour + 2*time.Minute + 3*time.Second, Fsp: types.DefaultFsp})
590+
input.AppendString(1, "%H:%i:%s")
591+
592+
result := chunk.NewColumn(formatType, 2)
593+
require.NoError(t, vecEvalType(ctx, f, types.ETString, input, result))
594+
require.Equal(t, 2, result.Rows())
595+
require.True(t, result.IsNull(0))
596+
require.False(t, result.IsNull(1))
597+
require.Equal(t, "01:02:03", result.GetString(1))
598+
}
599+
572600
func BenchmarkVectorizedBuiltinTimeEvalOneVec(b *testing.B) {
573601
benchmarkVectorizedEvalOneVec(b, vecBuiltinTimeCases)
574602
}

0 commit comments

Comments
 (0)