mirror of https://github.com/jackc/pgx.git
pgtype.Encode(Binary|Text) do not write length
To aid in composability, these methods no longer write their own length. This is especially useful for text formatted arrays and may be useful for future database/sql compatibility. It also makes the code a little simpler as the types no longer have to compute their own size. Along with this, these methods cannot encode NULL. They now return a boolean if they are NULL. This also benefits text array encoding as numeric arrays require NULL to be exactly `NULL` while string arrays require NULL to be `"NULL"`.v3-numeric-wip
parent
6c26c3a4a3
commit
1f3e484ca1
|
@ -5,8 +5,6 @@ import (
|
|||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/jackc/pgx/pgio"
|
||||
)
|
||||
|
||||
type Bool struct {
|
||||
|
@ -100,14 +98,12 @@ func (dst *Bool) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Bool) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 1)
|
||||
if err != nil {
|
||||
return nil
|
||||
func (src Bool) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
|
@ -117,18 +113,16 @@ func (src Bool) EncodeText(w io.Writer) error {
|
|||
buf = []byte{'f'}
|
||||
}
|
||||
|
||||
_, err = w.Write(buf)
|
||||
return err
|
||||
_, err := w.Write(buf)
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Bool) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 1)
|
||||
if err != nil {
|
||||
return nil
|
||||
func (src Bool) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
|
@ -138,6 +132,6 @@ func (src Bool) EncodeBinary(w io.Writer) error {
|
|||
buf = []byte{0}
|
||||
}
|
||||
|
||||
_, err = w.Write(buf)
|
||||
return err
|
||||
_, err := w.Write(buf)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -152,26 +152,22 @@ func (dst *BoolArray) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *BoolArray) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *BoolArray) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -185,100 +181,112 @@ func (src *BoolArray) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *BoolArray) EncodeBinary(w io.Writer) error {
|
||||
func (src *BoolArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, BoolOID)
|
||||
}
|
||||
|
||||
func (src *BoolArray) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *BoolArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/jackc/pgx/pgio"
|
||||
)
|
||||
|
||||
type Bytea struct {
|
||||
|
@ -101,37 +99,31 @@ func (dst *Bytea) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Bytea) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Bytea) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
str := hex.EncodeToString(src.Bytes)
|
||||
|
||||
_, err := pgio.WriteInt32(w, int32(len(str)+2))
|
||||
_, err := io.WriteString(w, `\x`)
|
||||
if err != nil {
|
||||
return nil
|
||||
return false, err
|
||||
}
|
||||
|
||||
_, err = io.WriteString(w, `\x`)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = io.WriteString(w, str)
|
||||
return err
|
||||
_, err = io.WriteString(w, hex.EncodeToString(src.Bytes))
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Bytea) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Bytea) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, int32(len(src.Bytes)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = w.Write(src.Bytes)
|
||||
return err
|
||||
_, err := w.Write(src.Bytes)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -38,10 +38,10 @@ func (dst *CID) DecodeBinary(src []byte) error {
|
|||
return (*pguint32)(dst).DecodeBinary(src)
|
||||
}
|
||||
|
||||
func (src CID) EncodeText(w io.Writer) error {
|
||||
func (src CID) EncodeText(w io.Writer) (bool, error) {
|
||||
return (pguint32)(src).EncodeText(w)
|
||||
}
|
||||
|
||||
func (src CID) EncodeBinary(w io.Writer) error {
|
||||
func (src CID) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return (pguint32)(src).EncodeBinary(w)
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@ func (dst *CidrArray) DecodeBinary(src []byte) error {
|
|||
return (*InetArray)(dst).DecodeBinary(src)
|
||||
}
|
||||
|
||||
func (src *CidrArray) EncodeText(w io.Writer) error {
|
||||
func (src *CidrArray) EncodeText(w io.Writer) (bool, error) {
|
||||
return (*InetArray)(src).EncodeText(w)
|
||||
}
|
||||
|
||||
func (src *CidrArray) EncodeBinary(w io.Writer) error {
|
||||
func (src *CidrArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return (*InetArray)(src).encodeBinary(w, CidrOID)
|
||||
}
|
||||
|
|
|
@ -116,9 +116,12 @@ func (dst *Date) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Date) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Date) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var s string
|
||||
|
@ -132,23 +135,16 @@ func (src Date) EncodeText(w io.Writer) error {
|
|||
s = "-infinity"
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, s)
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Date) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
func (src Date) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var daysSinceDateEpoch int32
|
||||
|
@ -165,6 +161,6 @@ func (src Date) EncodeBinary(w io.Writer) error {
|
|||
daysSinceDateEpoch = negativeInfinityDayOffset
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, daysSinceDateEpoch)
|
||||
return err
|
||||
_, err := pgio.WriteInt32(w, daysSinceDateEpoch)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -153,26 +153,22 @@ func (dst *DateArray) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *DateArray) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *DateArray) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -186,100 +182,112 @@ func (src *DateArray) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *DateArray) EncodeBinary(w io.Writer) error {
|
||||
func (src *DateArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, DateOID)
|
||||
}
|
||||
|
||||
func (src *DateArray) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *DateArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -124,30 +124,26 @@ func (dst *Float4) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Float4) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Float4) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
s := strconv.FormatFloat(float64(src.Float), 'f', -1, 32)
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, strconv.FormatFloat(float64(src.Float), 'f', -1, 32))
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Float4) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Float4) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(math.Float32bits(src.Float)))
|
||||
return err
|
||||
_, err := pgio.WriteInt32(w, int32(math.Float32bits(src.Float)))
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -152,26 +152,22 @@ func (dst *Float4Array) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *Float4Array) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Float4Array) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -185,100 +181,112 @@ func (src *Float4Array) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *Float4Array) EncodeBinary(w io.Writer) error {
|
||||
func (src *Float4Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, Float4OID)
|
||||
}
|
||||
|
||||
func (src *Float4Array) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Float4Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -114,30 +114,26 @@ func (dst *Float8) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Float8) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Float8) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
s := strconv.FormatFloat(float64(src.Float), 'f', -1, 64)
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, strconv.FormatFloat(float64(src.Float), 'f', -1, 64))
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Float8) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Float8) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt64(w, int64(math.Float64bits(src.Float)))
|
||||
return err
|
||||
_, err := pgio.WriteInt64(w, int64(math.Float64bits(src.Float)))
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -152,26 +152,22 @@ func (dst *Float8Array) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *Float8Array) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Float8Array) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -185,100 +181,112 @@ func (src *Float8Array) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *Float8Array) EncodeBinary(w io.Writer) error {
|
||||
func (src *Float8Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, Float8OID)
|
||||
}
|
||||
|
||||
func (src *Float8Array) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Float8Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -144,61 +144,55 @@ func (dst *Inet) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Inet) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Inet) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
s := src.IPNet.String()
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, src.IPNet.String())
|
||||
return false, err
|
||||
}
|
||||
|
||||
// EncodeBinary encodes src into w.
|
||||
func (src Inet) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Inet) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var size int32
|
||||
var family byte
|
||||
switch len(src.IPNet.IP) {
|
||||
case net.IPv4len:
|
||||
size = 8
|
||||
family = defaultAFInet
|
||||
case net.IPv6len:
|
||||
size = 20
|
||||
family = defaultAFInet6
|
||||
default:
|
||||
return fmt.Errorf("Unexpected IP length: %v", len(src.IPNet.IP))
|
||||
}
|
||||
|
||||
if _, err := pgio.WriteInt32(w, size); err != nil {
|
||||
return err
|
||||
return false, fmt.Errorf("Unexpected IP length: %v", len(src.IPNet.IP))
|
||||
}
|
||||
|
||||
if err := pgio.WriteByte(w, family); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
ones, _ := src.IPNet.Mask.Size()
|
||||
if err := pgio.WriteByte(w, byte(ones)); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// is_cidr is ignored on server
|
||||
if err := pgio.WriteByte(w, 0); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := pgio.WriteByte(w, byte(len(src.IPNet.IP))); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
_, err := w.Write(src.IPNet.IP)
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -184,26 +184,22 @@ func (dst *InetArray) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *InetArray) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *InetArray) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -217,100 +213,112 @@ func (src *InetArray) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *InetArray) EncodeBinary(w io.Writer) error {
|
||||
func (src *InetArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, InetOID)
|
||||
}
|
||||
|
||||
func (src *InetArray) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *InetArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -119,30 +119,26 @@ func (dst *Int2) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Int2) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Int2) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
s := strconv.FormatInt(int64(src.Int), 10)
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, strconv.FormatInt(int64(src.Int), 10))
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Int2) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Int2) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt16(w, src.Int)
|
||||
return err
|
||||
_, err := pgio.WriteInt16(w, src.Int)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -183,26 +183,22 @@ func (dst *Int2Array) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *Int2Array) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Int2Array) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -216,100 +212,112 @@ func (src *Int2Array) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *Int2Array) EncodeBinary(w io.Writer) error {
|
||||
func (src *Int2Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, Int2OID)
|
||||
}
|
||||
|
||||
func (src *Int2Array) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Int2Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -110,30 +110,26 @@ func (dst *Int4) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Int4) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Int4) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
s := strconv.FormatInt(int64(src.Int), 10)
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, strconv.FormatInt(int64(src.Int), 10))
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Int4) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Int4) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, src.Int)
|
||||
return err
|
||||
_, err := pgio.WriteInt32(w, src.Int)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -183,26 +183,22 @@ func (dst *Int4Array) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *Int4Array) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Int4Array) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -216,100 +212,112 @@ func (src *Int4Array) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *Int4Array) EncodeBinary(w io.Writer) error {
|
||||
func (src *Int4Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, Int4OID)
|
||||
}
|
||||
|
||||
func (src *Int4Array) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Int4Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -102,30 +102,26 @@ func (dst *Int8) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Int8) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Int8) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
s := strconv.FormatInt(src.Int, 10)
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, strconv.FormatInt(src.Int, 10))
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Int8) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Int8) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt64(w, src.Int)
|
||||
return err
|
||||
_, err := pgio.WriteInt64(w, src.Int)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -183,26 +183,22 @@ func (dst *Int8Array) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *Int8Array) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Int8Array) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -216,100 +212,112 @@ func (src *Int8Array) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *Int8Array) EncodeBinary(w io.Writer) error {
|
||||
func (src *Int8Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, Int8OID)
|
||||
}
|
||||
|
||||
func (src *Int8Array) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *Int8Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -35,10 +35,10 @@ func (dst *Name) DecodeBinary(src []byte) error {
|
|||
return (*Text)(dst).DecodeBinary(src)
|
||||
}
|
||||
|
||||
func (src Name) EncodeText(w io.Writer) error {
|
||||
func (src Name) EncodeText(w io.Writer) (bool, error) {
|
||||
return (Text)(src).EncodeText(w)
|
||||
}
|
||||
|
||||
func (src Name) EncodeBinary(w io.Writer) error {
|
||||
func (src Name) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return (Text)(src).EncodeBinary(w)
|
||||
}
|
||||
|
|
|
@ -32,10 +32,10 @@ func (dst *OID) DecodeBinary(src []byte) error {
|
|||
return (*pguint32)(dst).DecodeBinary(src)
|
||||
}
|
||||
|
||||
func (src OID) EncodeText(w io.Writer) error {
|
||||
func (src OID) EncodeText(w io.Writer) (bool, error) {
|
||||
return (pguint32)(src).EncodeText(w)
|
||||
}
|
||||
|
||||
func (src OID) EncodeBinary(w io.Writer) error {
|
||||
func (src OID) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return (pguint32)(src).EncodeBinary(w)
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ package pgtype
|
|||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/jackc/pgx/pgio"
|
||||
)
|
||||
|
||||
// PostgreSQL oids for common types
|
||||
|
@ -81,23 +79,24 @@ type TextDecoder interface {
|
|||
DecodeText(src []byte) error
|
||||
}
|
||||
|
||||
// BinaryEncoder is implemented by types that can encode themselves into the
|
||||
// PostgreSQL binary wire format.
|
||||
type BinaryEncoder interface {
|
||||
EncodeBinary(w io.Writer) error
|
||||
// EncodeBinary should encode the binary format of self to w. If self is the
|
||||
// SQL value NULL then write nothing and return (true, nil). The caller of
|
||||
// EncodeBinary is responsible for writing the correct NULL value or the
|
||||
// length of the data written.
|
||||
EncodeBinary(w io.Writer) (null bool, err error)
|
||||
}
|
||||
|
||||
// TextEncoder is implemented by types that can encode themselves into the
|
||||
// PostgreSQL text wire format.
|
||||
type TextEncoder interface {
|
||||
EncodeText(w io.Writer) error
|
||||
// EncodeText should encode the text format of self to w. If self is the SQL
|
||||
// value NULL then write nothing and return (true, nil). The caller of
|
||||
// EncodeText is responsible for writing the correct NULL value or the length
|
||||
// of the data written.
|
||||
EncodeText(w io.Writer) (null bool, err error)
|
||||
}
|
||||
|
||||
var errUndefined = errors.New("cannot encode status undefined")
|
||||
|
||||
func encodeNotPresent(w io.Writer, status Status) (done bool, err error) {
|
||||
switch status {
|
||||
case Undefined:
|
||||
return true, errUndefined
|
||||
case Null:
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
return true, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ type forceTextEncoder struct {
|
|||
e pgtype.TextEncoder
|
||||
}
|
||||
|
||||
func (f forceTextEncoder) EncodeText(w io.Writer) error {
|
||||
func (f forceTextEncoder) EncodeText(w io.Writer) (bool, error) {
|
||||
return f.e.EncodeText(w)
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ type forceBinaryEncoder struct {
|
|||
e pgtype.BinaryEncoder
|
||||
}
|
||||
|
||||
func (f forceBinaryEncoder) EncodeBinary(w io.Writer) error {
|
||||
func (f forceBinaryEncoder) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return f.e.EncodeBinary(w)
|
||||
}
|
||||
|
||||
|
|
|
@ -82,30 +82,26 @@ func (dst *pguint32) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src pguint32) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src pguint32) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
s := strconv.FormatUint(uint64(src.Uint), 10)
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, strconv.FormatUint(uint64(src.Uint), 10))
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src pguint32) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src pguint32) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteUint32(w, src.Uint)
|
||||
return err
|
||||
_, err := pgio.WriteUint32(w, src.Uint)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -120,15 +120,13 @@ func (dst *QChar) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src QChar) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src QChar) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 1)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return pgio.WriteByte(w, byte(src.Int))
|
||||
return false, pgio.WriteByte(w, byte(src.Int))
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/jackc/pgx/pgio"
|
||||
)
|
||||
|
||||
type Text struct {
|
||||
|
@ -85,20 +83,18 @@ func (dst *Text) DecodeBinary(src []byte) error {
|
|||
return dst.DecodeText(src)
|
||||
}
|
||||
|
||||
func (src Text) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Text) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, int32(len(src.String)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = io.WriteString(w, src.String)
|
||||
return err
|
||||
_, err := io.WriteString(w, src.String)
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Text) EncodeBinary(w io.Writer) error {
|
||||
func (src Text) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.EncodeText(w)
|
||||
}
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
package pgtype
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/jackc/pgx/pgio"
|
||||
)
|
||||
|
||||
// TextElementWriter is a wrapper that makes TextEncoders composable into other
|
||||
// TextEncoders. TextEncoder first writes the length of the subsequent value.
|
||||
// This is not necessary when the value is part of another value such as an
|
||||
// array. TextElementWriter requires one int32 to be written first which it
|
||||
// ignores. No other integer writes are valid.
|
||||
type TextElementWriter struct {
|
||||
w io.Writer
|
||||
lengthHeaderIgnored bool
|
||||
}
|
||||
|
||||
func NewTextElementWriter(w io.Writer) *TextElementWriter {
|
||||
return &TextElementWriter{w: w}
|
||||
}
|
||||
|
||||
func (w *TextElementWriter) WriteUint16(n uint16) (int, error) {
|
||||
return 0, errors.New("WriteUint16 should never be called on TextElementWriter")
|
||||
}
|
||||
|
||||
func (w *TextElementWriter) WriteUint32(n uint32) (int, error) {
|
||||
if !w.lengthHeaderIgnored {
|
||||
w.lengthHeaderIgnored = true
|
||||
|
||||
if int32(n) == -1 {
|
||||
return io.WriteString(w.w, "NULL")
|
||||
}
|
||||
|
||||
return 4, nil
|
||||
}
|
||||
|
||||
return 0, errors.New("WriteUint32 should only be called once on TextElementWriter")
|
||||
}
|
||||
|
||||
func (w *TextElementWriter) WriteUint64(n uint64) (int, error) {
|
||||
if w.lengthHeaderIgnored {
|
||||
return pgio.WriteUint64(w.w, n)
|
||||
}
|
||||
|
||||
return 0, errors.New("WriteUint64 should never be called on TextElementWriter")
|
||||
}
|
||||
|
||||
func (w *TextElementWriter) Write(buf []byte) (int, error) {
|
||||
if w.lengthHeaderIgnored {
|
||||
return w.w.Write(buf)
|
||||
}
|
||||
|
||||
return 0, errors.New("int32 must be written first")
|
||||
}
|
||||
|
||||
func (w *TextElementWriter) Reset() {
|
||||
w.lengthHeaderIgnored = false
|
||||
}
|
||||
|
||||
// TextElementReader is a wrapper that makes TextDecoders composable into other
|
||||
// TextDecoders. TextEncoders first read the length of the subsequent value.
|
||||
// This length value is not present when the value is part of another value such
|
||||
// as an array. TextElementReader provides a substitute length value from the
|
||||
// length of the string. No other integer reads are valid. Each time DecodeText
|
||||
// is called with a TextElementReader as the source the TextElementReader must
|
||||
// first have Reset called with the new element string data.
|
||||
type TextElementReader struct {
|
||||
buf *bytes.Buffer
|
||||
lengthHeaderIgnored bool
|
||||
}
|
||||
|
||||
func NewTextElementReader(r io.Reader) *TextElementReader {
|
||||
return &TextElementReader{buf: &bytes.Buffer{}}
|
||||
}
|
||||
|
||||
func (r *TextElementReader) ReadUint16() (uint16, error) {
|
||||
return 0, errors.New("ReadUint16 should never be called on TextElementReader")
|
||||
}
|
||||
|
||||
func (r *TextElementReader) ReadUint32() (uint32, error) {
|
||||
if !r.lengthHeaderIgnored {
|
||||
r.lengthHeaderIgnored = true
|
||||
if r.buf.String() == "NULL" {
|
||||
n32 := int32(-1)
|
||||
return uint32(n32), nil
|
||||
}
|
||||
return uint32(r.buf.Len()), nil
|
||||
}
|
||||
|
||||
return 0, errors.New("ReadUint32 should only be called once on TextElementReader")
|
||||
}
|
||||
|
||||
func (r *TextElementReader) WriteUint64(n uint64) (int, error) {
|
||||
return 0, errors.New("ReadUint64 should never be called on TextElementReader")
|
||||
}
|
||||
|
||||
func (r *TextElementReader) Read(buf []byte) (int, error) {
|
||||
if r.lengthHeaderIgnored {
|
||||
return r.buf.Read(buf)
|
||||
}
|
||||
|
||||
return 0, errors.New("int32 must be read first")
|
||||
}
|
||||
|
||||
func (r *TextElementReader) Reset(s string) {
|
||||
r.lengthHeaderIgnored = false
|
||||
r.buf.Reset()
|
||||
r.buf.WriteString(s)
|
||||
}
|
|
@ -152,26 +152,22 @@ func (dst *TextArray) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *TextArray) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *TextArray) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -185,112 +181,112 @@ func (src *TextArray) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
if elem.Status == Null {
|
||||
_, err := io.WriteString(buf, `"NULL"`)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `"NULL"`)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
} else if elem.String == "" {
|
||||
_, err := io.WriteString(buf, `""`)
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *TextArray) EncodeBinary(w io.Writer) error {
|
||||
func (src *TextArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, TextOID)
|
||||
}
|
||||
|
||||
func (src *TextArray) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *TextArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -127,12 +127,15 @@ func (dst *Timestamp) DecodeBinary(src []byte) error {
|
|||
|
||||
// EncodeText writes the text encoding of src into w. If src.Time is not in
|
||||
// the UTC time zone it returns an error.
|
||||
func (src Timestamp) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Timestamp) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
if src.Time.Location() != time.UTC {
|
||||
return fmt.Errorf("cannot encode non-UTC time into timestamp")
|
||||
return false, fmt.Errorf("cannot encode non-UTC time into timestamp")
|
||||
}
|
||||
|
||||
var s string
|
||||
|
@ -146,28 +149,21 @@ func (src Timestamp) EncodeText(w io.Writer) error {
|
|||
s = "-infinity"
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, s)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// EncodeBinary writes the binary encoding of src into w. If src.Time is not in
|
||||
// the UTC time zone it returns an error.
|
||||
func (src Timestamp) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Timestamp) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
if src.Time.Location() != time.UTC {
|
||||
return fmt.Errorf("cannot encode non-UTC time into timestamp")
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, fmt.Errorf("cannot encode non-UTC time into timestamp")
|
||||
}
|
||||
|
||||
var microsecSinceY2K int64
|
||||
|
@ -181,6 +177,6 @@ func (src Timestamp) EncodeBinary(w io.Writer) error {
|
|||
microsecSinceY2K = negativeInfinityMicrosecondOffset
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt64(w, microsecSinceY2K)
|
||||
return err
|
||||
_, err := pgio.WriteInt64(w, microsecSinceY2K)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -153,26 +153,22 @@ func (dst *TimestampArray) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *TimestampArray) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *TimestampArray) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -186,100 +182,112 @@ func (src *TimestampArray) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *TimestampArray) EncodeBinary(w io.Writer) error {
|
||||
func (src *TimestampArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, TimestampOID)
|
||||
}
|
||||
|
||||
func (src *TimestampArray) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *TimestampArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -131,9 +131,12 @@ func (dst *Timestamptz) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src Timestamptz) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src Timestamptz) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var s string
|
||||
|
@ -147,23 +150,16 @@ func (src Timestamptz) EncodeText(w io.Writer) error {
|
|||
s = "-infinity"
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
_, err := io.WriteString(w, s)
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src Timestamptz) EncodeBinary(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := pgio.WriteInt32(w, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
func (src Timestamptz) EncodeBinary(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var microsecSinceY2K int64
|
||||
|
@ -177,6 +173,6 @@ func (src Timestamptz) EncodeBinary(w io.Writer) error {
|
|||
microsecSinceY2K = negativeInfinityMicrosecondOffset
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt64(w, microsecSinceY2K)
|
||||
return err
|
||||
_, err := pgio.WriteInt64(w, microsecSinceY2K)
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -153,26 +153,22 @@ func (dst *TimestamptzArray) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *TimestamptzArray) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *TimestamptzArray) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -186,100 +182,112 @@ func (src *TimestamptzArray) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `NULL`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *TimestamptzArray) EncodeBinary(w io.Writer) error {
|
||||
func (src *TimestamptzArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, TimestamptzOID)
|
||||
}
|
||||
|
||||
func (src *TimestamptzArray) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *TimestamptzArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
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.
|
|
@ -151,26 +151,22 @@ func (dst *<%= pgtype_array_type %>) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src *<%= pgtype_array_type %>) EncodeText(w io.Writer) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *<%= pgtype_array_type %>) EncodeText(w io.Writer) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
if len(src.Dimensions) == 0 {
|
||||
_, err := pgio.WriteInt32(w, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte("{}"))
|
||||
return err
|
||||
_, err := io.WriteString(w, "{}")
|
||||
return false, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
||||
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
||||
|
@ -184,100 +180,112 @@ func (src *<%= pgtype_array_type %>) EncodeText(w io.Writer) error {
|
|||
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||
}
|
||||
|
||||
textElementWriter := NewTextElementWriter(buf)
|
||||
|
||||
for i, elem := range src.Elements {
|
||||
if i > 0 {
|
||||
err = pgio.WriteByte(buf, ',')
|
||||
err = pgio.WriteByte(w, ',')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if i%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '{')
|
||||
err = pgio.WriteByte(w, '{')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textElementWriter.Reset()
|
||||
err = elem.EncodeText(textElementWriter)
|
||||
elemBuf := &bytes.Buffer{}
|
||||
null, err := elem.EncodeText(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if null {
|
||||
_, err = io.WriteString(w, `<%= text_null %>`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if elemBuf.Len() == 0 {
|
||||
_, err = io.WriteString(w, `""`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dec := range dimElemCounts {
|
||||
if (i+1)%dec == 0 {
|
||||
err = pgio.WriteByte(buf, '}')
|
||||
err = pgio.WriteByte(w, '}')
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = buf.WriteTo(w)
|
||||
return err
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (src *<%= pgtype_array_type %>) EncodeBinary(w io.Writer) error {
|
||||
func (src *<%= pgtype_array_type %>) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return src.encodeBinary(w, <%= element_oid %>)
|
||||
}
|
||||
|
||||
func (src *<%= pgtype_array_type %>) encodeBinary(w io.Writer, elementOID int32) error {
|
||||
if done, err := encodeNotPresent(w, src.Status); done {
|
||||
return err
|
||||
func (src *<%= pgtype_array_type %>) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||
switch src.Status {
|
||||
case Null:
|
||||
return true, nil
|
||||
case Undefined:
|
||||
return false, errUndefined
|
||||
}
|
||||
|
||||
var arrayHeader ArrayHeader
|
||||
arrayHeader := ArrayHeader{
|
||||
ElementOID: elementOID,
|
||||
Dimensions: src.Dimensions,
|
||||
}
|
||||
|
||||
for i := range src.Elements {
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := arrayHeader.EncodeBinary(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
elemBuf := &bytes.Buffer{}
|
||||
|
||||
for i := range src.Elements {
|
||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
elemBuf.Reset()
|
||||
|
||||
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
if src.Elements[i].Status == Null {
|
||||
arrayHeader.ContainsNull = true
|
||||
if null {
|
||||
_, err = pgio.WriteInt32(w, -1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayHeader.ElementOID = elementOID
|
||||
arrayHeader.Dimensions = src.Dimensions
|
||||
|
||||
// TODO - consider how to avoid having to buffer array before writing length -
|
||||
// or how not pay allocations for the byte order conversions.
|
||||
headerBuf := &bytes.Buffer{}
|
||||
err := arrayHeader.EncodeBinary(headerBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = headerBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = elemBuf.WriteTo(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
erb pgtype_array_type=Int2Array pgtype_element_type=Int2 go_array_types=[]int16,[]uint16 element_oid=Int2OID typed_array.go.erb > int2array.go
|
||||
erb pgtype_array_type=Int4Array pgtype_element_type=Int4 go_array_types=[]int32,[]uint32 element_oid=Int4OID typed_array.go.erb > int4array.go
|
||||
erb pgtype_array_type=Int8Array pgtype_element_type=Int8 go_array_types=[]int64,[]uint64 element_oid=Int8OID typed_array.go.erb > int8array.go
|
||||
erb pgtype_array_type=BoolArray pgtype_element_type=Bool go_array_types=[]bool element_oid=BoolOID typed_array.go.erb > boolarray.go
|
||||
erb pgtype_array_type=DateArray pgtype_element_type=Date go_array_types=[]time.Time element_oid=DateOID typed_array.go.erb > datearray.go
|
||||
erb pgtype_array_type=TimestamptzArray pgtype_element_type=Timestamptz go_array_types=[]time.Time element_oid=TimestamptzOID typed_array.go.erb > timestamptzarray.go
|
||||
erb pgtype_array_type=TimestampArray pgtype_element_type=Timestamp go_array_types=[]time.Time element_oid=TimestampOID typed_array.go.erb > timestamparray.go
|
||||
erb pgtype_array_type=Float4Array pgtype_element_type=Float4 go_array_types=[]float32 element_oid=Float4OID typed_array.go.erb > float4array.go
|
||||
erb pgtype_array_type=Float8Array pgtype_element_type=Float8 go_array_types=[]float64 element_oid=Float8OID typed_array.go.erb > float8array.go
|
||||
erb pgtype_array_type=InetArray pgtype_element_type=Inet go_array_types=[]*net.IPNet,[]net.IP element_oid=InetOID typed_array.go.erb > inetarray.go
|
||||
erb pgtype_array_type=TextArray pgtype_element_type=Text go_array_types=[]string element_oid=TextOID typed_array.go.erb > textarray.go
|
||||
erb pgtype_array_type=Int2Array pgtype_element_type=Int2 go_array_types=[]int16,[]uint16 element_oid=Int2OID text_null=NULL typed_array.go.erb > int2array.go
|
||||
erb pgtype_array_type=Int4Array pgtype_element_type=Int4 go_array_types=[]int32,[]uint32 element_oid=Int4OID text_null=NULL typed_array.go.erb > int4array.go
|
||||
erb pgtype_array_type=Int8Array pgtype_element_type=Int8 go_array_types=[]int64,[]uint64 element_oid=Int8OID text_null=NULL typed_array.go.erb > int8array.go
|
||||
erb pgtype_array_type=BoolArray pgtype_element_type=Bool go_array_types=[]bool element_oid=BoolOID text_null=NULL typed_array.go.erb > boolarray.go
|
||||
erb pgtype_array_type=DateArray pgtype_element_type=Date go_array_types=[]time.Time element_oid=DateOID text_null=NULL typed_array.go.erb > datearray.go
|
||||
erb pgtype_array_type=TimestamptzArray pgtype_element_type=Timestamptz go_array_types=[]time.Time element_oid=TimestamptzOID text_null=NULL typed_array.go.erb > timestamptzarray.go
|
||||
erb pgtype_array_type=TimestampArray pgtype_element_type=Timestamp go_array_types=[]time.Time element_oid=TimestampOID text_null=NULL typed_array.go.erb > timestamparray.go
|
||||
erb pgtype_array_type=Float4Array pgtype_element_type=Float4 go_array_types=[]float32 element_oid=Float4OID text_null=NULL typed_array.go.erb > float4array.go
|
||||
erb pgtype_array_type=Float8Array pgtype_element_type=Float8 go_array_types=[]float64 element_oid=Float8OID text_null=NULL typed_array.go.erb > float8array.go
|
||||
erb pgtype_array_type=InetArray pgtype_element_type=Inet go_array_types=[]*net.IPNet,[]net.IP element_oid=InetOID text_null=NULL typed_array.go.erb > inetarray.go
|
||||
erb pgtype_array_type=TextArray pgtype_element_type=Text go_array_types=[]string element_oid=TextOID text_null='"NULL"' typed_array.go.erb > textarray.go
|
||||
|
|
|
@ -22,10 +22,10 @@ func (dst *VarcharArray) DecodeBinary(src []byte) error {
|
|||
return (*TextArray)(dst).DecodeBinary(src)
|
||||
}
|
||||
|
||||
func (src *VarcharArray) EncodeText(w io.Writer) error {
|
||||
func (src *VarcharArray) EncodeText(w io.Writer) (bool, error) {
|
||||
return (*TextArray)(src).EncodeText(w)
|
||||
}
|
||||
|
||||
func (src *VarcharArray) EncodeBinary(w io.Writer) error {
|
||||
func (src *VarcharArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return (*TextArray)(src).encodeBinary(w, VarcharOID)
|
||||
}
|
||||
|
|
|
@ -41,10 +41,10 @@ func (dst *XID) DecodeBinary(src []byte) error {
|
|||
return (*pguint32)(dst).DecodeBinary(src)
|
||||
}
|
||||
|
||||
func (src XID) EncodeText(w io.Writer) error {
|
||||
func (src XID) EncodeText(w io.Writer) (bool, error) {
|
||||
return (pguint32)(src).EncodeText(w)
|
||||
}
|
||||
|
||||
func (src XID) EncodeBinary(w io.Writer) error {
|
||||
func (src XID) EncodeBinary(w io.Writer) (bool, error) {
|
||||
return (pguint32)(src).EncodeBinary(w)
|
||||
}
|
||||
|
|
120
values.go
120
values.go
|
@ -408,7 +408,10 @@ func (n NullInt16) Encode(w *WriteBuf, oid OID) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
return pgtype.Int2{Int: n.Int16, Status: pgtype.Present}.EncodeBinary(w)
|
||||
w.WriteInt32(2)
|
||||
|
||||
_, err := pgtype.Int2{Int: n.Int16, Status: pgtype.Present}.EncodeBinary(w)
|
||||
return err
|
||||
}
|
||||
|
||||
// NullInt32 represents an integer that may be null. NullInt32 implements the
|
||||
|
@ -447,7 +450,10 @@ func (n NullInt32) Encode(w *WriteBuf, oid OID) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
return pgtype.Int4{Int: n.Int32, Status: pgtype.Present}.EncodeBinary(w)
|
||||
w.WriteInt32(4)
|
||||
|
||||
_, err := pgtype.Int4{Int: n.Int32, Status: pgtype.Present}.EncodeBinary(w)
|
||||
return err
|
||||
}
|
||||
|
||||
// OID (Object Identifier Type) is, according to https://www.postgresql.org/docs/current/static/datatype-oid.html,
|
||||
|
@ -484,24 +490,14 @@ func (dst *OID) DecodeBinary(src []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (src OID) EncodeText(w io.Writer) error {
|
||||
s := strconv.FormatUint(uint64(src), 10)
|
||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = w.Write([]byte(s))
|
||||
return err
|
||||
func (src OID) EncodeText(w io.Writer) (bool, error) {
|
||||
_, err := io.WriteString(w, strconv.FormatUint(uint64(src), 10))
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (src OID) EncodeBinary(w io.Writer) error {
|
||||
_, err := pgio.WriteInt32(w, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = pgio.WriteUint32(w, uint32(src))
|
||||
return err
|
||||
func (src OID) EncodeBinary(w io.Writer) (bool, error) {
|
||||
_, err := pgio.WriteUint32(w, uint32(src))
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Tid is PostgreSQL's Tuple Identifier type.
|
||||
|
@ -595,7 +591,10 @@ func (n NullInt64) Encode(w *WriteBuf, oid OID) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
return pgtype.Int8{Int: n.Int64, Status: pgtype.Present}.EncodeBinary(w)
|
||||
w.WriteInt32(8)
|
||||
|
||||
_, err := pgtype.Int8{Int: n.Int64, Status: pgtype.Present}.EncodeBinary(w)
|
||||
return err
|
||||
}
|
||||
|
||||
// NullBool represents an bool that may be null. NullBool implements the Scanner
|
||||
|
@ -634,7 +633,10 @@ func (n NullBool) Encode(w *WriteBuf, oid OID) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
return encodeBool(w, oid, n.Bool)
|
||||
w.WriteInt32(1)
|
||||
|
||||
_, err := pgtype.Bool{Bool: n.Bool, Status: pgtype.Present}.EncodeBinary(w)
|
||||
return err
|
||||
}
|
||||
|
||||
// NullTime represents an time.Time that may be null. NullTime implements the
|
||||
|
@ -834,9 +836,31 @@ func Encode(wbuf *WriteBuf, oid OID, arg interface{}) error {
|
|||
case Encoder:
|
||||
return arg.Encode(wbuf, oid)
|
||||
case pgtype.BinaryEncoder:
|
||||
return arg.EncodeBinary(wbuf)
|
||||
buf := &bytes.Buffer{}
|
||||
null, err := arg.EncodeBinary(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if null {
|
||||
wbuf.WriteInt32(-1)
|
||||
} else {
|
||||
wbuf.WriteInt32(int32(buf.Len()))
|
||||
wbuf.WriteBytes(buf.Bytes())
|
||||
}
|
||||
return nil
|
||||
case pgtype.TextEncoder:
|
||||
return arg.EncodeText(wbuf)
|
||||
buf := &bytes.Buffer{}
|
||||
null, err := arg.EncodeText(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if null {
|
||||
wbuf.WriteInt32(-1)
|
||||
} else {
|
||||
wbuf.WriteInt32(int32(buf.Len()))
|
||||
wbuf.WriteBytes(buf.Bytes())
|
||||
}
|
||||
return nil
|
||||
case driver.Valuer:
|
||||
v, err := arg.Value()
|
||||
if err != nil {
|
||||
|
@ -876,7 +900,19 @@ func Encode(wbuf *WriteBuf, oid OID, arg interface{}) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return value.(pgtype.BinaryEncoder).EncodeBinary(wbuf)
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
null, err := value.(pgtype.BinaryEncoder).EncodeBinary(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if null {
|
||||
wbuf.WriteInt32(-1)
|
||||
} else {
|
||||
wbuf.WriteInt32(int32(buf.Len()))
|
||||
wbuf.WriteBytes(buf.Bytes())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
switch arg := arg.(type) {
|
||||
|
@ -1026,15 +1062,6 @@ func decodeBool(vr *ValueReader) bool {
|
|||
return b.Bool
|
||||
}
|
||||
|
||||
func encodeBool(w *WriteBuf, oid OID, value bool) error {
|
||||
if oid != BoolOID {
|
||||
return fmt.Errorf("cannot encode Go %s into oid %d", "bool", oid)
|
||||
}
|
||||
|
||||
b := pgtype.Bool{Bool: value, Status: pgtype.Present}
|
||||
return b.EncodeBinary(w)
|
||||
}
|
||||
|
||||
func decodeInt(vr *ValueReader) int64 {
|
||||
switch vr.Type().DataType {
|
||||
case Int2OID:
|
||||
|
@ -1461,14 +1488,39 @@ func encodeTime(w *WriteBuf, oid OID, value time.Time) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.EncodeBinary(w)
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
null, err := d.EncodeBinary(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if null {
|
||||
w.WriteInt32(-1)
|
||||
} else {
|
||||
w.WriteInt32(int32(buf.Len()))
|
||||
w.WriteBytes(buf.Bytes())
|
||||
}
|
||||
return nil
|
||||
|
||||
case TimestampTzOID, TimestampOID:
|
||||
var t pgtype.Timestamptz
|
||||
err := t.ConvertFrom(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.EncodeBinary(w)
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
null, err := t.EncodeBinary(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if null {
|
||||
w.WriteInt32(-1)
|
||||
} else {
|
||||
w.WriteInt32(int32(buf.Len()))
|
||||
w.WriteBytes(buf.Bytes())
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "time.Time", oid)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue