2727 // ErrConvertingToTime is thrown when a value cannot be converted to a Time
2828 ErrConvertingToTime = errors .NewKind ("value %q can't be converted to time.Time" )
2929
30- // ErrVarCharTruncation is thrown when a value is textually longer than the destination capacity
30+ // ErrCharTruncation is thrown when a Char value is textually longer than the destination capacity
31+ ErrCharTruncation = errors .NewKind ("string value of %q is longer than destination capacity %d" )
32+
33+ // ErrVarCharTruncation is thrown when a VarChar value is textually longer than the destination capacity
3134 ErrVarCharTruncation = errors .NewKind ("string value of %q is longer than destination capacity %d" )
3235
3336 // ErrValueNotNil is thrown when a value that was expected to be nil, is not
@@ -198,6 +201,8 @@ var (
198201 Timestamp timestampT
199202 // Date is a date with day, month and year.
200203 Date dateT
204+ // Datetime is a date and a time
205+ Datetime datetimeT
201206 // Text is a string type.
202207 Text textT
203208 // Boolean is a boolean type.
@@ -218,6 +223,11 @@ func Array(underlying Type) Type {
218223 return arrayT {underlying }
219224}
220225
226+ // Char returns a new Char type of the given length.
227+ func Char (length int ) Type {
228+ return charT {length : length }
229+ }
230+
221231// VarChar returns a new VarChar type of the given length.
222232func VarChar (length int ) Type {
223233 return varCharT {length : length }
@@ -254,10 +264,16 @@ func MysqlTypeToType(sql query.Type) (Type, error) {
254264 return Date , nil
255265 case sqltypes .Text :
256266 return Text , nil
267+ case sqltypes .Char :
268+ // Since we can't get the size of the sqltypes.Char to instantiate a
269+ // specific Char(length) type we return a Text here
270+ return Text , nil
257271 case sqltypes .VarChar :
258272 // Since we can't get the size of the sqltypes.VarChar to instantiate a
259273 // specific VarChar(length) type we return a Text here
260274 return Text , nil
275+ case sqltypes .Datetime :
276+ return Datetime , nil
261277 case sqltypes .Bit :
262278 return Boolean , nil
263279 case sqltypes .TypeJSON :
@@ -597,6 +613,109 @@ func (t dateT) Compare(a, b interface{}) (int, error) {
597613 return 0 , nil
598614}
599615
616+ type datetimeT struct {}
617+
618+ // DatetimeLayout is the layout of the MySQL date format in the representation
619+ // Go understands.
620+ const DatetimeLayout = "2006-01-02 15:04:05"
621+
622+ func (t datetimeT ) String () string { return "DATETIME" }
623+
624+ func (t datetimeT ) Type () query.Type {
625+ return sqltypes .Datetime
626+ }
627+
628+ func (t datetimeT ) SQL (v interface {}) (sqltypes.Value , error ) {
629+ if v == nil {
630+ return sqltypes .NULL , nil
631+ }
632+
633+ v , err := t .Convert (v )
634+ if err != nil {
635+ return sqltypes.Value {}, err
636+ }
637+
638+ return sqltypes .MakeTrusted (
639+ sqltypes .Datetime ,
640+ []byte (v .(time.Time ).Format (DatetimeLayout )),
641+ ), nil
642+ }
643+
644+ func (t datetimeT ) Convert (v interface {}) (interface {}, error ) {
645+ switch value := v .(type ) {
646+ case time.Time :
647+ return value .UTC (), nil
648+ case string :
649+ t , err := time .Parse (DatetimeLayout , value )
650+ if err != nil {
651+ return nil , ErrConvertingToTime .Wrap (err , v )
652+ }
653+ return t .UTC (), nil
654+ default :
655+ ts , err := Int64 .Convert (v )
656+ if err != nil {
657+ return nil , ErrInvalidType .New (reflect .TypeOf (v ))
658+ }
659+
660+ return time .Unix (ts .(int64 ), 0 ).UTC (), nil
661+ }
662+ }
663+
664+ func (t datetimeT ) Compare (a , b interface {}) (int , error ) {
665+ av := a .(time.Time )
666+ bv := b .(time.Time )
667+ if av .Before (bv ) {
668+ return - 1 , nil
669+ } else if av .After (bv ) {
670+ return 1 , nil
671+ }
672+ return 0 , nil
673+ }
674+
675+ type charT struct {
676+ length int
677+ }
678+
679+ func (t charT ) Capacity () int { return t .length }
680+
681+ func (t charT ) String () string { return fmt .Sprintf ("CHAR(%d)" , t .length ) }
682+
683+ func (t charT ) Type () query.Type {
684+ return sqltypes .Char
685+ }
686+
687+ func (t charT ) SQL (v interface {}) (sqltypes.Value , error ) {
688+ if v == nil {
689+ return sqltypes .MakeTrusted (sqltypes .Char , nil ), nil
690+ }
691+
692+ v , err := t .Convert (v )
693+ if err != nil {
694+ return sqltypes.Value {}, err
695+ }
696+
697+ return sqltypes .MakeTrusted (sqltypes .Char , []byte (v .(string ))), nil
698+ }
699+
700+ // Converts any value that can be casted to a string
701+ func (t charT ) Convert (v interface {}) (interface {}, error ) {
702+ val , err := cast .ToStringE (v )
703+ if err != nil {
704+ return nil , ErrConvertToSQL .New (t )
705+ }
706+
707+ if len (val ) > t .length {
708+ return nil , ErrCharTruncation .New (val , t .length )
709+ }
710+ return val , nil
711+ }
712+
713+ // Compares two strings lexicographically
714+ func (t charT ) Compare (a interface {}, b interface {}) (int , error ) {
715+ return strings .Compare (a .(string ), b .(string )), nil
716+ }
717+
718+
600719type varCharT struct {
601720 length int
602721}
@@ -1013,9 +1132,9 @@ func IsInteger(t Type) bool {
10131132 return IsSigned (t ) || IsUnsigned (t )
10141133}
10151134
1016- // IsTime checks if t is a timestamp or date.
1135+ // IsTime checks if t is a timestamp, date or datetime
10171136func IsTime (t Type ) bool {
1018- return t == Timestamp || t == Date
1137+ return t == Timestamp || t == Date || t == Datetime
10191138}
10201139
10211140// IsDecimal checks if t is decimal type.
@@ -1025,7 +1144,13 @@ func IsDecimal(t Type) bool {
10251144
10261145// IsText checks if t is a text type.
10271146func IsText (t Type ) bool {
1028- return t == Text || t == Blob || t == JSON || IsVarChar (t )
1147+ return t == Text || t == Blob || t == JSON || IsVarChar (t ) || IsChar (t )
1148+ }
1149+
1150+ // IsChar checks if t is a Char type.
1151+ func IsChar (t Type ) bool {
1152+ _ , ok := t .(charT )
1153+ return ok
10291154}
10301155
10311156// IsVarChar checks if t is a varchar type.
@@ -1082,9 +1207,13 @@ func MySQLTypeName(t Type) string {
10821207 case sqltypes .Float64 :
10831208 return "DOUBLE"
10841209 case sqltypes .Timestamp :
1210+ return "TIMESTAMP"
1211+ case sqltypes .Datetime :
10851212 return "DATETIME"
10861213 case sqltypes .Date :
10871214 return "DATE"
1215+ case sqltypes .Char :
1216+ return "CHAR"
10881217 case sqltypes .VarChar :
10891218 return "VARCHAR"
10901219 case sqltypes .Text :
0 commit comments