Refactor pgio and types to append buffers

batch-wip
Jack Christensen 2017-05-02 20:38:26 -05:00
parent ee001a7cae
commit 6e64a0c867
78 changed files with 1551 additions and 2627 deletions

View File

@ -2,103 +2,39 @@ package pgio
import (
"encoding/binary"
"io"
)
type Uint16Reader interface {
ReadUint16() (n uint16, err error)
func NextByte(buf []byte) ([]byte, byte) {
b := buf[0]
return buf[1:], b
}
type Uint32Reader interface {
ReadUint32() (n uint32, err error)
func NextUint16(buf []byte) ([]byte, uint16) {
n := binary.BigEndian.Uint16(buf)
return buf[2:], n
}
type Uint64Reader interface {
ReadUint64() (n uint64, err error)
func NextUint32(buf []byte) ([]byte, uint32) {
n := binary.BigEndian.Uint32(buf)
return buf[4:], n
}
// ReadByte reads a byte from r.
func ReadByte(r io.Reader) (byte, error) {
if r, ok := r.(io.ByteReader); ok {
return r.ReadByte()
}
buf := make([]byte, 1)
_, err := r.Read(buf)
return buf[0], err
func NextUint64(buf []byte) ([]byte, uint64) {
n := binary.BigEndian.Uint64(buf)
return buf[8:], n
}
// ReadUint16 reads an uint16 from r in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Read if r provides a ReadUint16
// method.
func ReadUint16(r io.Reader) (uint16, error) {
if r, ok := r.(Uint16Reader); ok {
return r.ReadUint16()
}
buf := make([]byte, 2)
_, err := io.ReadFull(r, buf)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint16(buf), nil
func NextInt16(buf []byte) ([]byte, int16) {
buf, n := NextUint16(buf)
return buf, int16(n)
}
// ReadInt16 reads an int16 r in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Read if r provides a ReadUint16
// method.
func ReadInt16(r io.Reader) (int16, error) {
n, err := ReadUint16(r)
return int16(n), err
func NextInt32(buf []byte) ([]byte, int32) {
buf, n := NextUint32(buf)
return buf, int32(n)
}
// ReadUint32 reads an uint32 r in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Read if r provides a ReadUint32
// method.
func ReadUint32(r io.Reader) (uint32, error) {
if r, ok := r.(Uint32Reader); ok {
return r.ReadUint32()
}
buf := make([]byte, 4)
_, err := io.ReadFull(r, buf)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint32(buf), nil
}
// ReadInt32 reads an int32 r in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Read if r provides a ReadUint32
// method.
func ReadInt32(r io.Reader) (int32, error) {
n, err := ReadUint32(r)
return int32(n), err
}
// ReadUint64 reads an uint64 r in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Read if r provides a ReadUint64
// method.
func ReadUint64(r io.Reader) (uint64, error) {
if r, ok := r.(Uint64Reader); ok {
return r.ReadUint64()
}
buf := make([]byte, 8)
_, err := io.ReadFull(r, buf)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint64(buf), nil
}
// ReadInt64 reads an int64 r in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Read if r provides a ReadUint64
// method.
func ReadInt64(r io.Reader) (int64, error) {
n, err := ReadUint64(r)
return int64(n), err
func NextInt64(buf []byte) ([]byte, int64) {
buf, n := NextUint64(buf)
return buf, int64(n)
}

57
pgio/read_test.go Normal file
View File

@ -0,0 +1,57 @@
package pgio
import (
"testing"
)
func TestNextByte(t *testing.T) {
buf := []byte{42, 1}
var b byte
buf, b = NextByte(buf)
if b != 42 {
t.Errorf("NextByte(buf) => %v, want %v", b, 42)
}
buf, b = NextByte(buf)
if b != 1 {
t.Errorf("NextByte(buf) => %v, want %v", b, 1)
}
}
func TestNextUint16(t *testing.T) {
buf := []byte{0, 42, 0, 1}
var n uint16
buf, n = NextUint16(buf)
if n != 42 {
t.Errorf("NextUint16(buf) => %v, want %v", n, 42)
}
buf, n = NextUint16(buf)
if n != 1 {
t.Errorf("NextUint16(buf) => %v, want %v", n, 1)
}
}
func TestNextUint32(t *testing.T) {
buf := []byte{0, 0, 0, 42, 0, 0, 0, 1}
var n uint32
buf, n = NextUint32(buf)
if n != 42 {
t.Errorf("NextUint32(buf) => %v, want %v", n, 42)
}
buf, n = NextUint32(buf)
if n != 1 {
t.Errorf("NextUint32(buf) => %v, want %v", n, 1)
}
}
func TestNextUint64(t *testing.T) {
buf := []byte{0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 1}
var n uint64
buf, n = NextUint64(buf)
if n != 42 {
t.Errorf("NextUint64(buf) => %v, want %v", n, 42)
}
buf, n = NextUint64(buf)
if n != 1 {
t.Errorf("NextUint64(buf) => %v, want %v", n, 1)
}
}

View File

@ -1,97 +1,40 @@
package pgio
import (
"encoding/binary"
"io"
)
import "encoding/binary"
type Uint16Writer interface {
WriteUint16(uint16) (n int, err error)
func AppendUint16(buf []byte, n uint16) []byte {
wp := len(buf)
buf = append(buf, 0, 0)
binary.BigEndian.PutUint16(buf[wp:], n)
return buf
}
type Uint32Writer interface {
WriteUint32(uint32) (n int, err error)
func AppendUint32(buf []byte, n uint32) []byte {
wp := len(buf)
buf = append(buf, 0, 0, 0, 0)
binary.BigEndian.PutUint32(buf[wp:], n)
return buf
}
type Uint64Writer interface {
WriteUint64(uint64) (n int, err error)
func AppendUint64(buf []byte, n uint64) []byte {
wp := len(buf)
buf = append(buf, 0, 0, 0, 0, 0, 0, 0, 0)
binary.BigEndian.PutUint64(buf[wp:], n)
return buf
}
// WriteByte writes b to w.
func WriteByte(w io.Writer, b byte) error {
if w, ok := w.(io.ByteWriter); ok {
return w.WriteByte(b)
}
_, err := w.Write([]byte{b})
return err
func AppendInt16(buf []byte, n int16) []byte {
return AppendUint16(buf, uint16(n))
}
// WriteUint16 writes n to w in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Write if w provides a WriteUint16
// method.
func WriteUint16(w io.Writer, n uint16) (int, error) {
if w, ok := w.(Uint16Writer); ok {
return w.WriteUint16(n)
}
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, n)
return w.Write(b)
func AppendInt32(buf []byte, n int32) []byte {
return AppendUint32(buf, uint32(n))
}
// WriteInt16 writes n to w in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Write if w provides a WriteUint16
// method.
func WriteInt16(w io.Writer, n int16) (int, error) {
return WriteUint16(w, uint16(n))
func AppendInt64(buf []byte, n int64) []byte {
return AppendUint64(buf, uint64(n))
}
// WriteUint32 writes n to w in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Write if w provides a WriteUint32
// method.
func WriteUint32(w io.Writer, n uint32) (int, error) {
if w, ok := w.(Uint32Writer); ok {
return w.WriteUint32(n)
}
b := make([]byte, 4)
binary.BigEndian.PutUint32(b, n)
return w.Write(b)
}
// WriteInt32 writes n to w in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Write if w provides a WriteUint32
// method.
func WriteInt32(w io.Writer, n int32) (int, error) {
return WriteUint32(w, uint32(n))
}
// WriteUint64 writes n to w in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Write if w provides a WriteUint64
// method.
func WriteUint64(w io.Writer, n uint64) (int, error) {
if w, ok := w.(Uint64Writer); ok {
return w.WriteUint64(n)
}
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, n)
return w.Write(b)
}
// WriteInt64 writes n to w in PostgreSQL wire format (network byte order). This
// may be more efficient than directly using Write if w provides a WriteUint64
// method.
func WriteInt64(w io.Writer, n int64) (int, error) {
return WriteUint64(w, uint64(n))
}
// WriteCString writes s to w followed by a null byte.
func WriteCString(w io.Writer, s string) (int, error) {
n, err := io.WriteString(w, s)
if err != nil {
return n, err
}
err = WriteByte(w, 0)
if err != nil {
return n, err
}
return n + 1, nil
func SetInt32(buf []byte, n int32) {
binary.BigEndian.PutUint32(buf, uint32(n))
}

78
pgio/write_test.go Normal file
View File

@ -0,0 +1,78 @@
package pgio
import (
"reflect"
"testing"
)
func TestAppendUint16NilBuf(t *testing.T) {
buf := AppendUint16(nil, 1)
if !reflect.DeepEqual(buf, []byte{0, 1}) {
t.Errorf("AppendUint16(nil, 1) => %v, want %v", buf, []byte{0, 1})
}
}
func TestAppendUint16EmptyBuf(t *testing.T) {
buf := []byte{}
buf = AppendUint16(buf, 1)
if !reflect.DeepEqual(buf, []byte{0, 1}) {
t.Errorf("AppendUint16(nil, 1) => %v, want %v", buf, []byte{0, 1})
}
}
func TestAppendUint16BufWithCapacityDoesNotAllocate(t *testing.T) {
buf := make([]byte, 0, 4)
AppendUint16(buf, 1)
buf = buf[0:2]
if !reflect.DeepEqual(buf, []byte{0, 1}) {
t.Errorf("AppendUint16(nil, 1) => %v, want %v", buf, []byte{0, 1})
}
}
func TestAppendUint32NilBuf(t *testing.T) {
buf := AppendUint32(nil, 1)
if !reflect.DeepEqual(buf, []byte{0, 0, 0, 1}) {
t.Errorf("AppendUint32(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 1})
}
}
func TestAppendUint32EmptyBuf(t *testing.T) {
buf := []byte{}
buf = AppendUint32(buf, 1)
if !reflect.DeepEqual(buf, []byte{0, 0, 0, 1}) {
t.Errorf("AppendUint32(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 1})
}
}
func TestAppendUint32BufWithCapacityDoesNotAllocate(t *testing.T) {
buf := make([]byte, 0, 4)
AppendUint32(buf, 1)
buf = buf[0:4]
if !reflect.DeepEqual(buf, []byte{0, 0, 0, 1}) {
t.Errorf("AppendUint32(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 1})
}
}
func TestAppendUint64NilBuf(t *testing.T) {
buf := AppendUint64(nil, 1)
if !reflect.DeepEqual(buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) {
t.Errorf("AppendUint64(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 0, 0, 0, 0, 1})
}
}
func TestAppendUint64EmptyBuf(t *testing.T) {
buf := []byte{}
buf = AppendUint64(buf, 1)
if !reflect.DeepEqual(buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) {
t.Errorf("AppendUint64(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 0, 0, 0, 0, 1})
}
}
func TestAppendUint64BufWithCapacityDoesNotAllocate(t *testing.T) {
buf := make([]byte, 0, 8)
AppendUint64(buf, 1)
buf = buf[0:8]
if !reflect.DeepEqual(buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) {
t.Errorf("AppendUint64(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 0, 0, 0, 0, 1})
}
}

View File

@ -3,7 +3,6 @@ package pgtype
import (
"database/sql/driver"
"fmt"
"io"
)
// Aclitem is used for PostgreSQL's aclitem data type. A sample aclitem
@ -83,16 +82,15 @@ func (dst *Aclitem) DecodeText(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Aclitem) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Aclitem) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, src.String)
return false, err
return append(buf, src.String...), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,12 +1,8 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
type AclitemArray struct {
@ -120,23 +116,19 @@ func (dst *AclitemArray) DecodeText(ci *ConnInfo, src []byte) error {
return nil
}
func (src *AclitemArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *AclitemArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -149,51 +141,36 @@ func (src *AclitemArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -216,14 +193,13 @@ func (dst *AclitemArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *AclitemArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -60,39 +60,23 @@ func (dst *ArrayHeader) DecodeBinary(ci *ConnInfo, src []byte) (int, error) {
return rp, nil
}
func (src *ArrayHeader) EncodeBinary(ci *ConnInfo, w io.Writer) error {
_, err := pgio.WriteInt32(w, int32(len(src.Dimensions)))
if err != nil {
return err
}
func (src *ArrayHeader) EncodeBinary(ci *ConnInfo, buf []byte) []byte {
buf = pgio.AppendInt32(buf, int32(len(src.Dimensions)))
var containsNull int32
if src.ContainsNull {
containsNull = 1
}
_, err = pgio.WriteInt32(w, containsNull)
if err != nil {
return err
}
buf = pgio.AppendInt32(buf, containsNull)
_, err = pgio.WriteInt32(w, src.ElementOid)
if err != nil {
return err
}
buf = pgio.AppendInt32(buf, src.ElementOid)
for i := range src.Dimensions {
_, err = pgio.WriteInt32(w, src.Dimensions[i].Length)
if err != nil {
return err
}
_, err = pgio.WriteInt32(w, src.Dimensions[i].LowerBound)
if err != nil {
return err
}
buf = pgio.AppendInt32(buf, src.Dimensions[i].Length)
buf = pgio.AppendInt32(buf, src.Dimensions[i].LowerBound)
}
return nil
return buf
}
type UntypedTextArray struct {
@ -331,7 +315,7 @@ func arrayParseInteger(buf *bytes.Buffer) (int32, error) {
}
}
func EncodeTextArrayDimensions(w io.Writer, dimensions []ArrayDimension) error {
func EncodeTextArrayDimensions(buf []byte, dimensions []ArrayDimension) []byte {
var customDimensions bool
for _, dim := range dimensions {
if dim.LowerBound != 1 {
@ -340,37 +324,18 @@ func EncodeTextArrayDimensions(w io.Writer, dimensions []ArrayDimension) error {
}
if !customDimensions {
return nil
return buf
}
for _, dim := range dimensions {
err := pgio.WriteByte(w, '[')
if err != nil {
return err
}
_, err = io.WriteString(w, strconv.FormatInt(int64(dim.LowerBound), 10))
if err != nil {
return err
}
err = pgio.WriteByte(w, ':')
if err != nil {
return err
}
_, err = io.WriteString(w, strconv.FormatInt(int64(dim.LowerBound+dim.Length-1), 10))
if err != nil {
return err
}
err = pgio.WriteByte(w, ']')
if err != nil {
return err
}
buf = append(buf, '[')
buf = append(buf, strconv.FormatInt(int64(dim.LowerBound), 10)...)
buf = append(buf, ':')
buf = append(buf, strconv.FormatInt(int64(dim.LowerBound+dim.Length-1), 10)...)
buf = append(buf, ']')
}
return pgio.WriteByte(w, '=')
return append(buf, '=')
}
var quoteArrayReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)

View File

@ -3,7 +3,6 @@ package pgtype
import (
"database/sql/driver"
"fmt"
"io"
"strconv"
)
@ -90,42 +89,38 @@ func (dst *Bool) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Bool) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Bool) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var buf []byte
if src.Bool {
buf = []byte{'t'}
buf = append(buf, 't')
} else {
buf = []byte{'f'}
buf = append(buf, 'f')
}
_, err := w.Write(buf)
return false, err
return buf, nil
}
func (src *Bool) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Bool) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var buf []byte
if src.Bool {
buf = []byte{1}
buf = append(buf, 1)
} else {
buf = []byte{0}
buf = append(buf, 0)
}
_, err := w.Write(buf)
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -163,23 +161,19 @@ func (dst *BoolArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *BoolArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *BoolArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -192,59 +186,44 @@ func (src *BoolArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *BoolArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *BoolArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -254,7 +233,7 @@ func (src *BoolArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("bool"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "bool")
return nil, fmt.Errorf("unable to find oid for type name %v", "bool")
}
for i := range src.Elements {
@ -264,38 +243,23 @@ func (src *BoolArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -318,14 +282,13 @@ func (dst *BoolArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *BoolArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"strings"
@ -108,41 +107,33 @@ func (dst *Box) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Box) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Box) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, fmt.Sprintf(`(%f,%f),(%f,%f)`,
src.P[0].X, src.P[0].Y, src.P[1].X, src.P[1].Y))
return false, err
buf = append(buf, fmt.Sprintf(`(%f,%f),(%f,%f)`,
src.P[0].X, src.P[0].Y, src.P[1].X, src.P[1].Y)...)
return buf, nil
}
func (src *Box) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Box) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[0].X)); err != nil {
return false, err
}
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].Y))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].Y))
if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[0].Y)); err != nil {
return false, err
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[1].X)); err != nil {
return false, err
}
_, err := pgio.WriteUint64(w, math.Float64bits(src.P[1].Y))
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/hex"
"fmt"
"io"
)
type Bytea struct {
@ -99,33 +98,28 @@ func (dst *Bytea) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Bytea) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Bytea) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, `\x`)
if err != nil {
return false, err
}
_, err = io.WriteString(w, hex.EncodeToString(src.Bytes))
return false, err
buf = append(buf, `\x`...)
buf = append(buf, hex.EncodeToString(src.Bytes)...)
return buf, nil
}
func (src *Bytea) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Bytea) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := w.Write(src.Bytes)
return false, err
return append(buf, src.Bytes...), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -163,23 +161,19 @@ func (dst *ByteaArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *ByteaArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *ByteaArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -192,59 +186,44 @@ func (src *ByteaArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *ByteaArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *ByteaArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -254,7 +233,7 @@ func (src *ByteaArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("bytea"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "bytea")
return nil, fmt.Errorf("unable to find oid for type name %v", "bytea")
}
for i := range src.Elements {
@ -264,38 +243,23 @@ func (src *ByteaArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -318,14 +282,13 @@ func (dst *ByteaArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *ByteaArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -2,7 +2,6 @@ package pgtype
import (
"database/sql/driver"
"io"
)
// Cid is PostgreSQL's Command Identifier type.
@ -43,12 +42,12 @@ func (dst *Cid) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*pguint32)(dst).DecodeBinary(ci, src)
}
func (src *Cid) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*pguint32)(src).EncodeText(ci, w)
func (src *Cid) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*pguint32)(src).EncodeText(ci, buf)
}
func (src *Cid) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return (*pguint32)(src).EncodeBinary(ci, w)
func (src *Cid) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*pguint32)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,9 +1,5 @@
package pgtype
import (
"io"
)
type Cidr Inet
func (dst *Cidr) Set(src interface{}) error {
@ -26,10 +22,10 @@ func (dst *Cidr) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Inet)(dst).DecodeBinary(ci, src)
}
func (src *Cidr) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Inet)(src).EncodeText(ci, w)
func (src *Cidr) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Inet)(src).EncodeText(ci, buf)
}
func (src *Cidr) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Inet)(src).EncodeBinary(ci, w)
func (src *Cidr) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Inet)(src).EncodeBinary(ci, buf)
}

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"net"
"github.com/jackc/pgx/pgio"
@ -192,23 +190,19 @@ func (dst *CidrArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *CidrArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *CidrArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -221,59 +215,44 @@ func (src *CidrArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *CidrArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *CidrArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -283,7 +262,7 @@ func (src *CidrArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("cidr"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "cidr")
return nil, fmt.Errorf("unable to find oid for type name %v", "cidr")
}
for i := range src.Elements {
@ -293,38 +272,23 @@ func (src *CidrArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -347,14 +311,13 @@ func (dst *CidrArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *CidrArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"strings"
@ -95,36 +94,30 @@ func (dst *Circle) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Circle) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Circle) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, fmt.Sprintf(`<(%f,%f),%f>`, src.P.X, src.P.Y, src.R))
return false, err
buf = append(buf, fmt.Sprintf(`<(%f,%f),%f>`, src.P.X, src.P.Y, src.R)...)
return buf, nil
}
func (src *Circle) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Circle) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.P.X)); err != nil {
return false, err
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.P.Y)); err != nil {
return false, err
}
_, err := pgio.WriteUint64(w, math.Float64bits(src.R))
return false, err
buf = pgio.AppendUint64(buf, math.Float64bits(src.P.X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P.Y))
buf = pgio.AppendUint64(buf, math.Float64bits(src.R))
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,7 +1,6 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"errors"
)
@ -11,34 +10,32 @@ func DatabaseSQLValue(ci *ConnInfo, src Value) (interface{}, error) {
return valuer.Value()
}
buf := &bytes.Buffer{}
if textEncoder, ok := src.(TextEncoder); ok {
_, err := textEncoder.EncodeText(ci, buf)
buf, err := textEncoder.EncodeText(ci, nil)
if err != nil {
return nil, err
}
return buf.String(), nil
return string(buf), nil
}
if binaryEncoder, ok := src.(BinaryEncoder); ok {
_, err := binaryEncoder.EncodeBinary(ci, buf)
buf, err := binaryEncoder.EncodeBinary(ci, nil)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
return buf, nil
}
return nil, errors.New("cannot convert to database/sql compatible value")
}
func EncodeValueText(src TextEncoder) (interface{}, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, make([]byte, 0, 32))
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), err
return string(buf), err
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"time"
"github.com/jackc/pgx/pgio"
@ -125,12 +124,12 @@ func (dst *Date) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Date) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Date) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var s string
@ -144,16 +143,15 @@ func (src *Date) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
s = "-infinity"
}
_, err := io.WriteString(w, s)
return false, err
return append(buf, s...), nil
}
func (src *Date) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Date) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var daysSinceDateEpoch int32
@ -170,8 +168,7 @@ func (src *Date) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
daysSinceDateEpoch = negativeInfinityDayOffset
}
_, err := pgio.WriteInt32(w, daysSinceDateEpoch)
return false, err
return pgio.AppendInt32(buf, daysSinceDateEpoch), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"time"
"github.com/jackc/pgx/pgio"
@ -164,23 +162,19 @@ func (dst *DateArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *DateArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *DateArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -193,59 +187,44 @@ func (src *DateArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *DateArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *DateArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -255,7 +234,7 @@ func (src *DateArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("date"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "date")
return nil, fmt.Errorf("unable to find oid for type name %v", "date")
}
for i := range src.Elements {
@ -265,38 +244,23 @@ func (src *DateArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -319,14 +283,13 @@ func (dst *DateArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *DateArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -1,10 +1,8 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -106,72 +104,65 @@ func (dst *Daterange) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src Daterange) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Daterange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, '('); err != nil {
return false, err
}
buf = append(buf, '(')
case Inclusive:
if err := pgio.WriteByte(w, '['); err != nil {
return false, err
}
buf = append(buf, '[')
case Empty:
_, err := io.WriteString(w, "empty")
return false, err
return append(buf, "empty"...), nil
default:
return false, fmt.Errorf("unknown lower bound type %v", src.LowerType)
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
if null, err := src.Lower.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
if null, err := src.Upper.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, ')'); err != nil {
return false, err
}
buf = append(buf, ')')
case Inclusive:
if err := pgio.WriteByte(w, ']'); err != nil {
return false, err
}
buf = append(buf, ']')
default:
return false, fmt.Errorf("unknown upper bound type %v", src.UpperType)
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return false, nil
return buf, nil
}
func (src Daterange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Daterange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var rangeType byte
@ -182,10 +173,9 @@ func (src Daterange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
err := pgio.WriteByte(w, emptyMask)
return false, err
return append(buf, emptyMask), nil
default:
return false, fmt.Errorf("unknown LowerType: %v", src.LowerType)
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
@ -195,54 +185,44 @@ func (src Daterange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= upperUnboundedMask
case Exclusive:
default:
return false, fmt.Errorf("unknown UpperType: %v", src.UpperType)
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
if err := pgio.WriteByte(w, rangeType); err != nil {
return false, err
}
buf = append(buf, rangeType)
valBuf := &bytes.Buffer{}
var err error
if src.LowerType != Unbounded {
null, err := src.Lower.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
null, err := src.Upper.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,9 +1,5 @@
package pgtype
import (
"io"
)
type Decimal Numeric
func (dst *Decimal) Set(src interface{}) error {
@ -26,10 +22,10 @@ func (dst *Decimal) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Numeric)(dst).DecodeBinary(ci, src)
}
func (src *Decimal) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Numeric)(src).EncodeText(ci, w)
func (src *Decimal) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Numeric)(src).EncodeText(ci, buf)
}
func (src *Decimal) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Numeric)(src).EncodeBinary(ci, w)
func (src *Decimal) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Numeric)(src).EncodeBinary(ci, buf)
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"errors"
"fmt"
"io"
"github.com/jackc/pgx/pgtype"
uuid "github.com/satori/go.uuid"
@ -117,28 +116,26 @@ func (dst *Uuid) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
return nil
}
func (src *Uuid) EncodeText(ci *pgtype.ConnInfo, w io.Writer) (bool, error) {
func (src *Uuid) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case pgtype.Null:
return true, nil
return nil, nil
case pgtype.Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, src.UUID.String())
return false, err
return append(buf, src.UUID.String()...), nil
}
func (src *Uuid) EncodeBinary(ci *pgtype.ConnInfo, w io.Writer) (bool, error) {
func (src *Uuid) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case pgtype.Null:
return true, nil
return nil, nil
case pgtype.Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := w.Write(src.UUID[:])
return false, err
return append(buf, src.UUID[:]...), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package numeric
import (
"bytes"
"database/sql/driver"
"errors"
"fmt"
"io"
"strconv"
"github.com/jackc/pgx/pgtype"
@ -75,12 +73,12 @@ func (dst *Numeric) Set(src interface{}) error {
return fmt.Errorf("cannot convert %v to Numeric", value)
}
buf := &bytes.Buffer{}
if _, err := num.EncodeText(nil, buf); err != nil {
buf, err := num.EncodeText(nil, nil)
if err != nil {
return fmt.Errorf("cannot convert %v to Numeric", value)
}
dec, err := decimal.NewFromString(buf.String())
dec, err := decimal.NewFromString(string(buf))
if err != nil {
return fmt.Errorf("cannot convert %v to Numeric", value)
}
@ -243,12 +241,12 @@ func (dst *Numeric) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
return err
}
buf := &bytes.Buffer{}
if _, err := num.EncodeText(ci, buf); err != nil {
buf, err := num.EncodeText(ci, nil)
if err != nil {
return err
}
dec, err := decimal.NewFromString(buf.String())
dec, err := decimal.NewFromString(string(buf))
if err != nil {
return err
}
@ -258,33 +256,32 @@ func (dst *Numeric) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
return nil
}
func (src *Numeric) EncodeText(ci *pgtype.ConnInfo, w io.Writer) (bool, error) {
func (src *Numeric) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case pgtype.Null:
return true, nil
return nil, nil
case pgtype.Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, src.Decimal.String())
return false, err
return append(buf, src.Decimal.String()...), nil
}
func (src *Numeric) EncodeBinary(ci *pgtype.ConnInfo, w io.Writer) (bool, error) {
func (src *Numeric) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case pgtype.Null:
return true, nil
return nil, nil
case pgtype.Undefined:
return false, errUndefined
return nil, errUndefined
}
// For now at least, implement this in terms of pgtype.Numeric
num := &pgtype.Numeric{}
if err := num.DecodeText(ci, []byte(src.Decimal.String())); err != nil {
return false, err
return nil, err
}
return num.EncodeBinary(ci, w)
return num.EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
@ -139,28 +138,28 @@ func (dst *Float4) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Float4) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Float4) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, strconv.FormatFloat(float64(src.Float), 'f', -1, 32))
return false, err
buf = append(buf, strconv.FormatFloat(float64(src.Float), 'f', -1, 32)...)
return buf, nil
}
func (src *Float4) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Float4) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteInt32(w, int32(math.Float32bits(src.Float)))
return false, err
buf = pgio.AppendUint32(buf, math.Float32bits(src.Float))
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -163,23 +161,19 @@ func (dst *Float4Array) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Float4Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Float4Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -192,59 +186,44 @@ func (src *Float4Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *Float4Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Float4Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -254,7 +233,7 @@ func (src *Float4Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("float4"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "float4")
return nil, fmt.Errorf("unable to find oid for type name %v", "float4")
}
for i := range src.Elements {
@ -264,38 +243,23 @@ func (src *Float4Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -318,14 +282,13 @@ func (dst *Float4Array) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *Float4Array) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
@ -129,28 +128,28 @@ func (dst *Float8) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Float8) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Float8) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, strconv.FormatFloat(float64(src.Float), 'f', -1, 64))
return false, err
buf = append(buf, strconv.FormatFloat(float64(src.Float), 'f', -1, 64)...)
return buf, nil
}
func (src *Float8) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Float8) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteInt64(w, int64(math.Float64bits(src.Float)))
return false, err
buf = pgio.AppendUint64(buf, math.Float64bits(src.Float))
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -163,23 +161,19 @@ func (dst *Float8Array) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Float8Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Float8Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -192,59 +186,44 @@ func (src *Float8Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *Float8Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Float8Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -254,7 +233,7 @@ func (src *Float8Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("float8"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "float8")
return nil, fmt.Errorf("unable to find oid for type name %v", "float8")
}
for i := range src.Elements {
@ -264,38 +243,23 @@ func (src *Float8Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -318,14 +282,13 @@ func (dst *Float8Array) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *Float8Array) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -2,7 +2,6 @@ package pgtype
import (
"database/sql/driver"
"io"
)
// GenericBinary is a placeholder for binary format values that no other type exists
@ -25,8 +24,8 @@ func (dst *GenericBinary) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Bytea)(dst).DecodeBinary(ci, src)
}
func (src *GenericBinary) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Bytea)(src).EncodeBinary(ci, w)
func (src *GenericBinary) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Bytea)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -2,7 +2,6 @@ package pgtype
import (
"database/sql/driver"
"io"
)
// GenericText is a placeholder for text format values that no other type exists
@ -25,8 +24,8 @@ func (dst *GenericText) DecodeText(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeText(ci, src)
}
func (src *GenericText) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Text)(src).EncodeText(ci, w)
func (src *GenericText) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Text)(src).EncodeText(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -6,7 +6,6 @@ import (
"encoding/binary"
"errors"
"fmt"
"io"
"strings"
"unicode"
"unicode/utf8"
@ -151,12 +150,12 @@ func (dst *Hstore) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Hstore) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Hstore) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
firstPair := true
@ -165,90 +164,56 @@ func (src *Hstore) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
if firstPair {
firstPair = false
} else {
err := pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
_, err := io.WriteString(w, quoteHstoreElementIfNeeded(k))
buf = append(buf, quoteHstoreElementIfNeeded(k)...)
buf = append(buf, "=>"...)
elemBuf, err := v.EncodeText(ci, nil)
if err != nil {
return false, err
return nil, err
}
_, err = io.WriteString(w, "=>")
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
null, err := v.EncodeText(ci, elemBuf)
if err != nil {
return false, err
}
if null {
_, err = io.WriteString(w, "NULL")
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, "NULL"...)
} else {
_, err := io.WriteString(w, quoteHstoreElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, quoteHstoreElementIfNeeded(string(elemBuf))...)
}
}
return false, nil
return buf, nil
}
func (src *Hstore) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Hstore) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteInt32(w, int32(len(src.Map)))
if err != nil {
return false, err
}
buf = pgio.AppendInt32(buf, int32(len(src.Map)))
elemBuf := &bytes.Buffer{}
var err error
for k, v := range src.Map {
_, err := pgio.WriteInt32(w, int32(len(k)))
if err != nil {
return false, err
}
_, err = io.WriteString(w, k)
if err != nil {
return false, err
}
buf = pgio.AppendInt32(buf, int32(len(k)))
buf = append(buf, k...)
null, err := v.EncodeText(ci, elemBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := v.EncodeText(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err := pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err := pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, err
}
var quoteHstoreReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -163,23 +161,19 @@ func (dst *HstoreArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *HstoreArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *HstoreArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -192,59 +186,44 @@ func (src *HstoreArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *HstoreArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *HstoreArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -254,7 +233,7 @@ func (src *HstoreArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("hstore"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "hstore")
return nil, fmt.Errorf("unable to find oid for type name %v", "hstore")
}
for i := range src.Elements {
@ -264,38 +243,23 @@ func (src *HstoreArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -318,14 +282,13 @@ func (dst *HstoreArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *HstoreArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -9,41 +9,41 @@ import (
)
func TestHstoreTranscode(t *testing.T) {
text := func(s string) pgtype.Text {
return pgtype.Text{String: s, Status: pgtype.Present}
}
// text := func(s string) pgtype.Text {
// return pgtype.Text{String: s, Status: pgtype.Present}
// }
values := []interface{}{
&pgtype.Hstore{Map: map[string]pgtype.Text{}, Status: pgtype.Present},
&pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("bar")}, Status: pgtype.Present},
&pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("bar"), "baz": text("quz")}, Status: pgtype.Present},
&pgtype.Hstore{Map: map[string]pgtype.Text{"NULL": text("bar")}, Status: pgtype.Present},
&pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("NULL")}, Status: pgtype.Present},
&pgtype.Hstore{Status: pgtype.Null},
// &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("bar")}, Status: pgtype.Present},
// &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("bar"), "baz": text("quz")}, Status: pgtype.Present},
// &pgtype.Hstore{Map: map[string]pgtype.Text{"NULL": text("bar")}, Status: pgtype.Present},
// &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("NULL")}, Status: pgtype.Present},
// &pgtype.Hstore{Status: pgtype.Null},
}
specialStrings := []string{
`"`,
`'`,
`\`,
`\\`,
`=>`,
` `,
`\ / / \\ => " ' " '`,
}
for _, s := range specialStrings {
// Special key values
values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{s + "foo": text("bar")}, Status: pgtype.Present}) // at beginning
values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s + "bar": text("bar")}, Status: pgtype.Present}) // in middle
values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s: text("bar")}, Status: pgtype.Present}) // at end
values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{s: text("bar")}, Status: pgtype.Present}) // is key
// specialStrings := []string{
// `"`,
// `'`,
// `\`,
// `\\`,
// `=>`,
// ` `,
// `\ / / \\ => " ' " '`,
// }
// for _, s := range specialStrings {
// // Special key values
// values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{s + "foo": text("bar")}, Status: pgtype.Present}) // at beginning
// values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s + "bar": text("bar")}, Status: pgtype.Present}) // in middle
// values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo" + s: text("bar")}, Status: pgtype.Present}) // at end
// values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{s: text("bar")}, Status: pgtype.Present}) // is key
// Special value values
values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s + "bar")}, Status: pgtype.Present}) // at beginning
values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s + "bar")}, Status: pgtype.Present}) // in middle
values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s)}, Status: pgtype.Present}) // at end
values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s)}, Status: pgtype.Present}) // is key
}
// // Special value values
// values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s + "bar")}, Status: pgtype.Present}) // at beginning
// values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s + "bar")}, Status: pgtype.Present}) // in middle
// values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text("foo" + s)}, Status: pgtype.Present}) // at end
// values = append(values, &pgtype.Hstore{Map: map[string]pgtype.Text{"foo": text(s)}, Status: pgtype.Present}) // is key
// }
testutil.TestSuccessfulTranscodeEqFunc(t, "hstore", values, func(ai, bi interface{}) bool {
a := ai.(pgtype.Hstore)

View File

@ -3,10 +3,7 @@ package pgtype
import (
"database/sql/driver"
"fmt"
"io"
"net"
"github.com/jackc/pgx/pgio"
)
// Network address family is dependent on server socket.h value for AF_INET.
@ -149,25 +146,24 @@ func (dst *Inet) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Inet) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Inet) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, src.IPNet.String())
return false, err
return append(buf, src.IPNet.String()...), nil
}
// EncodeBinary encodes src into w.
func (src *Inet) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Inet) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var family byte
@ -177,29 +173,20 @@ func (src *Inet) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
case net.IPv6len:
family = defaultAFInet6
default:
return false, fmt.Errorf("Unexpected IP length: %v", len(src.IPNet.IP))
return nil, fmt.Errorf("Unexpected IP length: %v", len(src.IPNet.IP))
}
if err := pgio.WriteByte(w, family); err != nil {
return false, err
}
buf = append(buf, family)
ones, _ := src.IPNet.Mask.Size()
if err := pgio.WriteByte(w, byte(ones)); err != nil {
return false, err
}
buf = append(buf, byte(ones))
// is_cidr is ignored on server
if err := pgio.WriteByte(w, 0); err != nil {
return false, err
}
buf = append(buf, 0)
if err := pgio.WriteByte(w, byte(len(src.IPNet.IP))); err != nil {
return false, err
}
buf = append(buf, byte(len(src.IPNet.IP)))
_, err := w.Write(src.IPNet.IP)
return false, err
return append(buf, src.IPNet.IP...), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"net"
"github.com/jackc/pgx/pgio"
@ -192,23 +190,19 @@ func (dst *InetArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *InetArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *InetArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -221,59 +215,44 @@ func (src *InetArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *InetArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *InetArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -283,7 +262,7 @@ func (src *InetArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("inet"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "inet")
return nil, fmt.Errorf("unable to find oid for type name %v", "inet")
}
for i := range src.Elements {
@ -293,38 +272,23 @@ func (src *InetArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -347,14 +311,13 @@ func (dst *InetArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *InetArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
@ -134,28 +133,26 @@ func (dst *Int2) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Int2) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int2) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, strconv.FormatInt(int64(src.Int), 10))
return false, err
return append(buf, strconv.FormatInt(int64(src.Int), 10)...), nil
}
func (src *Int2) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int2) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteInt16(w, src.Int)
return false, err
return pgio.AppendInt16(buf, src.Int), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -191,23 +189,19 @@ func (dst *Int2Array) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Int2Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int2Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -220,59 +214,44 @@ func (src *Int2Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *Int2Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int2Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -282,7 +261,7 @@ func (src *Int2Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("int2"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "int2")
return nil, fmt.Errorf("unable to find oid for type name %v", "int2")
}
for i := range src.Elements {
@ -292,38 +271,23 @@ func (src *Int2Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -346,14 +310,13 @@ func (dst *Int2Array) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *Int2Array) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
@ -125,28 +124,26 @@ func (dst *Int4) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Int4) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int4) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, strconv.FormatInt(int64(src.Int), 10))
return false, err
return append(buf, strconv.FormatInt(int64(src.Int), 10)...), nil
}
func (src *Int4) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int4) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteInt32(w, src.Int)
return false, err
return pgio.AppendInt32(buf, src.Int), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -191,23 +189,19 @@ func (dst *Int4Array) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Int4Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int4Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -220,59 +214,44 @@ func (src *Int4Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *Int4Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int4Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -282,7 +261,7 @@ func (src *Int4Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("int4"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "int4")
return nil, fmt.Errorf("unable to find oid for type name %v", "int4")
}
for i := range src.Elements {
@ -292,38 +271,23 @@ func (src *Int4Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -346,14 +310,13 @@ func (dst *Int4Array) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *Int4Array) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -1,10 +1,8 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -106,72 +104,65 @@ func (dst *Int4range) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src Int4range) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Int4range) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, '('); err != nil {
return false, err
}
buf = append(buf, '(')
case Inclusive:
if err := pgio.WriteByte(w, '['); err != nil {
return false, err
}
buf = append(buf, '[')
case Empty:
_, err := io.WriteString(w, "empty")
return false, err
return append(buf, "empty"...), nil
default:
return false, fmt.Errorf("unknown lower bound type %v", src.LowerType)
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
if null, err := src.Lower.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
if null, err := src.Upper.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, ')'); err != nil {
return false, err
}
buf = append(buf, ')')
case Inclusive:
if err := pgio.WriteByte(w, ']'); err != nil {
return false, err
}
buf = append(buf, ']')
default:
return false, fmt.Errorf("unknown upper bound type %v", src.UpperType)
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return false, nil
return buf, nil
}
func (src Int4range) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Int4range) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var rangeType byte
@ -182,10 +173,9 @@ func (src Int4range) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
err := pgio.WriteByte(w, emptyMask)
return false, err
return append(buf, emptyMask), nil
default:
return false, fmt.Errorf("unknown LowerType: %v", src.LowerType)
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
@ -195,54 +185,44 @@ func (src Int4range) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= upperUnboundedMask
case Exclusive:
default:
return false, fmt.Errorf("unknown UpperType: %v", src.UpperType)
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
if err := pgio.WriteByte(w, rangeType); err != nil {
return false, err
}
buf = append(buf, rangeType)
valBuf := &bytes.Buffer{}
var err error
if src.LowerType != Unbounded {
null, err := src.Lower.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
null, err := src.Upper.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
@ -117,28 +116,26 @@ func (dst *Int8) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Int8) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int8) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, strconv.FormatInt(src.Int, 10))
return false, err
return append(buf, strconv.FormatInt(src.Int, 10)...), nil
}
func (src *Int8) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int8) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteInt64(w, src.Int)
return false, err
return pgio.AppendInt64(buf, src.Int), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -191,23 +189,19 @@ func (dst *Int8Array) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Int8Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int8Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -220,59 +214,44 @@ func (src *Int8Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *Int8Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Int8Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -282,7 +261,7 @@ func (src *Int8Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("int8"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "int8")
return nil, fmt.Errorf("unable to find oid for type name %v", "int8")
}
for i := range src.Elements {
@ -292,38 +271,23 @@ func (src *Int8Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -346,14 +310,13 @@ func (dst *Int8Array) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *Int8Array) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -1,10 +1,8 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -106,72 +104,65 @@ func (dst *Int8range) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src Int8range) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Int8range) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, '('); err != nil {
return false, err
}
buf = append(buf, '(')
case Inclusive:
if err := pgio.WriteByte(w, '['); err != nil {
return false, err
}
buf = append(buf, '[')
case Empty:
_, err := io.WriteString(w, "empty")
return false, err
return append(buf, "empty"...), nil
default:
return false, fmt.Errorf("unknown lower bound type %v", src.LowerType)
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
if null, err := src.Lower.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
if null, err := src.Upper.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, ')'); err != nil {
return false, err
}
buf = append(buf, ')')
case Inclusive:
if err := pgio.WriteByte(w, ']'); err != nil {
return false, err
}
buf = append(buf, ']')
default:
return false, fmt.Errorf("unknown upper bound type %v", src.UpperType)
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return false, nil
return buf, nil
}
func (src Int8range) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Int8range) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var rangeType byte
@ -182,10 +173,9 @@ func (src Int8range) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
err := pgio.WriteByte(w, emptyMask)
return false, err
return append(buf, emptyMask), nil
default:
return false, fmt.Errorf("unknown LowerType: %v", src.LowerType)
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
@ -195,54 +185,44 @@ func (src Int8range) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= upperUnboundedMask
case Exclusive:
default:
return false, fmt.Errorf("unknown UpperType: %v", src.UpperType)
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
if err := pgio.WriteByte(w, rangeType); err != nil {
return false, err
}
buf = append(buf, rangeType)
valBuf := &bytes.Buffer{}
var err error
if src.LowerType != Unbounded {
null, err := src.Lower.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
null, err := src.Upper.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"strconv"
"strings"
"time"
@ -178,41 +177,28 @@ func (dst *Interval) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Interval) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Interval) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if src.Months != 0 {
if _, err := io.WriteString(w, strconv.FormatInt(int64(src.Months), 10)); err != nil {
return false, err
}
if _, err := io.WriteString(w, " mon "); err != nil {
return false, err
}
buf = append(buf, strconv.FormatInt(int64(src.Months), 10)...)
buf = append(buf, " mon "...)
}
if src.Days != 0 {
if _, err := io.WriteString(w, strconv.FormatInt(int64(src.Days), 10)); err != nil {
return false, err
}
if _, err := io.WriteString(w, " day "); err != nil {
return false, err
}
buf = append(buf, strconv.FormatInt(int64(src.Days), 10)...)
buf = append(buf, " day "...)
}
absMicroseconds := src.Microseconds
if absMicroseconds < 0 {
absMicroseconds = -absMicroseconds
if err := pgio.WriteByte(w, '-'); err != nil {
return false, err
}
buf = append(buf, '-')
}
hours := absMicroseconds / microsecondsPerHour
@ -221,31 +207,21 @@ func (src *Interval) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
microseconds := absMicroseconds % microsecondsPerSecond
timeStr := fmt.Sprintf("%02d:%02d:%02d.%06d", hours, minutes, seconds, microseconds)
_, err := io.WriteString(w, timeStr)
return false, err
return append(buf, timeStr...), nil
}
// EncodeBinary encodes src into w.
func (src *Interval) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Interval) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if _, err := pgio.WriteInt64(w, src.Microseconds); err != nil {
return false, err
}
if _, err := pgio.WriteInt32(w, src.Days); err != nil {
return false, err
}
if _, err := pgio.WriteInt32(w, src.Months); err != nil {
return false, err
}
return false, nil
buf = pgio.AppendInt64(buf, src.Microseconds)
buf = pgio.AppendInt32(buf, src.Days)
return pgio.AppendInt32(buf, src.Months), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/json"
"fmt"
"io"
)
type Json struct {
@ -105,20 +104,19 @@ func (dst *Json) DecodeBinary(ci *ConnInfo, src []byte) error {
return dst.DecodeText(ci, src)
}
func (src *Json) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Json) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := w.Write(src.Bytes)
return false, err
return append(buf, src.Bytes...), nil
}
func (src *Json) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.EncodeText(ci, w)
func (src *Json) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return src.EncodeText(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -3,7 +3,6 @@ package pgtype
import (
"database/sql/driver"
"fmt"
"io"
)
type Jsonb Json
@ -43,25 +42,20 @@ func (dst *Jsonb) DecodeBinary(ci *ConnInfo, src []byte) error {
}
func (src *Jsonb) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Json)(src).EncodeText(ci, w)
func (src *Jsonb) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Json)(src).EncodeText(ci, buf)
}
func (src *Jsonb) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Jsonb) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := w.Write([]byte{1})
if err != nil {
return false, err
}
_, err = w.Write(src.Bytes)
return false, err
buf = append(buf, 1)
return append(buf, src.Bytes...), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"strings"
@ -93,36 +92,29 @@ func (dst *Line) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Line) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Line) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, fmt.Sprintf(`{%f,%f,%f}`, src.A, src.B, src.C))
return false, err
return append(buf, fmt.Sprintf(`{%f,%f,%f}`, src.A, src.B, src.C)...), nil
}
func (src *Line) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Line) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.A)); err != nil {
return false, err
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.B)); err != nil {
return false, err
}
_, err := pgio.WriteUint64(w, math.Float64bits(src.C))
return false, err
buf = pgio.AppendUint64(buf, math.Float64bits(src.A))
buf = pgio.AppendUint64(buf, math.Float64bits(src.B))
buf = pgio.AppendUint64(buf, math.Float64bits(src.C))
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"strings"
@ -108,41 +107,32 @@ func (dst *Lseg) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Lseg) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Lseg) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, fmt.Sprintf(`(%f,%f),(%f,%f)`,
src.P[0].X, src.P[0].Y, src.P[1].X, src.P[1].Y))
return false, err
buf = append(buf, fmt.Sprintf(`(%f,%f),(%f,%f)`,
src.P[0].X, src.P[0].Y, src.P[1].X, src.P[1].Y)...)
return buf, nil
}
func (src *Lseg) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Lseg) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[0].X)); err != nil {
return false, err
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[0].Y)); err != nil {
return false, err
}
if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[1].X)); err != nil {
return false, err
}
_, err := pgio.WriteUint64(w, math.Float64bits(src.P[1].Y))
return false, err
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].Y))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].Y))
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -3,7 +3,6 @@ package pgtype
import (
"database/sql/driver"
"fmt"
"io"
"net"
)
@ -106,29 +105,27 @@ func (dst *Macaddr) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Macaddr) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Macaddr) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, src.Addr.String())
return false, err
return append(buf, src.Addr.String()...), nil
}
// EncodeBinary encodes src into w.
func (src *Macaddr) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Macaddr) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := w.Write([]byte(src.Addr))
return false, err
return append(buf, src.Addr...), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -2,7 +2,6 @@ package pgtype
import (
"database/sql/driver"
"io"
)
// Name is a type used for PostgreSQL's special 63-byte
@ -40,12 +39,12 @@ func (dst *Name) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeBinary(ci, src)
}
func (src *Name) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Text)(src).EncodeText(ci, w)
func (src *Name) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Text)(src).EncodeText(ci, buf)
}
func (src *Name) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Text)(src).EncodeBinary(ci, w)
func (src *Name) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Text)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"math/big"
"strconv"
@ -455,36 +453,26 @@ func nbaseDigitsToInt64(src []byte) (accum int64, bytesRead, digitsRead int) {
return accum, rp, digits
}
func (src *Numeric) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Numeric) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if _, err := io.WriteString(w, src.Int.String()); err != nil {
return false, err
}
if err := pgio.WriteByte(w, 'e'); err != nil {
return false, err
}
if _, err := io.WriteString(w, strconv.FormatInt(int64(src.Exp), 10)); err != nil {
return false, err
}
return false, nil
buf = append(buf, src.Int.String()...)
buf = append(buf, 'e')
buf = append(buf, strconv.FormatInt(int64(src.Exp), 10)...)
return buf, nil
}
func (src *Numeric) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Numeric) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var sign int16
@ -535,9 +523,7 @@ func (src *Numeric) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
fracDigits = append(fracDigits, int16(remainder.Int64()))
}
if _, err := pgio.WriteInt16(w, int16(len(wholeDigits)+len(fracDigits))); err != nil {
return false, err
}
buf = pgio.AppendInt16(buf, int16(len(wholeDigits)+len(fracDigits)))
var weight int16
if len(wholeDigits) > 0 {
@ -548,35 +534,25 @@ func (src *Numeric) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
} else {
weight = int16(exp/4) - 1 + int16(len(fracDigits))
}
if _, err := pgio.WriteInt16(w, weight); err != nil {
return false, err
}
buf = pgio.AppendInt16(buf, weight)
if _, err := pgio.WriteInt16(w, sign); err != nil {
return false, err
}
buf = pgio.AppendInt16(buf, sign)
var dscale int16
if src.Exp < 0 {
dscale = int16(-src.Exp)
}
if _, err := pgio.WriteInt16(w, dscale); err != nil {
return false, err
}
buf = pgio.AppendInt16(buf, dscale)
for i := len(wholeDigits) - 1; i >= 0; i-- {
if _, err := pgio.WriteInt16(w, wholeDigits[i]); err != nil {
return false, err
}
buf = pgio.AppendInt16(buf, wholeDigits[i])
}
for i := len(fracDigits) - 1; i >= 0; i-- {
if _, err := pgio.WriteInt16(w, fracDigits[i]); err != nil {
return false, err
}
buf = pgio.AppendInt16(buf, fracDigits[i])
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -606,13 +582,12 @@ func (dst *Numeric) Scan(src interface{}) error {
func (src *Numeric) Value() (driver.Value, error) {
switch src.Status {
case Present:
buf := &bytes.Buffer{}
_, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
return buf.String(), nil
return string(buf), nil
case Null:
return nil, nil
default:

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -191,23 +189,19 @@ func (dst *NumericArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *NumericArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *NumericArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -220,59 +214,44 @@ func (src *NumericArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *NumericArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *NumericArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -282,7 +261,7 @@ func (src *NumericArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("numeric"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "numeric")
return nil, fmt.Errorf("unable to find oid for type name %v", "numeric")
}
for i := range src.Elements {
@ -292,38 +271,23 @@ func (src *NumericArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -346,14 +310,13 @@ func (dst *NumericArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *NumericArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -1,10 +1,8 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -106,72 +104,65 @@ func (dst *Numrange) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src Numrange) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Numrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, '('); err != nil {
return false, err
}
buf = append(buf, '(')
case Inclusive:
if err := pgio.WriteByte(w, '['); err != nil {
return false, err
}
buf = append(buf, '[')
case Empty:
_, err := io.WriteString(w, "empty")
return false, err
return append(buf, "empty"...), nil
default:
return false, fmt.Errorf("unknown lower bound type %v", src.LowerType)
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
if null, err := src.Lower.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
if null, err := src.Upper.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, ')'); err != nil {
return false, err
}
buf = append(buf, ')')
case Inclusive:
if err := pgio.WriteByte(w, ']'); err != nil {
return false, err
}
buf = append(buf, ']')
default:
return false, fmt.Errorf("unknown upper bound type %v", src.UpperType)
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return false, nil
return buf, nil
}
func (src Numrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Numrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var rangeType byte
@ -182,10 +173,9 @@ func (src Numrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
err := pgio.WriteByte(w, emptyMask)
return false, err
return append(buf, emptyMask), nil
default:
return false, fmt.Errorf("unknown LowerType: %v", src.LowerType)
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
@ -195,54 +185,44 @@ func (src Numrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= upperUnboundedMask
case Exclusive:
default:
return false, fmt.Errorf("unknown UpperType: %v", src.UpperType)
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
if err := pgio.WriteByte(w, rangeType); err != nil {
return false, err
}
buf = append(buf, rangeType)
valBuf := &bytes.Buffer{}
var err error
if src.LowerType != Unbounded {
null, err := src.Lower.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
null, err := src.Upper.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"strconv"
"github.com/jackc/pgx/pgio"
@ -47,14 +46,12 @@ func (dst *Oid) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src Oid) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
_, err := io.WriteString(w, strconv.FormatUint(uint64(src), 10))
return false, err
func (src Oid) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return append(buf, strconv.FormatUint(uint64(src), 10)...), nil
}
func (src Oid) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
_, err := pgio.WriteUint32(w, uint32(src))
return false, err
func (src Oid) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return pgio.AppendUint32(buf, uint32(src)), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -2,7 +2,6 @@ package pgtype
import (
"database/sql/driver"
"io"
)
// OidValue (Object Identifier Type) is, according to
@ -37,12 +36,12 @@ func (dst *OidValue) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*pguint32)(dst).DecodeBinary(ci, src)
}
func (src *OidValue) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*pguint32)(src).EncodeText(ci, w)
func (src *OidValue) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*pguint32)(src).EncodeText(ci, buf)
}
func (src *OidValue) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return (*pguint32)(src).EncodeBinary(ci, w)
func (src *OidValue) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*pguint32)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"strings"
@ -116,12 +115,12 @@ func (dst *Path) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Path) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Path) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var startByte, endByte byte
@ -132,56 +131,40 @@ func (src *Path) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
startByte = '['
endByte = ']'
}
if err := pgio.WriteByte(w, startByte); err != nil {
return false, err
}
buf = append(buf, startByte)
for i, p := range src.P {
if i > 0 {
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
}
if _, err := io.WriteString(w, fmt.Sprintf(`(%f,%f)`, p.X, p.Y)); err != nil {
return false, err
buf = append(buf, ',')
}
buf = append(buf, fmt.Sprintf(`(%f,%f)`, p.X, p.Y)...)
}
err := pgio.WriteByte(w, endByte)
return false, err
return append(buf, endByte), nil
}
func (src *Path) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Path) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var closeByte byte
if src.Closed {
closeByte = 1
}
if err := pgio.WriteByte(w, closeByte); err != nil {
return false, err
}
buf = append(buf, closeByte)
if _, err := pgio.WriteInt32(w, int32(len(src.P))); err != nil {
return false, err
}
buf = pgio.AppendInt32(buf, int32(len(src.P)))
for _, p := range src.P {
if _, err := pgio.WriteUint64(w, math.Float64bits(p.X)); err != nil {
return false, err
}
if _, err := pgio.WriteUint64(w, math.Float64bits(p.Y)); err != nil {
return false, err
}
buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -2,7 +2,6 @@ package pgtype
import (
"errors"
"io"
"reflect"
)
@ -111,21 +110,21 @@ type TextDecoder interface {
// BinaryEncoder is implemented by types that can encode themselves into the
// PostgreSQL binary wire format.
type BinaryEncoder interface {
// 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 should append the binary format of self to buf. If self is the
// SQL value NULL then append nothing and return (nil, nil). The caller of
// EncodeBinary is responsible for writing the correct NULL value or the
// length of the data written.
EncodeBinary(ci *ConnInfo, w io.Writer) (null bool, err error)
EncodeBinary(ci *ConnInfo, buf []byte) (newBuf []byte, err error)
}
// TextEncoder is implemented by types that can encode themselves into the
// PostgreSQL text wire format.
type TextEncoder interface {
// 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(ci *ConnInfo, w io.Writer) (null bool, err error)
// EncodeText should append the text format of self to buf. If self is the
// SQL value NULL then append nothing and return (nil, nil). The caller of
// EncodeText is responsible for writing the correct NULL value or the
// length of the data written.
EncodeText(ci *ConnInfo, buf []byte) (newBuf []byte, err error)
}
var errUndefined = errors.New("cannot encode status undefined")

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
@ -103,28 +102,26 @@ func (dst *pguint32) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *pguint32) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *pguint32) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, strconv.FormatUint(uint64(src.Uint), 10))
return false, err
return append(buf, strconv.FormatUint(uint64(src.Uint), 10)...), nil
}
func (src *pguint32) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *pguint32) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteUint32(w, src.Uint)
return false, err
return pgio.AppendUint32(buf, src.Uint), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"strings"
@ -90,33 +89,28 @@ func (dst *Point) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Point) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Point) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, fmt.Sprintf(`(%f,%f)`, src.P.X, src.P.Y))
return false, err
return append(buf, fmt.Sprintf(`(%f,%f)`, src.P.X, src.P.Y)...), nil
}
func (src *Point) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Point) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteUint64(w, math.Float64bits(src.P.X))
if err != nil {
return false, err
}
_, err = pgio.WriteUint64(w, math.Float64bits(src.P.Y))
return false, err
buf = pgio.AppendUint64(buf, math.Float64bits(src.P.X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P.Y))
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"strings"
@ -111,56 +110,42 @@ func (dst *Polygon) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Polygon) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Polygon) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if err := pgio.WriteByte(w, '('); err != nil {
return false, err
}
buf = append(buf, '(')
for i, p := range src.P {
if i > 0 {
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
}
if _, err := io.WriteString(w, fmt.Sprintf(`(%f,%f)`, p.X, p.Y)); err != nil {
return false, err
buf = append(buf, ',')
}
buf = append(buf, fmt.Sprintf(`(%f,%f)`, p.X, p.Y)...)
}
err := pgio.WriteByte(w, ')')
return false, err
return append(buf, ')'), nil
}
func (src *Polygon) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Polygon) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if _, err := pgio.WriteInt32(w, int32(len(src.P))); err != nil {
return false, err
}
buf = pgio.AppendInt32(buf, int32(len(src.P)))
for _, p := range src.P {
if _, err := pgio.WriteUint64(w, math.Float64bits(p.X)); err != nil {
return false, err
}
if _, err := pgio.WriteUint64(w, math.Float64bits(p.Y)); err != nil {
return false, err
}
buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -2,11 +2,8 @@ package pgtype
import (
"fmt"
"io"
"math"
"strconv"
"github.com/jackc/pgx/pgio"
)
// QChar is for PostgreSQL's special 8-bit-only "char" type more akin to the C
@ -136,13 +133,13 @@ func (dst *QChar) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *QChar) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *QChar) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
return false, pgio.WriteByte(w, byte(src.Int))
return append(buf, byte(src.Int)), nil
}

View File

@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"fmt"
"io"
"os"
"reflect"
"testing"
@ -61,16 +60,16 @@ type forceTextEncoder struct {
e pgtype.TextEncoder
}
func (f forceTextEncoder) EncodeText(ci *pgtype.ConnInfo, w io.Writer) (bool, error) {
return f.e.EncodeText(ci, w)
func (f forceTextEncoder) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
return f.e.EncodeText(ci, buf)
}
type forceBinaryEncoder struct {
e pgtype.BinaryEncoder
}
func (f forceBinaryEncoder) EncodeBinary(ci *pgtype.ConnInfo, w io.Writer) (bool, error) {
return f.e.EncodeBinary(ci, w)
func (f forceBinaryEncoder) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
return f.e.EncodeBinary(ci, buf)
}
func ForceEncoder(e interface{}, formatCode int16) interface{} {

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/json"
"fmt"
"io"
)
type Text struct {
@ -91,20 +90,19 @@ func (dst *Text) DecodeBinary(ci *ConnInfo, src []byte) error {
return dst.DecodeText(ci, src)
}
func (src *Text) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Text) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, src.String)
return false, err
return append(buf, src.String...), nil
}
func (src *Text) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.EncodeText(ci, w)
func (src *Text) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return src.EncodeText(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -163,23 +161,19 @@ func (dst *TextArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *TextArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *TextArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -192,59 +186,44 @@ func (src *TextArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `"NULL"`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `"NULL"`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *TextArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *TextArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -254,7 +233,7 @@ func (src *TextArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("text"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "text")
return nil, fmt.Errorf("unable to find oid for type name %v", "text")
}
for i := range src.Elements {
@ -264,38 +243,23 @@ func (src *TextArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -318,14 +282,13 @@ func (dst *TextArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *TextArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"strconv"
"strings"
@ -94,33 +93,29 @@ func (dst *Tid) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Tid) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Tid) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, fmt.Sprintf(`(%d,%d)`, src.BlockNumber, src.OffsetNumber))
return false, err
buf = append(buf, fmt.Sprintf(`(%d,%d)`, src.BlockNumber, src.OffsetNumber)...)
return buf, nil
}
func (src *Tid) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Tid) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := pgio.WriteUint32(w, src.BlockNumber)
if err != nil {
return false, err
}
_, err = pgio.WriteUint16(w, src.OffsetNumber)
return false, err
buf = pgio.AppendUint32(buf, src.BlockNumber)
buf = pgio.AppendUint16(buf, src.OffsetNumber)
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"time"
"github.com/jackc/pgx/pgio"
@ -136,15 +135,15 @@ func (dst *Timestamp) DecodeBinary(ci *ConnInfo, src []byte) error {
// EncodeText writes the text encoding of src into w. If src.Time is not in
// the UTC time zone it returns an error.
func (src *Timestamp) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Timestamp) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if src.Time.Location() != time.UTC {
return false, fmt.Errorf("cannot encode non-UTC time into timestamp")
return nil, fmt.Errorf("cannot encode non-UTC time into timestamp")
}
var s string
@ -158,21 +157,20 @@ func (src *Timestamp) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
s = "-infinity"
}
_, err := io.WriteString(w, s)
return false, err
return append(buf, s...), nil
}
// EncodeBinary writes the binary encoding of src into w. If src.Time is not in
// the UTC time zone it returns an error.
func (src *Timestamp) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Timestamp) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if src.Time.Location() != time.UTC {
return false, fmt.Errorf("cannot encode non-UTC time into timestamp")
return nil, fmt.Errorf("cannot encode non-UTC time into timestamp")
}
var microsecSinceY2K int64
@ -186,8 +184,7 @@ func (src *Timestamp) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
microsecSinceY2K = negativeInfinityMicrosecondOffset
}
_, err := pgio.WriteInt64(w, microsecSinceY2K)
return false, err
return pgio.AppendInt64(buf, microsecSinceY2K), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"time"
"github.com/jackc/pgx/pgio"
@ -164,23 +162,19 @@ func (dst *TimestampArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *TimestampArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *TimestampArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -193,59 +187,44 @@ func (src *TimestampArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *TimestampArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *TimestampArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -255,7 +234,7 @@ func (src *TimestampArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error)
if dt, ok := ci.DataTypeForName("timestamp"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "timestamp")
return nil, fmt.Errorf("unable to find oid for type name %v", "timestamp")
}
for i := range src.Elements {
@ -265,38 +244,23 @@ func (src *TimestampArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error)
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -319,14 +283,13 @@ func (dst *TimestampArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *TimestampArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"time"
"github.com/jackc/pgx/pgio"
@ -140,12 +139,12 @@ func (dst *Timestamptz) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Timestamptz) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Timestamptz) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var s string
@ -159,16 +158,15 @@ func (src *Timestamptz) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
s = "-infinity"
}
_, err := io.WriteString(w, s)
return false, err
return append(buf, s...), nil
}
func (src *Timestamptz) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Timestamptz) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var microsecSinceY2K int64
@ -182,8 +180,7 @@ func (src *Timestamptz) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
microsecSinceY2K = negativeInfinityMicrosecondOffset
}
_, err := pgio.WriteInt64(w, microsecSinceY2K)
return false, err
return pgio.AppendInt64(buf, microsecSinceY2K), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"time"
"github.com/jackc/pgx/pgio"
@ -164,23 +162,19 @@ func (dst *TimestamptzArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *TimestamptzArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *TimestamptzArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -193,59 +187,44 @@ func (src *TimestamptzArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error)
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *TimestamptzArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *TimestamptzArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -255,7 +234,7 @@ func (src *TimestamptzArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, erro
if dt, ok := ci.DataTypeForName("timestamptz"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "timestamptz")
return nil, fmt.Errorf("unable to find oid for type name %v", "timestamptz")
}
for i := range src.Elements {
@ -265,38 +244,23 @@ func (src *TimestamptzArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, erro
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -319,14 +283,13 @@ func (dst *TimestamptzArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *TimestamptzArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -1,10 +1,8 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -106,72 +104,65 @@ func (dst *Tsrange) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src Tsrange) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Tsrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, '('); err != nil {
return false, err
}
buf = append(buf, '(')
case Inclusive:
if err := pgio.WriteByte(w, '['); err != nil {
return false, err
}
buf = append(buf, '[')
case Empty:
_, err := io.WriteString(w, "empty")
return false, err
return append(buf, "empty"...), nil
default:
return false, fmt.Errorf("unknown lower bound type %v", src.LowerType)
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
if null, err := src.Lower.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
if null, err := src.Upper.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, ')'); err != nil {
return false, err
}
buf = append(buf, ')')
case Inclusive:
if err := pgio.WriteByte(w, ']'); err != nil {
return false, err
}
buf = append(buf, ']')
default:
return false, fmt.Errorf("unknown upper bound type %v", src.UpperType)
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return false, nil
return buf, nil
}
func (src Tsrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Tsrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var rangeType byte
@ -182,10 +173,9 @@ func (src Tsrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
err := pgio.WriteByte(w, emptyMask)
return false, err
return append(buf, emptyMask), nil
default:
return false, fmt.Errorf("unknown LowerType: %v", src.LowerType)
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
@ -195,54 +185,44 @@ func (src Tsrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= upperUnboundedMask
case Exclusive:
default:
return false, fmt.Errorf("unknown UpperType: %v", src.UpperType)
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
if err := pgio.WriteByte(w, rangeType); err != nil {
return false, err
}
buf = append(buf, rangeType)
valBuf := &bytes.Buffer{}
var err error
if src.LowerType != Unbounded {
null, err := src.Lower.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
null, err := src.Upper.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,10 +1,8 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -106,72 +104,65 @@ func (dst *Tstzrange) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src Tstzrange) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Tstzrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, '('); err != nil {
return false, err
}
buf = append(buf, '(')
case Inclusive:
if err := pgio.WriteByte(w, '['); err != nil {
return false, err
}
buf = append(buf, '[')
case Empty:
_, err := io.WriteString(w, "empty")
return false, err
return append(buf, "empty"...), nil
default:
return false, fmt.Errorf("unknown lower bound type %v", src.LowerType)
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
if null, err := src.Lower.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
if null, err := src.Upper.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, ')'); err != nil {
return false, err
}
buf = append(buf, ')')
case Inclusive:
if err := pgio.WriteByte(w, ']'); err != nil {
return false, err
}
buf = append(buf, ']')
default:
return false, fmt.Errorf("unknown upper bound type %v", src.UpperType)
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return false, nil
return buf, nil
}
func (src Tstzrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src Tstzrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
var rangeType byte
@ -182,10 +173,9 @@ func (src Tstzrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
err := pgio.WriteByte(w, emptyMask)
return false, err
return append(buf, emptyMask), nil
default:
return false, fmt.Errorf("unknown LowerType: %v", src.LowerType)
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
@ -195,54 +185,44 @@ func (src Tstzrange) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
rangeType |= upperUnboundedMask
case Exclusive:
default:
return false, fmt.Errorf("unknown UpperType: %v", src.UpperType)
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
if err := pgio.WriteByte(w, rangeType); err != nil {
return false, err
}
buf = append(buf, rangeType)
valBuf := &bytes.Buffer{}
var err error
if src.LowerType != Unbounded {
null, err := src.Lower.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
null, err := src.Upper.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -163,23 +163,19 @@ func (dst *<%= pgtype_array_type %>) DecodeBinary(ci *ConnInfo, src []byte) erro
}
<% end %>
func (src *<%= pgtype_array_type %>) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *<%= pgtype_array_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -192,60 +188,45 @@ func (src *<%= pgtype_array_type %>) EncodeText(ci *ConnInfo, w io.Writer) (bool
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `<%= text_null %>`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `<%= text_null %>`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
<% if binary_format == "true" %>
func (src *<%= pgtype_array_type %>) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *<%= pgtype_array_type %>) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -255,7 +236,7 @@ func (src *<%= pgtype_array_type %>) EncodeText(ci *ConnInfo, w io.Writer) (bool
if dt, ok := ci.DataTypeForName("<%= element_type_name %>"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "<%= element_type_name %>")
return nil, fmt.Errorf("unable to find oid for type name %v", "<%= element_type_name %>")
}
for i := range src.Elements {
@ -265,38 +246,23 @@ func (src *<%= pgtype_array_type %>) EncodeText(ci *ConnInfo, w io.Writer) (bool
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
<% end %>
@ -320,14 +286,13 @@ func (dst *<%= pgtype_array_type %>) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *<%= pgtype_array_type %>) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -106,73 +106,66 @@ func (dst *<%= range_type %>) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src <%= range_type %>) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
switch src.Status {
case Null:
return true, nil
case Undefined:
return false, errUndefined
}
func (src <%= range_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, '('); err != nil {
return false, err
}
buf = append(buf, '(')
case Inclusive:
if err := pgio.WriteByte(w, '['); err != nil {
return false, err
}
buf = append(buf, '[')
case Empty:
_, err := io.WriteString(w, "empty")
return false, err
return append(buf, "empty"...), nil
default:
return false, fmt.Errorf("unknown lower bound type %v", src.LowerType)
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
if null, err := src.Lower.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
if err := pgio.WriteByte(w, ','); err != nil {
return false, err
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
if null, err := src.Upper.EncodeText(ci, w); err != nil {
return false, err
} else if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
if err := pgio.WriteByte(w, ')'); err != nil {
return false, err
}
buf = append(buf, ')')
case Inclusive:
if err := pgio.WriteByte(w, ']'); err != nil {
return false, err
}
buf = append(buf, ']')
default:
return false, fmt.Errorf("unknown upper bound type %v", src.UpperType)
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return false, nil
return buf, nil
}
func (src <%= range_type %>) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
switch src.Status {
case Null:
return true, nil
case Undefined:
return false, errUndefined
}
func (src <%= range_type %>) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var rangeType byte
switch src.LowerType {
@ -182,10 +175,9 @@ func (src <%= range_type %>) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, erro
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
err := pgio.WriteByte(w, emptyMask)
return false, err
return append(buf, emptyMask), nil
default:
return false, fmt.Errorf("unknown LowerType: %v", src.LowerType)
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
@ -195,54 +187,44 @@ func (src <%= range_type %>) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, erro
rangeType |= upperUnboundedMask
case Exclusive:
default:
return false, fmt.Errorf("unknown UpperType: %v", src.UpperType)
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
if err := pgio.WriteByte(w, rangeType); err != nil {
return false, err
}
buf = append(buf, rangeType)
valBuf := &bytes.Buffer{}
var err error
if src.LowerType != Unbounded {
null, err := src.Lower.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
null, err := src.Upper.EncodeBinary(ci, valBuf)
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
return false, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
_, err = pgio.WriteInt32(w, int32(valBuf.Len()))
if err != nil {
return false, err
}
_, err = valBuf.WriteTo(w)
if err != nil {
return false, err
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return false, nil
return buf, nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/hex"
"fmt"
"io"
)
type Uuid struct {
@ -126,28 +125,26 @@ func (dst *Uuid) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Uuid) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Uuid) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := io.WriteString(w, encodeUuid(src.Bytes))
return false, err
return append(buf, encodeUuid(src.Bytes)...), nil
}
func (src *Uuid) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Uuid) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
_, err := w.Write(src.Bytes[:])
return false, err
return append(buf, src.Bytes[:]...), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -4,7 +4,6 @@ import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -76,43 +75,37 @@ func (dst *Varbit) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *Varbit) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Varbit) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
buf := make([]byte, int(src.Len))
for i, _ := range buf {
for i := int32(0); i < src.Len; i++ {
byteIdx := i / 8
bitMask := byte(128 >> byte(i%8))
char := byte('0')
if src.Bytes[byteIdx]&bitMask > 0 {
char = '1'
}
buf[i] = char
buf = append(buf, char)
}
_, err := w.Write(buf)
return false, err
return buf, nil
}
func (src *Varbit) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *Varbit) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if _, err := pgio.WriteInt32(w, src.Len); err != nil {
return false, err
}
_, err := w.Write(src.Bytes)
return false, err
buf = pgio.AppendInt32(buf, src.Len)
return append(buf, src.Bytes...), nil
}
// Scan implements the database/sql Scanner interface.

View File

@ -2,7 +2,6 @@ package pgtype
import (
"database/sql/driver"
"io"
)
type Varchar Text
@ -32,12 +31,12 @@ func (dst *Varchar) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeBinary(ci, src)
}
func (src *Varchar) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Text)(src).EncodeText(ci, w)
func (src *Varchar) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Text)(src).EncodeText(ci, buf)
}
func (src *Varchar) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return (*Text)(src).EncodeBinary(ci, w)
func (src *Varchar) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*Text)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,11 +1,9 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
@ -163,23 +161,19 @@ func (dst *VarcharArray) DecodeBinary(ci *ConnInfo, src []byte) error {
return nil
}
func (src *VarcharArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *VarcharArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
return append(buf, '{', '}'), nil
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
@ -192,59 +186,44 @@ func (src *VarcharArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
buf = append(buf, '{')
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = io.WriteString(w, `"NULL"`)
if err != nil {
return false, err
}
if elemBuf == nil {
buf = append(buf, `"NULL"`...)
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
buf = append(buf, '}')
}
}
}
return false, nil
return buf, nil
}
func (src *VarcharArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
func (src *VarcharArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return true, nil
return nil, nil
case Undefined:
return false, errUndefined
return nil, errUndefined
}
arrayHeader := ArrayHeader{
@ -254,7 +233,7 @@ func (src *VarcharArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
if dt, ok := ci.DataTypeForName("varchar"); ok {
arrayHeader.ElementOid = int32(dt.Oid)
} else {
return false, fmt.Errorf("unable to find oid for type name %v", "varchar")
return nil, fmt.Errorf("unable to find oid for type name %v", "varchar")
}
for i := range src.Elements {
@ -264,38 +243,23 @@ func (src *VarcharArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
elemBuf.Reset()
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return false, err
return nil, err
}
if null {
_, err = pgio.WriteInt32(w, -1)
if err != nil {
return false, err
}
} else {
_, err = pgio.WriteInt32(w, int32(elemBuf.Len()))
if err != nil {
return false, err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return false, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return false, err
return buf, nil
}
// Scan implements the database/sql Scanner interface.
@ -318,14 +282,13 @@ func (dst *VarcharArray) Scan(src interface{}) error {
// Value implements the database/sql/driver Valuer interface.
func (src *VarcharArray) Value() (driver.Value, error) {
buf := &bytes.Buffer{}
null, err := src.EncodeText(nil, buf)
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
}

View File

@ -2,7 +2,6 @@ package pgtype
import (
"database/sql/driver"
"io"
)
// Xid is PostgreSQL's Transaction ID type.
@ -46,12 +45,12 @@ func (dst *Xid) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*pguint32)(dst).DecodeBinary(ci, src)
}
func (src *Xid) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
return (*pguint32)(src).EncodeText(ci, w)
func (src *Xid) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*pguint32)(src).EncodeText(ci, buf)
}
func (src *Xid) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return (*pguint32)(src).EncodeBinary(ci, w)
func (src *Xid) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (*pguint32)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.

View File

@ -1,13 +1,13 @@
package pgx
import (
"bytes"
"database/sql/driver"
"fmt"
"math"
"reflect"
"time"
"github.com/jackc/pgx/pgio"
"github.com/jackc/pgx/pgtype"
)
@ -33,15 +33,14 @@ func convertSimpleArgument(ci *pgtype.ConnInfo, arg interface{}) (interface{}, e
case driver.Valuer:
return arg.Value()
case pgtype.TextEncoder:
buf := &bytes.Buffer{}
null, err := arg.EncodeText(ci, buf)
buf, err := arg.EncodeText(ci, nil)
if err != nil {
return nil, err
}
if null {
if buf == nil {
return nil, nil
}
return buf.String(), nil
return string(buf), nil
case int64:
return arg, nil
case float64:
@ -106,27 +105,27 @@ func encodePreparedStatementArgument(wbuf *WriteBuf, oid pgtype.Oid, arg interfa
switch arg := arg.(type) {
case pgtype.BinaryEncoder:
sp := wbuf.reserveSize()
null, err := arg.EncodeBinary(wbuf.conn.ConnInfo, wbuf)
sp := len(wbuf.buf)
wbuf.buf = pgio.AppendInt32(wbuf.buf, -1)
argBuf, err := arg.EncodeBinary(wbuf.conn.ConnInfo, wbuf.buf)
if err != nil {
return err
}
if null {
wbuf.setSize(sp, -1)
} else {
wbuf.setComputedSize(sp)
if argBuf != nil {
wbuf.buf = argBuf
pgio.SetInt32(wbuf.buf[sp:], int32(len(wbuf.buf[sp:])-4))
}
return nil
case pgtype.TextEncoder:
sp := wbuf.reserveSize()
null, err := arg.EncodeText(wbuf.conn.ConnInfo, wbuf)
sp := len(wbuf.buf)
wbuf.buf = pgio.AppendInt32(wbuf.buf, -1)
argBuf, err := arg.EncodeText(wbuf.conn.ConnInfo, wbuf.buf)
if err != nil {
return err
}
if null {
wbuf.setSize(sp, -1)
} else {
wbuf.setComputedSize(sp)
if argBuf != nil {
wbuf.buf = argBuf
pgio.SetInt32(wbuf.buf[sp:], int32(len(wbuf.buf[sp:])-4))
}
return nil
case driver.Valuer:
@ -159,15 +158,15 @@ func encodePreparedStatementArgument(wbuf *WriteBuf, oid pgtype.Oid, arg interfa
return err
}
sp := wbuf.reserveSize()
null, err := value.(pgtype.BinaryEncoder).EncodeBinary(wbuf.conn.ConnInfo, wbuf)
sp := len(wbuf.buf)
wbuf.buf = pgio.AppendInt32(wbuf.buf, -1)
argBuf, err := value.(pgtype.BinaryEncoder).EncodeBinary(wbuf.conn.ConnInfo, wbuf.buf)
if err != nil {
return err
}
if null {
wbuf.setSize(sp, -1)
} else {
wbuf.setComputedSize(sp)
if argBuf != nil {
wbuf.buf = argBuf
pgio.SetInt32(wbuf.buf[sp:], int32(len(wbuf.buf[sp:])-4))
}
return nil
}