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: refine date_add/sub return type and precision #35009

Merged
merged 60 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
6fbfb47
WIP
zanmato1984 May 14, 2022
402ac7d
Merge master
zanmato1984 May 15, 2022
09a2e06
WIP
zanmato1984 May 27, 2022
6e6f34b
Merge master
zanmato1984 May 27, 2022
6018f95
Fix pb code issue
zanmato1984 May 30, 2022
628c54d
Fix pb code issue
zanmato1984 May 30, 2022
ce91677
Merge branch 'master' into issue-31799
zanmato1984 May 30, 2022
9015444
Cleanup code and add more test
zanmato1984 May 30, 2022
6f917be
Fix generated vec tests for date_add/sub
zanmato1984 Jun 1, 2022
0b6a96b
Gen rest cases
zanmato1984 Jun 1, 2022
0c88cdb
Recover tests
zanmato1984 Jun 1, 2022
d11e439
Update tipb
zanmato1984 Jun 2, 2022
7ca6375
Updage go.sum
zanmato1984 Jun 2, 2022
935e4e0
Fix lint error
zanmato1984 Jun 2, 2022
c3e2d1c
Merge branch 'master' into issue-31799
zanmato1984 Jun 2, 2022
196ffca
Fix go mod tidy
zanmato1984 Jun 2, 2022
0674a70
Fix lint error
zanmato1984 Jun 2, 2022
9a72450
Fix lint error
zanmato1984 Jun 2, 2022
096d5b3
Fix for timestamp
zanmato1984 Jun 2, 2022
490ab0f
Recover all existing tests
zanmato1984 Jun 3, 2022
a9f1ea3
Merge branch 'master' into issue-31799
zanmato1984 Jun 3, 2022
0c51693
Add test for issue 31876
zanmato1984 Jun 4, 2022
a0f7223
Add integration tests for date_add/sub(duration, ...)
zanmato1984 Jun 4, 2022
72b37c1
Add more cases
zanmato1984 Jun 7, 2022
f57e23c
Merge branch 'master' into issue-31799
zanmato1984 Jun 7, 2022
380c891
Fix wording
zanmato1984 Jun 7, 2022
dca1c26
Fix typo
zanmato1984 Jun 7, 2022
4cfd8cf
Remove redundant line
zanmato1984 Jun 7, 2022
5bca370
Fix indention
zanmato1984 Jun 7, 2022
3adbda2
Add more comments
zanmato1984 Jun 7, 2022
576c8a4
Update expression/bench_test.go
zanmato1984 Jun 7, 2022
c713e10
Merge branch 'master' into issue-31799
hawkingrei Jun 7, 2022
86586e2
update bazel dep
hawkingrei Jun 7, 2022
492eabc
Update expression/builtin_time.go
zanmato1984 Jun 7, 2022
d46f141
Update expression/builtin_time.go
zanmato1984 Jun 7, 2022
1b6fe72
Apply suggestions from code review
zanmato1984 Jun 7, 2022
5be5674
Apply suggestions from code review
zanmato1984 Jun 7, 2022
f76a679
Ms -> us
zanmato1984 Jun 7, 2022
13ecc37
Refine comments
zanmato1984 Jun 8, 2022
d9a0501
Refine date/dateTimeDecimalGener
zanmato1984 Jun 8, 2022
e3fea3d
Remove unecessary parameter sc for parsing datetime from real/decimal
zanmato1984 Jun 8, 2022
8db9456
Remove impossible condition check of the first argument being timesta…
zanmato1984 Jun 8, 2022
0f1cdd3
Add reference of MySQL manual about treating timestamp as datetime
zanmato1984 Jun 8, 2022
691f138
Refine subDuration by reusing addDuration
zanmato1984 Jun 8, 2022
fc81946
Fix sub duration
zanmato1984 Jun 8, 2022
f9e4a10
Rename CustCheck to CheckWithFunc
zanmato1984 Jun 8, 2022
25fbcb8
Refine test codegen for interval unit
zanmato1984 Jun 8, 2022
e3ac0fc
Revert "Remove unecessary parameter sc for parsing datetime from real…
zanmato1984 Jun 8, 2022
e401d3a
Add an interesting case
zanmato1984 Jun 8, 2022
c7cbceb
Add case for date_add daylight saving gst
zanmato1984 Jun 8, 2022
163b0e4
Add case for date_add non-existing timestamp
zanmato1984 Jun 8, 2022
a0d537a
Merge branch 'master' into issue-31799
zanmato1984 Jun 9, 2022
20ec7a3
Merge branch 'master' into issue-31799
hawkingrei Jun 10, 2022
42cc6d0
Update expression/integration_test.go
zanmato1984 Jun 11, 2022
24244f9
Merge branch 'master' into issue-31799
zanmato1984 Jun 11, 2022
016658d
Fix indention
zanmato1984 Jun 11, 2022
17d21c8
Merge branch 'master' into issue-31799
zanmato1984 Jun 13, 2022
bb10bbc
Merge branch 'master' into issue-31799
zanmato1984 Jun 14, 2022
110d5e7
Address comment
zanmato1984 Jun 15, 2022
020b32a
Merge branch 'master' into issue-31799
zanmato1984 Jun 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions DEPS.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1914,8 +1914,8 @@ def go_deps():
name = "com_github_pingcap_tipb",
build_file_proto_mode = "disable_global",
importpath = "github.com/pingcap/tipb",
sum = "h1:+46isFI9fR9R+nJVDMI55tCC/TCwp+bvVA4HLGEv1rY=",
version = "v0.0.0-20220314125451-bfb5c2c55188",
sum = "h1:L4nZwfYSrIsWPAZR8zMwHaNQJy0Rjy3Od6Smj5mlOms=",
version = "v0.0.0-20220602075447-4847c5d68e73",
)
go_repository(
name = "com_github_pkg_browser",
Expand Down
221 changes: 213 additions & 8 deletions expression/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package expression
import (
"flag"
"fmt"
"math"
"math/rand"
"net"
"reflect"
Expand Down Expand Up @@ -715,6 +716,20 @@ func (g *randHexStrGener) gen() interface{} {
return string(buf)
}

// dateGener is used to generate a date
type dateGener struct {
randGen *defaultRandGen
}

func (g dateGener) gen() interface{} {
year := 1970 + g.randGen.Intn(100)
month := g.randGen.Intn(10) + 1
day := g.randGen.Intn(20) + 1
gt := types.FromDate(year, month, day, 0, 0, 0, 0)
d := types.NewTime(gt, mysql.TypeDate, types.DefaultFsp)
return d
}

// dateTimeGener is used to generate a dataTime
type dateTimeGener struct {
Fsp int
Expand Down Expand Up @@ -744,7 +759,9 @@ func (g *dateTimeGener) gen() interface{} {
return t
}

// dateTimeStrGener is used to generate strings which are dataTime format
// dateTimeStrGener is used to generate strings which are dateTime format.
// Fsp must be -1 to 9 otherwise will be ignored. -1 will generate a 0 to 9 random length fsp part, otherwise the fsp part will be of fixed length.
// Fsp more than 6 is to test robustness of fsp part parsing.
type dateTimeStrGener struct {
Fsp int
Year int
Expand All @@ -763,14 +780,17 @@ func (g *dateTimeStrGener) gen() interface{} {
if g.Day == 0 {
g.Day = g.randGen.Intn(20) + 1
}
if g.Fsp == -1 {
g.Fsp = g.randGen.Intn(10)
}
hour := g.randGen.Intn(12)
minute := g.randGen.Intn(60)
second := g.randGen.Intn(60)
dataTimeStr := fmt.Sprintf("%d-%d-%d %d:%d:%d",
g.Year, g.Month, g.Day, hour, minute, second)
if g.Fsp > 0 && g.Fsp <= 6 {
if g.Fsp > 0 && g.Fsp <= 9 {
microFmt := fmt.Sprintf(".%%0%dd", g.Fsp)
return dataTimeStr + fmt.Sprintf(microFmt, g.randGen.Int()%(10^g.Fsp))
return dataTimeStr + fmt.Sprintf(microFmt, g.randGen.Int()%int(math.Pow10(g.Fsp)))
}

return dataTimeStr
Expand Down Expand Up @@ -803,6 +823,21 @@ func (g *dateStrGener) gen() interface{} {
return fmt.Sprintf("%d-%d-%d", g.Year, g.Month, g.Day)
}

// dateOrDatetimeStrGener is used to generate strings which are date or datetime format.
type dateOrDatetimeStrGener struct {
dateRatio float64
dateStrGener
dateTimeStrGener
}

func (g dateOrDatetimeStrGener) gen() interface{} {
if g.dateRatio > 1e-6 && g.dateStrGener.randGen.Float64() < g.dateRatio {
return g.dateStrGener.gen()
}

return g.dateTimeStrGener.gen()
}

// timeStrGener is used to generate strings which are time format
type timeStrGener struct {
nullRation float64
Expand All @@ -820,24 +855,194 @@ func (g *timeStrGener) gen() interface{} {
return fmt.Sprintf("%d:%d:%d", hour, minute, second)
}

// dateIntGener is used to generate int values which are date format.
type dateIntGener struct {
dateGener
}

func (g dateIntGener) gen() interface{} {
t := g.dateGener.gen().(types.Time)
num, err := t.ToNumber().ToInt()
if err != nil {
panic(err)
}
return num
}

// dateTimeIntGener is used to generate int values which are dateTime format.
type dateTimeIntGener struct {
dateTimeGener
nullRation float64
}

func (g *dateTimeIntGener) gen() interface{} {
if g.randGen.Float64() < g.nullRation {
return nil
func (g dateTimeIntGener) gen() interface{} {
t := g.dateTimeGener.gen().(types.Time)
num, err := t.ToNumber().ToInt()
if err != nil {
panic(err)
}
return num
}

// dateOrDatetimeIntGener is used to generate int values which are date or datetime format.
type dateOrDatetimeIntGener struct {
dateRatio float64
dateIntGener
dateTimeIntGener
}

func (g dateOrDatetimeIntGener) gen() interface{} {
if g.dateRatio > 1e-6 && g.dateGener.randGen.Float64() < g.dateRatio {
return g.dateIntGener.gen()
}

return g.dateTimeIntGener.gen()
}

// dateRealGener is used to generate floating point values which are date format.
// `fspRatio` is used to control the ratio of values with fractional part. I.e., 20010203.000456789 is a valid representation of a date.
type dateRealGener struct {
fspRatio float64
dateGener
}

func (g dateRealGener) gen() interface{} {
t := g.dateGener.gen().(types.Time)
num, err := t.ToNumber().ToFloat64()
if err != nil {
panic(err)
}

if g.randGen.Float64() >= g.fspRatio {
return num
}

num += g.randGen.Float64()
return num
}

// dateTimeRealGener is used to generate floating point values which are dateTime format.
// `fspRatio` is used to control the ratio of values with fractional part.
type dateTimeRealGener struct {
fspRatio float64
dateTimeGener
}

func (g dateTimeRealGener) gen() interface{} {
t := g.dateTimeGener.gen().(types.Time)
num, err := t.ToNumber().ToInt()
tmp, err := t.ToNumber().ToInt()
if err != nil {
panic(err)
}
num := float64(tmp)

if g.randGen.Float64() >= g.fspRatio {
return num
}

// Not using `t`'s us part since it's too regular.
// Instead, generating a more arbitrary fractional part, e.g. with more than 6 digits.
// We want the parsing logic to be strong enough to deal with this arbitrary fractional number.
num += g.randGen.Float64()
return num
}

// dateOrDatetimeRealGener is used to generate floating point values which are date or datetime format.
type dateOrDatetimeRealGener struct {
dateRatio float64
dateRealGener
dateTimeRealGener
}

func (g dateOrDatetimeRealGener) gen() interface{} {
if g.dateRatio > 1e-6 && g.dateGener.randGen.Float64() < g.dateRatio {
return g.dateRealGener.gen()
}

return g.dateTimeRealGener.gen()
}

// dateDecimalGener is used to generate decimals which are date format.
// `fspRatio` is used to control the ratio of values with fractional part. I.e., 20010203.000456789 is a valid representation of a date.
type dateDecimalGener struct {
fspRatio float64
dateGener
}

func (g dateDecimalGener) gen() interface{} {
t := g.dateGener.gen().(types.Time)
intPart := t.ToNumber()

if g.randGen.Float64() >= g.fspRatio {
return intPart
}

// Generate a fractional part that is at most 9 digits.
fracDigits := g.randGen.Intn(1000000000)
fracPart := new(types.MyDecimal).FromInt(int64(fracDigits))
if err := fracPart.Shift(-9); err != nil {
panic(err)
}

res := new(types.MyDecimal)
err := types.DecimalAdd(intPart, fracPart, res)
if err != nil {
panic(err)
}
return res
}

// dateTimeDecimalGener is used to generate decimals which are dateTime format.
type dateTimeDecimalGener struct {
fspRatio float64
dateTimeGener
}

func (g dateTimeDecimalGener) gen() interface{} {
t := g.dateTimeGener.gen().(types.Time)
num := t.ToNumber()
// Not using `num`'s fractional part so that we can:
// 1. Return early for non-fsp values.
// 2. Generate a more arbitrary fractional part if needed.
i, err := num.ToInt()
if err != nil {
panic(err)
}
intPart := new(types.MyDecimal).FromInt(i)

if g.randGen.Float64() >= g.fspRatio {
return intPart
}

// Generate a fractional part that is at most 9 digits.
fracDigits := g.randGen.Intn(1000000000)
fracPart := new(types.MyDecimal).FromInt(int64(fracDigits))
if err := fracPart.Shift(-9); err != nil {
panic(err)
}

res := new(types.MyDecimal)
err = types.DecimalAdd(intPart, fracPart, res)
if err != nil {
panic(err)
}
return res
}

// dateOrDatetimeDecimalGener is used to generate decimals which are date or datetime format.
type dateOrDatetimeDecimalGener struct {
dateRatio float64
dateDecimalGener
dateTimeDecimalGener
}

func (g dateOrDatetimeDecimalGener) gen() interface{} {
if g.dateRatio > 1e-6 && g.dateGener.randGen.Float64() < g.dateRatio {
return g.dateDecimalGener.gen()
}

return g.dateTimeDecimalGener.gen()
}

// constStrGener always returns the given string
type constStrGener struct {
s string
Expand Down
8 changes: 4 additions & 4 deletions expression/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,10 @@ var funcs = map[string]functionClass{
ast.Truncate: &truncateFunctionClass{baseFunctionClass{ast.Truncate, 2, 2}},

// time functions
ast.AddDate: &addDateFunctionClass{baseFunctionClass{ast.AddDate, 3, 3}},
ast.DateAdd: &addDateFunctionClass{baseFunctionClass{ast.DateAdd, 3, 3}},
ast.SubDate: &subDateFunctionClass{baseFunctionClass{ast.SubDate, 3, 3}},
ast.DateSub: &subDateFunctionClass{baseFunctionClass{ast.DateSub, 3, 3}},
ast.AddDate: &addSubDateFunctionClass{baseFunctionClass{ast.AddDate, 3, 3}, addTime, addDuration, setAdd},
ast.DateAdd: &addSubDateFunctionClass{baseFunctionClass{ast.DateAdd, 3, 3}, addTime, addDuration, setAdd},
ast.SubDate: &addSubDateFunctionClass{baseFunctionClass{ast.SubDate, 3, 3}, subTime, subDuration, setSub},
ast.DateSub: &addSubDateFunctionClass{baseFunctionClass{ast.DateSub, 3, 3}, subTime, subDuration, setSub},
ast.AddTime: &addTimeFunctionClass{baseFunctionClass{ast.AddTime, 2, 2}},
ast.ConvertTz: &convertTzFunctionClass{baseFunctionClass{ast.ConvertTz, 3, 3}},
ast.Curdate: &currentDateFunctionClass{baseFunctionClass{ast.Curdate, 0, 0}},
Expand Down
Loading