Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packets.go
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
if rows.mc.parseTime {
dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.loc)
} else {
dest[i], err = formatBinaryDate(num, data[pos:])
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], false)
}

if err == nil {
Expand Down Expand Up @@ -1116,7 +1116,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
if rows.mc.parseTime {
dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.loc)
} else {
dest[i], err = formatBinaryDateTime(num, data[pos:])
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], true)
}

if err == nil {
Expand Down
100 changes: 54 additions & 46 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,55 +503,63 @@ func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Va
return nil, fmt.Errorf("Invalid DATETIME-packet length %d", num)
}

func formatBinaryDate(num uint64, data []byte) (driver.Value, error) {
switch num {
case 0:
return []byte("0000-00-00"), nil
func formatBinaryDateTime(src []byte, withTime bool) (driver.Value, error) {
const zeroDateTimeMicros = "0000-00-00 00:00:00.000000"
srclen := len(src)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to cache the length. The great thing about how slices and strings in Go are designed, is that getting the length is just reading an int64 - no indirection, no function calls: MOVQ src+8(FP),BX

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. It reads smoother to me. But that's a bad habit, I'll change it.

var dst []byte
if withTime {
if srclen == 11 {
dst = []byte(zeroDateTimeMicros)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could save []byte(zeroDateTimeMicros) as a global var to get rid of one allocation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, this only works if you don't edit the values (len=0, I guess).
But see my comment on your gist

} else {
dst = []byte(zeroDateTimeMicros[:19])
}
} else {
dst = []byte(zeroDateTimeMicros[:10])
}
switch srclen {
case 11:
microsecs := binary.LittleEndian.Uint32(src[7:11])
dst[20] += byte((microsecs / 100000) % 10)
dst[21] += byte((microsecs / 10000) % 10)
dst[22] += byte((microsecs / 1000) % 10)
dst[23] += byte((microsecs / 100) % 10)
dst[24] += byte((microsecs / 10) % 10)
dst[25] += byte(microsecs % 10)
fallthrough
case 7:
hour := src[4]
minute := src[5]
second := src[6]
dst[11] += (hour / 10) % 10
dst[12] += hour % 10
dst[14] += (minute / 10) % 10
dst[15] += minute % 10
dst[17] += (second / 10) % 10
dst[18] += second % 10
fallthrough
case 4:
return []byte(fmt.Sprintf(
"%04d-%02d-%02d",
binary.LittleEndian.Uint16(data[:2]),
data[2],
data[3],
)), nil
}
return nil, fmt.Errorf("Invalid DATE-packet length %d", num)
}

func formatBinaryDateTime(num uint64, data []byte) (driver.Value, error) {
switch num {
year := binary.LittleEndian.Uint16(src[:2])
month := src[2]
day := src[3]
dst[0] += byte((year / 1000) % 10)
dst[1] += byte((year / 100) % 10)
dst[2] += byte((year / 10) % 10)
dst[3] += byte(year % 10)
dst[5] += (month / 10) % 10
dst[6] += month % 10
dst[8] += (day / 10) % 10
dst[9] += day % 10
return dst, nil
case 0:
return []byte("0000-00-00 00:00:00"), nil
case 4:
return []byte(fmt.Sprintf(
"%04d-%02d-%02d 00:00:00",
binary.LittleEndian.Uint16(data[:2]),
data[2],
data[3],
)), nil
case 7:
return []byte(fmt.Sprintf(
"%04d-%02d-%02d %02d:%02d:%02d",
binary.LittleEndian.Uint16(data[:2]),
data[2],
data[3],
data[4],
data[5],
data[6],
)), nil
case 11:
return []byte(fmt.Sprintf(
"%04d-%02d-%02d %02d:%02d:%02d.%06d",
binary.LittleEndian.Uint16(data[:2]),
data[2],
data[3],
data[4],
data[5],
data[6],
binary.LittleEndian.Uint32(data[7:11]),
)), nil
return dst, nil
}
return nil, fmt.Errorf("Invalid DATETIME-packet length %d", num)
var mode string
if withTime {
mode = "DATETIME"
} else {
mode = "DATE"
}
return nil, fmt.Errorf("invalid %s-packet length %d", mode, srclen)
}

/******************************************************************************
Expand Down