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"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/jackc/pgx/pgio"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bool struct {
|
type Bool struct {
|
||||||
|
@ -100,14 +98,12 @@ func (dst *Bool) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Bool) EncodeText(w io.Writer) error {
|
func (src Bool) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
}
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
_, err := pgio.WriteInt32(w, 1)
|
return false, errUndefined
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf []byte
|
var buf []byte
|
||||||
|
@ -117,18 +113,16 @@ func (src Bool) EncodeText(w io.Writer) error {
|
||||||
buf = []byte{'f'}
|
buf = []byte{'f'}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write(buf)
|
_, err := w.Write(buf)
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Bool) EncodeBinary(w io.Writer) error {
|
func (src Bool) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
}
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
_, err := pgio.WriteInt32(w, 1)
|
return false, errUndefined
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf []byte
|
var buf []byte
|
||||||
|
@ -138,6 +132,6 @@ func (src Bool) EncodeBinary(w io.Writer) error {
|
||||||
buf = []byte{0}
|
buf = []byte{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write(buf)
|
_, err := w.Write(buf)
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,26 +152,22 @@ func (dst *BoolArray) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *BoolArray) EncodeText(w io.Writer) error {
|
func (src *BoolArray) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *BoolArray) EncodeBinary(w io.Writer) error {
|
func (src *BoolArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, BoolOID)
|
return src.encodeBinary(w, BoolOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *BoolArray) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *BoolArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/jackc/pgx/pgio"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bytea struct {
|
type Bytea struct {
|
||||||
|
@ -101,37 +99,31 @@ func (dst *Bytea) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Bytea) EncodeText(w io.Writer) error {
|
func (src Bytea) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
str := hex.EncodeToString(src.Bytes)
|
_, err := io.WriteString(w, `\x`)
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, int32(len(str)+2))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.WriteString(w, `\x`)
|
_, err = io.WriteString(w, hex.EncodeToString(src.Bytes))
|
||||||
if err != nil {
|
return false, err
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.WriteString(w, str)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Bytea) EncodeBinary(w io.Writer) error {
|
func (src Bytea) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, int32(len(src.Bytes)))
|
_, err := w.Write(src.Bytes)
|
||||||
if err != nil {
|
return false, err
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = w.Write(src.Bytes)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,10 @@ func (dst *CID) DecodeBinary(src []byte) error {
|
||||||
return (*pguint32)(dst).DecodeBinary(src)
|
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)
|
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)
|
return (pguint32)(src).EncodeBinary(w)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,10 @@ func (dst *CidrArray) DecodeBinary(src []byte) error {
|
||||||
return (*InetArray)(dst).DecodeBinary(src)
|
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)
|
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)
|
return (*InetArray)(src).encodeBinary(w, CidrOID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,9 +116,12 @@ func (dst *Date) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Date) EncodeText(w io.Writer) error {
|
func (src Date) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
var s string
|
var s string
|
||||||
|
@ -132,23 +135,16 @@ func (src Date) EncodeText(w io.Writer) error {
|
||||||
s = "-infinity"
|
s = "-infinity"
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
_, err := io.WriteString(w, s)
|
||||||
if err != nil {
|
return false, err
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Date) EncodeBinary(w io.Writer) error {
|
func (src Date) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
}
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
_, err := pgio.WriteInt32(w, 4)
|
return false, errUndefined
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var daysSinceDateEpoch int32
|
var daysSinceDateEpoch int32
|
||||||
|
@ -165,6 +161,6 @@ func (src Date) EncodeBinary(w io.Writer) error {
|
||||||
daysSinceDateEpoch = negativeInfinityDayOffset
|
daysSinceDateEpoch = negativeInfinityDayOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, daysSinceDateEpoch)
|
_, err := pgio.WriteInt32(w, daysSinceDateEpoch)
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,26 +153,22 @@ func (dst *DateArray) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *DateArray) EncodeText(w io.Writer) error {
|
func (src *DateArray) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *DateArray) EncodeBinary(w io.Writer) error {
|
func (src *DateArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, DateOID)
|
return src.encodeBinary(w, DateOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *DateArray) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *DateArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,30 +124,26 @@ func (dst *Float4) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Float4) EncodeText(w io.Writer) error {
|
func (src Float4) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strconv.FormatFloat(float64(src.Float), 'f', -1, 32)
|
_, err := io.WriteString(w, strconv.FormatFloat(float64(src.Float), 'f', -1, 32))
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Float4) EncodeBinary(w io.Writer) error {
|
func (src Float4) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, 4)
|
_, err := pgio.WriteInt32(w, int32(math.Float32bits(src.Float)))
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(math.Float32bits(src.Float)))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,26 +152,22 @@ func (dst *Float4Array) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Float4Array) EncodeText(w io.Writer) error {
|
func (src *Float4Array) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Float4Array) EncodeBinary(w io.Writer) error {
|
func (src *Float4Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, Float4OID)
|
return src.encodeBinary(w, Float4OID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Float4Array) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *Float4Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,30 +114,26 @@ func (dst *Float8) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Float8) EncodeText(w io.Writer) error {
|
func (src Float8) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strconv.FormatFloat(float64(src.Float), 'f', -1, 64)
|
_, err := io.WriteString(w, strconv.FormatFloat(float64(src.Float), 'f', -1, 64))
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Float8) EncodeBinary(w io.Writer) error {
|
func (src Float8) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, 8)
|
_, err := pgio.WriteInt64(w, int64(math.Float64bits(src.Float)))
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = pgio.WriteInt64(w, int64(math.Float64bits(src.Float)))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,26 +152,22 @@ func (dst *Float8Array) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Float8Array) EncodeText(w io.Writer) error {
|
func (src *Float8Array) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Float8Array) EncodeBinary(w io.Writer) error {
|
func (src *Float8Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, Float8OID)
|
return src.encodeBinary(w, Float8OID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Float8Array) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *Float8Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,61 +144,55 @@ func (dst *Inet) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Inet) EncodeText(w io.Writer) error {
|
func (src Inet) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
s := src.IPNet.String()
|
_, err := io.WriteString(w, src.IPNet.String())
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary encodes src into w.
|
// EncodeBinary encodes src into w.
|
||||||
func (src Inet) EncodeBinary(w io.Writer) error {
|
func (src Inet) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
var size int32
|
|
||||||
var family byte
|
var family byte
|
||||||
switch len(src.IPNet.IP) {
|
switch len(src.IPNet.IP) {
|
||||||
case net.IPv4len:
|
case net.IPv4len:
|
||||||
size = 8
|
|
||||||
family = defaultAFInet
|
family = defaultAFInet
|
||||||
case net.IPv6len:
|
case net.IPv6len:
|
||||||
size = 20
|
|
||||||
family = defaultAFInet6
|
family = defaultAFInet6
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unexpected IP length: %v", len(src.IPNet.IP))
|
return false, fmt.Errorf("Unexpected IP length: %v", len(src.IPNet.IP))
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := pgio.WriteInt32(w, size); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pgio.WriteByte(w, family); err != nil {
|
if err := pgio.WriteByte(w, family); err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ones, _ := src.IPNet.Mask.Size()
|
ones, _ := src.IPNet.Mask.Size()
|
||||||
if err := pgio.WriteByte(w, byte(ones)); err != nil {
|
if err := pgio.WriteByte(w, byte(ones)); err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_cidr is ignored on server
|
// is_cidr is ignored on server
|
||||||
if err := pgio.WriteByte(w, 0); err != nil {
|
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 {
|
if err := pgio.WriteByte(w, byte(len(src.IPNet.IP))); err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := w.Write(src.IPNet.IP)
|
_, err := w.Write(src.IPNet.IP)
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,26 +184,22 @@ func (dst *InetArray) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *InetArray) EncodeText(w io.Writer) error {
|
func (src *InetArray) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *InetArray) EncodeBinary(w io.Writer) error {
|
func (src *InetArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, InetOID)
|
return src.encodeBinary(w, InetOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *InetArray) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *InetArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,30 +119,26 @@ func (dst *Int2) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Int2) EncodeText(w io.Writer) error {
|
func (src Int2) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strconv.FormatInt(int64(src.Int), 10)
|
_, err := io.WriteString(w, strconv.FormatInt(int64(src.Int), 10))
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Int2) EncodeBinary(w io.Writer) error {
|
func (src Int2) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := pgio.WriteInt16(w, src.Int)
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = pgio.WriteInt16(w, src.Int)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,26 +183,22 @@ func (dst *Int2Array) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int2Array) EncodeText(w io.Writer) error {
|
func (src *Int2Array) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int2Array) EncodeBinary(w io.Writer) error {
|
func (src *Int2Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, Int2OID)
|
return src.encodeBinary(w, Int2OID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int2Array) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *Int2Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,30 +110,26 @@ func (dst *Int4) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Int4) EncodeText(w io.Writer) error {
|
func (src Int4) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strconv.FormatInt(int64(src.Int), 10)
|
_, err := io.WriteString(w, strconv.FormatInt(int64(src.Int), 10))
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Int4) EncodeBinary(w io.Writer) error {
|
func (src Int4) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, 4)
|
_, err := pgio.WriteInt32(w, src.Int)
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, src.Int)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,26 +183,22 @@ func (dst *Int4Array) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int4Array) EncodeText(w io.Writer) error {
|
func (src *Int4Array) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int4Array) EncodeBinary(w io.Writer) error {
|
func (src *Int4Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, Int4OID)
|
return src.encodeBinary(w, Int4OID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int4Array) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *Int4Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,30 +102,26 @@ func (dst *Int8) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Int8) EncodeText(w io.Writer) error {
|
func (src Int8) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strconv.FormatInt(src.Int, 10)
|
_, err := io.WriteString(w, strconv.FormatInt(src.Int, 10))
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Int8) EncodeBinary(w io.Writer) error {
|
func (src Int8) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, 8)
|
_, err := pgio.WriteInt64(w, src.Int)
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = pgio.WriteInt64(w, src.Int)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,26 +183,22 @@ func (dst *Int8Array) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int8Array) EncodeText(w io.Writer) error {
|
func (src *Int8Array) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int8Array) EncodeBinary(w io.Writer) error {
|
func (src *Int8Array) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, Int8OID)
|
return src.encodeBinary(w, Int8OID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *Int8Array) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *Int8Array) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,10 @@ func (dst *Name) DecodeBinary(src []byte) error {
|
||||||
return (*Text)(dst).DecodeBinary(src)
|
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)
|
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)
|
return (Text)(src).EncodeBinary(w)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,10 @@ func (dst *OID) DecodeBinary(src []byte) error {
|
||||||
return (*pguint32)(dst).DecodeBinary(src)
|
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)
|
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)
|
return (pguint32)(src).EncodeBinary(w)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@ package pgtype
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/jackc/pgx/pgio"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PostgreSQL oids for common types
|
// PostgreSQL oids for common types
|
||||||
|
@ -81,23 +79,24 @@ type TextDecoder interface {
|
||||||
DecodeText(src []byte) error
|
DecodeText(src []byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BinaryEncoder is implemented by types that can encode themselves into the
|
||||||
|
// PostgreSQL binary wire format.
|
||||||
type BinaryEncoder interface {
|
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 {
|
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")
|
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
|
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)
|
return f.e.EncodeText(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ type forceBinaryEncoder struct {
|
||||||
e pgtype.BinaryEncoder
|
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)
|
return f.e.EncodeBinary(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,30 +82,26 @@ func (dst *pguint32) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src pguint32) EncodeText(w io.Writer) error {
|
func (src pguint32) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strconv.FormatUint(uint64(src.Uint), 10)
|
_, err := io.WriteString(w, strconv.FormatUint(uint64(src.Uint), 10))
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src pguint32) EncodeBinary(w io.Writer) error {
|
func (src pguint32) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, 4)
|
_, err := pgio.WriteUint32(w, src.Uint)
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = pgio.WriteUint32(w, src.Uint)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,15 +120,13 @@ func (dst *QChar) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src QChar) EncodeBinary(w io.Writer) error {
|
func (src QChar) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, 1)
|
return false, pgio.WriteByte(w, byte(src.Int))
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return pgio.WriteByte(w, byte(src.Int))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/jackc/pgx/pgio"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Text struct {
|
type Text struct {
|
||||||
|
@ -85,20 +83,18 @@ func (dst *Text) DecodeBinary(src []byte) error {
|
||||||
return dst.DecodeText(src)
|
return dst.DecodeText(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Text) EncodeText(w io.Writer) error {
|
func (src Text) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, int32(len(src.String)))
|
_, err := io.WriteString(w, src.String)
|
||||||
if err != nil {
|
return false, err
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.WriteString(w, src.String)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Text) EncodeBinary(w io.Writer) error {
|
func (src Text) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.EncodeText(w)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TextArray) EncodeText(w io.Writer) error {
|
func (src *TextArray) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
if elem.Status == Null {
|
null, err := elem.EncodeText(elemBuf)
|
||||||
_, err := io.WriteString(buf, `"NULL"`)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
} else if elem.String == "" {
|
if null {
|
||||||
_, err := io.WriteString(buf, `""`)
|
_, err = io.WriteString(w, `"NULL"`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
} else if elemBuf.Len() == 0 {
|
||||||
|
_, err = io.WriteString(w, `""`)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = elem.EncodeText(textElementWriter)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TextArray) EncodeBinary(w io.Writer) error {
|
func (src *TextArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, TextOID)
|
return src.encodeBinary(w, TextOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TextArray) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *TextArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, 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
|
// EncodeText writes the text encoding of src into w. If src.Time is not in
|
||||||
// the UTC time zone it returns an error.
|
// the UTC time zone it returns an error.
|
||||||
func (src Timestamp) EncodeText(w io.Writer) error {
|
func (src Timestamp) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
if src.Time.Location() != time.UTC {
|
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
|
var s string
|
||||||
|
@ -146,28 +149,21 @@ func (src Timestamp) EncodeText(w io.Writer) error {
|
||||||
s = "-infinity"
|
s = "-infinity"
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
_, err := io.WriteString(w, s)
|
||||||
if err != nil {
|
return false, err
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary writes the binary encoding of src into w. If src.Time is not in
|
// EncodeBinary writes the binary encoding of src into w. If src.Time is not in
|
||||||
// the UTC time zone it returns an error.
|
// the UTC time zone it returns an error.
|
||||||
func (src Timestamp) EncodeBinary(w io.Writer) error {
|
func (src Timestamp) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
if src.Time.Location() != time.UTC {
|
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")
|
||||||
}
|
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, 8)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var microsecSinceY2K int64
|
var microsecSinceY2K int64
|
||||||
|
@ -181,6 +177,6 @@ func (src Timestamp) EncodeBinary(w io.Writer) error {
|
||||||
microsecSinceY2K = negativeInfinityMicrosecondOffset
|
microsecSinceY2K = negativeInfinityMicrosecondOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt64(w, microsecSinceY2K)
|
_, err := pgio.WriteInt64(w, microsecSinceY2K)
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,26 +153,22 @@ func (dst *TimestampArray) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TimestampArray) EncodeText(w io.Writer) error {
|
func (src *TimestampArray) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TimestampArray) EncodeBinary(w io.Writer) error {
|
func (src *TimestampArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, TimestampOID)
|
return src.encodeBinary(w, TimestampOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TimestampArray) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *TimestampArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,9 +131,12 @@ func (dst *Timestamptz) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Timestamptz) EncodeText(w io.Writer) error {
|
func (src Timestamptz) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
var s string
|
var s string
|
||||||
|
@ -147,23 +150,16 @@ func (src Timestamptz) EncodeText(w io.Writer) error {
|
||||||
s = "-infinity"
|
s = "-infinity"
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
_, err := io.WriteString(w, s)
|
||||||
if err != nil {
|
return false, err
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Timestamptz) EncodeBinary(w io.Writer) error {
|
func (src Timestamptz) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
}
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
_, err := pgio.WriteInt32(w, 8)
|
return false, errUndefined
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var microsecSinceY2K int64
|
var microsecSinceY2K int64
|
||||||
|
@ -177,6 +173,6 @@ func (src Timestamptz) EncodeBinary(w io.Writer) error {
|
||||||
microsecSinceY2K = negativeInfinityMicrosecondOffset
|
microsecSinceY2K = negativeInfinityMicrosecondOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt64(w, microsecSinceY2K)
|
_, err := pgio.WriteInt64(w, microsecSinceY2K)
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,26 +153,22 @@ func (dst *TimestamptzArray) DecodeBinary(src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TimestamptzArray) EncodeText(w io.Writer) error {
|
func (src *TimestamptzArray) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TimestamptzArray) EncodeBinary(w io.Writer) error {
|
func (src *TimestamptzArray) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
return src.encodeBinary(w, TimestamptzOID)
|
return src.encodeBinary(w, TimestamptzOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *TimestamptzArray) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *TimestamptzArray) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *<%= pgtype_array_type %>) EncodeText(w io.Writer) error {
|
func (src *<%= pgtype_array_type %>) EncodeText(w io.Writer) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src.Dimensions) == 0 {
|
if len(src.Dimensions) == 0 {
|
||||||
_, err := pgio.WriteInt32(w, 2)
|
_, err := io.WriteString(w, "{}")
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte("{}"))
|
err := EncodeTextArrayDimensions(w, src.Dimensions)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
err := EncodeTextArrayDimensions(buf, src.Dimensions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// dimElemCounts is the multiples of elements that each array lies on. For
|
// 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]
|
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter := NewTextElementWriter(buf)
|
|
||||||
|
|
||||||
for i, elem := range src.Elements {
|
for i, elem := range src.Elements {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
err = pgio.WriteByte(buf, ',')
|
err = pgio.WriteByte(w, ',')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dec := range dimElemCounts {
|
for _, dec := range dimElemCounts {
|
||||||
if i%dec == 0 {
|
if i%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '{')
|
err = pgio.WriteByte(w, '{')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textElementWriter.Reset()
|
elemBuf := &bytes.Buffer{}
|
||||||
err = elem.EncodeText(textElementWriter)
|
null, err := elem.EncodeText(elemBuf)
|
||||||
if err != nil {
|
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 {
|
for _, dec := range dimElemCounts {
|
||||||
if (i+1)%dec == 0 {
|
if (i+1)%dec == 0 {
|
||||||
err = pgio.WriteByte(buf, '}')
|
err = pgio.WriteByte(w, '}')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pgio.WriteInt32(w, int32(buf.Len()))
|
return false, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 %>)
|
return src.encodeBinary(w, <%= element_oid %>)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *<%= pgtype_array_type %>) encodeBinary(w io.Writer, elementOID int32) error {
|
func (src *<%= pgtype_array_type %>) encodeBinary(w io.Writer, elementOID int32) (bool, error) {
|
||||||
if done, err := encodeNotPresent(w, src.Status); done {
|
switch src.Status {
|
||||||
return err
|
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{}
|
elemBuf := &bytes.Buffer{}
|
||||||
|
|
||||||
for i := range src.Elements {
|
for i := range src.Elements {
|
||||||
err := src.Elements[i].EncodeBinary(elemBuf)
|
elemBuf.Reset()
|
||||||
|
|
||||||
|
null, err := src.Elements[i].EncodeBinary(elemBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if src.Elements[i].Status == Null {
|
if null {
|
||||||
arrayHeader.ContainsNull = true
|
_, err = pgio.WriteInt32(w, -1)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
|
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = headerBuf.WriteTo(w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = elemBuf.WriteTo(w)
|
_, err = elemBuf.WriteTo(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, 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=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 typed_array.go.erb > int4array.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 typed_array.go.erb > int8array.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 typed_array.go.erb > boolarray.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 typed_array.go.erb > datearray.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 typed_array.go.erb > timestamptzarray.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 typed_array.go.erb > timestamparray.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 typed_array.go.erb > float4array.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 typed_array.go.erb > float8array.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 typed_array.go.erb > inetarray.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 typed_array.go.erb > textarray.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)
|
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)
|
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)
|
return (*TextArray)(src).encodeBinary(w, VarcharOID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,10 @@ func (dst *XID) DecodeBinary(src []byte) error {
|
||||||
return (*pguint32)(dst).DecodeBinary(src)
|
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)
|
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)
|
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 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
|
// 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 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,
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src OID) EncodeText(w io.Writer) error {
|
func (src OID) EncodeText(w io.Writer) (bool, error) {
|
||||||
s := strconv.FormatUint(uint64(src), 10)
|
_, err := io.WriteString(w, strconv.FormatUint(uint64(src), 10))
|
||||||
_, err := pgio.WriteInt32(w, int32(len(s)))
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err = w.Write([]byte(s))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src OID) EncodeBinary(w io.Writer) error {
|
func (src OID) EncodeBinary(w io.Writer) (bool, error) {
|
||||||
_, err := pgio.WriteInt32(w, 4)
|
_, err := pgio.WriteUint32(w, uint32(src))
|
||||||
if err != nil {
|
return false, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = pgio.WriteUint32(w, uint32(src))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tid is PostgreSQL's Tuple Identifier type.
|
// Tid is PostgreSQL's Tuple Identifier type.
|
||||||
|
@ -595,7 +591,10 @@ func (n NullInt64) Encode(w *WriteBuf, oid OID) error {
|
||||||
return nil
|
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
|
// 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 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
|
// 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:
|
case Encoder:
|
||||||
return arg.Encode(wbuf, oid)
|
return arg.Encode(wbuf, oid)
|
||||||
case pgtype.BinaryEncoder:
|
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:
|
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:
|
case driver.Valuer:
|
||||||
v, err := arg.Value()
|
v, err := arg.Value()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -876,7 +900,19 @@ func Encode(wbuf *WriteBuf, oid OID, arg interface{}) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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) {
|
switch arg := arg.(type) {
|
||||||
|
@ -1026,15 +1062,6 @@ func decodeBool(vr *ValueReader) bool {
|
||||||
return b.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 {
|
func decodeInt(vr *ValueReader) int64 {
|
||||||
switch vr.Type().DataType {
|
switch vr.Type().DataType {
|
||||||
case Int2OID:
|
case Int2OID:
|
||||||
|
@ -1461,14 +1488,39 @@ func encodeTime(w *WriteBuf, oid OID, value time.Time) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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:
|
case TimestampTzOID, TimestampOID:
|
||||||
var t pgtype.Timestamptz
|
var t pgtype.Timestamptz
|
||||||
err := t.ConvertFrom(value)
|
err := t.ConvertFrom(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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:
|
default:
|
||||||
return fmt.Errorf("cannot encode %s into oid %v", "time.Time", oid)
|
return fmt.Errorf("cannot encode %s into oid %v", "time.Time", oid)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue