@@ -503,62 +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+ // 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+
506512func formatBinaryDateTime (src []byte , withTime bool ) (driver.Value , error ) {
507- const zeroDateTimeMicros = "0000-00-00 00:00:00.000000"
513+ if len (src ) == 0 {
514+ if withTime {
515+ return zeroDateTime , nil
516+ }
517+ return zeroDateTime [:10 ], nil
518+ }
508519 var dst []byte
509520 if withTime {
510521 if len (src ) == 11 {
511- dst = []byte (zeroDateTimeMicros )
522+ dst = []byte ("0000-00-00 00:00:00.000000" )
512523 } else {
513- dst = []byte (zeroDateTimeMicros [: 19 ] )
524+ dst = []byte ("0000-00-00 00:00:00" )
514525 }
515526 } else {
516- dst = []byte (zeroDateTimeMicros [: 10 ] )
527+ dst = []byte ("0000-00-00" )
517528 }
518529 switch len (src ) {
519530 case 11 :
520531 microsecs := binary .LittleEndian .Uint32 (src [7 :11 ])
521- dst [20 ] += byte ((microsecs / 100000 ) % 10 )
522- dst [21 ] += byte ((microsecs / 10000 ) % 10 )
523- dst [22 ] += byte ((microsecs / 1000 ) % 10 )
524- dst [23 ] += byte ((microsecs / 100 ) % 10 )
525- dst [24 ] += byte ((microsecs / 10 ) % 10 )
526- dst [25 ] += byte (microsecs % 10 )
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 )
527543 fallthrough
528544 case 7 :
529- hour := src [4 ]
530- minute := src [5 ]
531545 second := src [6 ]
532- dst [11 ] += (hour / 10 ) % 10
533- dst [12 ] += hour % 10
534- dst [14 ] += (minute / 10 ) % 10
535- dst [15 ] += minute % 10
536- dst [17 ] += (second / 10 ) % 10
537- dst [18 ] += second % 10
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
538557 fallthrough
539558 case 4 :
540- year := binary .LittleEndian .Uint16 (src [:2 ])
541- month := src [2 ]
542559 day := src [3 ]
543- dst [0 ] += byte ((year / 1000 ) % 10 )
544- dst [1 ] += byte ((year / 100 ) % 10 )
545- dst [2 ] += byte ((year / 10 ) % 10 )
546- dst [3 ] += byte (year % 10 )
547- dst [5 ] += (month / 10 ) % 10
548- dst [6 ] += month % 10
549- dst [8 ] += (day / 10 ) % 10
550- dst [9 ] += day % 10
551- return dst , nil
552- case 0 :
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 )
553575 return dst , nil
554576 }
555- var mode string
577+ var t string
556578 if withTime {
557- mode = "DATETIME"
579+ t = "DATETIME"
558580 } else {
559- mode = "DATE"
581+ t = "DATE"
560582 }
561- return nil , fmt .Errorf ("invalid %s-packet length %d" , mode , len (src ))
583+ return nil , fmt .Errorf ("invalid %s-packet length %d" , t , len (src ))
562584}
563585
564586/******************************************************************************
0 commit comments