func dumpBinaryDateTime(t types.Time, loc *time.Location) (data []byte) { if t.Type == mysql.TypeTimestamp && loc != nil { t1, err := t.Time.GoTime() if err != nil { // TODO: Fix here. } t.Time = types.FromGoTime(t1.In(loc)) } year, mon, day := t.Time.Year(), t.Time.Month(), t.Time.Day() if t.IsZero() { year, mon, day = 1, int(time.January), 1 } switch t.Type { case mysql.TypeTimestamp, mysql.TypeDatetime: data = append(data, 11) data = append(data, dumpUint16(uint16(year))...) data = append(data, byte(mon), byte(day), byte(t.Time.Hour()), byte(t.Time.Minute()), byte(t.Time.Second())) data = append(data, dumpUint32(uint32(t.Time.Microsecond()))...) case mysql.TypeDate, mysql.TypeNewDate: data = append(data, 4) data = append(data, dumpUint16(uint16(year))...) //year data = append(data, byte(mon), byte(day)) } return }
// Unflatten converts a raw datum to a column datum. func Unflatten(datum types.Datum, ft *types.FieldType, inIndex bool) (types.Datum, error) { if datum.IsNull() { return datum, nil } switch ft.Tp { case mysql.TypeFloat: datum.SetFloat32(float32(datum.GetFloat64())) return datum, nil case mysql.TypeTiny, mysql.TypeShort, mysql.TypeYear, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeDouble, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob, mysql.TypeVarchar, mysql.TypeString: return datum, nil case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp: var t types.Time t.Type = ft.Tp t.Fsp = ft.Decimal var err error err = t.FromPackedUint(datum.GetUint64()) if err != nil { return datum, errors.Trace(err) } datum.SetMysqlTime(t) return datum, nil case mysql.TypeDuration: dur := types.Duration{Duration: time.Duration(datum.GetInt64())} datum.SetValue(dur) return datum, nil case mysql.TypeEnum: enum, err := types.ParseEnumValue(ft.Elems, datum.GetUint64()) if err != nil { return datum, errors.Trace(err) } datum.SetValue(enum) return datum, nil case mysql.TypeSet: set, err := types.ParseSetValue(ft.Elems, datum.GetUint64()) if err != nil { return datum, errors.Trace(err) } datum.SetValue(set) return datum, nil case mysql.TypeBit: bit := types.Bit{Value: datum.GetUint64(), Width: ft.Flen} datum.SetValue(bit) return datum, nil } return datum, nil }
// See https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date func builtinStrToDate(args []types.Datum, _ context.Context) (types.Datum, error) { date := args[0].GetString() format := args[1].GetString() var ( d types.Datum t types.Time ) succ := t.StrToDate(date, format) if !succ { d.SetNull() return d, nil } d.SetMysqlTime(t) return d, nil }
func (s *testCodecSuite) TestTime(c *C) { defer testleak.AfterTest(c)() tbl := []string{ "2011-01-01 00:00:00", "2011-01-01 00:00:00", "0001-01-01 00:00:00", } for _, t := range tbl { m := types.NewDatum(parseTime(c, t)) b, err := EncodeKey(nil, m) c.Assert(err, IsNil) v, err := Decode(b, 1) c.Assert(err, IsNil) var t types.Time t.Type = mysql.TypeDatetime t.FromPackedUint(v[0].GetUint64()) c.Assert(types.NewDatum(t), DeepEquals, m) } tblCmp := []struct { Arg1 string Arg2 string Ret int }{ {"2011-10-10 00:00:00", "2000-12-12 11:11:11", 1}, {"2000-10-10 00:00:00", "2001-10-10 00:00:00", -1}, {"2000-10-10 00:00:00", "2000-10-10 00:00:00", 0}, } for _, t := range tblCmp { m1 := types.NewDatum(parseTime(c, t.Arg1)) m2 := types.NewDatum(parseTime(c, t.Arg2)) b1, err := EncodeKey(nil, m1) c.Assert(err, IsNil) b2, err := EncodeKey(nil, m2) c.Assert(err, IsNil) ret := bytes.Compare(b1, b2) c.Assert(ret, Equals, t.Ret) } }
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-unixtime func builtinFromUnixTime(args []types.Datum, ctx context.Context) (d types.Datum, err error) { sc := ctx.GetSessionVars().StmtCtx unixTimeStamp, err := args[0].ToDecimal(sc) if err != nil { return d, errors.Trace(err) } // 0 <= unixTimeStamp <= INT32_MAX if unixTimeStamp.IsNegative() { return } integralPart, err := unixTimeStamp.ToInt() if err == types.ErrTruncated { err = nil } if err != nil { return d, errors.Trace(err) } if integralPart > int64(math.MaxInt32) { return } // Split the integral part and fractional part of a decimal timestamp. // e.g. for timestamp 12345.678, // first get the integral part 12345, // then (12345.678 - 12345) * (10^9) to get the decimal part and convert it to nanosecond precision. integerDecimalTp := new(types.MyDecimal).FromInt(integralPart) fracDecimalTp := new(types.MyDecimal) err = types.DecimalSub(unixTimeStamp, integerDecimalTp, fracDecimalTp) if err != nil { return d, errors.Trace(err) } nano := new(types.MyDecimal).FromInt(int64(time.Second)) x := new(types.MyDecimal) err = types.DecimalMul(fracDecimalTp, nano, x) if err != nil { return d, errors.Trace(err) } fractionalPart, err := x.ToInt() // here fractionalPart is result multiplying the original fractional part by 10^9. if err == types.ErrTruncated { err = nil } if err != nil { return d, errors.Trace(err) } _, fracDigitsNumber := unixTimeStamp.PrecisionAndFrac() fsp := fracDigitsNumber if fracDigitsNumber > types.MaxFsp { fsp = types.MaxFsp } tr, err := types.RoundFrac(time.Unix(integralPart, fractionalPart), fsp) if err != nil { return d, errors.Trace(err) } t := types.Time{ Time: types.FromGoTime(tr), Type: mysql.TypeDatetime, Fsp: fsp, } if args[0].Kind() == types.KindString { // Keep consistent with MySQL. t.Fsp = types.MaxFsp } d.SetMysqlTime(t) if len(args) == 1 { return } return builtinDateFormat([]types.Datum{d, args[1]}, ctx) }
func getTimeValue(ctx context.Context, v interface{}, tp byte, fsp int) (d types.Datum, err error) { value := types.Time{ Type: tp, Fsp: fsp, } defaultTime, err := getSystemTimestamp(ctx) if err != nil { return d, errors.Trace(err) } switch x := v.(type) { case string: upperX := strings.ToUpper(x) if upperX == CurrentTimestamp { value.Time = types.FromGoTime(defaultTime) } else if upperX == ZeroTimestamp { value, _ = types.ParseTimeFromNum(0, tp, fsp) } else { value, err = types.ParseTime(x, tp, fsp) if err != nil { return d, errors.Trace(err) } } case *ast.ValueExpr: switch x.Kind() { case types.KindString: value, err = types.ParseTime(x.GetString(), tp, fsp) if err != nil { return d, errors.Trace(err) } case types.KindInt64: value, err = types.ParseTimeFromNum(x.GetInt64(), tp, fsp) if err != nil { return d, errors.Trace(err) } case types.KindNull: return d, nil default: return d, errors.Trace(errDefaultValue) } case *ast.FuncCallExpr: if x.FnName.L == currentTimestampL { d.SetString(CurrentTimestamp) return d, nil } return d, errors.Trace(errDefaultValue) case *ast.UnaryOperationExpr: // support some expression, like `-1` v, err := Eval(ctx, x) if err != nil { return d, errors.Trace(err) } ft := types.NewFieldType(mysql.TypeLonglong) xval, err := v.ConvertTo(ctx.GetSessionVars().StmtCtx, ft) if err != nil { return d, errors.Trace(err) } value, err = types.ParseTimeFromNum(xval.GetInt64(), tp, fsp) if err != nil { return d, errors.Trace(err) } default: return d, nil } d.SetMysqlTime(value) return d, nil }