Decode(Text|Binary) now accepts []byte instead of io.Reader

This commit is contained in:
Jack Christensen 2017-03-10 16:08:47 -06:00
parent ac9228a1a3
commit 8162634259
38 changed files with 506 additions and 855 deletions

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
@ -25,40 +26,37 @@ type ArrayDimension struct {
LowerBound int32 LowerBound int32
} }
func (dst *ArrayHeader) DecodeBinary(r io.Reader) error { func (dst *ArrayHeader) DecodeBinary(src []byte) (int, error) {
numDims, err := pgio.ReadInt32(r) if len(src) < 12 {
if err != nil { return 0, fmt.Errorf("array header too short: %d", len(src))
return err
} }
rp := 0
numDims := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
dst.ContainsNull = binary.BigEndian.Uint32(src[rp:]) == 1
rp += 4
dst.ElementOID = int32(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if numDims > 0 { if numDims > 0 {
dst.Dimensions = make([]ArrayDimension, numDims) dst.Dimensions = make([]ArrayDimension, numDims)
} }
if len(src) < 12+numDims*8 {
containsNull, err := pgio.ReadInt32(r) return 0, fmt.Errorf("array header too short for %d dimensions: %d", numDims, len(src))
if err != nil {
return err
} }
dst.ContainsNull = containsNull == 1
dst.ElementOID, err = pgio.ReadInt32(r)
if err != nil {
return err
}
for i := range dst.Dimensions { for i := range dst.Dimensions {
dst.Dimensions[i].Length, err = pgio.ReadInt32(r) dst.Dimensions[i].Length = int32(binary.BigEndian.Uint32(src[rp:]))
if err != nil { rp += 4
return err
}
dst.Dimensions[i].LowerBound, err = pgio.ReadInt32(r) dst.Dimensions[i].LowerBound = int32(binary.BigEndian.Uint32(src[rp:]))
if err != nil { rp += 4
return err
}
} }
return nil return rp, nil
} }
func (src *ArrayHeader) EncodeBinary(w io.Writer) error { func (src *ArrayHeader) EncodeBinary(w io.Writer) error {

View File

@ -72,51 +72,31 @@ func (src *Bool) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Bool) DecodeText(r io.Reader) error { func (dst *Bool) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Bool{Status: Null} *dst = Bool{Status: Null}
return nil return nil
} }
if size != 1 { if len(src) != 1 {
return fmt.Errorf("invalid length for bool: %v", size) return fmt.Errorf("invalid length for bool: %v", len(src))
} }
byt, err := pgio.ReadByte(r) *dst = Bool{Bool: src[0] == 't', Status: Present}
if err != nil {
return err
}
*dst = Bool{Bool: byt == 't', Status: Present}
return nil return nil
} }
func (dst *Bool) DecodeBinary(r io.Reader) error { func (dst *Bool) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Bool{Status: Null} *dst = Bool{Status: Null}
return nil return nil
} }
if size != 1 { if len(src) != 1 {
return fmt.Errorf("invalid length for bool: %v", size) return fmt.Errorf("invalid length for bool: %v", len(src))
} }
byt, err := pgio.ReadByte(r) *dst = Bool{Bool: src[0] == 1, Status: Present}
if err != nil {
return err
}
*dst = Bool{Bool: byt == 1, Status: Present}
return nil return nil
} }

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
@ -73,29 +74,17 @@ func (src *BoolArray) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *BoolArray) DecodeText(r io.Reader) error { func (dst *BoolArray) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = BoolArray{Status: Null} *dst = BoolArray{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Bool var elements []Bool
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -103,8 +92,11 @@ func (dst *BoolArray) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Bool var elem Bool
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -118,19 +110,14 @@ func (dst *BoolArray) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *BoolArray) DecodeBinary(r io.Reader) error { func (dst *BoolArray) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = BoolArray{Status: Null} *dst = BoolArray{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -148,7 +135,14 @@ func (dst *BoolArray) DecodeBinary(r io.Reader) error {
elements := make([]Bool, elementCount) elements := make([]Bool, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -236,6 +230,10 @@ func (src *BoolArray) EncodeText(w io.Writer) error {
} }
func (src *BoolArray) EncodeBinary(w io.Writer) error { func (src *BoolArray) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, BoolOID)
}
func (src *BoolArray) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -256,7 +254,7 @@ func (src *BoolArray) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = BoolOID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

View File

@ -71,29 +71,18 @@ func (src *Bytea) AssignTo(dst interface{}) error {
// DecodeText only supports the hex format. This has been the default since // DecodeText only supports the hex format. This has been the default since
// PostgreSQL 9.0. // PostgreSQL 9.0.
func (dst *Bytea) DecodeText(r io.Reader) error { func (dst *Bytea) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Bytea{Status: Null} *dst = Bytea{Status: Null}
return nil return nil
} }
sbuf := make([]byte, int(size)) if len(src) < 2 || src[0] != '\\' || src[1] != 'x' {
_, err = io.ReadFull(r, sbuf)
if err != nil {
return err
}
if len(sbuf) < 2 || sbuf[0] != '\\' || sbuf[1] != 'x' {
return fmt.Errorf("invalid hex format") return fmt.Errorf("invalid hex format")
} }
buf := make([]byte, (len(sbuf)-2)/2) buf := make([]byte, (len(src)-2)/2)
_, err = hex.Decode(buf, sbuf[2:]) _, err := hex.Decode(buf, src[2:])
if err != nil { if err != nil {
return err return err
} }
@ -102,25 +91,13 @@ func (dst *Bytea) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Bytea) DecodeBinary(r io.Reader) error { func (dst *Bytea) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Bytea{Status: Null} *dst = Bytea{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) *dst = Bytea{Bytes: src, Status: Present}
_, err = io.ReadFull(r, buf)
if err != nil {
return err
}
*dst = Bytea{Bytes: buf, Status: Present}
return nil return nil
} }

View File

@ -30,12 +30,12 @@ func (src *CID) AssignTo(dst interface{}) error {
return (*pguint32)(src).AssignTo(dst) return (*pguint32)(src).AssignTo(dst)
} }
func (dst *CID) DecodeText(r io.Reader) error { func (dst *CID) DecodeText(src []byte) error {
return (*pguint32)(dst).DecodeText(r) return (*pguint32)(dst).DecodeText(src)
} }
func (dst *CID) DecodeBinary(r io.Reader) error { func (dst *CID) DecodeBinary(src []byte) error {
return (*pguint32)(dst).DecodeBinary(r) return (*pguint32)(dst).DecodeBinary(src)
} }
func (src CID) EncodeText(w io.Writer) error { func (src CID) EncodeText(w io.Writer) error {

View File

@ -14,12 +14,12 @@ func (src *CidrArray) AssignTo(dst interface{}) error {
return (*InetArray)(src).AssignTo(dst) return (*InetArray)(src).AssignTo(dst)
} }
func (dst *CidrArray) DecodeText(r io.Reader) error { func (dst *CidrArray) DecodeText(src []byte) error {
return (*InetArray)(dst).DecodeText(r) return (*InetArray)(dst).DecodeText(src)
} }
func (dst *CidrArray) DecodeBinary(r io.Reader) error { func (dst *CidrArray) DecodeBinary(src []byte) error {
return (*InetArray)(dst).DecodeBinary(r) return (*InetArray)(dst).DecodeBinary(src)
} }
func (src *CidrArray) EncodeText(w io.Writer) error { func (src *CidrArray) EncodeText(w io.Writer) error {

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
@ -66,24 +67,13 @@ func (src *Date) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Date) DecodeText(r io.Reader) error { func (dst *Date) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Date{Status: Null} *dst = Date{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) sbuf := string(src)
_, err = r.Read(buf)
if err != nil {
return err
}
sbuf := string(buf)
switch sbuf { switch sbuf {
case "infinity": case "infinity":
*dst = Date{Status: Present, InfinityModifier: Infinity} *dst = Date{Status: Present, InfinityModifier: Infinity}
@ -101,25 +91,17 @@ func (dst *Date) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Date) DecodeBinary(r io.Reader) error { func (dst *Date) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Date{Status: Null} *dst = Date{Status: Null}
return nil return nil
} }
if size != 4 { if len(src) != 4 {
return fmt.Errorf("invalid length for date: %v", size) return fmt.Errorf("invalid length for date: %v", len(src))
} }
dayOffset, err := pgio.ReadInt32(r) dayOffset := int32(binary.BigEndian.Uint32(src))
if err != nil {
return err
}
switch dayOffset { switch dayOffset {
case infinityDayOffset: case infinityDayOffset:

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"time" "time"
@ -74,29 +75,17 @@ func (src *DateArray) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *DateArray) DecodeText(r io.Reader) error { func (dst *DateArray) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = DateArray{Status: Null} *dst = DateArray{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Date var elements []Date
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -104,8 +93,11 @@ func (dst *DateArray) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Date var elem Date
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -119,19 +111,14 @@ func (dst *DateArray) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *DateArray) DecodeBinary(r io.Reader) error { func (dst *DateArray) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = DateArray{Status: Null} *dst = DateArray{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -149,7 +136,14 @@ func (dst *DateArray) DecodeBinary(r io.Reader) error {
elements := make([]Date, elementCount) elements := make([]Date, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -237,6 +231,10 @@ func (src *DateArray) EncodeText(w io.Writer) error {
} }
func (src *DateArray) EncodeBinary(w io.Writer) error { func (src *DateArray) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, DateOID)
}
func (src *DateArray) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -257,7 +255,7 @@ func (src *DateArray) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = DateOID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"math" "math"
@ -92,24 +93,13 @@ func (src *Float4) AssignTo(dst interface{}) error {
return float64AssignTo(float64(src.Float), src.Status, dst) return float64AssignTo(float64(src.Float), src.Status, dst)
} }
func (dst *Float4) DecodeText(r io.Reader) error { func (dst *Float4) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Float4{Status: Null} *dst = Float4{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) n, err := strconv.ParseFloat(string(src), 32)
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseFloat(string(buf), 32)
if err != nil { if err != nil {
return err return err
} }
@ -118,25 +108,17 @@ func (dst *Float4) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Float4) DecodeBinary(r io.Reader) error { func (dst *Float4) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Float4{Status: Null} *dst = Float4{Status: Null}
return nil return nil
} }
if size != 4 { if len(src) != 4 {
return fmt.Errorf("invalid length for float4: %v", size) return fmt.Errorf("invalid length for float4: %v", len(src))
} }
n, err := pgio.ReadInt32(r) n := int32(binary.BigEndian.Uint32(src))
if err != nil {
return err
}
*dst = Float4{Float: math.Float32frombits(uint32(n)), Status: Present} *dst = Float4{Float: math.Float32frombits(uint32(n)), Status: Present}
return nil return nil

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
@ -73,29 +74,17 @@ func (src *Float4Array) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Float4Array) DecodeText(r io.Reader) error { func (dst *Float4Array) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Float4Array{Status: Null} *dst = Float4Array{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Float4 var elements []Float4
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -103,8 +92,11 @@ func (dst *Float4Array) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Float4 var elem Float4
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -118,19 +110,14 @@ func (dst *Float4Array) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Float4Array) DecodeBinary(r io.Reader) error { func (dst *Float4Array) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Float4Array{Status: Null} *dst = Float4Array{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -148,7 +135,14 @@ func (dst *Float4Array) DecodeBinary(r io.Reader) error {
elements := make([]Float4, elementCount) elements := make([]Float4, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -236,6 +230,10 @@ func (src *Float4Array) EncodeText(w io.Writer) error {
} }
func (src *Float4Array) EncodeBinary(w io.Writer) error { func (src *Float4Array) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, Float4OID)
}
func (src *Float4Array) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -256,7 +254,7 @@ func (src *Float4Array) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = Float4OID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"math" "math"
@ -82,24 +83,13 @@ func (src *Float8) AssignTo(dst interface{}) error {
return float64AssignTo(src.Float, src.Status, dst) return float64AssignTo(src.Float, src.Status, dst)
} }
func (dst *Float8) DecodeText(r io.Reader) error { func (dst *Float8) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Float8{Status: Null} *dst = Float8{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) n, err := strconv.ParseFloat(string(src), 64)
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseFloat(string(buf), 64)
if err != nil { if err != nil {
return err return err
} }
@ -108,25 +98,17 @@ func (dst *Float8) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Float8) DecodeBinary(r io.Reader) error { func (dst *Float8) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Float8{Status: Null} *dst = Float8{Status: Null}
return nil return nil
} }
if size != 8 { if len(src) != 8 {
return fmt.Errorf("invalid length for float4: %v", size) return fmt.Errorf("invalid length for float4: %v", len(src))
} }
n, err := pgio.ReadInt64(r) n := int64(binary.BigEndian.Uint64(src))
if err != nil {
return err
}
*dst = Float8{Float: math.Float64frombits(uint64(n)), Status: Present} *dst = Float8{Float: math.Float64frombits(uint64(n)), Status: Present}
return nil return nil

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
@ -73,29 +74,17 @@ func (src *Float8Array) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Float8Array) DecodeText(r io.Reader) error { func (dst *Float8Array) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Float8Array{Status: Null} *dst = Float8Array{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Float8 var elements []Float8
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -103,8 +92,11 @@ func (dst *Float8Array) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Float8 var elem Float8
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -118,19 +110,14 @@ func (dst *Float8Array) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Float8Array) DecodeBinary(r io.Reader) error { func (dst *Float8Array) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Float8Array{Status: Null} *dst = Float8Array{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -148,7 +135,14 @@ func (dst *Float8Array) DecodeBinary(r io.Reader) error {
elements := make([]Float8, elementCount) elements := make([]Float8, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -236,6 +230,10 @@ func (src *Float8Array) EncodeText(w io.Writer) error {
} }
func (src *Float8Array) EncodeBinary(w io.Writer) error { func (src *Float8Array) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, Float8OID)
}
func (src *Float8Array) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -256,7 +254,7 @@ func (src *Float8Array) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = Float8OID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

View File

@ -91,26 +91,16 @@ func (src *Inet) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Inet) DecodeText(r io.Reader) error { func (dst *Inet) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Inet{Status: Null} *dst = Inet{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size))
_, err = io.ReadFull(r, buf)
if err != nil {
return err
}
var ipnet *net.IPNet var ipnet *net.IPNet
var err error
if ip := net.ParseIP(string(buf)); ip != nil { if ip := net.ParseIP(string(src)); ip != nil {
ipv4 := ip.To4() ipv4 := ip.To4()
if ipv4 != nil { if ipv4 != nil {
ip = ipv4 ip = ipv4
@ -119,7 +109,7 @@ func (dst *Inet) DecodeText(r io.Reader) error {
mask := net.CIDRMask(bitCount, bitCount) mask := net.CIDRMask(bitCount, bitCount)
ipnet = &net.IPNet{Mask: mask, IP: ip} ipnet = &net.IPNet{Mask: mask, IP: ip}
} else { } else {
_, ipnet, err = net.ParseCIDR(string(buf)) _, ipnet, err = net.ParseCIDR(string(src))
if err != nil { if err != nil {
return err return err
} }
@ -129,50 +119,24 @@ func (dst *Inet) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Inet) DecodeBinary(r io.Reader) error { func (dst *Inet) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Inet{Status: Null} *dst = Inet{Status: Null}
return nil return nil
} }
if size != 8 && size != 20 { if len(src) != 8 && len(src) != 20 {
return fmt.Errorf("Received an invalid size for a inet: %d", size) return fmt.Errorf("Received an invalid size for a inet: %d", len(src))
} }
// ignore family // ignore family
_, err = pgio.ReadByte(r) bits := src[1]
if err != nil {
return err
}
bits, err := pgio.ReadByte(r)
if err != nil {
return err
}
// ignore is_cidr // ignore is_cidr
_, err = pgio.ReadByte(r) addressLength := src[3]
if err != nil {
return err
}
addressLength, err := pgio.ReadByte(r)
if err != nil {
return err
}
var ipnet net.IPNet var ipnet net.IPNet
ipnet.IP = make(net.IP, int(addressLength)) ipnet.IP = make(net.IP, int(addressLength))
_, err = r.Read(ipnet.IP) copy(ipnet.IP, src[4:])
if err != nil {
return err
}
ipnet.Mask = net.CIDRMask(int(bits), int(addressLength)*8) ipnet.Mask = net.CIDRMask(int(bits), int(addressLength)*8)
*dst = Inet{IPNet: &ipnet, Status: Present} *dst = Inet{IPNet: &ipnet, Status: Present}

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"net" "net"
@ -19,8 +20,7 @@ func (dst *InetArray) ConvertFrom(src interface{}) error {
switch value := src.(type) { switch value := src.(type) {
case InetArray: case InetArray:
*dst = value *dst = value
case CidrArray:
*dst = InetArray(value)
case []*net.IPNet: case []*net.IPNet:
if value == nil { if value == nil {
*dst = InetArray{Status: Null} *dst = InetArray{Status: Null}
@ -39,6 +39,7 @@ func (dst *InetArray) ConvertFrom(src interface{}) error {
Status: Present, Status: Present,
} }
} }
case []net.IP: case []net.IP:
if value == nil { if value == nil {
*dst = InetArray{Status: Null} *dst = InetArray{Status: Null}
@ -57,6 +58,7 @@ func (dst *InetArray) ConvertFrom(src interface{}) error {
Status: Present, Status: Present,
} }
} }
default: default:
if originalSrc, ok := underlyingSliceType(src); ok { if originalSrc, ok := underlyingSliceType(src); ok {
return dst.ConvertFrom(originalSrc) return dst.ConvertFrom(originalSrc)
@ -81,6 +83,7 @@ func (src *InetArray) AssignTo(dst interface{}) error {
} else { } else {
*v = nil *v = nil
} }
case *[]net.IP: case *[]net.IP:
if src.Status == Present { if src.Status == Present {
*v = make([]net.IP, len(src.Elements)) *v = make([]net.IP, len(src.Elements))
@ -103,29 +106,17 @@ func (src *InetArray) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *InetArray) DecodeText(r io.Reader) error { func (dst *InetArray) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = InetArray{Status: Null} *dst = InetArray{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Inet var elements []Inet
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -133,8 +124,11 @@ func (dst *InetArray) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Inet var elem Inet
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -148,19 +142,14 @@ func (dst *InetArray) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *InetArray) DecodeBinary(r io.Reader) error { func (dst *InetArray) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = InetArray{Status: Null} *dst = InetArray{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -178,7 +167,14 @@ func (dst *InetArray) DecodeBinary(r io.Reader) error {
elements := make([]Inet, elementCount) elements := make([]Inet, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"math" "math"
@ -88,24 +89,13 @@ func (src *Int2) AssignTo(dst interface{}) error {
return int64AssignTo(int64(src.Int), src.Status, dst) return int64AssignTo(int64(src.Int), src.Status, dst)
} }
func (dst *Int2) DecodeText(r io.Reader) error { func (dst *Int2) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int2{Status: Null} *dst = Int2{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) n, err := strconv.ParseInt(string(src), 10, 16)
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseInt(string(buf), 10, 16)
if err != nil { if err != nil {
return err return err
} }
@ -114,27 +104,18 @@ func (dst *Int2) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Int2) DecodeBinary(r io.Reader) error { func (dst *Int2) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int2{Status: Null} *dst = Int2{Status: Null}
return nil return nil
} }
if size != 2 { if len(src) != 2 {
return fmt.Errorf("invalid length for int2: %v", size) return fmt.Errorf("invalid length for int2: %v", len(src))
} }
n, err := pgio.ReadInt16(r) n := int16(binary.BigEndian.Uint16(src))
if err != nil { *dst = Int2{Int: n, Status: Present}
return err
}
*dst = Int2{Int: int16(n), Status: Present}
return nil return nil
} }

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
@ -104,29 +105,17 @@ func (src *Int2Array) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Int2Array) DecodeText(r io.Reader) error { func (dst *Int2Array) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int2Array{Status: Null} *dst = Int2Array{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Int2 var elements []Int2
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -134,8 +123,11 @@ func (dst *Int2Array) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Int2 var elem Int2
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -149,19 +141,14 @@ func (dst *Int2Array) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Int2Array) DecodeBinary(r io.Reader) error { func (dst *Int2Array) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int2Array{Status: Null} *dst = Int2Array{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -179,7 +166,14 @@ func (dst *Int2Array) DecodeBinary(r io.Reader) error {
elements := make([]Int2, elementCount) elements := make([]Int2, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -267,6 +261,10 @@ func (src *Int2Array) EncodeText(w io.Writer) error {
} }
func (src *Int2Array) EncodeBinary(w io.Writer) error { func (src *Int2Array) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, Int2OID)
}
func (src *Int2Array) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -287,7 +285,7 @@ func (src *Int2Array) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = Int2OID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"math" "math"
@ -79,24 +80,13 @@ func (src *Int4) AssignTo(dst interface{}) error {
return int64AssignTo(int64(src.Int), src.Status, dst) return int64AssignTo(int64(src.Int), src.Status, dst)
} }
func (dst *Int4) DecodeText(r io.Reader) error { func (dst *Int4) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int4{Status: Null} *dst = Int4{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) n, err := strconv.ParseInt(string(src), 10, 32)
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseInt(string(buf), 10, 32)
if err != nil { if err != nil {
return err return err
} }
@ -105,26 +95,17 @@ func (dst *Int4) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Int4) DecodeBinary(r io.Reader) error { func (dst *Int4) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int4{Status: Null} *dst = Int4{Status: Null}
return nil return nil
} }
if size != 4 { if len(src) != 4 {
return fmt.Errorf("invalid length for int4: %v", size) return fmt.Errorf("invalid length for int4: %v", len(src))
}
n, err := pgio.ReadInt32(r)
if err != nil {
return err
} }
n := int32(binary.BigEndian.Uint32(src))
*dst = Int4{Int: n, Status: Present} *dst = Int4{Int: n, Status: Present}
return nil return nil
} }

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
@ -104,29 +105,17 @@ func (src *Int4Array) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Int4Array) DecodeText(r io.Reader) error { func (dst *Int4Array) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int4Array{Status: Null} *dst = Int4Array{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Int4 var elements []Int4
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -134,8 +123,11 @@ func (dst *Int4Array) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Int4 var elem Int4
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -149,19 +141,14 @@ func (dst *Int4Array) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Int4Array) DecodeBinary(r io.Reader) error { func (dst *Int4Array) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int4Array{Status: Null} *dst = Int4Array{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -179,7 +166,14 @@ func (dst *Int4Array) DecodeBinary(r io.Reader) error {
elements := make([]Int4, elementCount) elements := make([]Int4, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -267,6 +261,10 @@ func (src *Int4Array) EncodeText(w io.Writer) error {
} }
func (src *Int4Array) EncodeBinary(w io.Writer) error { func (src *Int4Array) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, Int4OID)
}
func (src *Int4Array) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -287,7 +285,7 @@ func (src *Int4Array) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = Int4OID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"math" "math"
@ -70,24 +71,13 @@ func (src *Int8) AssignTo(dst interface{}) error {
return int64AssignTo(int64(src.Int), src.Status, dst) return int64AssignTo(int64(src.Int), src.Status, dst)
} }
func (dst *Int8) DecodeText(r io.Reader) error { func (dst *Int8) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int8{Status: Null} *dst = Int8{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) n, err := strconv.ParseInt(string(src), 10, 64)
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseInt(string(buf), 10, 64)
if err != nil { if err != nil {
return err return err
} }
@ -96,25 +86,17 @@ func (dst *Int8) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Int8) DecodeBinary(r io.Reader) error { func (dst *Int8) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int8{Status: Null} *dst = Int8{Status: Null}
return nil return nil
} }
if size != 8 { if len(src) != 8 {
return fmt.Errorf("invalid length for int8: %v", size) return fmt.Errorf("invalid length for int8: %v", len(src))
} }
n, err := pgio.ReadInt64(r) n := int64(binary.BigEndian.Uint64(src))
if err != nil {
return err
}
*dst = Int8{Int: n, Status: Present} *dst = Int8{Int: n, Status: Present}
return nil return nil

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
@ -104,29 +105,17 @@ func (src *Int8Array) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Int8Array) DecodeText(r io.Reader) error { func (dst *Int8Array) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int8Array{Status: Null} *dst = Int8Array{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Int8 var elements []Int8
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -134,8 +123,11 @@ func (dst *Int8Array) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Int8 var elem Int8
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -149,19 +141,14 @@ func (dst *Int8Array) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Int8Array) DecodeBinary(r io.Reader) error { func (dst *Int8Array) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Int8Array{Status: Null} *dst = Int8Array{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -179,7 +166,14 @@ func (dst *Int8Array) DecodeBinary(r io.Reader) error {
elements := make([]Int8, elementCount) elements := make([]Int8, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -267,6 +261,10 @@ func (src *Int8Array) EncodeText(w io.Writer) error {
} }
func (src *Int8Array) EncodeBinary(w io.Writer) error { func (src *Int8Array) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, Int8OID)
}
func (src *Int8Array) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -287,7 +285,7 @@ func (src *Int8Array) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = Int8OID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

View File

@ -27,12 +27,12 @@ func (src *Name) AssignTo(dst interface{}) error {
return (*Text)(src).AssignTo(dst) return (*Text)(src).AssignTo(dst)
} }
func (dst *Name) DecodeText(r io.Reader) error { func (dst *Name) DecodeText(src []byte) error {
return (*Text)(dst).DecodeText(r) return (*Text)(dst).DecodeText(src)
} }
func (dst *Name) DecodeBinary(r io.Reader) error { func (dst *Name) DecodeBinary(src []byte) error {
return (*Text)(dst).DecodeBinary(r) return (*Text)(dst).DecodeBinary(src)
} }
func (src Name) EncodeText(w io.Writer) error { func (src Name) EncodeText(w io.Writer) error {

View File

@ -24,12 +24,12 @@ func (src *OID) AssignTo(dst interface{}) error {
return (*pguint32)(src).AssignTo(dst) return (*pguint32)(src).AssignTo(dst)
} }
func (dst *OID) DecodeText(r io.Reader) error { func (dst *OID) DecodeText(src []byte) error {
return (*pguint32)(dst).DecodeText(r) return (*pguint32)(dst).DecodeText(src)
} }
func (dst *OID) DecodeBinary(r io.Reader) error { func (dst *OID) DecodeBinary(src []byte) error {
return (*pguint32)(dst).DecodeBinary(r) return (*pguint32)(dst).DecodeBinary(src)
} }
func (src OID) EncodeText(w io.Writer) error { func (src OID) EncodeText(w io.Writer) error {

View File

@ -74,11 +74,11 @@ type Value interface {
} }
type BinaryDecoder interface { type BinaryDecoder interface {
DecodeBinary(r io.Reader) error DecodeBinary(src []byte) error
} }
type TextDecoder interface { type TextDecoder interface {
DecodeText(r io.Reader) error DecodeText(src []byte) error
} }
type BinaryEncoder interface { type BinaryEncoder interface {

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
@ -51,24 +52,13 @@ func (src *pguint32) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *pguint32) DecodeText(r io.Reader) error { func (dst *pguint32) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = pguint32{Status: Null} *dst = pguint32{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) n, err := strconv.ParseUint(string(src), 10, 32)
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseUint(string(buf), 10, 32)
if err != nil { if err != nil {
return err return err
} }
@ -77,26 +67,17 @@ func (dst *pguint32) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *pguint32) DecodeBinary(r io.Reader) error { func (dst *pguint32) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = pguint32{Status: Null} *dst = pguint32{Status: Null}
return nil return nil
} }
if size != 4 { if len(src) != 4 {
return fmt.Errorf("invalid length: %v", size) return fmt.Errorf("invalid length: %v", len(src))
}
n, err := pgio.ReadUint32(r)
if err != nil {
return err
} }
n := binary.BigEndian.Uint32(src)
*dst = pguint32{Uint: n, Status: Present} *dst = pguint32{Uint: n, Status: Present}
return nil return nil
} }

View File

@ -106,27 +106,17 @@ func (src *QChar) AssignTo(dst interface{}) error {
return int64AssignTo(int64(src.Int), src.Status, dst) return int64AssignTo(int64(src.Int), src.Status, dst)
} }
func (dst *QChar) DecodeBinary(r io.Reader) error { func (dst *QChar) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = QChar{Status: Null} *dst = QChar{Status: Null}
return nil return nil
} }
if size != 1 { if len(src) != 1 {
return fmt.Errorf(`invalid length for "char": %v`, size) return fmt.Errorf(`invalid length for "char": %v`, len(src))
} }
byt, err := pgio.ReadByte(r) *dst = QChar{Int: int8(src[0]), Status: Present}
if err != nil {
return err
}
*dst = QChar{Int: int8(byt), Status: Present}
return nil return nil
} }

View File

@ -71,29 +71,18 @@ func (src *Text) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Text) DecodeText(r io.Reader) error { func (dst *Text) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Text{Status: Null} *dst = Text{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) *dst = Text{String: string(src), Status: Present}
_, err = r.Read(buf)
if err != nil {
return err
}
*dst = Text{String: string(buf), Status: Present}
return nil return nil
} }
func (dst *Text) DecodeBinary(r io.Reader) error { func (dst *Text) DecodeBinary(src []byte) error {
return dst.DecodeText(r) return dst.DecodeText(src)
} }
func (src Text) EncodeText(w io.Writer) error { func (src Text) EncodeText(w io.Writer) error {

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
@ -73,29 +74,17 @@ func (src *TextArray) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *TextArray) DecodeText(r io.Reader) error { func (dst *TextArray) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = TextArray{Status: Null} *dst = TextArray{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Text var elements []Text
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -103,8 +92,11 @@ func (dst *TextArray) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Text var elem Text
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -118,19 +110,14 @@ func (dst *TextArray) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *TextArray) DecodeBinary(r io.Reader) error { func (dst *TextArray) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = TextArray{Status: Null} *dst = TextArray{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -148,7 +135,14 @@ func (dst *TextArray) DecodeBinary(r io.Reader) error {
elements := make([]Text, elementCount) elements := make([]Text, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -211,7 +205,12 @@ func (src *TextArray) EncodeText(w io.Writer) error {
} }
textElementWriter.Reset() textElementWriter.Reset()
if elem.String == "" && elem.Status == Present { if elem.Status == Null {
_, err := io.WriteString(buf, `"NULL"`)
if err != nil {
return err
}
} else if elem.String == "" {
_, err := io.WriteString(buf, `""`) _, err := io.WriteString(buf, `""`)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
@ -72,24 +73,13 @@ func (src *Timestamp) AssignTo(dst interface{}) error {
// DecodeText decodes from src into dst. The decoded time is considered to // DecodeText decodes from src into dst. The decoded time is considered to
// be in UTC. // be in UTC.
func (dst *Timestamp) DecodeText(r io.Reader) error { func (dst *Timestamp) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Timestamp{Status: Null} *dst = Timestamp{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) sbuf := string(src)
_, err = r.Read(buf)
if err != nil {
return err
}
sbuf := string(buf)
switch sbuf { switch sbuf {
case "infinity": case "infinity":
*dst = Timestamp{Status: Present, InfinityModifier: Infinity} *dst = Timestamp{Status: Present, InfinityModifier: Infinity}
@ -109,25 +99,17 @@ func (dst *Timestamp) DecodeText(r io.Reader) error {
// DecodeBinary decodes from src into dst. The decoded time is considered to // DecodeBinary decodes from src into dst. The decoded time is considered to
// be in UTC. // be in UTC.
func (dst *Timestamp) DecodeBinary(r io.Reader) error { func (dst *Timestamp) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Timestamp{Status: Null} *dst = Timestamp{Status: Null}
return nil return nil
} }
if size != 8 { if len(src) != 8 {
return fmt.Errorf("invalid length for timestamp: %v", size) return fmt.Errorf("invalid length for timestamp: %v", len(src))
} }
microsecSinceY2K, err := pgio.ReadInt64(r) microsecSinceY2K := int64(binary.BigEndian.Uint64(src))
if err != nil {
return err
}
switch microsecSinceY2K { switch microsecSinceY2K {
case infinityMicrosecondOffset: case infinityMicrosecondOffset:

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"time" "time"
@ -74,29 +75,17 @@ func (src *TimestampArray) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *TimestampArray) DecodeText(r io.Reader) error { func (dst *TimestampArray) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = TimestampArray{Status: Null} *dst = TimestampArray{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Timestamp var elements []Timestamp
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -104,8 +93,11 @@ func (dst *TimestampArray) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Timestamp var elem Timestamp
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -119,19 +111,14 @@ func (dst *TimestampArray) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *TimestampArray) DecodeBinary(r io.Reader) error { func (dst *TimestampArray) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = TimestampArray{Status: Null} *dst = TimestampArray{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -149,7 +136,14 @@ func (dst *TimestampArray) DecodeBinary(r io.Reader) error {
elements := make([]Timestamp, elementCount) elements := make([]Timestamp, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -237,6 +231,10 @@ func (src *TimestampArray) EncodeText(w io.Writer) error {
} }
func (src *TimestampArray) EncodeBinary(w io.Writer) error { func (src *TimestampArray) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, TimestampOID)
}
func (src *TimestampArray) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -257,7 +255,7 @@ func (src *TimestampArray) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = TimestampOID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"encoding/binary"
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
@ -71,24 +72,13 @@ func (src *Timestamptz) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *Timestamptz) DecodeText(r io.Reader) error { func (dst *Timestamptz) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Timestamptz{Status: Null} *dst = Timestamptz{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) sbuf := string(src)
_, err = r.Read(buf)
if err != nil {
return err
}
sbuf := string(buf)
switch sbuf { switch sbuf {
case "infinity": case "infinity":
*dst = Timestamptz{Status: Present, InfinityModifier: Infinity} *dst = Timestamptz{Status: Present, InfinityModifier: Infinity}
@ -115,25 +105,17 @@ func (dst *Timestamptz) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *Timestamptz) DecodeBinary(r io.Reader) error { func (dst *Timestamptz) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = Timestamptz{Status: Null} *dst = Timestamptz{Status: Null}
return nil return nil
} }
if size != 8 { if len(src) != 8 {
return fmt.Errorf("invalid length for timestamptz: %v", size) return fmt.Errorf("invalid length for timestamptz: %v", len(src))
} }
microsecSinceY2K, err := pgio.ReadInt64(r) microsecSinceY2K := int64(binary.BigEndian.Uint64(src))
if err != nil {
return err
}
switch microsecSinceY2K { switch microsecSinceY2K {
case infinityMicrosecondOffset: case infinityMicrosecondOffset:

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"time" "time"
@ -74,29 +75,17 @@ func (src *TimestamptzArray) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *TimestamptzArray) DecodeText(r io.Reader) error { func (dst *TimestamptzArray) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = TimestamptzArray{Status: Null} *dst = TimestamptzArray{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Timestamptz var elements []Timestamptz
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -104,8 +93,11 @@ func (dst *TimestamptzArray) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem Timestamptz var elem Timestamptz
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -119,19 +111,14 @@ func (dst *TimestamptzArray) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *TimestamptzArray) DecodeBinary(r io.Reader) error { func (dst *TimestamptzArray) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = TimestamptzArray{Status: Null} *dst = TimestamptzArray{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -149,7 +136,14 @@ func (dst *TimestamptzArray) DecodeBinary(r io.Reader) error {
elements := make([]Timestamptz, elementCount) elements := make([]Timestamptz, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -237,6 +231,10 @@ func (src *TimestamptzArray) EncodeText(w io.Writer) error {
} }
func (src *TimestamptzArray) EncodeBinary(w io.Writer) error { func (src *TimestamptzArray) EncodeBinary(w io.Writer) error {
return src.encodeBinary(w, TimestamptzOID)
}
func (src *TimestamptzArray) encodeBinary(w io.Writer, elementOID int32) error {
if done, err := encodeNotPresent(w, src.Status); done { if done, err := encodeNotPresent(w, src.Status); done {
return err return err
} }
@ -257,7 +255,7 @@ func (src *TimestamptzArray) EncodeBinary(w io.Writer) error {
} }
} }
arrayHeader.ElementOID = TimestamptzOID arrayHeader.ElementOID = elementOID
arrayHeader.Dimensions = src.Dimensions arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length - // TODO - consider how to avoid having to buffer array before writing length -

9
pgtype/to-consider.txt Normal file
View File

@ -0,0 +1,9 @@
DecodeText and DecodeBinary take []byte instead of io.Reader
EncodeText and EncodeBinary do not write size
Add Nullable interface with IsNull() and SetNull()
The above would keep types from needing to worry about writing their own size. Could make EncodeText and DecodeText easier to use with sql.Scanner and driver.Valuer. SetNull() could be removed as DecodeText and DecodeBinary could interpret a nil slice as null.
EncodeText and EncodeBinary could return (null bool, err error). That would finish removing Nullable interface.
Also, consider whether arrays and ranges could be represented as generic data types or more common code could be extracted instead of using code generation.

View File

@ -73,29 +73,17 @@ func (src *<%= pgtype_array_type %>) AssignTo(dst interface{}) error {
return nil return nil
} }
func (dst *<%= pgtype_array_type %>) DecodeText(r io.Reader) error { func (dst *<%= pgtype_array_type %>) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = <%= pgtype_array_type %>{Status: Null} *dst = <%= pgtype_array_type %>{Status: Null}
return nil return nil
} }
buf := make([]byte, int(size)) uta, err := ParseUntypedTextArray(string(src))
_, err = io.ReadFull(r, buf)
if err != nil { if err != nil {
return err return err
} }
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []<%= pgtype_element_type %> var elements []<%= pgtype_element_type %>
if len(uta.Elements) > 0 { if len(uta.Elements) > 0 {
@ -103,8 +91,11 @@ func (dst *<%= pgtype_array_type %>) DecodeText(r io.Reader) error {
for i, s := range uta.Elements { for i, s := range uta.Elements {
var elem <%= pgtype_element_type %> var elem <%= pgtype_element_type %>
textElementReader.Reset(s) var elemSrc []byte
err = elem.DecodeText(textElementReader) if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -118,19 +109,14 @@ func (dst *<%= pgtype_array_type %>) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *<%= pgtype_array_type %>) DecodeBinary(r io.Reader) error { func (dst *<%= pgtype_array_type %>) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
*dst = <%= pgtype_array_type %>{Status: Null} *dst = <%= pgtype_array_type %>{Status: Null}
return nil return nil
} }
var arrayHeader ArrayHeader var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r) rp, err := arrayHeader.DecodeBinary(src)
if err != nil { if err != nil {
return err return err
} }
@ -148,7 +134,14 @@ func (dst *<%= pgtype_array_type %>) DecodeBinary(r io.Reader) error {
elements := make([]<%= pgtype_element_type %>, elementCount) elements := make([]<%= pgtype_element_type %>, elementCount)
for i := range elements { for i := range elements {
err = elements[i].DecodeBinary(r) elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp:rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(elemSrc)
if err != nil { if err != nil {
return err return err
} }
@ -211,16 +204,9 @@ func (src *<%= pgtype_array_type %>) EncodeText(w io.Writer) error {
} }
textElementWriter.Reset() textElementWriter.Reset()
if elem.String == "" && elem.Status == Present { err = elem.EncodeText(textElementWriter)
_, err := io.WriteString(buf, `""`) if err != nil {
if err != nil { return err
return err
}
} else {
err = elem.EncodeText(textElementWriter)
if err != nil {
return err
}
} }
for _, dec := range dimElemCounts { for _, dec := range dimElemCounts {

View File

@ -14,12 +14,12 @@ func (src *VarcharArray) AssignTo(dst interface{}) error {
return (*TextArray)(src).AssignTo(dst) return (*TextArray)(src).AssignTo(dst)
} }
func (dst *VarcharArray) DecodeText(r io.Reader) error { func (dst *VarcharArray) DecodeText(src []byte) error {
return (*TextArray)(dst).DecodeText(r) return (*TextArray)(dst).DecodeText(src)
} }
func (dst *VarcharArray) DecodeBinary(r io.Reader) error { func (dst *VarcharArray) DecodeBinary(src []byte) error {
return (*TextArray)(dst).DecodeBinary(r) return (*TextArray)(dst).DecodeBinary(src)
} }
func (src *VarcharArray) EncodeText(w io.Writer) error { func (src *VarcharArray) EncodeText(w io.Writer) error {

View File

@ -33,12 +33,12 @@ func (src *XID) AssignTo(dst interface{}) error {
return (*pguint32)(src).AssignTo(dst) return (*pguint32)(src).AssignTo(dst)
} }
func (dst *XID) DecodeText(r io.Reader) error { func (dst *XID) DecodeText(src []byte) error {
return (*pguint32)(dst).DecodeText(r) return (*pguint32)(dst).DecodeText(src)
} }
func (dst *XID) DecodeBinary(r io.Reader) error { func (dst *XID) DecodeBinary(src []byte) error {
return (*pguint32)(dst).DecodeBinary(r) return (*pguint32)(dst).DecodeBinary(src)
} }
func (src XID) EncodeText(w io.Writer) error { func (src XID) EncodeText(w io.Writer) error {

View File

@ -231,14 +231,12 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
rows.Fatal(scanArgError{col: i, err: err}) rows.Fatal(scanArgError{col: i, err: err})
} }
} else if s, ok := d.(pgtype.BinaryDecoder); ok && vr.Type().FormatCode == BinaryFormatCode { } else if s, ok := d.(pgtype.BinaryDecoder); ok && vr.Type().FormatCode == BinaryFormatCode {
vr.err = errRewoundLen err = s.DecodeBinary(vr.bytes())
err = s.DecodeBinary(&valueReader2{vr})
if err != nil { if err != nil {
rows.Fatal(scanArgError{col: i, err: err}) rows.Fatal(scanArgError{col: i, err: err})
} }
} else if s, ok := d.(pgtype.TextDecoder); ok && vr.Type().FormatCode == TextFormatCode { } else if s, ok := d.(pgtype.TextDecoder); ok && vr.Type().FormatCode == TextFormatCode {
vr.err = errRewoundLen err = s.DecodeText(vr.bytes())
err = s.DecodeText(&valueReader2{vr})
if err != nil { if err != nil {
rows.Fatal(scanArgError{col: i, err: err}) rows.Fatal(scanArgError{col: i, err: err})
} }
@ -290,8 +288,7 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
switch vr.Type().FormatCode { switch vr.Type().FormatCode {
case TextFormatCode: case TextFormatCode:
if textDecoder, ok := pgVal.(pgtype.TextDecoder); ok { if textDecoder, ok := pgVal.(pgtype.TextDecoder); ok {
vr.err = errRewoundLen err = textDecoder.DecodeText(vr.bytes())
err = textDecoder.DecodeText(&valueReader2{vr})
if err != nil { if err != nil {
vr.Fatal(err) vr.Fatal(err)
} }
@ -300,8 +297,7 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
} }
case BinaryFormatCode: case BinaryFormatCode:
if binaryDecoder, ok := pgVal.(pgtype.BinaryDecoder); ok { if binaryDecoder, ok := pgVal.(pgtype.BinaryDecoder); ok {
vr.err = errRewoundLen err = binaryDecoder.DecodeBinary(vr.bytes())
err = binaryDecoder.DecodeBinary(&valueReader2{vr})
if err != nil { if err != nil {
vr.Fatal(err) vr.Fatal(err)
} }

View File

@ -4,8 +4,6 @@ import (
"errors" "errors"
) )
var errRewoundLen = errors.New("len was rewound")
// ValueReader is used by the Scanner interface to decode values. // ValueReader is used by the Scanner interface to decode values.
type ValueReader struct { type ValueReader struct {
mr *msgReader mr *msgReader
@ -157,27 +155,10 @@ func (r *ValueReader) ReadBytes(count int32) []byte {
return r.mr.readBytes(count) return r.mr.readBytes(count)
} }
type valueReader2 struct { // bytes is a compatibility function for pgtype.TextDecoder and pgtype.BinaryDecoder
*ValueReader func (r *ValueReader) bytes() []byte {
} if r.Len() >= 0 {
return r.ReadBytes(r.Len())
func (r *valueReader2) Read(dst []byte) (int, error) {
if r.err != nil {
return 0, r.err
} }
return nil
src := r.ReadBytes(int32(len(dst)))
copy(dst, src)
return len(dst), nil
}
func (r *valueReader2) ReadUint32() (uint32, error) {
if r.err == errRewoundLen {
r.err = nil
return uint32(r.Len()), nil
}
return r.ValueReader.ReadUint32(), nil
} }

View File

@ -3,6 +3,7 @@ package pgx
import ( import (
"bytes" "bytes"
"database/sql/driver" "database/sql/driver"
"encoding/binary"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -455,23 +456,12 @@ func (n NullInt32) Encode(w *WriteBuf, oid OID) error {
// in the PostgreSQL sources. OID cannot be NULL. To allow for NULL OIDs use pgtype.OID. // in the PostgreSQL sources. OID cannot be NULL. To allow for NULL OIDs use pgtype.OID.
type OID uint32 type OID uint32
func (dst *OID) DecodeText(r io.Reader) error { func (dst *OID) DecodeText(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
return fmt.Errorf("cannot decode nil into OID") return fmt.Errorf("cannot decode nil into OID")
} }
buf := make([]byte, int(size)) n, err := strconv.ParseUint(string(src), 10, 32)
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseUint(string(buf), 10, 32)
if err != nil { if err != nil {
return err return err
} }
@ -480,25 +470,16 @@ func (dst *OID) DecodeText(r io.Reader) error {
return nil return nil
} }
func (dst *OID) DecodeBinary(r io.Reader) error { func (dst *OID) DecodeBinary(src []byte) error {
size, err := pgio.ReadInt32(r) if src == nil {
if err != nil {
return err
}
if size == -1 {
return fmt.Errorf("cannot decode nil into OID") return fmt.Errorf("cannot decode nil into OID")
} }
if size != 4 { if len(src) != 4 {
return fmt.Errorf("invalid length for OID: %v", size) return fmt.Errorf("invalid length: %v", len(src))
}
n, err := pgio.ReadUint32(r)
if err != nil {
return err
} }
n := binary.BigEndian.Uint32(src)
*dst = OID(n) *dst = OID(n)
return nil return nil
} }
@ -1020,15 +1001,13 @@ func decodeBool(vr *ValueReader) bool {
return false return false
} }
vr.err = errRewoundLen
var b pgtype.Bool var b pgtype.Bool
var err error var err error
switch vr.Type().FormatCode { switch vr.Type().FormatCode {
case TextFormatCode: case TextFormatCode:
err = b.DecodeText(&valueReader2{vr}) err = b.DecodeText(vr.bytes())
case BinaryFormatCode: case BinaryFormatCode:
err = b.DecodeBinary(&valueReader2{vr}) err = b.DecodeBinary(vr.bytes())
default: default:
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode))) vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
return false return false
@ -1081,15 +1060,13 @@ func decodeInt8(vr *ValueReader) int64 {
return 0 return 0
} }
vr.err = errRewoundLen
var n pgtype.Int8 var n pgtype.Int8
var err error var err error
switch vr.Type().FormatCode { switch vr.Type().FormatCode {
case TextFormatCode: case TextFormatCode:
err = n.DecodeText(&valueReader2{vr}) err = n.DecodeText(vr.bytes())
case BinaryFormatCode: case BinaryFormatCode:
err = n.DecodeBinary(&valueReader2{vr}) err = n.DecodeBinary(vr.bytes())
default: default:
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode))) vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
return 0 return 0
@ -1115,15 +1092,13 @@ func decodeInt2(vr *ValueReader) int16 {
return 0 return 0
} }
vr.err = errRewoundLen
var n pgtype.Int2 var n pgtype.Int2
var err error var err error
switch vr.Type().FormatCode { switch vr.Type().FormatCode {
case TextFormatCode: case TextFormatCode:
err = n.DecodeText(&valueReader2{vr}) err = n.DecodeText(vr.bytes())
case BinaryFormatCode: case BinaryFormatCode:
err = n.DecodeBinary(&valueReader2{vr}) err = n.DecodeBinary(vr.bytes())
default: default:
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode))) vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
return 0 return 0
@ -1153,15 +1128,13 @@ func decodeInt4(vr *ValueReader) int32 {
return 0 return 0
} }
vr.err = errRewoundLen
var n pgtype.Int4 var n pgtype.Int4
var err error var err error
switch vr.Type().FormatCode { switch vr.Type().FormatCode {
case TextFormatCode: case TextFormatCode:
err = n.DecodeText(&valueReader2{vr}) err = n.DecodeText(vr.bytes())
case BinaryFormatCode: case BinaryFormatCode:
err = n.DecodeBinary(&valueReader2{vr}) err = n.DecodeBinary(vr.bytes())
default: default:
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode))) vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
return 0 return 0
@ -1455,15 +1428,13 @@ func decodeDate(vr *ValueReader) time.Time {
return time.Time{} return time.Time{}
} }
vr.err = errRewoundLen
var d pgtype.Date var d pgtype.Date
var err error var err error
switch vr.Type().FormatCode { switch vr.Type().FormatCode {
case TextFormatCode: case TextFormatCode:
err = d.DecodeText(&valueReader2{vr}) err = d.DecodeText(vr.bytes())
case BinaryFormatCode: case BinaryFormatCode:
err = d.DecodeBinary(&valueReader2{vr}) err = d.DecodeBinary(vr.bytes())
default: default:
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode))) vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
return time.Time{} return time.Time{}
@ -1518,15 +1489,13 @@ func decodeTimestampTz(vr *ValueReader) time.Time {
return zeroTime return zeroTime
} }
vr.err = errRewoundLen
var t pgtype.Timestamptz var t pgtype.Timestamptz
var err error var err error
switch vr.Type().FormatCode { switch vr.Type().FormatCode {
case TextFormatCode: case TextFormatCode:
err = t.DecodeText(&valueReader2{vr}) err = t.DecodeText(vr.bytes())
case BinaryFormatCode: case BinaryFormatCode:
err = t.DecodeBinary(&valueReader2{vr}) err = t.DecodeBinary(vr.bytes())
default: default:
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode))) vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
return time.Time{} return time.Time{}