Add float4, float8 and arrays

v3-numeric-wip
Jack Christensen 2017-03-04 13:29:04 -06:00
parent 3179e2debc
commit 2010bea555
17 changed files with 1563 additions and 27 deletions

View File

@ -283,6 +283,10 @@ func (c *Conn) connect(config ConnConfig, network, address string, tlsConfig *tl
BoolOID: &pgtype.Bool{},
DateArrayOID: &pgtype.DateArray{},
DateOID: &pgtype.Date{},
Float4ArrayOID: &pgtype.Float4Array{},
Float4OID: &pgtype.Float4{},
Float8ArrayOID: &pgtype.Float8Array{},
Float8OID: &pgtype.Float8{},
Int2ArrayOID: &pgtype.Int2Array{},
Int2OID: &pgtype.Int2{},
Int4ArrayOID: &pgtype.Int4Array{},

View File

@ -11,8 +11,8 @@ const maxUint = ^uint(0)
const maxInt = int(maxUint >> 1)
const minInt = -maxInt - 1
// underlyingIntType gets the underlying type that can be converted to Int2, Int4, or Int8
func underlyingIntType(val interface{}) (interface{}, bool) {
// underlyingNumberType gets the underlying type that can be converted to Int2, Int4, Int8, Float4, or Float8
func underlyingNumberType(val interface{}) (interface{}, bool) {
refVal := reflect.ValueOf(val)
switch refVal.Kind() {
@ -52,6 +52,12 @@ func underlyingIntType(val interface{}) (interface{}, bool) {
case reflect.Uint64:
convVal := uint64(refVal.Uint())
return convVal, reflect.TypeOf(convVal) != refVal.Type()
case reflect.Float32:
convVal := float32(refVal.Float())
return convVal, reflect.TypeOf(convVal) != refVal.Type()
case reflect.Float64:
convVal := refVal.Float()
return convVal, reflect.TypeOf(convVal) != refVal.Type()
case reflect.String:
convVal := refVal.String()
return convVal, reflect.TypeOf(convVal) != refVal.Type()
@ -259,3 +265,45 @@ func int64AssignTo(srcVal int64, srcStatus Status, dst interface{}) error {
return fmt.Errorf("cannot assign %v %v into %T", srcVal, srcStatus, dst)
}
func float64AssignTo(srcVal float64, srcStatus Status, dst interface{}) error {
if srcStatus == Present {
switch v := dst.(type) {
case *float32:
*v = float32(srcVal)
case *float64:
*v = srcVal
default:
if v := reflect.ValueOf(dst); v.Kind() == reflect.Ptr {
el := v.Elem()
switch el.Kind() {
// if dst is a pointer to pointer, strip the pointer and try again
case reflect.Ptr:
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return float64AssignTo(srcVal, srcStatus, el.Interface())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
i64 := int64(srcVal)
if float64(i64) == srcVal {
return int64AssignTo(i64, srcStatus, dst)
}
}
}
return fmt.Errorf("cannot assign %v into %T", srcVal, dst)
}
return nil
}
// if dst is a pointer to pointer and srcStatus is not Present, nil it out
if v := reflect.ValueOf(dst); v.Kind() == reflect.Ptr {
el := v.Elem()
if el.Kind() == reflect.Ptr {
el.Set(reflect.Zero(el.Type()))
return nil
}
}
return fmt.Errorf("cannot assign %v %v into %T", srcVal, srcStatus, dst)
}

171
pgtype/float4.go Normal file
View File

@ -0,0 +1,171 @@
package pgtype
import (
"fmt"
"io"
"math"
"strconv"
"github.com/jackc/pgx/pgio"
)
type Float4 struct {
Float float32
Status Status
}
func (dst *Float4) ConvertFrom(src interface{}) error {
switch value := src.(type) {
case Float4:
*dst = value
case float32:
*dst = Float4{Float: value, Status: Present}
case float64:
*dst = Float4{Float: float32(value), Status: Present}
case int8:
*dst = Float4{Float: float32(value), Status: Present}
case uint8:
*dst = Float4{Float: float32(value), Status: Present}
case int16:
*dst = Float4{Float: float32(value), Status: Present}
case uint16:
*dst = Float4{Float: float32(value), Status: Present}
case int32:
f32 := float32(value)
if int32(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case uint32:
f32 := float32(value)
if uint32(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case int64:
f32 := float32(value)
if int64(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case uint64:
f32 := float32(value)
if uint64(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case int:
f32 := float32(value)
if int(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case uint:
f32 := float32(value)
if uint(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case string:
num, err := strconv.ParseFloat(value, 32)
if err != nil {
return err
}
*dst = Float4{Float: float32(num), Status: Present}
default:
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.ConvertFrom(originalSrc)
}
return fmt.Errorf("cannot convert %v to Float8", value)
}
return nil
}
func (src *Float4) AssignTo(dst interface{}) error {
return float64AssignTo(float64(src.Float), src.Status, dst)
}
func (dst *Float4) DecodeText(r io.Reader) error {
size, err := pgio.ReadInt32(r)
if err != nil {
return err
}
if size == -1 {
*dst = Float4{Status: Null}
return nil
}
buf := make([]byte, int(size))
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseFloat(string(buf), 32)
if err != nil {
return err
}
*dst = Float4{Float: float32(n), Status: Present}
return nil
}
func (dst *Float4) DecodeBinary(r io.Reader) error {
size, err := pgio.ReadInt32(r)
if err != nil {
return err
}
if size == -1 {
*dst = Float4{Status: Null}
return nil
}
if size != 4 {
return fmt.Errorf("invalid length for float4: %v", size)
}
n, err := pgio.ReadInt32(r)
if err != nil {
return err
}
*dst = Float4{Float: math.Float32frombits(uint32(n)), Status: Present}
return nil
}
func (src Float4) EncodeText(w io.Writer) error {
if done, err := encodeNotPresent(w, src.Status); done {
return err
}
s := strconv.FormatFloat(float64(src.Float), 'f', -1, 32)
_, err := pgio.WriteInt32(w, int32(len(s)))
if err != nil {
return nil
}
_, err = w.Write([]byte(s))
return err
}
func (src Float4) EncodeBinary(w io.Writer) error {
if done, err := encodeNotPresent(w, src.Status); done {
return err
}
_, err := pgio.WriteInt32(w, 4)
if err != nil {
return err
}
_, err = pgio.WriteInt32(w, int32(math.Float32bits(src.Float)))
return err
}

148
pgtype/float4_test.go Normal file
View File

@ -0,0 +1,148 @@
package pgtype_test
import (
"reflect"
"testing"
"github.com/jackc/pgx/pgtype"
)
func TestFloat4Transcode(t *testing.T) {
testSuccessfulTranscode(t, "float4", []interface{}{
pgtype.Float4{Float: -1, Status: pgtype.Present},
pgtype.Float4{Float: 0, Status: pgtype.Present},
pgtype.Float4{Float: 0.00001, Status: pgtype.Present},
pgtype.Float4{Float: 1, Status: pgtype.Present},
pgtype.Float4{Float: 9999.99, Status: pgtype.Present},
pgtype.Float4{Float: 0, Status: pgtype.Null},
})
}
func TestFloat4ConvertFrom(t *testing.T) {
successfulTests := []struct {
source interface{}
result pgtype.Float4
}{
{source: float32(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: float64(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: int8(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: int16(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: int32(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: int64(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: int8(-1), result: pgtype.Float4{Float: -1, Status: pgtype.Present}},
{source: int16(-1), result: pgtype.Float4{Float: -1, Status: pgtype.Present}},
{source: int32(-1), result: pgtype.Float4{Float: -1, Status: pgtype.Present}},
{source: int64(-1), result: pgtype.Float4{Float: -1, Status: pgtype.Present}},
{source: uint8(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: uint16(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: uint32(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: uint64(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: "1", result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
{source: _int8(1), result: pgtype.Float4{Float: 1, Status: pgtype.Present}},
}
for i, tt := range successfulTests {
var r pgtype.Float4
err := r.ConvertFrom(tt.source)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if r != tt.result {
t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
}
}
}
func TestFloat4AssignTo(t *testing.T) {
var i8 int8
var i16 int16
var i32 int32
var i64 int64
var i int
var ui8 uint8
var ui16 uint16
var ui32 uint32
var ui64 uint64
var ui uint
var pi8 *int8
var _i8 _int8
var _pi8 *_int8
var f32 float32
var f64 float64
var pf32 *float32
var pf64 *float64
simpleTests := []struct {
src pgtype.Float4
dst interface{}
expected interface{}
}{
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &f32, expected: float32(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &f64, expected: float64(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &i16, expected: int16(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &i32, expected: int32(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &i64, expected: int64(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &i, expected: int(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &ui8, expected: uint8(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &ui16, expected: uint16(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &ui32, expected: uint32(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &ui64, expected: uint64(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &ui, expected: uint(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &_i8, expected: _int8(42)},
{src: pgtype.Float4{Float: 0, Status: pgtype.Null}, dst: &pi8, expected: ((*int8)(nil))},
{src: pgtype.Float4{Float: 0, Status: pgtype.Null}, dst: &_pi8, expected: ((*_int8)(nil))},
}
for i, tt := range simpleTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if dst := reflect.ValueOf(tt.dst).Elem().Interface(); dst != tt.expected {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
}
}
pointerAllocTests := []struct {
src pgtype.Float4
dst interface{}
expected interface{}
}{
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &pf32, expected: float32(42)},
{src: pgtype.Float4{Float: 42, Status: pgtype.Present}, dst: &pf64, expected: float64(42)},
}
for i, tt := range pointerAllocTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if dst := reflect.ValueOf(tt.dst).Elem().Elem().Interface(); dst != tt.expected {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
}
}
errorTests := []struct {
src pgtype.Float4
dst interface{}
}{
{src: pgtype.Float4{Float: 150, Status: pgtype.Present}, dst: &i8},
{src: pgtype.Float4{Float: 40000, Status: pgtype.Present}, dst: &i16},
{src: pgtype.Float4{Float: -1, Status: pgtype.Present}, dst: &ui8},
{src: pgtype.Float4{Float: -1, Status: pgtype.Present}, dst: &ui16},
{src: pgtype.Float4{Float: -1, Status: pgtype.Present}, dst: &ui32},
{src: pgtype.Float4{Float: -1, Status: pgtype.Present}, dst: &ui64},
{src: pgtype.Float4{Float: -1, Status: pgtype.Present}, dst: &ui},
{src: pgtype.Float4{Float: 0, Status: pgtype.Null}, dst: &i32},
}
for i, tt := range errorTests {
err := tt.src.AssignTo(tt.dst)
if err == nil {
t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst)
}
}
}

286
pgtype/float4array.go Normal file
View File

@ -0,0 +1,286 @@
package pgtype
import (
"bytes"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
type Float4Array struct {
Elements []Float4
Dimensions []ArrayDimension
Status Status
}
func (dst *Float4Array) ConvertFrom(src interface{}) error {
switch value := src.(type) {
case Float4Array:
*dst = value
case []float32:
if value == nil {
*dst = Float4Array{Status: Null}
} else if len(value) == 0 {
*dst = Float4Array{Status: Present}
} else {
elements := make([]Float4, len(value))
for i := range value {
if err := elements[i].ConvertFrom(value[i]); err != nil {
return err
}
}
*dst = Float4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
default:
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.ConvertFrom(originalSrc)
}
return fmt.Errorf("cannot convert %v to Float4", value)
}
return nil
}
func (src *Float4Array) AssignTo(dst interface{}) error {
switch v := dst.(type) {
case *[]float32:
if src.Status == Present {
*v = make([]float32, 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 put decode %v into %T", src, dst)
}
return nil
}
func (dst *Float4Array) DecodeText(r io.Reader) error {
size, err := pgio.ReadInt32(r)
if err != nil {
return err
}
if size == -1 {
*dst = Float4Array{Status: Null}
return nil
}
buf := make([]byte, int(size))
_, err = io.ReadFull(r, buf)
if err != nil {
return err
}
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Float4
if len(uta.Elements) > 0 {
elements = make([]Float4, len(uta.Elements))
for i, s := range uta.Elements {
var elem Float4
textElementReader.Reset(s)
err = elem.DecodeText(textElementReader)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Float4Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *Float4Array) DecodeBinary(r io.Reader) error {
size, err := pgio.ReadInt32(r)
if err != nil {
return err
}
if size == -1 {
*dst = Float4Array{Status: Null}
return nil
}
var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = Float4Array{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Float4, elementCount)
for i := range elements {
err = elements[i].DecodeBinary(r)
if err != nil {
return err
}
}
*dst = Float4Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src *Float4Array) EncodeText(w io.Writer) error {
if done, err := encodeNotPresent(w, src.Status); done {
return err
}
if len(src.Dimensions) == 0 {
_, err := pgio.WriteInt32(w, 2)
if err != nil {
return err
}
_, err = w.Write([]byte("{}"))
return err
}
buf := &bytes.Buffer{}
err := EncodeTextArrayDimensions(buf, src.Dimensions)
if err != nil {
return 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]
}
textElementWriter := NewTextElementWriter(buf)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(buf, ',')
if err != nil {
return err
}
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(buf, '{')
if err != nil {
return err
}
}
}
textElementWriter.Reset()
err = elem.EncodeText(textElementWriter)
if err != nil {
return err
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(buf, '}')
if err != nil {
return err
}
}
}
}
_, err = pgio.WriteInt32(w, int32(buf.Len()))
if err != nil {
return err
}
_, err = buf.WriteTo(w)
return err
}
func (src *Float4Array) EncodeBinary(w io.Writer) error {
if done, err := encodeNotPresent(w, src.Status); done {
return err
}
var arrayHeader ArrayHeader
// TODO - consider how to avoid having to buffer array before writing length -
// or how not pay allocations for the byte order conversions.
elemBuf := &bytes.Buffer{}
for i := range src.Elements {
err := src.Elements[i].EncodeBinary(elemBuf)
if err != nil {
return err
}
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
}
}
arrayHeader.ElementOID = Float4OID
arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length -
// or how not pay allocations for the byte order conversions.
headerBuf := &bytes.Buffer{}
err := arrayHeader.EncodeBinary(headerBuf)
if err != nil {
return err
}
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
if err != nil {
return err
}
_, err = headerBuf.WriteTo(w)
if err != nil {
return err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return err
}
return err
}

151
pgtype/float4array_test.go Normal file
View File

@ -0,0 +1,151 @@
package pgtype_test
import (
"reflect"
"testing"
"github.com/jackc/pgx/pgtype"
)
func TestFloat4ArrayTranscode(t *testing.T) {
testSuccessfulTranscode(t, "float4[]", []interface{}{
&pgtype.Float4Array{
Elements: nil,
Dimensions: nil,
Status: pgtype.Present,
},
&pgtype.Float4Array{
Elements: []pgtype.Float4{
pgtype.Float4{Float: 1, Status: pgtype.Present},
pgtype.Float4{Status: pgtype.Null},
},
Dimensions: []pgtype.ArrayDimension{{Length: 2, LowerBound: 1}},
Status: pgtype.Present,
},
&pgtype.Float4Array{Status: pgtype.Null},
&pgtype.Float4Array{
Elements: []pgtype.Float4{
pgtype.Float4{Float: 1, Status: pgtype.Present},
pgtype.Float4{Float: 2, Status: pgtype.Present},
pgtype.Float4{Float: 3, Status: pgtype.Present},
pgtype.Float4{Float: 4, Status: pgtype.Present},
pgtype.Float4{Status: pgtype.Null},
pgtype.Float4{Float: 6, Status: pgtype.Present},
},
Dimensions: []pgtype.ArrayDimension{{Length: 3, LowerBound: 1}, {Length: 2, LowerBound: 1}},
Status: pgtype.Present,
},
&pgtype.Float4Array{
Elements: []pgtype.Float4{
pgtype.Float4{Float: 1, Status: pgtype.Present},
pgtype.Float4{Float: 2, Status: pgtype.Present},
pgtype.Float4{Float: 3, Status: pgtype.Present},
pgtype.Float4{Float: 4, Status: pgtype.Present},
},
Dimensions: []pgtype.ArrayDimension{
{Length: 2, LowerBound: 4},
{Length: 2, LowerBound: 2},
},
Status: pgtype.Present,
},
})
}
func TestFloat4ArrayConvertFrom(t *testing.T) {
successfulTests := []struct {
source interface{}
result pgtype.Float4Array
}{
{
source: []float32{1},
result: pgtype.Float4Array{
Elements: []pgtype.Float4{{Float: 1, Status: pgtype.Present}},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present},
},
{
source: (([]float32)(nil)),
result: pgtype.Float4Array{Status: pgtype.Null},
},
}
for i, tt := range successfulTests {
var r pgtype.Float4Array
err := r.ConvertFrom(tt.source)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if !reflect.DeepEqual(r, tt.result) {
t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
}
}
}
func TestFloat4ArrayAssignTo(t *testing.T) {
var float32Slice []float32
var namedFloat32Slice _float32Slice
simpleTests := []struct {
src pgtype.Float4Array
dst interface{}
expected interface{}
}{
{
src: pgtype.Float4Array{
Elements: []pgtype.Float4{{Float: 1.23, Status: pgtype.Present}},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
dst: &float32Slice,
expected: []float32{1.23},
},
{
src: pgtype.Float4Array{
Elements: []pgtype.Float4{{Float: 1.23, Status: pgtype.Present}},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
dst: &namedFloat32Slice,
expected: _float32Slice{1.23},
},
{
src: pgtype.Float4Array{Status: pgtype.Null},
dst: &float32Slice,
expected: (([]float32)(nil)),
},
}
for i, tt := range simpleTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if dst := reflect.ValueOf(tt.dst).Elem().Interface(); !reflect.DeepEqual(dst, tt.expected) {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
}
}
errorTests := []struct {
src pgtype.Float4Array
dst interface{}
}{
{
src: pgtype.Float4Array{
Elements: []pgtype.Float4{{Status: pgtype.Null}},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
dst: &float32Slice,
},
}
for i, tt := range errorTests {
err := tt.src.AssignTo(tt.dst)
if err == nil {
t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst)
}
}
}

161
pgtype/float8.go Normal file
View File

@ -0,0 +1,161 @@
package pgtype
import (
"fmt"
"io"
"math"
"strconv"
"github.com/jackc/pgx/pgio"
)
type Float8 struct {
Float float64
Status Status
}
func (dst *Float8) ConvertFrom(src interface{}) error {
switch value := src.(type) {
case Float8:
*dst = value
case float32:
*dst = Float8{Float: float64(value), Status: Present}
case float64:
*dst = Float8{Float: value, Status: Present}
case int8:
*dst = Float8{Float: float64(value), Status: Present}
case uint8:
*dst = Float8{Float: float64(value), Status: Present}
case int16:
*dst = Float8{Float: float64(value), Status: Present}
case uint16:
*dst = Float8{Float: float64(value), Status: Present}
case int32:
*dst = Float8{Float: float64(value), Status: Present}
case uint32:
*dst = Float8{Float: float64(value), Status: Present}
case int64:
f64 := float64(value)
if int64(f64) == value {
*dst = Float8{Float: f64, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float64", value)
}
case uint64:
f64 := float64(value)
if uint64(f64) == value {
*dst = Float8{Float: f64, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float64", value)
}
case int:
f64 := float64(value)
if int(f64) == value {
*dst = Float8{Float: f64, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float64", value)
}
case uint:
f64 := float64(value)
if uint(f64) == value {
*dst = Float8{Float: f64, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float64", value)
}
case string:
num, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
*dst = Float8{Float: float64(num), Status: Present}
default:
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.ConvertFrom(originalSrc)
}
return fmt.Errorf("cannot convert %v to Float8", value)
}
return nil
}
func (src *Float8) AssignTo(dst interface{}) error {
return float64AssignTo(src.Float, src.Status, dst)
}
func (dst *Float8) DecodeText(r io.Reader) error {
size, err := pgio.ReadInt32(r)
if err != nil {
return err
}
if size == -1 {
*dst = Float8{Status: Null}
return nil
}
buf := make([]byte, int(size))
_, err = r.Read(buf)
if err != nil {
return err
}
n, err := strconv.ParseFloat(string(buf), 64)
if err != nil {
return err
}
*dst = Float8{Float: n, Status: Present}
return nil
}
func (dst *Float8) DecodeBinary(r io.Reader) error {
size, err := pgio.ReadInt32(r)
if err != nil {
return err
}
if size == -1 {
*dst = Float8{Status: Null}
return nil
}
if size != 8 {
return fmt.Errorf("invalid length for float4: %v", size)
}
n, err := pgio.ReadInt64(r)
if err != nil {
return err
}
*dst = Float8{Float: math.Float64frombits(uint64(n)), Status: Present}
return nil
}
func (src Float8) EncodeText(w io.Writer) error {
if done, err := encodeNotPresent(w, src.Status); done {
return err
}
s := strconv.FormatFloat(float64(src.Float), 'f', -1, 64)
_, err := pgio.WriteInt32(w, int32(len(s)))
if err != nil {
return nil
}
_, err = w.Write([]byte(s))
return err
}
func (src Float8) EncodeBinary(w io.Writer) error {
if done, err := encodeNotPresent(w, src.Status); done {
return err
}
_, err := pgio.WriteInt32(w, 8)
if err != nil {
return err
}
_, err = pgio.WriteInt64(w, int64(math.Float64bits(src.Float)))
return err
}

148
pgtype/float8_test.go Normal file
View File

@ -0,0 +1,148 @@
package pgtype_test
import (
"reflect"
"testing"
"github.com/jackc/pgx/pgtype"
)
func TestFloat8Transcode(t *testing.T) {
testSuccessfulTranscode(t, "float8", []interface{}{
pgtype.Float8{Float: -1, Status: pgtype.Present},
pgtype.Float8{Float: 0, Status: pgtype.Present},
pgtype.Float8{Float: 0.00001, Status: pgtype.Present},
pgtype.Float8{Float: 1, Status: pgtype.Present},
pgtype.Float8{Float: 9999.99, Status: pgtype.Present},
pgtype.Float8{Float: 0, Status: pgtype.Null},
})
}
func TestFloat8ConvertFrom(t *testing.T) {
successfulTests := []struct {
source interface{}
result pgtype.Float8
}{
{source: float32(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: float64(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: int8(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: int16(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: int32(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: int64(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: int8(-1), result: pgtype.Float8{Float: -1, Status: pgtype.Present}},
{source: int16(-1), result: pgtype.Float8{Float: -1, Status: pgtype.Present}},
{source: int32(-1), result: pgtype.Float8{Float: -1, Status: pgtype.Present}},
{source: int64(-1), result: pgtype.Float8{Float: -1, Status: pgtype.Present}},
{source: uint8(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: uint16(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: uint32(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: uint64(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: "1", result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
{source: _int8(1), result: pgtype.Float8{Float: 1, Status: pgtype.Present}},
}
for i, tt := range successfulTests {
var r pgtype.Float8
err := r.ConvertFrom(tt.source)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if r != tt.result {
t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
}
}
}
func TestFloat8AssignTo(t *testing.T) {
var i8 int8
var i16 int16
var i32 int32
var i64 int64
var i int
var ui8 uint8
var ui16 uint16
var ui32 uint32
var ui64 uint64
var ui uint
var pi8 *int8
var _i8 _int8
var _pi8 *_int8
var f32 float32
var f64 float64
var pf32 *float32
var pf64 *float64
simpleTests := []struct {
src pgtype.Float8
dst interface{}
expected interface{}
}{
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &f32, expected: float32(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &f64, expected: float64(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &i16, expected: int16(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &i32, expected: int32(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &i64, expected: int64(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &i, expected: int(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &ui8, expected: uint8(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &ui16, expected: uint16(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &ui32, expected: uint32(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &ui64, expected: uint64(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &ui, expected: uint(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &_i8, expected: _int8(42)},
{src: pgtype.Float8{Float: 0, Status: pgtype.Null}, dst: &pi8, expected: ((*int8)(nil))},
{src: pgtype.Float8{Float: 0, Status: pgtype.Null}, dst: &_pi8, expected: ((*_int8)(nil))},
}
for i, tt := range simpleTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if dst := reflect.ValueOf(tt.dst).Elem().Interface(); dst != tt.expected {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
}
}
pointerAllocTests := []struct {
src pgtype.Float8
dst interface{}
expected interface{}
}{
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &pf32, expected: float32(42)},
{src: pgtype.Float8{Float: 42, Status: pgtype.Present}, dst: &pf64, expected: float64(42)},
}
for i, tt := range pointerAllocTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if dst := reflect.ValueOf(tt.dst).Elem().Elem().Interface(); dst != tt.expected {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
}
}
errorTests := []struct {
src pgtype.Float8
dst interface{}
}{
{src: pgtype.Float8{Float: 150, Status: pgtype.Present}, dst: &i8},
{src: pgtype.Float8{Float: 40000, Status: pgtype.Present}, dst: &i16},
{src: pgtype.Float8{Float: -1, Status: pgtype.Present}, dst: &ui8},
{src: pgtype.Float8{Float: -1, Status: pgtype.Present}, dst: &ui16},
{src: pgtype.Float8{Float: -1, Status: pgtype.Present}, dst: &ui32},
{src: pgtype.Float8{Float: -1, Status: pgtype.Present}, dst: &ui64},
{src: pgtype.Float8{Float: -1, Status: pgtype.Present}, dst: &ui},
{src: pgtype.Float8{Float: 0, Status: pgtype.Null}, dst: &i32},
}
for i, tt := range errorTests {
err := tt.src.AssignTo(tt.dst)
if err == nil {
t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst)
}
}
}

286
pgtype/float8array.go Normal file
View File

@ -0,0 +1,286 @@
package pgtype
import (
"bytes"
"fmt"
"io"
"github.com/jackc/pgx/pgio"
)
type Float8Array struct {
Elements []Float8
Dimensions []ArrayDimension
Status Status
}
func (dst *Float8Array) ConvertFrom(src interface{}) error {
switch value := src.(type) {
case Float8Array:
*dst = value
case []float64:
if value == nil {
*dst = Float8Array{Status: Null}
} else if len(value) == 0 {
*dst = Float8Array{Status: Present}
} else {
elements := make([]Float8, len(value))
for i := range value {
if err := elements[i].ConvertFrom(value[i]); err != nil {
return err
}
}
*dst = Float8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
default:
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.ConvertFrom(originalSrc)
}
return fmt.Errorf("cannot convert %v to Float8", value)
}
return nil
}
func (src *Float8Array) AssignTo(dst interface{}) error {
switch v := dst.(type) {
case *[]float64:
if src.Status == Present {
*v = make([]float64, 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 put decode %v into %T", src, dst)
}
return nil
}
func (dst *Float8Array) DecodeText(r io.Reader) error {
size, err := pgio.ReadInt32(r)
if err != nil {
return err
}
if size == -1 {
*dst = Float8Array{Status: Null}
return nil
}
buf := make([]byte, int(size))
_, err = io.ReadFull(r, buf)
if err != nil {
return err
}
uta, err := ParseUntypedTextArray(string(buf))
if err != nil {
return err
}
textElementReader := NewTextElementReader(r)
var elements []Float8
if len(uta.Elements) > 0 {
elements = make([]Float8, len(uta.Elements))
for i, s := range uta.Elements {
var elem Float8
textElementReader.Reset(s)
err = elem.DecodeText(textElementReader)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Float8Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *Float8Array) DecodeBinary(r io.Reader) error {
size, err := pgio.ReadInt32(r)
if err != nil {
return err
}
if size == -1 {
*dst = Float8Array{Status: Null}
return nil
}
var arrayHeader ArrayHeader
err = arrayHeader.DecodeBinary(r)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = Float8Array{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Float8, elementCount)
for i := range elements {
err = elements[i].DecodeBinary(r)
if err != nil {
return err
}
}
*dst = Float8Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src *Float8Array) EncodeText(w io.Writer) error {
if done, err := encodeNotPresent(w, src.Status); done {
return err
}
if len(src.Dimensions) == 0 {
_, err := pgio.WriteInt32(w, 2)
if err != nil {
return err
}
_, err = w.Write([]byte("{}"))
return err
}
buf := &bytes.Buffer{}
err := EncodeTextArrayDimensions(buf, src.Dimensions)
if err != nil {
return 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]
}
textElementWriter := NewTextElementWriter(buf)
for i, elem := range src.Elements {
if i > 0 {
err = pgio.WriteByte(buf, ',')
if err != nil {
return err
}
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
err = pgio.WriteByte(buf, '{')
if err != nil {
return err
}
}
}
textElementWriter.Reset()
err = elem.EncodeText(textElementWriter)
if err != nil {
return err
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
err = pgio.WriteByte(buf, '}')
if err != nil {
return err
}
}
}
}
_, err = pgio.WriteInt32(w, int32(buf.Len()))
if err != nil {
return err
}
_, err = buf.WriteTo(w)
return err
}
func (src *Float8Array) EncodeBinary(w io.Writer) error {
if done, err := encodeNotPresent(w, src.Status); done {
return err
}
var arrayHeader ArrayHeader
// TODO - consider how to avoid having to buffer array before writing length -
// or how not pay allocations for the byte order conversions.
elemBuf := &bytes.Buffer{}
for i := range src.Elements {
err := src.Elements[i].EncodeBinary(elemBuf)
if err != nil {
return err
}
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
}
}
arrayHeader.ElementOID = Float8OID
arrayHeader.Dimensions = src.Dimensions
// TODO - consider how to avoid having to buffer array before writing length -
// or how not pay allocations for the byte order conversions.
headerBuf := &bytes.Buffer{}
err := arrayHeader.EncodeBinary(headerBuf)
if err != nil {
return err
}
_, err = pgio.WriteInt32(w, int32(headerBuf.Len()+elemBuf.Len()))
if err != nil {
return err
}
_, err = headerBuf.WriteTo(w)
if err != nil {
return err
}
_, err = elemBuf.WriteTo(w)
if err != nil {
return err
}
return err
}

151
pgtype/float8array_test.go Normal file
View File

@ -0,0 +1,151 @@
package pgtype_test
import (
"reflect"
"testing"
"github.com/jackc/pgx/pgtype"
)
func TestFloat8ArrayTranscode(t *testing.T) {
testSuccessfulTranscode(t, "float8[]", []interface{}{
&pgtype.Float8Array{
Elements: nil,
Dimensions: nil,
Status: pgtype.Present,
},
&pgtype.Float8Array{
Elements: []pgtype.Float8{
pgtype.Float8{Float: 1, Status: pgtype.Present},
pgtype.Float8{Status: pgtype.Null},
},
Dimensions: []pgtype.ArrayDimension{{Length: 2, LowerBound: 1}},
Status: pgtype.Present,
},
&pgtype.Float8Array{Status: pgtype.Null},
&pgtype.Float8Array{
Elements: []pgtype.Float8{
pgtype.Float8{Float: 1, Status: pgtype.Present},
pgtype.Float8{Float: 2, Status: pgtype.Present},
pgtype.Float8{Float: 3, Status: pgtype.Present},
pgtype.Float8{Float: 4, Status: pgtype.Present},
pgtype.Float8{Status: pgtype.Null},
pgtype.Float8{Float: 6, Status: pgtype.Present},
},
Dimensions: []pgtype.ArrayDimension{{Length: 3, LowerBound: 1}, {Length: 2, LowerBound: 1}},
Status: pgtype.Present,
},
&pgtype.Float8Array{
Elements: []pgtype.Float8{
pgtype.Float8{Float: 1, Status: pgtype.Present},
pgtype.Float8{Float: 2, Status: pgtype.Present},
pgtype.Float8{Float: 3, Status: pgtype.Present},
pgtype.Float8{Float: 4, Status: pgtype.Present},
},
Dimensions: []pgtype.ArrayDimension{
{Length: 2, LowerBound: 4},
{Length: 2, LowerBound: 2},
},
Status: pgtype.Present,
},
})
}
func TestFloat8ArrayConvertFrom(t *testing.T) {
successfulTests := []struct {
source interface{}
result pgtype.Float8Array
}{
{
source: []float64{1},
result: pgtype.Float8Array{
Elements: []pgtype.Float8{{Float: 1, Status: pgtype.Present}},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present},
},
{
source: (([]float64)(nil)),
result: pgtype.Float8Array{Status: pgtype.Null},
},
}
for i, tt := range successfulTests {
var r pgtype.Float8Array
err := r.ConvertFrom(tt.source)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if !reflect.DeepEqual(r, tt.result) {
t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
}
}
}
func TestFloat8ArrayAssignTo(t *testing.T) {
var float64Slice []float64
var namedFloat64Slice _float64Slice
simpleTests := []struct {
src pgtype.Float8Array
dst interface{}
expected interface{}
}{
{
src: pgtype.Float8Array{
Elements: []pgtype.Float8{{Float: 1.23, Status: pgtype.Present}},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
dst: &float64Slice,
expected: []float64{1.23},
},
{
src: pgtype.Float8Array{
Elements: []pgtype.Float8{{Float: 1.23, Status: pgtype.Present}},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
dst: &namedFloat64Slice,
expected: _float64Slice{1.23},
},
{
src: pgtype.Float8Array{Status: pgtype.Null},
dst: &float64Slice,
expected: (([]float64)(nil)),
},
}
for i, tt := range simpleTests {
err := tt.src.AssignTo(tt.dst)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if dst := reflect.ValueOf(tt.dst).Elem().Interface(); !reflect.DeepEqual(dst, tt.expected) {
t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
}
}
errorTests := []struct {
src pgtype.Float8Array
dst interface{}
}{
{
src: pgtype.Float8Array{
Elements: []pgtype.Float8{{Status: pgtype.Null}},
Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
Status: pgtype.Present,
},
dst: &float64Slice,
},
}
for i, tt := range errorTests {
err := tt.src.AssignTo(tt.dst)
if err == nil {
t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst)
}
}
}

View File

@ -75,7 +75,7 @@ func (dst *Int2) ConvertFrom(src interface{}) error {
}
*dst = Int2{Int: int16(num), Status: Present}
default:
if originalSrc, ok := underlyingIntType(src); ok {
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.ConvertFrom(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int2", value)

View File

@ -66,7 +66,7 @@ func (dst *Int4) ConvertFrom(src interface{}) error {
}
*dst = Int4{Int: int32(num), Status: Present}
default:
if originalSrc, ok := underlyingIntType(src); ok {
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.ConvertFrom(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int8", value)

View File

@ -57,7 +57,7 @@ func (dst *Int8) ConvertFrom(src interface{}) error {
}
*dst = Int8{Int: num, Status: Present}
default:
if originalSrc, ok := underlyingIntType(src); ok {
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.ConvertFrom(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int8", value)

View File

@ -18,6 +18,8 @@ type _int16 int16
type _int16Slice []int16
type _int32Slice []int32
type _int64Slice []int64
type _float32Slice []float32
type _float64Slice []float64
func mustConnectPgx(t testing.TB) *pgx.Conn {
config, err := pgx.ParseURI(os.Getenv("DATABASE_URL"))

View File

@ -5,3 +5,5 @@ erb pgtype_array_type=BoolArray pgtype_element_type=Bool go_array_types=[]bool e
erb pgtype_array_type=DateArray pgtype_element_type=Date go_array_types=[]time.Time element_oid=DateOID typed_array.go.erb > datearray.go
erb pgtype_array_type=TimestamptzArray pgtype_element_type=Timestamptz go_array_types=[]time.Time element_oid=TimestamptzOID typed_array.go.erb > timestamptzarray.go
erb pgtype_array_type=TimestampArray pgtype_element_type=Timestamp go_array_types=[]time.Time element_oid=TimestampOID typed_array.go.erb > timestamparray.go
erb pgtype_array_type=Float4Array pgtype_element_type=Float4 go_array_types=[]float32 element_oid=Float4OID typed_array.go.erb > float4array.go
erb pgtype_array_type=Float8Array pgtype_element_type=Float8 go_array_types=[]float64 element_oid=Float8OID typed_array.go.erb > float8array.go

View File

@ -1151,9 +1151,6 @@ func TestQueryRowCoreFloat32Slice(t *testing.T) {
if err == nil {
t.Error("Expected null to cause error when scanned into slice, but it didn't")
}
if err != nil && !strings.Contains(err.Error(), "Cannot decode null") {
t.Errorf(`Expected null to cause error "Cannot decode null..." but it was %v`, err)
}
ensureConnValid(t, conn)
}
@ -1198,9 +1195,6 @@ func TestQueryRowCoreFloat64Slice(t *testing.T) {
if err == nil {
t.Error("Expected null to cause error when scanned into slice, but it didn't")
}
if err != nil && !strings.Contains(err.Error(), "Cannot decode null") {
t.Errorf(`Expected null to cause error "Cannot decode null..." but it was %v`, err)
}
ensureConnValid(t, conn)
}

View File

@ -1088,14 +1088,6 @@ func Encode(wbuf *WriteBuf, oid OID, arg interface{}) error {
// The name data type goes over the wire using the same format as string,
// so just cast to string and use encodeString
return encodeString(wbuf, oid, string(arg))
case float32:
return encodeFloat32(wbuf, oid, arg)
case []float32:
return encodeFloat32Slice(wbuf, oid, arg)
case float64:
return encodeFloat64(wbuf, oid, arg)
case []float64:
return encodeFloat64Slice(wbuf, oid, arg)
case net.IP:
return encodeIP(wbuf, oid, arg)
case []net.IP:
@ -1195,16 +1187,8 @@ func Decode(vr *ValueReader, d interface{}) error {
*v = decodeCid(vr)
case *string:
*v = decodeText(vr)
case *float32:
*v = decodeFloat4(vr)
case *float64:
*v = decodeFloat8(vr)
case *[]AclItem:
*v = decodeAclItemArray(vr)
case *[]float32:
*v = decodeFloat4Array(vr)
case *[]float64:
*v = decodeFloat8Array(vr)
case *[]string:
*v = decodeTextArray(vr)
case *[][]byte: