You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-library/vendor/github.com/uptrace/bun/driver/pgdriver/column.go

194 lines
3.9 KiB

package pgdriver
import (
"encoding/hex"
"fmt"
"io"
"strconv"
"strings"
"time"
)
const (
pgBool = 16
pgInt2 = 21
pgInt4 = 23
pgInt8 = 20
pgFloat4 = 700
pgFloat8 = 701
pgText = 25
pgVarchar = 1043
pgBytea = 17
pgDate = 1082
pgTimestamp = 1114
pgTimestamptz = 1184
)
func readColumnValue(rd *reader, dataType int32, dataLen int) (interface{}, error) {
if dataLen == -1 {
return nil, nil
}
switch dataType {
case pgBool:
return readBoolCol(rd, dataLen)
case pgInt2:
return readIntCol(rd, dataLen, 16)
case pgInt4:
return readIntCol(rd, dataLen, 32)
case pgInt8:
return readIntCol(rd, dataLen, 64)
case pgFloat4:
return readFloatCol(rd, dataLen, 32)
case pgFloat8:
return readFloatCol(rd, dataLen, 64)
case pgTimestamp:
return readTimeCol(rd, dataLen)
case pgTimestamptz:
return readTimeCol(rd, dataLen)
case pgDate:
// Return a string and let the scanner to convert string to time.Time if necessary.
return readStringCol(rd, dataLen)
case pgText, pgVarchar:
return readStringCol(rd, dataLen)
case pgBytea:
return readBytesCol(rd, dataLen)
}
b := make([]byte, dataLen)
if _, err := io.ReadFull(rd, b); err != nil {
return nil, err
}
return b, nil
}
func readBoolCol(rd *reader, n int) (interface{}, error) {
tmp, err := rd.ReadTemp(n)
if err != nil {
return nil, err
}
return len(tmp) == 1 && (tmp[0] == 't' || tmp[0] == '1'), nil
}
func readIntCol(rd *reader, n int, bitSize int) (interface{}, error) {
if n <= 0 {
return 0, nil
}
tmp, err := rd.ReadTemp(n)
if err != nil {
return 0, err
}
return strconv.ParseInt(bytesToString(tmp), 10, bitSize)
}
func readFloatCol(rd *reader, n int, bitSize int) (interface{}, error) {
if n <= 0 {
return 0, nil
}
tmp, err := rd.ReadTemp(n)
if err != nil {
return 0, err
}
return strconv.ParseFloat(bytesToString(tmp), bitSize)
}
func readStringCol(rd *reader, n int) (interface{}, error) {
if n <= 0 {
return "", nil
}
b := make([]byte, n)
if _, err := io.ReadFull(rd, b); err != nil {
return nil, err
}
return bytesToString(b), nil
}
func readBytesCol(rd *reader, n int) (interface{}, error) {
if n <= 0 {
return []byte{}, nil
}
tmp, err := rd.ReadTemp(n)
if err != nil {
return nil, err
}
if len(tmp) < 2 || tmp[0] != '\\' || tmp[1] != 'x' {
return nil, fmt.Errorf("pgdriver: can't parse bytea: %q", tmp)
}
tmp = tmp[2:] // Cut off "\x".
b := make([]byte, hex.DecodedLen(len(tmp)))
if _, err := hex.Decode(b, tmp); err != nil {
return nil, err
}
return b, nil
}
func readTimeCol(rd *reader, n int) (interface{}, error) {
if n <= 0 {
return time.Time{}, nil
}
tmp, err := rd.ReadTemp(n)
if err != nil {
return time.Time{}, err
}
tm, err := ParseTime(bytesToString(tmp))
if err != nil {
return time.Time{}, err
}
return tm, nil
}
const (
dateFormat = "2006-01-02"
timeFormat = "15:04:05.999999999"
timestampFormat = "2006-01-02 15:04:05.999999999"
timestamptzFormat = "2006-01-02 15:04:05.999999999-07:00:00"
timestamptzFormat2 = "2006-01-02 15:04:05.999999999-07:00"
timestamptzFormat3 = "2006-01-02 15:04:05.999999999-07"
)
func ParseTime(s string) (time.Time, error) {
switch l := len(s); {
case l < len("15:04:05"):
return time.Time{}, fmt.Errorf("pgdriver: can't parse time=%q", s)
case l <= len(timeFormat):
if s[2] == ':' {
return time.ParseInLocation(timeFormat, s, time.UTC)
}
return time.ParseInLocation(dateFormat, s, time.UTC)
default:
if s[10] == 'T' {
return time.Parse(time.RFC3339Nano, s)
}
if c := s[l-9]; c == '+' || c == '-' {
return time.Parse(timestamptzFormat, s)
}
if c := s[l-6]; c == '+' || c == '-' {
return time.Parse(timestamptzFormat2, s)
}
if c := s[l-3]; c == '+' || c == '-' {
if strings.HasSuffix(s, "+00") {
s = s[:len(s)-3]
return time.ParseInLocation(timestampFormat, s, time.UTC)
}
return time.Parse(timestamptzFormat3, s)
}
return time.ParseInLocation(timestampFormat, s, time.UTC)
}
}