mirror of https://github.com/jackc/pgx.git
253 lines
5.6 KiB
Go
253 lines
5.6 KiB
Go
package pgx
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"strconv"
|
|
"unsafe"
|
|
)
|
|
|
|
type valueTranscoder struct {
|
|
DecodeText func(*MessageReader, int32) interface{}
|
|
DecodeBinary func(*MessageReader, int32) interface{}
|
|
EncodeTo func(*messageWriter, interface{})
|
|
EncodeFormat int16
|
|
}
|
|
|
|
var valueTranscoders map[Oid]*valueTranscoder
|
|
var defaultTranscoder *valueTranscoder
|
|
|
|
func init() {
|
|
valueTranscoders = make(map[Oid]*valueTranscoder)
|
|
|
|
// bool
|
|
valueTranscoders[Oid(16)] = &valueTranscoder{
|
|
DecodeText: decodeBoolFromText,
|
|
DecodeBinary: decodeBoolFromBinary,
|
|
EncodeTo: encodeBool,
|
|
EncodeFormat: 1}
|
|
|
|
// bytea
|
|
valueTranscoders[Oid(17)] = &valueTranscoder{
|
|
DecodeText: decodeByteaFromText,
|
|
EncodeTo: encodeBytea,
|
|
EncodeFormat: 1}
|
|
|
|
// int8
|
|
valueTranscoders[Oid(20)] = &valueTranscoder{
|
|
DecodeText: decodeInt8FromText,
|
|
DecodeBinary: decodeInt8FromBinary,
|
|
EncodeTo: encodeInt8,
|
|
EncodeFormat: 1}
|
|
|
|
// int2
|
|
valueTranscoders[Oid(21)] = &valueTranscoder{
|
|
DecodeText: decodeInt2FromText,
|
|
DecodeBinary: decodeInt2FromBinary,
|
|
EncodeTo: encodeInt2,
|
|
EncodeFormat: 1}
|
|
|
|
// int4
|
|
valueTranscoders[Oid(23)] = &valueTranscoder{
|
|
DecodeText: decodeInt4FromText,
|
|
DecodeBinary: decodeInt4FromBinary,
|
|
EncodeTo: encodeInt4,
|
|
EncodeFormat: 1}
|
|
|
|
// text
|
|
valueTranscoders[Oid(25)] = &valueTranscoder{
|
|
DecodeText: decodeTextFromText,
|
|
EncodeTo: encodeText}
|
|
|
|
// float4
|
|
valueTranscoders[Oid(700)] = &valueTranscoder{
|
|
DecodeText: decodeFloat4FromText,
|
|
DecodeBinary: decodeFloat4FromBinary,
|
|
EncodeTo: encodeFloat4,
|
|
EncodeFormat: 1}
|
|
|
|
// float8
|
|
valueTranscoders[Oid(701)] = &valueTranscoder{
|
|
DecodeText: decodeFloat8FromText,
|
|
DecodeBinary: decodeFloat8FromBinary,
|
|
EncodeTo: encodeFloat8,
|
|
EncodeFormat: 1}
|
|
|
|
// varchar -- same as text
|
|
valueTranscoders[Oid(1043)] = valueTranscoders[Oid(25)]
|
|
|
|
// use text transcoder for anything we don't understand
|
|
defaultTranscoder = valueTranscoders[Oid(25)]
|
|
}
|
|
|
|
func decodeBoolFromText(mr *MessageReader, size int32) interface{} {
|
|
s := mr.ReadByteString(size)
|
|
switch s {
|
|
case "t":
|
|
return true
|
|
case "f":
|
|
return false
|
|
default:
|
|
panic(fmt.Sprintf("Received invalid bool: %v", s))
|
|
}
|
|
}
|
|
|
|
func decodeBoolFromBinary(mr *MessageReader, size int32) interface{} {
|
|
if size != 1 {
|
|
panic("Received an invalid size for an bool")
|
|
}
|
|
b := mr.ReadByte()
|
|
return b != 0
|
|
}
|
|
|
|
func encodeBool(w *messageWriter, value interface{}) {
|
|
v := value.(bool)
|
|
w.write(int32(1))
|
|
if v {
|
|
w.writeByte(1)
|
|
} else {
|
|
w.writeByte(0)
|
|
}
|
|
}
|
|
|
|
func decodeInt8FromText(mr *MessageReader, size int32) interface{} {
|
|
s := mr.ReadByteString(size)
|
|
n, err := strconv.ParseInt(s, 10, 64)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Received invalid int8: %v", s))
|
|
}
|
|
return n
|
|
}
|
|
|
|
func decodeInt8FromBinary(mr *MessageReader, size int32) interface{} {
|
|
if size != 8 {
|
|
panic("Received an invalid size for an int8")
|
|
}
|
|
return mr.ReadInt64()
|
|
}
|
|
|
|
func encodeInt8(w *messageWriter, value interface{}) {
|
|
v := value.(int64)
|
|
w.write(int32(8))
|
|
w.write(v)
|
|
}
|
|
|
|
func decodeInt2FromText(mr *MessageReader, size int32) interface{} {
|
|
s := mr.ReadByteString(size)
|
|
n, err := strconv.ParseInt(s, 10, 16)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Received invalid int2: %v", s))
|
|
}
|
|
return int16(n)
|
|
}
|
|
|
|
func decodeInt2FromBinary(mr *MessageReader, size int32) interface{} {
|
|
if size != 2 {
|
|
panic("Received an invalid size for an int8")
|
|
}
|
|
return mr.ReadInt16()
|
|
}
|
|
|
|
func encodeInt2(w *messageWriter, value interface{}) {
|
|
v := value.(int16)
|
|
w.write(int32(2))
|
|
w.write(v)
|
|
}
|
|
|
|
func decodeInt4FromText(mr *MessageReader, size int32) interface{} {
|
|
s := mr.ReadByteString(size)
|
|
n, err := strconv.ParseInt(s, 10, 32)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Received invalid int4: %v", s))
|
|
}
|
|
return int32(n)
|
|
}
|
|
|
|
func decodeInt4FromBinary(mr *MessageReader, size int32) interface{} {
|
|
if size != 4 {
|
|
panic("Received an invalid size for an int4")
|
|
}
|
|
return mr.ReadInt32()
|
|
}
|
|
|
|
func encodeInt4(w *messageWriter, value interface{}) {
|
|
v := value.(int32)
|
|
w.write(int32(4))
|
|
w.write(v)
|
|
}
|
|
|
|
func decodeFloat4FromText(mr *MessageReader, size int32) interface{} {
|
|
s := mr.ReadByteString(size)
|
|
n, err := strconv.ParseFloat(s, 32)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Received invalid float4: %v", s))
|
|
}
|
|
return float32(n)
|
|
}
|
|
|
|
func decodeFloat4FromBinary(mr *MessageReader, size int32) interface{} {
|
|
if size != 4 {
|
|
panic("Received an invalid size for an float4")
|
|
}
|
|
|
|
i := mr.ReadInt32()
|
|
p := unsafe.Pointer(&i)
|
|
return *(*float32)(p)
|
|
}
|
|
|
|
func encodeFloat4(w *messageWriter, value interface{}) {
|
|
v := value.(float32)
|
|
w.write(int32(4))
|
|
w.write(v)
|
|
}
|
|
|
|
func decodeFloat8FromText(mr *MessageReader, size int32) interface{} {
|
|
s := mr.ReadByteString(size)
|
|
v, err := strconv.ParseFloat(s, 64)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Received invalid float8: %v", s))
|
|
}
|
|
return v
|
|
}
|
|
|
|
func decodeFloat8FromBinary(mr *MessageReader, size int32) interface{} {
|
|
if size != 8 {
|
|
panic("Received an invalid size for an float4")
|
|
}
|
|
|
|
i := mr.ReadInt64()
|
|
p := unsafe.Pointer(&i)
|
|
return *(*float64)(p)
|
|
}
|
|
|
|
func encodeFloat8(w *messageWriter, value interface{}) {
|
|
v := value.(float64)
|
|
w.write(int32(8))
|
|
w.write(v)
|
|
}
|
|
|
|
func decodeTextFromText(mr *MessageReader, size int32) interface{} {
|
|
return mr.ReadByteString(size)
|
|
}
|
|
|
|
func encodeText(w *messageWriter, value interface{}) {
|
|
s := value.(string)
|
|
w.write(int32(len(s)))
|
|
w.writeString(s)
|
|
}
|
|
|
|
func decodeByteaFromText(mr *MessageReader, size int32) interface{} {
|
|
s := mr.ReadByteString(size)
|
|
b, err := hex.DecodeString(s[2:])
|
|
if err != nil {
|
|
panic("Can't decode byte array")
|
|
}
|
|
return b
|
|
}
|
|
|
|
func encodeBytea(w *messageWriter, value interface{}) {
|
|
b := value.([]byte)
|
|
w.write(int32(len(b)))
|
|
w.write(b)
|
|
}
|