Skip to content

Commit

Permalink
evalengine: Implement SEC_TO_TIME (#15755)
Browse files Browse the repository at this point in the history
Signed-off-by: Noble Mittal <[email protected]>
  • Loading branch information
beingnoble03 authored Apr 23, 2024
1 parent 2c51ba6 commit 204bc50
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 5 deletions.
55 changes: 54 additions & 1 deletion go/mysql/datetime/datetime.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ type DateTime struct {
Time Time
}

const DefaultPrecision = 6
const (
DefaultPrecision = 6
MaxHours = 838
)

func (t Time) AppendFormat(b []byte, prec uint8) []byte {
if t.Neg() {
Expand Down Expand Up @@ -719,6 +722,56 @@ func NewTimeFromStd(t time.Time) Time {
}
}

var (
decSecondsInHour = decimal.NewFromInt(3600)
decMinutesInHour = decimal.NewFromInt(60)
decMaxHours = decimal.NewFromInt(MaxHours)
)

func NewTimeFromSeconds(seconds decimal.Decimal) Time {
var neg bool
if seconds.Sign() < 0 {
neg = true
seconds = seconds.Abs()
}

sec, frac := seconds.QuoRem(decimal.New(1, 0), 0)
ns := frac.Mul(decimal.New(1, 9))

h, sec := sec.QuoRem(decSecondsInHour, 0)
min, sec := sec.QuoRem(decMinutesInHour, 0)

if h.Cmp(decMaxHours) > 0 {
h := uint16(MaxHours)
if neg {
h |= negMask
}

return Time{
hour: h,
minute: 59,
second: 59,
nanosecond: 0,
}
}

hour, _ := h.Int64()
if neg {
hour |= int64(negMask)
}

m, _ := min.Int64()
s, _ := sec.Int64()
nsec, _ := ns.Int64()

return Time{
hour: uint16(hour),
minute: uint8(m),
second: uint8(s),
nanosecond: uint32(nsec),
}
}

func NewDateTimeFromStd(t time.Time) DateTime {
return DateTime{
Date: NewDateFromStd(t),
Expand Down
2 changes: 1 addition & 1 deletion go/mysql/datetime/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ func ParseTimeInt64(i int64) (t Time, ok bool) {
return t, false
}

if i > 838 {
if i > MaxHours {
return t, false
}
t.hour = uint16(i)
Expand Down
12 changes: 12 additions & 0 deletions go/vt/vtgate/evalengine/cached_size.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions go/vt/vtgate/evalengine/compiler_asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4103,6 +4103,27 @@ func (asm *assembler) Fn_FROM_DAYS() {
}, "FN FROM_DAYS INT64(SP-1)")
}

func (asm *assembler) Fn_SEC_TO_TIME_D() {
asm.emit(func(env *ExpressionEnv) int {
e := env.vm.stack[env.vm.sp-1].(*evalTemporal)
prec := int(e.prec)

sec := newEvalDecimalWithPrec(e.toDecimal(), int32(prec))
env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalTime(datetime.NewTimeFromSeconds(sec.dec), prec)
return 1
}, "FN SEC_TO_TIME TEMPORAL(SP-1)")
}

func (asm *assembler) Fn_SEC_TO_TIME_d() {
asm.emit(func(env *ExpressionEnv) int {
e := env.vm.stack[env.vm.sp-1].(*evalDecimal)
prec := min(evalDecimalPrecision(e), datetime.DefaultPrecision)

env.vm.stack[env.vm.sp-1] = env.vm.arena.newEvalTime(datetime.NewTimeFromSeconds(e.dec), int(prec))
return 1
}, "FN SEC_TO_TIME DECIMAL(SP-1)")
}

func (asm *assembler) Fn_TIME_TO_SEC() {
asm.emit(func(env *ExpressionEnv) int {
if env.vm.stack[env.vm.sp-1] == nil {
Expand Down
75 changes: 72 additions & 3 deletions go/vt/vtgate/evalengine/fn_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ type (
CallExpr
}

builtinSecToTime struct {
CallExpr
}

builtinTimeToSec struct {
CallExpr
}
Expand Down Expand Up @@ -197,6 +201,7 @@ var _ IR = (*builtinMonthName)(nil)
var _ IR = (*builtinLastDay)(nil)
var _ IR = (*builtinToDays)(nil)
var _ IR = (*builtinFromDays)(nil)
var _ IR = (*builtinSecToTime)(nil)
var _ IR = (*builtinTimeToSec)(nil)
var _ IR = (*builtinToSeconds)(nil)
var _ IR = (*builtinQuarter)(nil)
Expand Down Expand Up @@ -886,12 +891,12 @@ func (call *builtinMakedate) compile(c *compiler) (ctype, error) {

func clampHourMinute(h, m int64) (int64, int64, bool, bool) {
var clamped bool
if h > 838 || h < -838 {
if h > datetime.MaxHours || h < -datetime.MaxHours {
clamped = true
if h > 0 {
h = 838
h = datetime.MaxHours
} else {
h = -838
h = -datetime.MaxHours
}
m = 59
}
Expand Down Expand Up @@ -1371,6 +1376,70 @@ func (call *builtinFromDays) compile(c *compiler) (ctype, error) {
return ctype{Type: sqltypes.Date, Flag: arg.Flag | flagNullable}, nil
}

func (b *builtinSecToTime) eval(env *ExpressionEnv) (eval, error) {
arg, err := b.arg1(env)
if arg == nil {
return nil, nil
}
if err != nil {
return nil, err
}

var e *evalDecimal
prec := datetime.DefaultPrecision

switch {
case sqltypes.IsDecimal(arg.SQLType()):
e = arg.(*evalDecimal)
case sqltypes.IsIntegral(arg.SQLType()):
e = evalToDecimal(arg, 0, 0)
case sqltypes.IsTextOrBinary(arg.SQLType()):
b := arg.(*evalBytes)
if b.isHexOrBitLiteral() {
e = evalToDecimal(arg, 0, 0)
} else {
e = evalToDecimal(arg, 0, datetime.DefaultPrecision)
}
case sqltypes.IsDateOrTime(arg.SQLType()):
d := arg.(*evalTemporal)
e = evalToDecimal(d, 0, int32(d.prec))
prec = int(d.prec)
default:
e = evalToDecimal(arg, 0, datetime.DefaultPrecision)
}

prec = min(int(evalDecimalPrecision(e)), prec)
return newEvalTime(datetime.NewTimeFromSeconds(e.dec), prec), nil
}

func (call *builtinSecToTime) compile(c *compiler) (ctype, error) {
arg, err := call.Arguments[0].compile(c)
if err != nil {
return ctype{}, err
}

skip := c.compileNullCheck1(arg)

switch {
case sqltypes.IsDecimal(arg.Type):
c.asm.Fn_SEC_TO_TIME_d()
case sqltypes.IsIntegral(arg.Type):
c.asm.Convert_xd(1, 0, 0)
c.asm.Fn_SEC_TO_TIME_d()
case sqltypes.IsTextOrBinary(arg.Type) && arg.isHexOrBitLiteral():
c.asm.Convert_xd(1, 0, 0)
c.asm.Fn_SEC_TO_TIME_d()
case sqltypes.IsDateOrTime(arg.Type):
c.asm.Fn_SEC_TO_TIME_D()
default:
c.asm.Convert_xd(1, 0, datetime.DefaultPrecision)
c.asm.Fn_SEC_TO_TIME_d()
}

c.asm.jumpDestination(skip)
return ctype{Type: sqltypes.Time, Flag: arg.Flag}, nil
}

func (b *builtinTimeToSec) eval(env *ExpressionEnv) (eval, error) {
arg, err := b.arg1(env)
if arg == nil {
Expand Down
16 changes: 16 additions & 0 deletions go/vt/vtgate/evalengine/testcases/cases.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ var Cases = []TestCase{
{Run: FnLastDay},
{Run: FnToDays},
{Run: FnFromDays},
{Run: FnSecToTime},
{Run: FnTimeToSec},
{Run: FnToSeconds},
{Run: FnQuarter},
Expand Down Expand Up @@ -2060,6 +2061,21 @@ func FnFromDays(yield Query) {
}
}

func FnSecToTime(yield Query) {
for _, s := range inputConversions {
yield(fmt.Sprintf("SEC_TO_TIME(%s)", s), nil)
}

mysqlDocSamples := []string{
`SEC_TO_TIME(2378)`,
`SEC_TO_TIME(2378) + 0`,
}

for _, q := range mysqlDocSamples {
yield(q, nil)
}
}

func FnTimeToSec(yield Query) {
for _, d := range inputConversions {
yield(fmt.Sprintf("TIME_TO_SEC(%s)", d), nil)
Expand Down
5 changes: 5 additions & 0 deletions go/vt/vtgate/evalengine/translate_builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ func (ast *astCompiler) translateFuncExpr(fn *sqlparser.FuncExpr) (IR, error) {
return nil, argError(method)
}
return &builtinFromDays{CallExpr: call}, nil
case "sec_to_time":
if len(args) != 1 {
return nil, argError(method)
}
return &builtinSecToTime{CallExpr: call}, nil
case "time_to_sec":
if len(args) != 1 {
return nil, argError(method)
Expand Down

0 comments on commit 204bc50

Please sign in to comment.