diff --git a/enginetest/queries/script_queries.go b/enginetest/queries/script_queries.go index 1956b88f35..afabb2c3d8 100644 --- a/enginetest/queries/script_queries.go +++ b/enginetest/queries/script_queries.go @@ -3068,7 +3068,7 @@ CREATE TABLE tab3 ( { Query: "SELECT unix_timestamp(timestamp_col), unix_timestamp(datetime_col) from datetime_table", Expected: []sql.Row{ - {"86400.000000", "57600.000000"}, + {"86400", "57600"}, }, }, }, @@ -5133,6 +5133,11 @@ CREATE TABLE tab3 ( Name: "UNIX_TIMESTAMP function preserves trailing 0s", SetUpScript: []string{ "SET time_zone = '+07:00';", + "create table dt (dt0 datetime(0), dt1 datetime(1), dt2 datetime(2), dt3 datetime(3), dt4 datetime(4), dt5 datetime(5), dt6 datetime(6));", + "insert into dt values ('2020-01-02 12:34:56.123456', '2020-01-02 12:34:56.123456', '2020-01-02 12:34:56.123456', '2020-01-02 12:34:56.123456', '2020-01-02 12:34:56.123456', '2020-01-02 12:34:56.123456', '2020-01-02 12:34:56.123456')", + // TODO: time length not supported, so by default we have max precision + "create table t (d date, tt time);", + "insert into t values ('2020-01-02 12:34:56.123456', '12:34:56.123456');", }, Assertions: []ScriptTestAssertion{ { @@ -5153,6 +5158,18 @@ CREATE TABLE tab3 ( {"981178496.123457"}, }, }, + { + Query: "select unix_timestamp(dt0), unix_timestamp(dt1), unix_timestamp(dt2), unix_timestamp(dt3), unix_timestamp(dt4), unix_timestamp(dt5), unix_timestamp(dt6) from dt;", + Expected: []sql.Row{ + {"1577943296", "1577943296.1", "1577943296.12", "1577943296.123", "1577943296.1235", "1577943296.12346", "1577943296.123456"}, + }, + }, + { + Query: "select unix_timestamp(d), unix_timestamp(tt) from t;", + Expected: []sql.Row{ + {"1577898000", "1743140096.123456"}, + }, + }, }, }, diff --git a/sql/expression/convert.go b/sql/expression/convert.go index 9f1136dc96..7bfb084974 100644 --- a/sql/expression/convert.go +++ b/sql/expression/convert.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "github.com/dolthub/vitess/go/sqltypes" "github.com/sirupsen/logrus" "gopkg.in/src-d/go-errors.v1" @@ -155,7 +156,7 @@ func (c *Convert) Type() sql.Type { case ConvertToDate: return types.Date case ConvertToDatetime: - return types.DatetimeMaxPrecision + return types.MustCreateDatetimeType(sqltypes.Datetime, c.typeLength) case ConvertToDecimal: if c.cachedDecimalType == nil { c.cachedDecimalType = createConvertedDecimalType(c.typeLength, c.typeScale, true) diff --git a/sql/expression/function/date.go b/sql/expression/function/date.go index e2568b54f2..56dbf0f8ad 100644 --- a/sql/expression/function/date.go +++ b/sql/expression/function/date.go @@ -405,19 +405,18 @@ var _ sql.CollationCoercible = (*UnixTimestamp)(nil) const MaxUnixTimeMicroSecs = 32536771199999999 -// noEval returns true if the expression contains an expression that cannot be evaluated without sql.Context or sql.Row. -func noEval(expr sql.Expression) bool { - var hasBadExpr bool +// canEval returns if the expression contains an expression that cannot be evaluated without sql.Context or sql.Row. +func canEval(expr sql.Expression) bool { + evaluable := true transform.InspectExpr(expr, func(e sql.Expression) bool { switch e.(type) { - case *expression.GetField: - hasBadExpr = true - case *ConvertTz: - hasBadExpr = true + case *expression.GetField, *ConvertTz: + evaluable = false + return true } - return hasBadExpr + return false }) - return hasBadExpr + return evaluable } func getNowExpr(expr sql.Expression) *Now { @@ -436,7 +435,7 @@ func evalNowType(now *Now) sql.Type { if now.prec == nil { return types.Int64 } - if noEval(now.prec) { + if !canEval(now.prec) { return types.MustCreateDecimalType(19, 6) } prec, pErr := now.prec.Eval(nil, nil) @@ -463,7 +462,10 @@ func NewUnixTimestamp(args ...sql.Expression) (sql.Expression, error) { } arg := args[0] - if noEval(arg) { + if dtType, isDtType := arg.Type().(sql.DatetimeType); isDtType { + return &UnixTimestamp{Date: arg, typ: types.MustCreateDecimalType(19, uint8(dtType.Precision()))}, nil + } + if !canEval(arg) { return &UnixTimestamp{Date: arg, typ: types.MustCreateDecimalType(19, 6)}, nil } if now := getNowExpr(arg); now != nil { diff --git a/sql/types/datetime.go b/sql/types/datetime.go index 01813d87b8..8f7479bc79 100644 --- a/sql/types/datetime.go +++ b/sql/types/datetime.go @@ -350,7 +350,10 @@ func (t datetimeType) MustConvert(v interface{}) interface{} { // Equals implements the Type interface. func (t datetimeType) Equals(otherType sql.Type) bool { - return t.baseType == otherType.Type() + if dtType, isDtType := otherType.(sql.DatetimeType); isDtType { + return t.baseType == dtType.Type() && t.precision == dtType.Precision() + } + return false } // MaxTextResponseByteLength implements the Type interface