Skip to content

Commit

Permalink
cherry pick pingcap#35009 to release-5.0
Browse files Browse the repository at this point in the history
Signed-off-by: ti-srebot <[email protected]>
  • Loading branch information
zanmato1984 authored and ti-srebot committed Jun 16, 2022
1 parent 6416f8d commit 8f7402a
Show file tree
Hide file tree
Showing 19 changed files with 17,675 additions and 1,928 deletions.
3,154 changes: 3,154 additions & 0 deletions DEPS.bzl

Large diffs are not rendered by default.

221 changes: 213 additions & 8 deletions expression/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package expression
import (
"flag"
"fmt"
"math"
"math/rand"
"net"
"reflect"
Expand Down Expand Up @@ -697,6 +698,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 @@ -726,7 +741,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 @@ -745,14 +762,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 @@ -785,6 +805,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 @@ -802,24 +837,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 @@ -625,10 +625,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

0 comments on commit 8f7402a

Please sign in to comment.