Factor out duplication in AssignTo

v3-numeric-wip
Jack Christensen 2017-03-18 16:54:08 -05:00
parent 264823e6ab
commit 4d9c44fc01
28 changed files with 430 additions and 492 deletions

View File

@ -3,7 +3,6 @@ package pgtype
import (
"fmt"
"io"
"reflect"
)
// Aclitem is used for PostgreSQL's aclitem data type. A sample aclitem
@ -55,39 +54,22 @@ func (dst *Aclitem) Get() interface{} {
}
func (src *Aclitem) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *string:
if src.Status != Present {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = src.String
return nil
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 src.Status == Null {
el.Set(reflect.Zero(el.Type()))
return nil
}
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return src.AssignTo(el.Interface())
case reflect.String:
if src.Status != Present {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
el.SetString(src.String)
return nil
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Aclitem) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -58,28 +58,29 @@ func (dst *AclitemArray) Get() interface{} {
}
func (src *AclitemArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]string:
if src.Status == Present {
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *AclitemArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -3,7 +3,6 @@ package pgtype
import (
"fmt"
"io"
"reflect"
"strconv"
)
@ -44,39 +43,22 @@ func (dst *Bool) Get() interface{} {
}
func (src *Bool) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *bool:
if src.Status != Present {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = src.Bool
return nil
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 src.Status == Null {
el.Set(reflect.Zero(el.Type()))
return nil
}
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return src.AssignTo(el.Interface())
case reflect.Bool:
if src.Status != Present {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
el.SetBool(src.Bool)
return nil
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Bool) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -59,28 +59,29 @@ func (dst *BoolArray) Get() interface{} {
}
func (src *BoolArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]bool:
if src.Status == Present {
*v = make([]bool, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *BoolArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -4,7 +4,6 @@ import (
"encoding/hex"
"fmt"
"io"
"reflect"
)
type Bytea struct {
@ -42,38 +41,24 @@ func (dst *Bytea) Get() interface{} {
}
func (src *Bytea) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]byte:
if src.Status == Present {
*v = src.Bytes
} else {
*v = nil
}
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 src.Status == Null {
el.Set(reflect.Zero(el.Type()))
buf := make([]byte, len(src.Bytes))
copy(buf, src.Bytes)
*v = buf
return nil
}
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return src.AssignTo(el.Interface())
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
}
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
// DecodeText only supports the hex format. This has been the default since

View File

@ -59,28 +59,29 @@ func (dst *ByteaArray) Get() interface{} {
}
func (src *ByteaArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[][]byte:
if src.Status == Present {
*v = make([][]byte, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *ByteaArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -79,40 +79,38 @@ func (dst *CidrArray) Get() interface{} {
}
func (src *CidrArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]*net.IPNet:
if src.Status == Present {
*v = make([]*net.IPNet, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
case *[]net.IP:
if src.Status == Present {
*v = make([]net.IP, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *CidrArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -184,28 +184,6 @@ func underlyingSliceType(val interface{}) (interface{}, bool) {
return nil, false
}
func underlyingPtrSliceType(val interface{}) (interface{}, bool) {
refVal := reflect.ValueOf(val)
if refVal.Kind() != reflect.Ptr {
return nil, false
}
if refVal.IsNil() {
return nil, false
}
sliceVal := refVal.Elem().Interface()
baseSliceType := reflect.SliceOf(reflect.TypeOf(sliceVal).Elem())
ptrBaseSliceType := reflect.PtrTo(baseSliceType)
if refVal.Type().ConvertibleTo(ptrBaseSliceType) {
convVal := refVal.Convert(ptrBaseSliceType)
return convVal.Interface(), reflect.TypeOf(convVal.Interface()) != refVal.Type()
}
return nil, false
}
func int64AssignTo(srcVal int64, srcStatus Status, dst interface{}) error {
if srcStatus == Present {
switch v := dst.(type) {
@ -363,3 +341,83 @@ func float64AssignTo(srcVal float64, srcStatus Status, dst interface{}) error {
return fmt.Errorf("cannot assign %v %v into %T", srcVal, srcStatus, dst)
}
func nullAssignTo(dst interface{}) error {
dstPtr := reflect.ValueOf(dst)
// AssignTo dst must always be a pointer
if dstPtr.Kind() != reflect.Ptr {
return fmt.Errorf("cannot assign NULL to %T", dst)
}
dstVal := dstPtr.Elem()
switch dstVal.Kind() {
case reflect.Ptr, reflect.Slice, reflect.Map:
dstVal.Set(reflect.Zero(dstVal.Type()))
return nil
}
return fmt.Errorf("cannot assign NULL to %T", dst)
}
var kindTypes map[reflect.Kind]reflect.Type
// GetAssignToDstType attempts to convert dst to something AssignTo can assign
// to. If dst is a pointer to pointer it allocates a value and returns the
// dereferences pointer. If dst is a named type such as *Foo where Foo is type
// Foo int16, it converts dst to *int16.
//
// GetAssignToDstType returns the converted dst and a bool representing if any
// change was made.
func GetAssignToDstType(dst interface{}) (interface{}, bool) {
dstPtr := reflect.ValueOf(dst)
// AssignTo dst must always be a pointer
if dstPtr.Kind() != reflect.Ptr {
return nil, false
}
dstVal := dstPtr.Elem()
// if dst is a pointer to pointer, allocate space try again with the dereferenced pointer
if dstVal.Kind() == reflect.Ptr {
dstVal.Set(reflect.New(dstVal.Type().Elem()))
return dstVal.Interface(), true
}
// if dst is pointer to a base type that has been renamed
if baseValType, ok := kindTypes[dstVal.Kind()]; ok {
nextDst := dstPtr.Convert(reflect.PtrTo(baseValType))
return nextDst.Interface(), dstPtr.Type() != nextDst.Type()
}
if dstVal.Kind() == reflect.Slice {
if baseElemType, ok := kindTypes[dstVal.Type().Elem().Kind()]; ok {
baseSliceType := reflect.PtrTo(reflect.SliceOf(baseElemType))
nextDst := dstPtr.Convert(baseSliceType)
return nextDst.Interface(), dstPtr.Type() != nextDst.Type()
}
}
return nil, false
}
func init() {
kindTypes = map[reflect.Kind]reflect.Type{
reflect.Bool: reflect.TypeOf(false),
reflect.Float32: reflect.TypeOf(float32(0)),
reflect.Float64: reflect.TypeOf(float64(0)),
reflect.Int: reflect.TypeOf(int(0)),
reflect.Int8: reflect.TypeOf(int8(0)),
reflect.Int16: reflect.TypeOf(int16(0)),
reflect.Int32: reflect.TypeOf(int32(0)),
reflect.Int64: reflect.TypeOf(int64(0)),
reflect.Uint: reflect.TypeOf(uint(0)),
reflect.Uint8: reflect.TypeOf(uint8(0)),
reflect.Uint16: reflect.TypeOf(uint16(0)),
reflect.Uint32: reflect.TypeOf(uint32(0)),
reflect.Uint64: reflect.TypeOf(uint64(0)),
reflect.String: reflect.TypeOf(""),
}
}

View File

@ -4,7 +4,6 @@ import (
"encoding/binary"
"fmt"
"io"
"reflect"
"time"
"github.com/jackc/pgx/pgio"
@ -50,33 +49,25 @@ func (dst *Date) Get() interface{} {
}
func (src *Date) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *time.Time:
if src.Status != Present || src.InfinityModifier != None {
if src.InfinityModifier != None {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = src.Time
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 src.Status == Null {
el.Set(reflect.Zero(el.Type()))
return nil
}
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return src.AssignTo(el.Interface())
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Date) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -60,28 +60,29 @@ func (dst *DateArray) Get() interface{} {
}
func (src *DateArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]time.Time:
if src.Status == Present {
*v = make([]time.Time, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *DateArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -59,28 +59,29 @@ func (dst *Float4Array) Get() interface{} {
}
func (src *Float4Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
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
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Float4Array) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -59,28 +59,29 @@ func (dst *Float8Array) Get() interface{} {
}
func (src *Float8Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
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
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Float8Array) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -47,10 +47,10 @@ func (dst *Hstore) Get() interface{} {
}
func (src *Hstore) AssignTo(dst interface{}) error {
switch v := dst.(type) {
case *map[string]string:
switch src.Status {
case Present:
switch v := dst.(type) {
case *map[string]string:
*v = make(map[string]string, len(src.Map))
for k, val := range src.Map {
if val.Status != Present {
@ -58,16 +58,17 @@ func (src *Hstore) AssignTo(dst interface{}) error {
}
(*v)[k] = val.String
}
case Null:
*v = nil
return nil
default:
return fmt.Errorf("cannot decode %v into %T", src, dst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
default:
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Hstore) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -59,28 +59,29 @@ func (dst *HstoreArray) Get() interface{} {
}
func (src *HstoreArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
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
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *HstoreArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -4,7 +4,6 @@ import (
"fmt"
"io"
"net"
"reflect"
"github.com/jackc/pgx/pgio"
)
@ -61,43 +60,28 @@ func (dst *Inet) Get() interface{} {
}
func (src *Inet) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *net.IPNet:
if src.Status != Present {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = *src.IPNet
return nil
case *net.IP:
if src.Status == Present {
if oneCount, bitCount := src.IPNet.Mask.Size(); oneCount != bitCount {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = src.IPNet.IP
} else {
*v = nil
}
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 src.Status == Null {
el.Set(reflect.Zero(el.Type()))
return nil
}
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return src.AssignTo(el.Interface())
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Inet) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -79,40 +79,38 @@ func (dst *InetArray) Get() interface{} {
}
func (src *InetArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]*net.IPNet:
if src.Status == Present {
*v = make([]*net.IPNet, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
case *[]net.IP:
if src.Status == Present {
*v = make([]net.IP, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *InetArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -78,40 +78,38 @@ func (dst *Int2Array) Get() interface{} {
}
func (src *Int2Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]int16:
if src.Status == Present {
*v = make([]int16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
case *[]uint16:
if src.Status == Present {
*v = make([]uint16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Int2Array) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -78,40 +78,38 @@ func (dst *Int4Array) Get() interface{} {
}
func (src *Int4Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]int32:
if src.Status == Present {
*v = make([]int32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
case *[]uint32:
if src.Status == Present {
*v = make([]uint32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Int4Array) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -78,40 +78,38 @@ func (dst *Int8Array) Get() interface{} {
}
func (src *Int8Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]int64:
if src.Status == Present {
*v = make([]int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
case *[]uint64:
if src.Status == Present {
*v = make([]uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Int8Array) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -38,34 +38,29 @@ func (dst *Record) Get() interface{} {
}
func (src *Record) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]Value:
switch src.Status {
case Present:
*v = make([]Value, len(src.Fields))
copy(*v, src.Fields)
case Null:
*v = nil
default:
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
return nil
case *[]interface{}:
switch src.Status {
case Present:
*v = make([]interface{}, len(src.Fields))
for i := range *v {
(*v)[i] = src.Fields[i].Get()
}
case Null:
*v = nil
return nil
default:
return fmt.Errorf("cannot decode %v into %T", src, dst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
default:
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Record) DecodeBinary(ci *ConnInfo, src []byte) error {

View File

@ -3,7 +3,6 @@ package pgtype
import (
"fmt"
"io"
"reflect"
)
type Text struct {
@ -43,49 +42,26 @@ func (dst *Text) Get() interface{} {
}
func (src *Text) AssignTo(dst interface{}) error {
switch v := dst.(type) {
case *string:
if src.Status != Present {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = src.String
case *[]byte:
switch src.Status {
case Present:
switch v := dst.(type) {
case *string:
*v = src.String
return nil
case *[]byte:
*v = make([]byte, len(src.String))
copy(*v, src.String)
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
}
case Null:
*v = nil
default:
return fmt.Errorf("unknown status")
}
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 src.Status == Null {
el.Set(reflect.Zero(el.Type()))
return nil
}
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return src.AssignTo(el.Interface())
case reflect.String:
if src.Status != Present {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
el.SetString(src.String)
return nil
}
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Text) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -59,28 +59,29 @@ func (dst *TextArray) Get() interface{} {
}
func (src *TextArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]string:
if src.Status == Present {
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *TextArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -4,7 +4,6 @@ import (
"encoding/binary"
"fmt"
"io"
"reflect"
"time"
"github.com/jackc/pgx/pgio"
@ -54,33 +53,25 @@ func (dst *Timestamp) Get() interface{} {
}
func (src *Timestamp) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *time.Time:
if src.Status != Present || src.InfinityModifier != None {
if src.InfinityModifier != None {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = src.Time
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 src.Status == Null {
el.Set(reflect.Zero(el.Type()))
return nil
}
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return src.AssignTo(el.Interface())
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
}
return fmt.Errorf("cannot assign %v into %T", src, dst)
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
// DecodeText decodes from src into dst. The decoded time is considered to

View File

@ -60,28 +60,29 @@ func (dst *TimestampArray) Get() interface{} {
}
func (src *TimestampArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]time.Time:
if src.Status == Present {
*v = make([]time.Time, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *TimestampArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -4,7 +4,6 @@ import (
"encoding/binary"
"fmt"
"io"
"reflect"
"time"
"github.com/jackc/pgx/pgio"
@ -55,33 +54,25 @@ func (dst *Timestamptz) Get() interface{} {
}
func (src *Timestamptz) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *time.Time:
if src.Status != Present || src.InfinityModifier != None {
if src.InfinityModifier != None {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = src.Time
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 src.Status == Null {
el.Set(reflect.Zero(el.Type()))
return nil
}
if el.IsNil() {
// allocate destination
el.Set(reflect.New(el.Type().Elem()))
}
return src.AssignTo(el.Interface())
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
}
return fmt.Errorf("cannot assign %v into %T", src, dst)
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *Timestamptz) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -60,28 +60,29 @@ func (dst *TimestamptzArray) Get() interface{} {
}
func (src *TimestamptzArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]time.Time:
if src.Status == Present {
*v = make([]time.Time, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *TimestamptzArray) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -58,28 +58,29 @@ func (dst *<%= pgtype_array_type %>) Get() interface{} {
}
func (src *<%= pgtype_array_type %>) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
<% go_array_types.split(",").each do |t| %>
case *<%= t %>:
if src.Status == Present {
*v = make(<%= t %>, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
<% end %>
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *<%= pgtype_array_type %>) DecodeText(ci *ConnInfo, src []byte) error {

View File

@ -59,28 +59,29 @@ func (dst *VarcharArray) Get() interface{} {
}
func (src *VarcharArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]string:
if src.Status == Present {
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
} else {
*v = nil
}
return nil
default:
if originalDst, ok := underlyingPtrSliceType(dst); ok {
return src.AssignTo(originalDst)
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
case Null:
return nullAssignTo(dst)
}
return nil
return fmt.Errorf("cannot decode %v into %T", src, dst)
}
func (dst *VarcharArray) DecodeText(ci *ConnInfo, src []byte) error {