169 lines
5.1 KiB
Go
169 lines
5.1 KiB
Go
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
// The MIT License (MIT)
|
|
//
|
|
// Copyright (c) 2014 wandoulabs
|
|
// Copyright (c) 2014 siddontang
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
// this software and associated documentation files (the "Software"), to deal in
|
|
// the Software without restriction, including without limitation the rights to
|
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
|
// subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
|
|
package dump
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"time"
|
|
|
|
"github.com/pingcap/tidb/parser/mysql"
|
|
"github.com/pingcap/tidb/types"
|
|
)
|
|
|
|
// LengthEncodedString dumps a string as length encoded byte slice.
|
|
func LengthEncodedString(buffer []byte, bytes []byte) []byte {
|
|
buffer = LengthEncodedInt(buffer, uint64(len(bytes)))
|
|
buffer = append(buffer, bytes...)
|
|
return buffer
|
|
}
|
|
|
|
// LengthEncodedInt dumps an integer as length encoded byte slice.
|
|
func LengthEncodedInt(buffer []byte, n uint64) []byte {
|
|
switch {
|
|
case n <= 250:
|
|
return append(buffer, byte(n))
|
|
|
|
case n <= 0xffff:
|
|
return append(buffer, 0xfc, byte(n), byte(n>>8))
|
|
|
|
case n <= 0xffffff:
|
|
return append(buffer, 0xfd, byte(n), byte(n>>8), byte(n>>16))
|
|
|
|
case n <= 0xffffffffffffffff:
|
|
return append(buffer, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24),
|
|
byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56))
|
|
}
|
|
|
|
return buffer
|
|
}
|
|
|
|
// Uint16 dumps an uint16 as byte slice.
|
|
func Uint16(buffer []byte, n uint16) []byte {
|
|
buffer = append(buffer, byte(n))
|
|
buffer = append(buffer, byte(n>>8))
|
|
return buffer
|
|
}
|
|
|
|
// Uint32 dumps an uint32 as byte slice.
|
|
func Uint32(buffer []byte, n uint32) []byte {
|
|
buffer = append(buffer, byte(n))
|
|
buffer = append(buffer, byte(n>>8))
|
|
buffer = append(buffer, byte(n>>16))
|
|
buffer = append(buffer, byte(n>>24))
|
|
return buffer
|
|
}
|
|
|
|
// Uint64 dumps an uint64 as byte slice.
|
|
func Uint64(buffer []byte, n uint64) []byte {
|
|
buffer = append(buffer, byte(n))
|
|
buffer = append(buffer, byte(n>>8))
|
|
buffer = append(buffer, byte(n>>16))
|
|
buffer = append(buffer, byte(n>>24))
|
|
buffer = append(buffer, byte(n>>32))
|
|
buffer = append(buffer, byte(n>>40))
|
|
buffer = append(buffer, byte(n>>48))
|
|
buffer = append(buffer, byte(n>>56))
|
|
return buffer
|
|
}
|
|
|
|
// BinaryTime dumps a time as binary byte slice.
|
|
func BinaryTime(dur time.Duration) (data []byte) {
|
|
if dur == 0 {
|
|
return []byte{0}
|
|
}
|
|
data = make([]byte, 13)
|
|
data[0] = 12
|
|
if dur < 0 {
|
|
data[1] = 1
|
|
dur = -dur
|
|
}
|
|
days := dur / (24 * time.Hour)
|
|
dur -= days * 24 * time.Hour //nolint:durationcheck
|
|
data[2] = byte(days)
|
|
hours := dur / time.Hour
|
|
dur -= hours * time.Hour //nolint:durationcheck
|
|
data[6] = byte(hours)
|
|
minutes := dur / time.Minute
|
|
dur -= minutes * time.Minute //nolint:durationcheck
|
|
data[7] = byte(minutes)
|
|
seconds := dur / time.Second
|
|
dur -= seconds * time.Second //nolint:durationcheck
|
|
data[8] = byte(seconds)
|
|
if dur == 0 {
|
|
data[0] = 8
|
|
return data[:9]
|
|
}
|
|
binary.LittleEndian.PutUint32(data[9:13], uint32(dur/time.Microsecond))
|
|
return
|
|
}
|
|
|
|
// BinaryDateTime dumps a datetime as binary byte slice.
|
|
func BinaryDateTime(data []byte, t types.Time) []byte {
|
|
year, mon, day := t.Year(), t.Month(), t.Day()
|
|
switch t.Type() {
|
|
case mysql.TypeTimestamp, mysql.TypeDatetime:
|
|
if t.IsZero() {
|
|
// All zero.
|
|
data = append(data, 0)
|
|
} else if t.Microsecond() != 0 {
|
|
// Has micro seconds.
|
|
data = append(data, 11)
|
|
data = Uint16(data, uint16(year))
|
|
data = append(data, byte(mon), byte(day), byte(t.Hour()), byte(t.Minute()), byte(t.Second()))
|
|
data = Uint32(data, uint32(t.Microsecond()))
|
|
} else if t.Hour() != 0 || t.Minute() != 0 || t.Second() != 0 {
|
|
// Has HH:MM:SS
|
|
data = append(data, 7)
|
|
data = Uint16(data, uint16(year))
|
|
data = append(data, byte(mon), byte(day), byte(t.Hour()), byte(t.Minute()), byte(t.Second()))
|
|
} else {
|
|
// Only YY:MM:DD
|
|
data = append(data, 4)
|
|
data = Uint16(data, uint16(year))
|
|
data = append(data, byte(mon), byte(day))
|
|
}
|
|
case mysql.TypeDate:
|
|
if t.IsZero() {
|
|
data = append(data, 0)
|
|
} else {
|
|
data = append(data, 4)
|
|
data = Uint16(data, uint16(year)) // year
|
|
data = append(data, byte(mon), byte(day))
|
|
}
|
|
}
|
|
return data
|
|
}
|