mirror of https://github.com/jackc/pgx.git
support NaN in Numeric encode and decode methods
parent
b708c8b985
commit
f2a2797a88
32
numeric.go
32
numeric.go
|
@ -15,6 +15,11 @@ import (
|
||||||
// PostgreSQL internal numeric storage uses 16-bit "digits" with base of 10,000
|
// PostgreSQL internal numeric storage uses 16-bit "digits" with base of 10,000
|
||||||
const nbase = 10000
|
const nbase = 10000
|
||||||
|
|
||||||
|
const (
|
||||||
|
pgNumericNaN = 0x000000000c000000
|
||||||
|
pgNumericNaNSign = 0x0c00
|
||||||
|
)
|
||||||
|
|
||||||
var big0 *big.Int = big.NewInt(0)
|
var big0 *big.Int = big.NewInt(0)
|
||||||
var big1 *big.Int = big.NewInt(1)
|
var big1 *big.Int = big.NewInt(1)
|
||||||
var big10 *big.Int = big.NewInt(10)
|
var big10 *big.Int = big.NewInt(10)
|
||||||
|
@ -323,6 +328,11 @@ func (dst *Numeric) DecodeText(ci *ConnInfo, src []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if string(src) == "NaN" {
|
||||||
|
*dst = Numeric{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
num, exp, err := parseNumericString(string(src))
|
num, exp, err := parseNumericString(string(src))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -366,12 +376,6 @@ func (dst *Numeric) DecodeBinary(ci *ConnInfo, src []byte) error {
|
||||||
rp := 0
|
rp := 0
|
||||||
ndigits := int16(binary.BigEndian.Uint16(src[rp:]))
|
ndigits := int16(binary.BigEndian.Uint16(src[rp:]))
|
||||||
rp += 2
|
rp += 2
|
||||||
|
|
||||||
if ndigits == 0 {
|
|
||||||
*dst = Numeric{Int: big.NewInt(0), Status: Present}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
weight := int16(binary.BigEndian.Uint16(src[rp:]))
|
weight := int16(binary.BigEndian.Uint16(src[rp:]))
|
||||||
rp += 2
|
rp += 2
|
||||||
sign := int16(binary.BigEndian.Uint16(src[rp:]))
|
sign := int16(binary.BigEndian.Uint16(src[rp:]))
|
||||||
|
@ -379,6 +383,16 @@ func (dst *Numeric) DecodeBinary(ci *ConnInfo, src []byte) error {
|
||||||
dscale := int16(binary.BigEndian.Uint16(src[rp:]))
|
dscale := int16(binary.BigEndian.Uint16(src[rp:]))
|
||||||
rp += 2
|
rp += 2
|
||||||
|
|
||||||
|
if sign == pgNumericNaNSign {
|
||||||
|
*dst = Numeric{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ndigits == 0 {
|
||||||
|
*dst = Numeric{Int: big.NewInt(0), Status: Present}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if len(src[rp:]) < int(ndigits)*2 {
|
if len(src[rp:]) < int(ndigits)*2 {
|
||||||
return errors.Errorf("numeric incomplete %v", src)
|
return errors.Errorf("numeric incomplete %v", src)
|
||||||
}
|
}
|
||||||
|
@ -477,7 +491,8 @@ func (src Numeric) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
case Null:
|
case Null:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case Undefined:
|
case Undefined:
|
||||||
return nil, errUndefined
|
buf = append(buf, []byte("NaN")...)
|
||||||
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = append(buf, src.Int.String()...)
|
buf = append(buf, src.Int.String()...)
|
||||||
|
@ -491,7 +506,8 @@ func (src Numeric) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
case Null:
|
case Null:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case Undefined:
|
case Undefined:
|
||||||
return nil, errUndefined
|
buf = pgio.AppendUint64(buf, pgNumericNaN)
|
||||||
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var sign int16
|
var sign int16
|
||||||
|
|
|
@ -344,6 +344,8 @@ func TestNumericEncodeDecodeBinary(t *testing.T) {
|
||||||
123,
|
123,
|
||||||
0.000012345,
|
0.000012345,
|
||||||
1.00002345,
|
1.00002345,
|
||||||
|
math.NaN(),
|
||||||
|
float32(math.NaN()),
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
|
@ -351,7 +353,7 @@ func TestNumericEncodeDecodeBinary(t *testing.T) {
|
||||||
ci := pgtype.NewConnInfo()
|
ci := pgtype.NewConnInfo()
|
||||||
text, err := n.EncodeText(ci, nil)
|
text, err := n.EncodeText(ci, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d: %v", i, err)
|
t.Errorf("%d (EncodeText): %v", i, err)
|
||||||
}
|
}
|
||||||
return string(text)
|
return string(text)
|
||||||
}
|
}
|
||||||
|
@ -360,10 +362,13 @@ func TestNumericEncodeDecodeBinary(t *testing.T) {
|
||||||
|
|
||||||
encoded, err := numeric.EncodeBinary(ci, nil)
|
encoded, err := numeric.EncodeBinary(ci, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d: %v", i, err)
|
t.Errorf("%d (EncodeBinary): %v", i, err)
|
||||||
}
|
}
|
||||||
decoded := &pgtype.Numeric{}
|
decoded := &pgtype.Numeric{}
|
||||||
decoded.DecodeBinary(ci, encoded)
|
err = decoded.DecodeBinary(ci, encoded)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d (DecodeBinary): %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
text0 := toString(numeric)
|
text0 := toString(numeric)
|
||||||
text1 := toString(decoded)
|
text1 := toString(decoded)
|
||||||
|
|
Loading…
Reference in New Issue