diff --git a/go/vt/vtgate/evalengine/compiler_test.go b/go/vt/vtgate/evalengine/compiler_test.go index 435e6491828..a9ecd8f977e 100644 --- a/go/vt/vtgate/evalengine/compiler_test.go +++ b/go/vt/vtgate/evalengine/compiler_test.go @@ -635,6 +635,42 @@ func TestCompilerSingle(t *testing.T) { expression: `1 * unix_timestamp(utc_timestamp(1))`, result: `DECIMAL(1698134400.1)`, }, + { + expression: `1 * unix_timestamp(CONVERT_TZ(20040101120000.10e0,'+00:00','+10:00'))`, + result: `DECIMAL(1072990800.101563)`, + }, + { + expression: `1 * unix_timestamp(CONVERT_TZ(20040101120000.10,'+00:00','+10:00'))`, + result: `DECIMAL(1072990800.10)`, + }, + { + expression: `1 * unix_timestamp(CONVERT_TZ(timestamp'2004-01-01 12:00:00.10','+00:00','+10:00'))`, + result: `DECIMAL(1072990800.10)`, + }, + { + expression: `1 * unix_timestamp(CONVERT_TZ('2004-01-01 12:00:00.10','+00:00','+10:00'))`, + result: `DECIMAL(1072990800.10)`, + }, + { + expression: `1 * unix_timestamp('2004-01-01 12:00:00.10')`, + result: `DECIMAL(1072954800.10)`, + }, + { + expression: `1 * unix_timestamp(from_unixtime(1447430881.123))`, + result: `DECIMAL(1447430881.123)`, + }, + { + expression: `1 * unix_timestamp(from_unixtime('1447430881.123'))`, + result: `DECIMAL(1447430881.123000)`, + }, + { + expression: `1 * unix_timestamp(from_unixtime(time '31:34:58'))`, + result: `INT64(313458)`, + }, + { + expression: `1 * unix_timestamp(from_unixtime(time '31:34:58.123'))`, + result: `DECIMAL(313458.123)`, + }, } tz, _ := time.LoadLocation("Europe/Madrid") diff --git a/go/vt/vtgate/evalengine/fn_info.go b/go/vt/vtgate/evalengine/fn_info.go index 9380d58fca7..53d2a1a8892 100644 --- a/go/vt/vtgate/evalengine/fn_info.go +++ b/go/vt/vtgate/evalengine/fn_info.go @@ -51,7 +51,7 @@ func (call *builtinVersion) eval(env *ExpressionEnv) (eval, error) { func (*builtinVersion) compile(c *compiler) (ctype, error) { c.asm.Fn_Version() - return ctype{Type: sqltypes.Datetime, Col: collationUtf8mb3}, nil + return ctype{Type: sqltypes.VarChar, Col: collationUtf8mb3}, nil } type builtinDatabase struct { @@ -70,7 +70,7 @@ func (call *builtinDatabase) eval(env *ExpressionEnv) (eval, error) { func (*builtinDatabase) compile(c *compiler) (ctype, error) { c.asm.Fn_Database() - return ctype{Type: sqltypes.Datetime, Col: collationUtf8mb3}, nil + return ctype{Type: sqltypes.VarChar, Col: collationUtf8mb3}, nil } func (call *builtinDatabase) constant() bool { diff --git a/go/vt/vtgate/evalengine/fn_time.go b/go/vt/vtgate/evalengine/fn_time.go index 1a0b6ede18e..cbc1613f5fe 100644 --- a/go/vt/vtgate/evalengine/fn_time.go +++ b/go/vt/vtgate/evalengine/fn_time.go @@ -29,7 +29,7 @@ import ( var SystemTime = time.Now -const maxTimePrec = 6 +const maxTimePrec = datetime.DefaultPrecision type ( builtinNow struct { @@ -424,15 +424,28 @@ func (call *builtinConvertTz) compile(c *compiler) (ctype, error) { c.asm.Convert_xb(1, sqltypes.VarBinary, nil) } + var prec int32 switch n.Type { case sqltypes.Datetime, sqltypes.Date: + prec = n.Size + case sqltypes.Decimal, sqltypes.Time: + prec = n.Size + c.asm.Convert_xDT(3, -1, false) + case sqltypes.VarChar, sqltypes.VarBinary: + if lit, ok := call.Arguments[0].(*Literal); ok && !n.isHexOrBitLiteral() { + if dt := evalToDateTime(lit.inner, -1, time.Now(), c.sqlmode.AllowZeroDate()); dt != nil { + prec = int32(dt.prec) + } + } + c.asm.Convert_xDT(3, -1, false) default: + prec = maxTimePrec c.asm.Convert_xDT(3, -1, false) } c.asm.Fn_CONVERT_TZ() c.asm.jumpDestination(skip) - return ctype{Type: sqltypes.Datetime, Col: collationBinary, Flag: n.Flag | flagNullable}, nil + return ctype{Type: sqltypes.Datetime, Col: collationBinary, Flag: n.Flag | flagNullable, Size: prec}, nil } func (b *builtinDate) eval(env *ExpressionEnv) (eval, error) { @@ -689,17 +702,21 @@ func (call *builtinFromUnixtime) compile(c *compiler) (ctype, error) { } skip1 := c.compileNullCheck1(arg) + var prec int32 switch arg.Type { case sqltypes.Int64: c.asm.Fn_FROM_UNIXTIME_i() case sqltypes.Uint64: c.asm.Fn_FROM_UNIXTIME_u() case sqltypes.Float64: + prec = maxTimePrec c.asm.Fn_FROM_UNIXTIME_f() case sqltypes.Decimal: + prec = arg.Size c.asm.Fn_FROM_UNIXTIME_d() case sqltypes.Datetime, sqltypes.Date, sqltypes.Time: - if arg.Size == 0 { + prec = arg.Size + if prec == 0 { c.asm.Convert_Ti(1) c.asm.Fn_FROM_UNIXTIME_i() } else { @@ -711,17 +728,19 @@ func (call *builtinFromUnixtime) compile(c *compiler) (ctype, error) { c.asm.Convert_xu(1) c.asm.Fn_FROM_UNIXTIME_u() } else { + prec = maxTimePrec c.asm.Convert_xf(1) c.asm.Fn_FROM_UNIXTIME_f() } default: + prec = maxTimePrec c.asm.Convert_xf(1) c.asm.Fn_FROM_UNIXTIME_f() } if len(call.Arguments) == 1 { c.asm.jumpDestination(skip1) - return ctype{Type: sqltypes.Datetime, Col: collationBinary, Flag: arg.Flag | flagNullable}, nil + return ctype{Type: sqltypes.Datetime, Col: collationBinary, Flag: arg.Flag | flagNullable, Size: prec}, nil } format, err := call.Arguments[1].compile(c)