@@ -503,55 +503,84 @@ func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Va
503503 return nil , fmt .Errorf ("Invalid DATETIME-packet length %d" , num )
504504}
505505
506- func formatBinaryDate (num uint64 , data []byte ) (driver.Value , error ) {
507- switch num {
508- case 0 :
509- return []byte ("0000-00-00" ), nil
510- case 4 :
511- return []byte (fmt .Sprintf (
512- "%04d-%02d-%02d" ,
513- binary .LittleEndian .Uint16 (data [:2 ]),
514- data [2 ],
515- data [3 ],
516- )), nil
517- }
518- return nil , fmt .Errorf ("Invalid DATE-packet length %d" , num )
519- }
520-
521- func formatBinaryDateTime (num uint64 , data []byte ) (driver.Value , error ) {
522- switch num {
523- case 0 :
524- return []byte ("0000-00-00 00:00:00" ), nil
525- case 4 :
526- return []byte (fmt .Sprintf (
527- "%04d-%02d-%02d 00:00:00" ,
528- binary .LittleEndian .Uint16 (data [:2 ]),
529- data [2 ],
530- data [3 ],
531- )), nil
532- case 7 :
533- return []byte (fmt .Sprintf (
534- "%04d-%02d-%02d %02d:%02d:%02d" ,
535- binary .LittleEndian .Uint16 (data [:2 ]),
536- data [2 ],
537- data [3 ],
538- data [4 ],
539- data [5 ],
540- data [6 ],
541- )), nil
542- case 11 :
543- return []byte (fmt .Sprintf (
544- "%04d-%02d-%02d %02d:%02d:%02d.%06d" ,
545- binary .LittleEndian .Uint16 (data [:2 ]),
546- data [2 ],
547- data [3 ],
548- data [4 ],
549- data [5 ],
550- data [6 ],
551- binary .LittleEndian .Uint32 (data [7 :11 ]),
552- )), nil
506+ // zeroDateTime is used in formatBinaryDateTime to avoid an allocation
507+ // if the DATE or DATETIME has the zero value.
508+ // It must never be changed.
509+ // The current behavior depends on database/sql copying the result.
510+ var zeroDateTime = []byte ("0000-00-00 00:00:00" )
511+
512+ func formatBinaryDateTime (src []byte , withTime bool ) (driver.Value , error ) {
513+ if len (src ) == 0 {
514+ if withTime {
515+ return zeroDateTime , nil
516+ }
517+ return zeroDateTime [:10 ], nil
518+ }
519+ var dst []byte
520+ if withTime {
521+ if len (src ) == 11 {
522+ dst = []byte ("0000-00-00 00:00:00.000000" )
523+ } else {
524+ dst = []byte ("0000-00-00 00:00:00" )
525+ }
526+ } else {
527+ dst = []byte ("0000-00-00" )
553528 }
554- return nil , fmt .Errorf ("Invalid DATETIME-packet length %d" , num )
529+ switch len (src ) {
530+ case 11 :
531+ microsecs := binary .LittleEndian .Uint32 (src [7 :11 ])
532+ tmp32 := microsecs / 10
533+ dst [25 ] += byte (microsecs - 10 * tmp32 )
534+ tmp32 , microsecs = tmp32 / 10 , tmp32
535+ dst [24 ] += byte (microsecs - 10 * tmp32 )
536+ tmp32 , microsecs = tmp32 / 10 , tmp32
537+ dst [23 ] += byte (microsecs - 10 * tmp32 )
538+ tmp32 , microsecs = tmp32 / 10 , tmp32
539+ dst [22 ] += byte (microsecs - 10 * tmp32 )
540+ tmp32 , microsecs = tmp32 / 10 , tmp32
541+ dst [21 ] += byte (microsecs - 10 * tmp32 )
542+ dst [20 ] += byte (microsecs / 10 )
543+ fallthrough
544+ case 7 :
545+ second := src [6 ]
546+ tmp := second / 10
547+ dst [18 ] += second - 10 * tmp
548+ dst [17 ] += tmp
549+ minute := src [5 ]
550+ tmp = minute / 10
551+ dst [15 ] += minute - 10 * tmp
552+ dst [14 ] += tmp
553+ hour := src [4 ]
554+ tmp = hour / 10
555+ dst [12 ] += hour - 10 * tmp
556+ dst [11 ] += tmp
557+ fallthrough
558+ case 4 :
559+ day := src [3 ]
560+ tmp := day / 10
561+ dst [9 ] += day - 10 * tmp
562+ dst [8 ] += tmp
563+ month := src [2 ]
564+ tmp = month / 10
565+ dst [6 ] += month - 10 * tmp
566+ dst [5 ] += tmp
567+ year := binary .LittleEndian .Uint16 (src [:2 ])
568+ tmp16 := year / 10
569+ dst [3 ] += byte (year - 10 * tmp16 )
570+ tmp16 , year = tmp16 / 10 , tmp16
571+ dst [2 ] += byte (year - 10 * tmp16 )
572+ tmp16 , year = tmp16 / 10 , tmp16
573+ dst [1 ] += byte (year - 10 * tmp16 )
574+ dst [0 ] += byte (tmp16 )
575+ return dst , nil
576+ }
577+ var t string
578+ if withTime {
579+ t = "DATETIME"
580+ } else {
581+ t = "DATE"
582+ }
583+ return nil , fmt .Errorf ("invalid %s-packet length %d" , t , len (src ))
555584}
556585
557586/******************************************************************************
0 commit comments