Add pgtype.HstoreArray

This required restructuring array types to lookup oid of element instead of
hard-coding it due to hstore having a variable oid.
v3-numeric-wip
Jack Christensen 2017-03-18 12:40:54 -05:00
parent 19c6689752
commit cf70e6b9f4
18 changed files with 586 additions and 90 deletions

View File

@ -238,10 +238,6 @@ func (src *BoolArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *BoolArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, BoolOid)
}
func (src *BoolArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -250,10 +246,15 @@ func (src *BoolArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -238,10 +238,6 @@ func (src *ByteaArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *ByteaArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, ByteaOid)
}
func (src *ByteaArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -250,10 +246,15 @@ func (src *ByteaArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -270,10 +270,6 @@ func (src *CidrArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *CidrArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, CidrOid)
}
func (src *CidrArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -282,10 +278,15 @@ func (src *CidrArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -239,10 +239,6 @@ func (src *DateArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *DateArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, DateOid)
}
func (src *DateArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -251,10 +247,15 @@ func (src *DateArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -238,10 +238,6 @@ func (src *Float4Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *Float4Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, Float4Oid)
}
func (src *Float4Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -250,10 +246,15 @@ func (src *Float4Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -238,10 +238,6 @@ func (src *Float8Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *Float8Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, Float8Oid)
}
func (src *Float8Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -250,10 +246,15 @@ func (src *Float8Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

297
pgtype/hstore_array.go Normal file
View File

@ -0,0 +1,297 @@
package pgtype
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
type HstoreArray struct {
Elements []Hstore
Dimensions []ArrayDimension
Status Status
}
func (dst *HstoreArray) Set(src interface{}) error {
switch value := src.(type) {
case []map[string]string:
if value == nil {
*dst = HstoreArray{Status: Null}
} else if len(value) == 0 {
*dst = HstoreArray{Status: Present}
} else {
elements := make([]Hstore, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = HstoreArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
default:
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Hstore", value)
}
return nil
}
func (dst *HstoreArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *HstoreArray) AssignTo(dst interface{}) error {
switch v := dst.(type) {
case *[]map[string]string:
if src.Status == Present {
*v = make([]map[string]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
return nil
}
func (dst *HstoreArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = HstoreArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Hstore
if len(uta.Elements) > 0 {
elements = make([]Hstore, len(uta.Elements))
for i, s := range uta.Elements {
var elem Hstore
var elemSrc []byte
if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = HstoreArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *HstoreArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = HstoreArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = HstoreArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Hstore, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = HstoreArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src *HstoreArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
switch src.Status {
case Null:
return true, nil
case Undefined:
return false, errUndefined
}
if len(src.Dimensions) == 0 {
_, err := io.WriteString(w, "{}")
return false, err
}
err := EncodeTextArrayDimensions(w, src.Dimensions)
if err != nil {
return false, err
}
// 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
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(w, ',')
if err != nil {
return false, err
}
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(w, '{')
if err != nil {
return false, err
}
}
}
elemBuf := &bytes.Buffer{}
null, err := elem.EncodeText(ci, elemBuf)
if err != nil {
return false, err
}
if null {
_, err = io.WriteString(w, `NULL`)
if err != nil {
return false, err
}
} else {
_, err = io.WriteString(w, QuoteArrayElementIfNeeded(elemBuf.String()))
if err != nil {
return false, err
}
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(w, '}')
if err != nil {
return false, err
}
}
}
}
return false, nil
}
func (src *HstoreArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
switch src.Status {
case Null:
return true, nil
case Undefined:
return false, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
err := arrayHeader.EncodeBinary(ci, w)
if err != nil {
return false, err
}
elemBuf := &bytes.Buffer{}
for i := range src.Elements {
elemBuf.Reset()
null, err := src.Elements[i].EncodeBinary(ci, elemBuf)
if err != nil {
return false, 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
}
}
}
return false, err
}

183
pgtype/hstore_array_test.go Normal file
View File

@ -0,0 +1,183 @@
package pgtype_test
import (
"reflect"
"testing"
"github.com/jackc/pgx"
"github.com/jackc/pgx/pgtype"
)
func TestHstoreArrayTranscode(t *testing.T) {
conn := mustConnectPgx(t)
defer mustClose(t, conn)
text := func(s string) pgtype.Text {
return pgtype.Text{String: s, Status: pgtype.Present}
}
values := []pgtype.Hstore{
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},
}
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
}
src := pgtype.HstoreArray{
Elements: values,
Dimensions: []pgtype.ArrayDimension{{Length: int32(len(values)), LowerBound: 1}},
Status: pgtype.Present,
}
ps, err := conn.Prepare("test", "select $1::hstore[]")
if err != nil {
t.Fatal(err)
}
formats := []struct {
name string
formatCode int16
}{
{name: "TextFormat", formatCode: pgx.TextFormatCode},
{name: "BinaryFormat", formatCode: pgx.BinaryFormatCode},
}
for _, fc := range formats {
ps.FieldDescriptions[0].FormatCode = fc.formatCode
vEncoder := forceEncoder(src, fc.formatCode)
if vEncoder == nil {
t.Logf("%#v does not implement %v", src, fc.name)
continue
}
var result pgtype.HstoreArray
err := conn.QueryRow("test", vEncoder).Scan(&result)
if err != nil {
t.Errorf("%v: %v", fc.name, err)
continue
}
if result.Status != src.Status {
t.Errorf("%v: expected Status %v, got %v", fc.formatCode, src.Status, result.Status)
continue
}
if len(result.Elements) != len(src.Elements) {
t.Errorf("%v: expected %v elements, got %v", fc.formatCode, len(src.Elements), len(result.Elements))
continue
}
for i := range result.Elements {
a := src.Elements[i]
b := result.Elements[i]
if a.Status != b.Status {
t.Errorf("%v element idx %d: expected status %v, got %v", fc.formatCode, i, a.Status, b.Status)
}
if len(a.Map) != len(b.Map) {
t.Errorf("%v element idx %d: expected %v pairs, got %v", fc.formatCode, i, len(a.Map), len(b.Map))
}
for k := range a.Map {
if a.Map[k] != b.Map[k] {
t.Errorf("%v element idx %d: expected key %v to be %v, got %v", fc.formatCode, i, k, a.Map[k], b.Map[k])
}
}
}
}
}
func TestHstoreArraySet(t *testing.T) {
successfulTests := []struct {
src []map[string]string
result pgtype.HstoreArray
}{
{
src: []map[string]string{map[string]string{"foo": "bar"}},
result: pgtype.HstoreArray{
Elements: []pgtype.Hstore{
{
Map: map[string]pgtype.Text{"foo": pgtype.Text{String: "bar", Status: pgtype.Present}},
Status: pgtype.Present,
},
},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
},
}
for i, tt := range successfulTests {
var dst pgtype.HstoreArray
err := dst.Set(tt.src)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if !reflect.DeepEqual(dst, tt.result) {
t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.src, tt.result, dst)
}
}
}
func TestHstoreArrayAssignTo(t *testing.T) {
var m []map[string]string
simpleTests := []struct {
src pgtype.HstoreArray
dst *[]map[string]string
expected []map[string]string
}{
{
src: pgtype.HstoreArray{
Elements: []pgtype.Hstore{
{
Map: map[string]pgtype.Text{"foo": pgtype.Text{String: "bar", Status: pgtype.Present}},
Status: pgtype.Present,
},
},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
dst: &m,
expected: []map[string]string{{"foo": "bar"}}},
{src: pgtype.HstoreArray{Status: pgtype.Null}, dst: &m, expected: (([]map[string]string)(nil))},
}
for i, tt := range simpleTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if !reflect.DeepEqual(*tt.dst, tt.expected) {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, *tt.dst)
}
}
}

View File

@ -270,10 +270,6 @@ func (src *InetArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *InetArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, InetOid)
}
func (src *InetArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -282,10 +278,15 @@ func (src *InetArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -269,10 +269,6 @@ func (src *Int2Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *Int2Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, Int2Oid)
}
func (src *Int2Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -281,10 +277,15 @@ func (src *Int2Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -269,10 +269,6 @@ func (src *Int4Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *Int4Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, Int4Oid)
}
func (src *Int4Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -281,10 +277,15 @@ func (src *Int4Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -269,10 +269,6 @@ func (src *Int8Array) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *Int8Array) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, Int8Oid)
}
func (src *Int8Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -281,10 +277,15 @@ func (src *Int8Array) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -238,10 +238,6 @@ func (src *TextArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *TextArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, TextOid)
}
func (src *TextArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -250,10 +246,15 @@ func (src *TextArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32)
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -239,10 +239,6 @@ func (src *TimestampArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *TimestampArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, TimestampOid)
}
func (src *TimestampArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -251,10 +247,15 @@ func (src *TimestampArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid in
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -239,10 +239,6 @@ func (src *TimestamptzArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error)
}
func (src *TimestamptzArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, TimestamptzOid)
}
func (src *TimestamptzArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -251,10 +247,15 @@ func (src *TimestamptzArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -237,10 +237,6 @@ func (src *<%= pgtype_array_type %>) EncodeText(ci *ConnInfo, w io.Writer) (bool
}
func (src *<%= pgtype_array_type %>) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, <%= element_oid %>)
}
func (src *<%= pgtype_array_type %>) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -249,10 +245,15 @@ func (src *<%= pgtype_array_type %>) encodeBinary(ci *ConnInfo, w io.Writer, ele
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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 %>")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true

View File

@ -1,15 +1,16 @@
erb pgtype_array_type=Int2Array pgtype_element_type=Int2 go_array_types=[]int16,[]uint16 element_oid=Int2Oid text_null=NULL typed_array.go.erb > int2_array.go
erb pgtype_array_type=Int4Array pgtype_element_type=Int4 go_array_types=[]int32,[]uint32 element_oid=Int4Oid text_null=NULL typed_array.go.erb > int4_array.go
erb pgtype_array_type=Int8Array pgtype_element_type=Int8 go_array_types=[]int64,[]uint64 element_oid=Int8Oid text_null=NULL typed_array.go.erb > int8_array.go
erb pgtype_array_type=BoolArray pgtype_element_type=Bool go_array_types=[]bool element_oid=BoolOid text_null=NULL typed_array.go.erb > bool_array.go
erb pgtype_array_type=DateArray pgtype_element_type=Date go_array_types=[]time.Time element_oid=DateOid text_null=NULL typed_array.go.erb > date_array.go
erb pgtype_array_type=TimestamptzArray pgtype_element_type=Timestamptz go_array_types=[]time.Time element_oid=TimestamptzOid text_null=NULL typed_array.go.erb > timestamptz_array.go
erb pgtype_array_type=TimestampArray pgtype_element_type=Timestamp go_array_types=[]time.Time element_oid=TimestampOid text_null=NULL typed_array.go.erb > timestamp_array.go
erb pgtype_array_type=Float4Array pgtype_element_type=Float4 go_array_types=[]float32 element_oid=Float4Oid text_null=NULL typed_array.go.erb > float4_array.go
erb pgtype_array_type=Float8Array pgtype_element_type=Float8 go_array_types=[]float64 element_oid=Float8Oid text_null=NULL typed_array.go.erb > float8_array.go
erb pgtype_array_type=InetArray pgtype_element_type=Inet go_array_types=[]*net.IPNet,[]net.IP element_oid=InetOid text_null=NULL typed_array.go.erb > inet_array.go
erb pgtype_array_type=CidrArray pgtype_element_type=Cidr go_array_types=[]*net.IPNet,[]net.IP element_oid=CidrOid text_null=NULL typed_array.go.erb > cidr_array.go
erb pgtype_array_type=TextArray pgtype_element_type=Text go_array_types=[]string element_oid=TextOid text_null='"NULL"' typed_array.go.erb > text_array.go
erb pgtype_array_type=VarcharArray pgtype_element_type=Varchar go_array_types=[]string element_oid=VarcharOid text_null='"NULL"' typed_array.go.erb > varchar_array.go
erb pgtype_array_type=ByteaArray pgtype_element_type=Bytea go_array_types=[][]byte element_oid=ByteaOid text_null=NULL typed_array.go.erb > bytea_array.go
erb pgtype_array_type=AclitemArray pgtype_element_type=Aclitem go_array_types=[]string element_oid=AclitemOid text_null=NULL typed_array.go.erb > aclitem_array.go
erb pgtype_array_type=Int2Array pgtype_element_type=Int2 go_array_types=[]int16,[]uint16 element_type_name=int2 text_null=NULL typed_array.go.erb > int2_array.go
erb pgtype_array_type=Int4Array pgtype_element_type=Int4 go_array_types=[]int32,[]uint32 element_type_name=int4 text_null=NULL typed_array.go.erb > int4_array.go
erb pgtype_array_type=Int8Array pgtype_element_type=Int8 go_array_types=[]int64,[]uint64 element_type_name=int8 text_null=NULL typed_array.go.erb > int8_array.go
erb pgtype_array_type=BoolArray pgtype_element_type=Bool go_array_types=[]bool element_type_name=bool text_null=NULL typed_array.go.erb > bool_array.go
erb pgtype_array_type=DateArray pgtype_element_type=Date go_array_types=[]time.Time element_type_name=date text_null=NULL typed_array.go.erb > date_array.go
erb pgtype_array_type=TimestamptzArray pgtype_element_type=Timestamptz go_array_types=[]time.Time element_type_name=timestamptz text_null=NULL typed_array.go.erb > timestamptz_array.go
erb pgtype_array_type=TimestampArray pgtype_element_type=Timestamp go_array_types=[]time.Time element_type_name=timestamp text_null=NULL typed_array.go.erb > timestamp_array.go
erb pgtype_array_type=Float4Array pgtype_element_type=Float4 go_array_types=[]float32 element_type_name=float4 text_null=NULL typed_array.go.erb > float4_array.go
erb pgtype_array_type=Float8Array pgtype_element_type=Float8 go_array_types=[]float64 element_type_name=float8 text_null=NULL typed_array.go.erb > float8_array.go
erb pgtype_array_type=InetArray pgtype_element_type=Inet go_array_types=[]*net.IPNet,[]net.IP element_type_name=inet text_null=NULL typed_array.go.erb > inet_array.go
erb pgtype_array_type=CidrArray pgtype_element_type=Cidr go_array_types=[]*net.IPNet,[]net.IP element_type_name=cidr text_null=NULL typed_array.go.erb > cidr_array.go
erb pgtype_array_type=TextArray pgtype_element_type=Text go_array_types=[]string element_type_name=text text_null='"NULL"' typed_array.go.erb > text_array.go
erb pgtype_array_type=VarcharArray pgtype_element_type=Varchar go_array_types=[]string element_type_name=varchar text_null='"NULL"' typed_array.go.erb > varchar_array.go
erb pgtype_array_type=ByteaArray pgtype_element_type=Bytea go_array_types=[][]byte element_type_name=bytea text_null=NULL typed_array.go.erb > bytea_array.go
erb pgtype_array_type=AclitemArray pgtype_element_type=Aclitem go_array_types=[]string element_type_name=aclitem text_null=NULL typed_array.go.erb > aclitem_array.go
erb pgtype_array_type=HstoreArray pgtype_element_type=Hstore go_array_types=[]map[string]string element_type_name=hstore text_null=NULL typed_array.go.erb > hstore_array.go

View File

@ -238,10 +238,6 @@ func (src *VarcharArray) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
}
func (src *VarcharArray) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
return src.encodeBinary(ci, w, VarcharOid)
}
func (src *VarcharArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int32) (bool, error) {
switch src.Status {
case Null:
return true, nil
@ -250,10 +246,15 @@ func (src *VarcharArray) encodeBinary(ci *ConnInfo, w io.Writer, elementOid int3
}
arrayHeader := ArrayHeader{
ElementOid: elementOid,
Dimensions: src.Dimensions,
}
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")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true