Initial proof-of-concept for pgtype
Squashed commit of the following: commit c19454582b335ce5bdda6320f7e4e8c76cfeaf44 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Mar 3 15:24:47 2017 -0600 Add AssignTo to pgtype.Timestamptz Also handle infinity for pgtype.Date commit 7329933610b38f4bc15731b1f7c55c520b49e300 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Mar 3 15:12:18 2017 -0600 Implement AssignTo for most pgtypes commit cc3d1e4af896d34ec98c3bf2e982d0367451f21c Author: Jack Christensen <jack@jackchristensen.com> Date: Thu Mar 2 21:19:07 2017 -0600 Use pgtype.Int2Array in pgx commit 36da5cc2178d1a31a56dc6e6f128843bd80dea0b Author: Jack Christensen <jack@jackchristensen.com> Date: Tue Feb 28 21:45:33 2017 -0600 Add text array transcoding commit 1b0f18d99f38b69f8c2db26388815e67b2b03d59 Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 27 19:28:55 2017 -0600 Add ParseUntypedTextArray commit 0f50ce3e833fc38495d333228daf04f5142be676 Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 27 18:54:20 2017 -0600 wip commit d934f273627d79997035c282416db922f2fbe87a Author: Jack Christensen <jack@jackchristensen.com> Date: Sun Feb 26 17:14:32 2017 -0600 WIP - beginning text format array parsing commit 7276ad33ce7fa9c250745a3ed909998f3dae4a32 Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 22:50:11 2017 -0600 Beginning binary arrays commit 917faa5a3175d376222423c10aca297a20f96448 Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 19:36:35 2017 -0600 Fix incomplete tests commit de8c140cfb98b7b047d53c5718ccbf12eaf813a1 Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 19:32:22 2017 -0600 Add timestamptz null and infinity commit 7d9f954de4e071a1eccac762248079b90dbeb53f Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 18:19:38 2017 -0600 Add infinity to pgtype.Date commit 7bf783ae20ba05571c2fb9f661183233c95eab41 Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 17:19:55 2017 -0600 Add Status to pgtype.Date commit 984500455c9b9a4b6221758540d248e6410d93a4 Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 16:54:01 2017 -0600 Add status to Int4 and Int8 commit 6fe76fcfc2de31552790db3b093480a9d5b2a742 Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 16:40:27 2017 -0600 Extract testSuccessfulTranscode commit 001647c1da03f796014cf21f41c9a7fd2cfadfde Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 16:15:51 2017 -0600 Add Status to pgtype.Int2 commit 720451f06d13d9c9fa2a0482e010f24bf4627c2a Author: Jack Christensen <jack@jackchristensen.com> Date: Sat Feb 25 15:56:44 2017 -0600 Add status to pgtype.Bool commit 325f700b6edff215a692b10bc5b94cdfe1100769 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 24 17:28:15 2017 -0600 Add date to conversion system commit 4a9343e45d3897f59eab98a0009d2ddbe07e02d7 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 24 16:28:35 2017 -0600 Add bool to oid based encoding commit d984fcafab1476cf84852485b6711f4b2069eb6d Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 24 16:15:38 2017 -0600 Add pgtype interfaces commit 0f93bfc2de4023b069b966c0988bf7f0469d1809 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 24 14:48:34 2017 -0600 Begin introduction of Convert commit e5707023cac7c07342b8c910e480d09a1caaf6ee Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 24 14:10:56 2017 -0600 Move bool to pgtype commit bb764d2129efe7fb21e841dbb35e6d0dc7586d37 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 24 13:45:05 2017 -0600 Add Int2 test commit 08c49437f455a32f7c3f0a524cd21a895d440301 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 24 13:44:09 2017 -0600 Add Int4 test commit 16722952222fd15c53c8fa84974645504a6d0dc0 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 24 08:56:59 2017 -0600 Add int8 tests commit 83a5447cd2c46b58d0880023cc4e9af0c84988a2 Author: Jack Christensen <jack@jackchristensen.com> Date: Wed Feb 22 18:08:05 2017 -0600 wip commit 0ca0ee72068a72b016729b01fccef22474595285 Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 20 18:56:52 2017 -0600 wip commit d2c2baf4ea2cd0793d68c7094c425217df952bec Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 20 18:46:10 2017 -0600 wip commit f78371da0098356527b193fd496a338da5fe414b Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 20 17:43:39 2017 -0600 wip commit 3366699bea62ec0110db05f3cb2998d58ac9ce5d Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 20 14:07:47 2017 -0600 wip commit 66b79e940870fd0133ebb10ac1547e1d4d7d0b51 Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 20 13:35:37 2017 -0600 Extract pgio commit 8b07d97d1305ed98fd76db6e306a289c0af92d56 Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 20 13:20:00 2017 -0600 wip commit 62f1adb3427f4317b708da075dce50c4d4daff7b Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 20 12:08:46 2017 -0600 wip commit a712d2546933a5a8433c65eef0ff2ee135077c87 Author: Jack Christensen <jack@jackchristensen.com> Date: Mon Feb 20 09:30:52 2017 -0600 wip commit 4faf97cc588126dda160fc360680719572a23105 Author: Jack Christensen <jack@jackchristensen.com> Date: Fri Feb 17 22:20:18 2017 -0600 wip
This commit is contained in:
@@ -13,6 +13,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/pgtype"
|
||||
)
|
||||
|
||||
// PostgreSQL oids for common types
|
||||
@@ -200,6 +202,10 @@ type Encoder interface {
|
||||
FormatCode() int16
|
||||
}
|
||||
|
||||
type ScannerV3 interface {
|
||||
ScanPgxV3(fieldDescription interface{}, src interface{}) error
|
||||
}
|
||||
|
||||
// NullFloat32 represents an float4 that may be null. NullFloat32 implements the
|
||||
// Scanner and Encoder interfaces so it may be used both as an argument to
|
||||
// Query[Row] and a destination for Scan.
|
||||
@@ -497,7 +503,7 @@ func (n NullInt16) Encode(w *WriteBuf, oid OID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return encodeInt16(w, oid, n.Int16)
|
||||
return pgtype.Int2{Int: n.Int16, Status: pgtype.Present}.EncodeBinary(w)
|
||||
}
|
||||
|
||||
// NullInt32 represents an integer that may be null. NullInt32 implements the
|
||||
@@ -536,7 +542,7 @@ func (n NullInt32) Encode(w *WriteBuf, oid OID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return encodeInt32(w, oid, n.Int32)
|
||||
return pgtype.Int4{Int: n.Int32, Status: pgtype.Present}.EncodeBinary(w)
|
||||
}
|
||||
|
||||
// OID (Object Identifier Type) is, according to https://www.postgresql.org/docs/current/static/datatype-oid.html,
|
||||
@@ -782,7 +788,7 @@ func (n NullInt64) Encode(w *WriteBuf, oid OID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return encodeInt64(w, oid, n.Int64)
|
||||
return pgtype.Int8{Int: n.Int64, Status: pgtype.Present}.EncodeBinary(w)
|
||||
}
|
||||
|
||||
// NullBool represents an bool that may be null. NullBool implements the Scanner
|
||||
@@ -1020,6 +1026,10 @@ func Encode(wbuf *WriteBuf, oid OID, arg interface{}) error {
|
||||
switch arg := arg.(type) {
|
||||
case Encoder:
|
||||
return arg.Encode(wbuf, oid)
|
||||
case pgtype.BinaryEncoder:
|
||||
return arg.EncodeBinary(wbuf)
|
||||
case pgtype.TextEncoder:
|
||||
return arg.EncodeText(wbuf)
|
||||
case driver.Valuer:
|
||||
v, err := arg.Value()
|
||||
if err != nil {
|
||||
@@ -1054,17 +1064,19 @@ func Encode(wbuf *WriteBuf, oid OID, arg interface{}) error {
|
||||
return encodeJSONB(wbuf, oid, arg)
|
||||
}
|
||||
|
||||
if value, ok := wbuf.conn.oidPgtypeValues[oid]; ok {
|
||||
err := value.ConvertFrom(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return value.(pgtype.BinaryEncoder).EncodeBinary(wbuf)
|
||||
}
|
||||
|
||||
switch arg := arg.(type) {
|
||||
case []string:
|
||||
return encodeStringSlice(wbuf, oid, arg)
|
||||
case bool:
|
||||
return encodeBool(wbuf, oid, arg)
|
||||
case []bool:
|
||||
return encodeBoolSlice(wbuf, oid, arg)
|
||||
case int:
|
||||
return encodeInt(wbuf, oid, arg)
|
||||
case uint:
|
||||
return encodeUInt(wbuf, oid, arg)
|
||||
case Char:
|
||||
return encodeChar(wbuf, oid, arg)
|
||||
case AclItem:
|
||||
@@ -1075,32 +1087,12 @@ 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 int8:
|
||||
return encodeInt8(wbuf, oid, arg)
|
||||
case uint8:
|
||||
return encodeUInt8(wbuf, oid, arg)
|
||||
case int16:
|
||||
return encodeInt16(wbuf, oid, arg)
|
||||
case []int16:
|
||||
return encodeInt16Slice(wbuf, oid, arg)
|
||||
case uint16:
|
||||
return encodeUInt16(wbuf, oid, arg)
|
||||
case []uint16:
|
||||
return encodeUInt16Slice(wbuf, oid, arg)
|
||||
case int32:
|
||||
return encodeInt32(wbuf, oid, arg)
|
||||
case []int32:
|
||||
return encodeInt32Slice(wbuf, oid, arg)
|
||||
case uint32:
|
||||
return encodeUInt32(wbuf, oid, arg)
|
||||
case []uint32:
|
||||
return encodeUInt32Slice(wbuf, oid, arg)
|
||||
case int64:
|
||||
return encodeInt64(wbuf, oid, arg)
|
||||
case []int64:
|
||||
return encodeInt64Slice(wbuf, oid, arg)
|
||||
case uint64:
|
||||
return encodeUInt64(wbuf, oid, arg)
|
||||
case []uint64:
|
||||
return encodeUInt64Slice(wbuf, oid, arg)
|
||||
case float32:
|
||||
@@ -1140,32 +1132,57 @@ func Encode(wbuf *WriteBuf, oid OID, arg interface{}) error {
|
||||
func stripNamedType(val *reflect.Value) (interface{}, bool) {
|
||||
switch val.Kind() {
|
||||
case reflect.Int:
|
||||
return int(val.Int()), true
|
||||
convVal := int(val.Int())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Int8:
|
||||
return int8(val.Int()), true
|
||||
convVal := int8(val.Int())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Int16:
|
||||
return int16(val.Int()), true
|
||||
convVal := int16(val.Int())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Int32:
|
||||
return int32(val.Int()), true
|
||||
convVal := int32(val.Int())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Int64:
|
||||
return int64(val.Int()), true
|
||||
convVal := int64(val.Int())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Uint:
|
||||
return uint(val.Uint()), true
|
||||
convVal := uint(val.Uint())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Uint8:
|
||||
return uint8(val.Uint()), true
|
||||
convVal := uint8(val.Uint())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Uint16:
|
||||
return uint16(val.Uint()), true
|
||||
convVal := uint16(val.Uint())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Uint32:
|
||||
return uint32(val.Uint()), true
|
||||
convVal := uint32(val.Uint())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.Uint64:
|
||||
return uint64(val.Uint()), true
|
||||
convVal := uint64(val.Uint())
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
case reflect.String:
|
||||
return val.String(), true
|
||||
convVal := val.String()
|
||||
return convVal, reflect.TypeOf(convVal) != val.Type()
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func decodeByOID(vr *ValueReader) (interface{}, error) {
|
||||
switch vr.Type().DataType {
|
||||
case Int2OID, Int4OID, Int8OID:
|
||||
n := decodeInt(vr)
|
||||
return n, vr.Err()
|
||||
case BoolOID:
|
||||
b := decodeBool(vr)
|
||||
return b, vr.Err()
|
||||
default:
|
||||
buf := vr.ReadBytes(vr.Len())
|
||||
return buf, vr.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// Decode decodes from vr into d. d must be a pointer. This allows
|
||||
// implementations of the Decoder interface to delegate the actual work of
|
||||
// decoding to the built-in functionality.
|
||||
@@ -1381,28 +1398,36 @@ func Decode(vr *ValueReader, d interface{}) error {
|
||||
}
|
||||
|
||||
func decodeBool(vr *ValueReader) bool {
|
||||
if vr.Len() == -1 {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into bool"))
|
||||
return false
|
||||
}
|
||||
|
||||
if vr.Type().DataType != BoolOID {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Cannot decode oid %v into bool", vr.Type().DataType)))
|
||||
return false
|
||||
}
|
||||
|
||||
if vr.Type().FormatCode != BinaryFormatCode {
|
||||
vr.err = errRewoundLen
|
||||
|
||||
var b pgtype.Bool
|
||||
var err error
|
||||
switch vr.Type().FormatCode {
|
||||
case TextFormatCode:
|
||||
err = b.DecodeText(&valueReader2{vr})
|
||||
case BinaryFormatCode:
|
||||
err = b.DecodeBinary(&valueReader2{vr})
|
||||
default:
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
|
||||
return false
|
||||
}
|
||||
|
||||
if vr.Len() != 1 {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an bool: %d", vr.Len())))
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
return false
|
||||
}
|
||||
|
||||
b := vr.ReadByte()
|
||||
return b != 0
|
||||
if b.Status != pgtype.Present {
|
||||
vr.Fatal(fmt.Errorf("Cannot decode null into bool"))
|
||||
return false
|
||||
}
|
||||
|
||||
return b.Bool
|
||||
}
|
||||
|
||||
func encodeBool(w *WriteBuf, oid OID, value bool) error {
|
||||
@@ -1410,16 +1435,8 @@ func encodeBool(w *WriteBuf, oid OID, value bool) error {
|
||||
return fmt.Errorf("cannot encode Go %s into oid %d", "bool", oid)
|
||||
}
|
||||
|
||||
w.WriteInt32(1)
|
||||
|
||||
var n byte
|
||||
if value {
|
||||
n = 1
|
||||
}
|
||||
|
||||
w.WriteByte(n)
|
||||
|
||||
return nil
|
||||
b := pgtype.Bool{Bool: value, Status: pgtype.Present}
|
||||
return b.EncodeBinary(w)
|
||||
}
|
||||
|
||||
func decodeInt(vr *ValueReader) int64 {
|
||||
@@ -1447,17 +1464,31 @@ func decodeInt8(vr *ValueReader) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if vr.Type().FormatCode != BinaryFormatCode {
|
||||
vr.err = errRewoundLen
|
||||
|
||||
var n pgtype.Int8
|
||||
var err error
|
||||
switch vr.Type().FormatCode {
|
||||
case TextFormatCode:
|
||||
err = n.DecodeText(&valueReader2{vr})
|
||||
case BinaryFormatCode:
|
||||
err = n.DecodeBinary(&valueReader2{vr})
|
||||
default:
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
|
||||
return 0
|
||||
}
|
||||
|
||||
if vr.Len() != 8 {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int8: %d", vr.Len())))
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
return 0
|
||||
}
|
||||
|
||||
return vr.ReadInt64()
|
||||
if n.Status == pgtype.Null {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into int16"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return n.Int
|
||||
}
|
||||
|
||||
func decodeChar(vr *ValueReader) Char {
|
||||
@@ -1485,88 +1516,37 @@ func decodeChar(vr *ValueReader) Char {
|
||||
}
|
||||
|
||||
func decodeInt2(vr *ValueReader) int16 {
|
||||
if vr.Len() == -1 {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into int16"))
|
||||
return 0
|
||||
}
|
||||
|
||||
if vr.Type().DataType != Int2OID {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Cannot decode oid %v into int16", vr.Type().DataType)))
|
||||
return 0
|
||||
}
|
||||
|
||||
if vr.Type().FormatCode != BinaryFormatCode {
|
||||
vr.err = errRewoundLen
|
||||
|
||||
var n pgtype.Int2
|
||||
var err error
|
||||
switch vr.Type().FormatCode {
|
||||
case TextFormatCode:
|
||||
err = n.DecodeText(&valueReader2{vr})
|
||||
case BinaryFormatCode:
|
||||
err = n.DecodeBinary(&valueReader2{vr})
|
||||
default:
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
|
||||
return 0
|
||||
}
|
||||
|
||||
if vr.Len() != 2 {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int2: %d", vr.Len())))
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
return 0
|
||||
}
|
||||
|
||||
return vr.ReadInt16()
|
||||
}
|
||||
|
||||
func encodeInt(w *WriteBuf, oid OID, value int) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
if value < math.MinInt16 {
|
||||
return fmt.Errorf("%d is less than min pg:int2", value)
|
||||
} else if value > math.MaxInt16 {
|
||||
return fmt.Errorf("%d is greater than max pg:int2", value)
|
||||
}
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
case Int4OID:
|
||||
if value < math.MinInt32 {
|
||||
return fmt.Errorf("%d is less than min pg:int4", value)
|
||||
} else if value > math.MaxInt32 {
|
||||
return fmt.Errorf("%d is greater than max pg:int4", value)
|
||||
}
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
case Int8OID:
|
||||
if int64(value) <= int64(math.MaxInt64) {
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is larger than max int64 %d", value, int64(math.MaxInt64))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "int8", oid)
|
||||
if n.Status == pgtype.Null {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into int16"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeUInt(w *WriteBuf, oid OID, value uint) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
if value > math.MaxInt16 {
|
||||
return fmt.Errorf("%d is greater than max pg:int2", value)
|
||||
}
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
case Int4OID:
|
||||
if value > math.MaxInt32 {
|
||||
return fmt.Errorf("%d is greater than max pg:int4", value)
|
||||
}
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
case Int8OID:
|
||||
//****** Changed value to int64(value) and math.MaxInt64 to int64(math.MaxInt64)
|
||||
if int64(value) > int64(math.MaxInt64) {
|
||||
return fmt.Errorf("%d is greater than max pg:int8", value)
|
||||
}
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "uint8", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
return n.Int
|
||||
}
|
||||
|
||||
func encodeChar(w *WriteBuf, oid OID, value Char) error {
|
||||
@@ -1575,187 +1555,6 @@ func encodeChar(w *WriteBuf, oid OID, value Char) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeInt8(w *WriteBuf, oid OID, value int8) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
case Int4OID:
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
case Int8OID:
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "int8", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeUInt8(w *WriteBuf, oid OID, value uint8) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
case Int4OID:
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
case Int8OID:
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "uint8", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeInt16(w *WriteBuf, oid OID, value int16) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(value)
|
||||
case Int4OID:
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
case Int8OID:
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "int16", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeUInt16(w *WriteBuf, oid OID, value uint16) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
if value <= math.MaxInt16 {
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int16 %d", value, math.MaxInt16)
|
||||
}
|
||||
case Int4OID:
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
case Int8OID:
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "int16", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeInt32(w *WriteBuf, oid OID, value int32) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
if value <= math.MaxInt16 {
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int16 %d", value, math.MaxInt16)
|
||||
}
|
||||
case Int4OID:
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(value)
|
||||
case Int8OID:
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "int32", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeUInt32(w *WriteBuf, oid OID, value uint32) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
if value <= math.MaxInt16 {
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int16 %d", value, math.MaxInt16)
|
||||
}
|
||||
case Int4OID:
|
||||
if value <= math.MaxInt32 {
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int32 %d", value, math.MaxInt32)
|
||||
}
|
||||
case Int8OID:
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "uint32", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeInt64(w *WriteBuf, oid OID, value int64) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
if value <= math.MaxInt16 {
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int16 %d", value, math.MaxInt16)
|
||||
}
|
||||
case Int4OID:
|
||||
if value <= math.MaxInt32 {
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int32 %d", value, math.MaxInt32)
|
||||
}
|
||||
case Int8OID:
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(value)
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "int64", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeUInt64(w *WriteBuf, oid OID, value uint64) error {
|
||||
switch oid {
|
||||
case Int2OID:
|
||||
if value <= math.MaxInt16 {
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int16 %d", value, math.MaxInt16)
|
||||
}
|
||||
case Int4OID:
|
||||
if value <= math.MaxInt32 {
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int32 %d", value, math.MaxInt32)
|
||||
}
|
||||
case Int8OID:
|
||||
|
||||
if value <= math.MaxInt64 {
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(int64(value))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max int64 %d", value, int64(math.MaxInt64))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "uint64", oid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInt4(vr *ValueReader) int32 {
|
||||
if vr.Len() == -1 {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into int32"))
|
||||
@@ -1767,17 +1566,31 @@ func decodeInt4(vr *ValueReader) int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if vr.Type().FormatCode != BinaryFormatCode {
|
||||
vr.err = errRewoundLen
|
||||
|
||||
var n pgtype.Int4
|
||||
var err error
|
||||
switch vr.Type().FormatCode {
|
||||
case TextFormatCode:
|
||||
err = n.DecodeText(&valueReader2{vr})
|
||||
case BinaryFormatCode:
|
||||
err = n.DecodeBinary(&valueReader2{vr})
|
||||
default:
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
|
||||
return 0
|
||||
}
|
||||
|
||||
if vr.Len() != 4 {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int4: %d", vr.Len())))
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
return 0
|
||||
}
|
||||
|
||||
return vr.ReadInt32()
|
||||
if n.Status == pgtype.Null {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into int16"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return n.Int
|
||||
}
|
||||
|
||||
func decodeOID(vr *ValueReader) OID {
|
||||
@@ -2179,51 +1992,54 @@ func encodeJSONB(w *WriteBuf, oid OID, value interface{}) error {
|
||||
}
|
||||
|
||||
func decodeDate(vr *ValueReader) time.Time {
|
||||
var zeroTime time.Time
|
||||
|
||||
if vr.Len() == -1 {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into time.Time"))
|
||||
return zeroTime
|
||||
}
|
||||
|
||||
if vr.Type().DataType != DateOID {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Cannot decode oid %v into time.Time", vr.Type().DataType)))
|
||||
return zeroTime
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
if vr.Type().FormatCode != BinaryFormatCode {
|
||||
vr.err = errRewoundLen
|
||||
|
||||
var d pgtype.Date
|
||||
var err error
|
||||
switch vr.Type().FormatCode {
|
||||
case TextFormatCode:
|
||||
err = d.DecodeText(&valueReader2{vr})
|
||||
case BinaryFormatCode:
|
||||
err = d.DecodeBinary(&valueReader2{vr})
|
||||
default:
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
|
||||
return zeroTime
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
if vr.Len() != 4 {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an date: %d", vr.Len())))
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
return time.Time{}
|
||||
}
|
||||
dayOffset := vr.ReadInt32()
|
||||
return time.Date(2000, 1, int(1+dayOffset), 0, 0, 0, 0, time.Local)
|
||||
|
||||
if d.Status == pgtype.Null {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into int16"))
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
return d.Time
|
||||
}
|
||||
|
||||
func encodeTime(w *WriteBuf, oid OID, value time.Time) error {
|
||||
switch oid {
|
||||
case DateOID:
|
||||
tUnix := time.Date(value.Year(), value.Month(), value.Day(), 0, 0, 0, 0, time.UTC).Unix()
|
||||
dateEpoch := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).Unix()
|
||||
|
||||
secSinceDateEpoch := tUnix - dateEpoch
|
||||
daysSinceDateEpoch := secSinceDateEpoch / 86400
|
||||
|
||||
w.WriteInt32(4)
|
||||
w.WriteInt32(int32(daysSinceDateEpoch))
|
||||
|
||||
return nil
|
||||
var d pgtype.Date
|
||||
err := d.ConvertFrom(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.EncodeBinary(w)
|
||||
case TimestampTzOID, TimestampOID:
|
||||
microsecSinceUnixEpoch := value.Unix()*1000000 + int64(value.Nanosecond())/1000
|
||||
microsecSinceY2K := microsecSinceUnixEpoch - microsecFromUnixEpochToY2K
|
||||
|
||||
w.WriteInt32(8)
|
||||
w.WriteInt64(microsecSinceY2K)
|
||||
|
||||
return nil
|
||||
var t pgtype.Timestamptz
|
||||
err := t.ConvertFrom(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.EncodeBinary(w)
|
||||
default:
|
||||
return fmt.Errorf("cannot encode %s into oid %v", "time.Time", oid)
|
||||
}
|
||||
@@ -2244,19 +2060,31 @@ func decodeTimestampTz(vr *ValueReader) time.Time {
|
||||
return zeroTime
|
||||
}
|
||||
|
||||
if vr.Type().FormatCode != BinaryFormatCode {
|
||||
vr.err = errRewoundLen
|
||||
|
||||
var t pgtype.Timestamptz
|
||||
var err error
|
||||
switch vr.Type().FormatCode {
|
||||
case TextFormatCode:
|
||||
err = t.DecodeText(&valueReader2{vr})
|
||||
case BinaryFormatCode:
|
||||
err = t.DecodeBinary(&valueReader2{vr})
|
||||
default:
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
|
||||
return zeroTime
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
if vr.Len() != 8 {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an timestamptz: %d", vr.Len())))
|
||||
return zeroTime
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
microsecSinceY2K := vr.ReadInt64()
|
||||
microsecSinceUnixEpoch := microsecFromUnixEpochToY2K + microsecSinceY2K
|
||||
return time.Unix(microsecSinceUnixEpoch/1000000, (microsecSinceUnixEpoch%1000000)*1000)
|
||||
if t.Status == pgtype.Null {
|
||||
vr.Fatal(ProtocolError("Cannot decode null into time.Time"))
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
return t.Time
|
||||
}
|
||||
|
||||
func decodeTimestamp(vr *ValueReader) time.Time {
|
||||
@@ -2578,42 +2406,45 @@ func encodeByteSliceSlice(w *WriteBuf, oid OID, value [][]byte) error {
|
||||
}
|
||||
|
||||
func decodeInt2Array(vr *ValueReader) []int16 {
|
||||
if vr.Len() == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if vr.Type().DataType != Int2ArrayOID {
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Cannot decode oid %v into []int16", vr.Type().DataType)))
|
||||
return nil
|
||||
}
|
||||
|
||||
if vr.Type().FormatCode != BinaryFormatCode {
|
||||
vr.err = errRewoundLen
|
||||
|
||||
var a pgtype.Int2Array
|
||||
var err error
|
||||
switch vr.Type().FormatCode {
|
||||
case TextFormatCode:
|
||||
err = a.DecodeText(&valueReader2{vr})
|
||||
case BinaryFormatCode:
|
||||
err = a.DecodeBinary(&valueReader2{vr})
|
||||
default:
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
|
||||
return nil
|
||||
}
|
||||
|
||||
numElems, err := decode1dArrayHeader(vr)
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
a := make([]int16, int(numElems))
|
||||
for i := 0; i < len(a); i++ {
|
||||
elSize := vr.ReadInt32()
|
||||
switch elSize {
|
||||
case 2:
|
||||
a[i] = vr.ReadInt16()
|
||||
case -1:
|
||||
if a.Status == pgtype.Null {
|
||||
return nil
|
||||
}
|
||||
|
||||
rawArray := make([]int16, len(a.Elements))
|
||||
for i := range a.Elements {
|
||||
if a.Elements[i].Status == pgtype.Present {
|
||||
rawArray[i] = a.Elements[i].Int
|
||||
} else {
|
||||
vr.Fatal(ProtocolError("Cannot decode null element"))
|
||||
return nil
|
||||
default:
|
||||
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int2 element: %d", elSize)))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return a
|
||||
return rawArray
|
||||
}
|
||||
|
||||
func decodeInt2ArrayToUInt(vr *ValueReader) []uint16 {
|
||||
@@ -2660,38 +2491,6 @@ func decodeInt2ArrayToUInt(vr *ValueReader) []uint16 {
|
||||
return a
|
||||
}
|
||||
|
||||
func encodeInt16Slice(w *WriteBuf, oid OID, slice []int16) error {
|
||||
if oid != Int2ArrayOID {
|
||||
return fmt.Errorf("cannot encode Go %s into oid %d", "[]int16", oid)
|
||||
}
|
||||
|
||||
encodeArrayHeader(w, Int2OID, len(slice), 6)
|
||||
for _, v := range slice {
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeUInt16Slice(w *WriteBuf, oid OID, slice []uint16) error {
|
||||
if oid != Int2ArrayOID {
|
||||
return fmt.Errorf("cannot encode Go %s into oid %d", "[]uint16", oid)
|
||||
}
|
||||
|
||||
encodeArrayHeader(w, Int2OID, len(slice), 6)
|
||||
for _, v := range slice {
|
||||
if v <= math.MaxInt16 {
|
||||
w.WriteInt32(2)
|
||||
w.WriteInt16(int16(v))
|
||||
} else {
|
||||
return fmt.Errorf("%d is greater than max smallint %d", v, math.MaxInt16)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInt4Array(vr *ValueReader) []int32 {
|
||||
if vr.Len() == -1 {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user