...

Source file src/github.com/jackc/pgx/v5/pgtype/numeric.go

Documentation: github.com/jackc/pgx/v5/pgtype

     1  package pgtype
     2  
     3  import (
     4  	"bytes"
     5  	"database/sql/driver"
     6  	"encoding/binary"
     7  	"fmt"
     8  	"math"
     9  	"math/big"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/jackc/pgx/v5/internal/pgio"
    14  )
    15  
    16  // PostgreSQL internal numeric storage uses 16-bit "digits" with base of 10,000
    17  const nbase = 10000
    18  
    19  const (
    20  	pgNumericNaN     = 0x00000000c0000000
    21  	pgNumericNaNSign = 0xc000
    22  
    23  	pgNumericPosInf     = 0x00000000d0000000
    24  	pgNumericPosInfSign = 0xd000
    25  
    26  	pgNumericNegInf     = 0x00000000f0000000
    27  	pgNumericNegInfSign = 0xf000
    28  )
    29  
    30  var big0 *big.Int = big.NewInt(0)
    31  var big1 *big.Int = big.NewInt(1)
    32  var big10 *big.Int = big.NewInt(10)
    33  var big100 *big.Int = big.NewInt(100)
    34  var big1000 *big.Int = big.NewInt(1000)
    35  
    36  var bigNBase *big.Int = big.NewInt(nbase)
    37  var bigNBaseX2 *big.Int = big.NewInt(nbase * nbase)
    38  var bigNBaseX3 *big.Int = big.NewInt(nbase * nbase * nbase)
    39  var bigNBaseX4 *big.Int = big.NewInt(nbase * nbase * nbase * nbase)
    40  
    41  type NumericScanner interface {
    42  	ScanNumeric(v Numeric) error
    43  }
    44  
    45  type NumericValuer interface {
    46  	NumericValue() (Numeric, error)
    47  }
    48  
    49  type Numeric struct {
    50  	Int              *big.Int
    51  	Exp              int32
    52  	NaN              bool
    53  	InfinityModifier InfinityModifier
    54  	Valid            bool
    55  }
    56  
    57  func (n *Numeric) ScanNumeric(v Numeric) error {
    58  	*n = v
    59  	return nil
    60  }
    61  
    62  func (n Numeric) NumericValue() (Numeric, error) {
    63  	return n, nil
    64  }
    65  
    66  func (n Numeric) Float64Value() (Float8, error) {
    67  	if !n.Valid {
    68  		return Float8{}, nil
    69  	} else if n.NaN {
    70  		return Float8{Float64: math.NaN(), Valid: true}, nil
    71  	} else if n.InfinityModifier == Infinity {
    72  		return Float8{Float64: math.Inf(1), Valid: true}, nil
    73  	} else if n.InfinityModifier == NegativeInfinity {
    74  		return Float8{Float64: math.Inf(-1), Valid: true}, nil
    75  	}
    76  
    77  	buf := make([]byte, 0, 32)
    78  
    79  	if n.Int == nil {
    80  		buf = append(buf, '0')
    81  	} else {
    82  		buf = append(buf, n.Int.String()...)
    83  	}
    84  	buf = append(buf, 'e')
    85  	buf = append(buf, strconv.FormatInt(int64(n.Exp), 10)...)
    86  
    87  	f, err := strconv.ParseFloat(string(buf), 64)
    88  	if err != nil {
    89  		return Float8{}, err
    90  	}
    91  
    92  	return Float8{Float64: f, Valid: true}, nil
    93  }
    94  
    95  func (n *Numeric) ScanInt64(v Int8) error {
    96  	if !v.Valid {
    97  		*n = Numeric{}
    98  		return nil
    99  	}
   100  
   101  	*n = Numeric{Int: big.NewInt(v.Int64), Valid: true}
   102  	return nil
   103  }
   104  
   105  func (n Numeric) Int64Value() (Int8, error) {
   106  	if !n.Valid {
   107  		return Int8{}, nil
   108  	}
   109  
   110  	bi, err := n.toBigInt()
   111  	if err != nil {
   112  		return Int8{}, err
   113  	}
   114  
   115  	if !bi.IsInt64() {
   116  		return Int8{}, fmt.Errorf("cannot convert %v to int64", n)
   117  	}
   118  
   119  	return Int8{Int64: bi.Int64(), Valid: true}, nil
   120  }
   121  
   122  func (n *Numeric) ScanScientific(src string) error {
   123  	if !strings.ContainsAny("eE", src) {
   124  		return scanPlanTextAnyToNumericScanner{}.Scan([]byte(src), n)
   125  	}
   126  
   127  	if bigF, ok := new(big.Float).SetString(string(src)); ok {
   128  		smallF, _ := bigF.Float64()
   129  		src = strconv.FormatFloat(smallF, 'f', -1, 64)
   130  	}
   131  
   132  	num, exp, err := parseNumericString(src)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	*n = Numeric{Int: num, Exp: exp, Valid: true}
   138  
   139  	return nil
   140  }
   141  
   142  func (n *Numeric) toBigInt() (*big.Int, error) {
   143  	if n.Exp == 0 {
   144  		return n.Int, nil
   145  	}
   146  
   147  	num := &big.Int{}
   148  	num.Set(n.Int)
   149  	if n.Exp > 0 {
   150  		mul := &big.Int{}
   151  		mul.Exp(big10, big.NewInt(int64(n.Exp)), nil)
   152  		num.Mul(num, mul)
   153  		return num, nil
   154  	}
   155  
   156  	div := &big.Int{}
   157  	div.Exp(big10, big.NewInt(int64(-n.Exp)), nil)
   158  	remainder := &big.Int{}
   159  	num.DivMod(num, div, remainder)
   160  	if remainder.Cmp(big0) != 0 {
   161  		return nil, fmt.Errorf("cannot convert %v to integer", n)
   162  	}
   163  	return num, nil
   164  }
   165  
   166  func parseNumericString(str string) (n *big.Int, exp int32, err error) {
   167  	idx := strings.IndexByte(str, '.')
   168  
   169  	if idx == -1 {
   170  		for len(str) > 1 && str[len(str)-1] == '0' && str[len(str)-2] != '-' {
   171  			str = str[:len(str)-1]
   172  			exp++
   173  		}
   174  	} else {
   175  		exp = int32(-(len(str) - idx - 1))
   176  		str = str[:idx] + str[idx+1:]
   177  	}
   178  
   179  	accum := &big.Int{}
   180  	if _, ok := accum.SetString(str, 10); !ok {
   181  		return nil, 0, fmt.Errorf("%s is not a number", str)
   182  	}
   183  
   184  	return accum, exp, nil
   185  }
   186  
   187  func nbaseDigitsToInt64(src []byte) (accum int64, bytesRead, digitsRead int) {
   188  	digits := len(src) / 2
   189  	if digits > 4 {
   190  		digits = 4
   191  	}
   192  
   193  	rp := 0
   194  
   195  	for i := 0; i < digits; i++ {
   196  		if i > 0 {
   197  			accum *= nbase
   198  		}
   199  		accum += int64(binary.BigEndian.Uint16(src[rp:]))
   200  		rp += 2
   201  	}
   202  
   203  	return accum, rp, digits
   204  }
   205  
   206  // Scan implements the database/sql Scanner interface.
   207  func (n *Numeric) Scan(src any) error {
   208  	if src == nil {
   209  		*n = Numeric{}
   210  		return nil
   211  	}
   212  
   213  	switch src := src.(type) {
   214  	case string:
   215  		return scanPlanTextAnyToNumericScanner{}.Scan([]byte(src), n)
   216  	}
   217  
   218  	return fmt.Errorf("cannot scan %T", src)
   219  }
   220  
   221  // Value implements the database/sql/driver Valuer interface.
   222  func (n Numeric) Value() (driver.Value, error) {
   223  	if !n.Valid {
   224  		return nil, nil
   225  	}
   226  
   227  	buf, err := NumericCodec{}.PlanEncode(nil, 0, TextFormatCode, n).Encode(n, nil)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	return string(buf), err
   232  }
   233  
   234  func (n Numeric) MarshalJSON() ([]byte, error) {
   235  	if !n.Valid {
   236  		return []byte("null"), nil
   237  	}
   238  
   239  	if n.NaN {
   240  		return []byte(`"NaN"`), nil
   241  	}
   242  
   243  	return n.numberTextBytes(), nil
   244  }
   245  
   246  func (n *Numeric) UnmarshalJSON(src []byte) error {
   247  	if bytes.Equal(src, []byte(`null`)) {
   248  		*n = Numeric{}
   249  		return nil
   250  	}
   251  	if bytes.Equal(src, []byte(`"NaN"`)) {
   252  		*n = Numeric{NaN: true, Valid: true}
   253  		return nil
   254  	}
   255  	return scanPlanTextAnyToNumericScanner{}.Scan(src, n)
   256  }
   257  
   258  // numberString returns a string of the number. undefined if NaN, infinite, or NULL
   259  func (n Numeric) numberTextBytes() []byte {
   260  	intStr := n.Int.String()
   261  
   262  	buf := &bytes.Buffer{}
   263  
   264  	if len(intStr) > 0 && intStr[:1] == "-" {
   265  		intStr = intStr[1:]
   266  		buf.WriteByte('-')
   267  	}
   268  
   269  	exp := int(n.Exp)
   270  	if exp > 0 {
   271  		buf.WriteString(intStr)
   272  		for i := 0; i < exp; i++ {
   273  			buf.WriteByte('0')
   274  		}
   275  	} else if exp < 0 {
   276  		if len(intStr) <= -exp {
   277  			buf.WriteString("0.")
   278  			leadingZeros := -exp - len(intStr)
   279  			for i := 0; i < leadingZeros; i++ {
   280  				buf.WriteByte('0')
   281  			}
   282  			buf.WriteString(intStr)
   283  		} else if len(intStr) > -exp {
   284  			dpPos := len(intStr) + exp
   285  			buf.WriteString(intStr[:dpPos])
   286  			buf.WriteByte('.')
   287  			buf.WriteString(intStr[dpPos:])
   288  		}
   289  	} else {
   290  		buf.WriteString(intStr)
   291  	}
   292  
   293  	return buf.Bytes()
   294  }
   295  
   296  type NumericCodec struct{}
   297  
   298  func (NumericCodec) FormatSupported(format int16) bool {
   299  	return format == TextFormatCode || format == BinaryFormatCode
   300  }
   301  
   302  func (NumericCodec) PreferredFormat() int16 {
   303  	return BinaryFormatCode
   304  }
   305  
   306  func (NumericCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
   307  	switch format {
   308  	case BinaryFormatCode:
   309  		switch value.(type) {
   310  		case NumericValuer:
   311  			return encodePlanNumericCodecBinaryNumericValuer{}
   312  		case Float64Valuer:
   313  			return encodePlanNumericCodecBinaryFloat64Valuer{}
   314  		case Int64Valuer:
   315  			return encodePlanNumericCodecBinaryInt64Valuer{}
   316  		}
   317  	case TextFormatCode:
   318  		switch value.(type) {
   319  		case NumericValuer:
   320  			return encodePlanNumericCodecTextNumericValuer{}
   321  		case Float64Valuer:
   322  			return encodePlanNumericCodecTextFloat64Valuer{}
   323  		case Int64Valuer:
   324  			return encodePlanNumericCodecTextInt64Valuer{}
   325  		}
   326  	}
   327  
   328  	return nil
   329  }
   330  
   331  type encodePlanNumericCodecBinaryNumericValuer struct{}
   332  
   333  func (encodePlanNumericCodecBinaryNumericValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   334  	n, err := value.(NumericValuer).NumericValue()
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  
   339  	return encodeNumericBinary(n, buf)
   340  }
   341  
   342  type encodePlanNumericCodecBinaryFloat64Valuer struct{}
   343  
   344  func (encodePlanNumericCodecBinaryFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   345  	n, err := value.(Float64Valuer).Float64Value()
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  
   350  	if !n.Valid {
   351  		return nil, nil
   352  	}
   353  
   354  	if math.IsNaN(n.Float64) {
   355  		return encodeNumericBinary(Numeric{NaN: true, Valid: true}, buf)
   356  	} else if math.IsInf(n.Float64, 1) {
   357  		return encodeNumericBinary(Numeric{InfinityModifier: Infinity, Valid: true}, buf)
   358  	} else if math.IsInf(n.Float64, -1) {
   359  		return encodeNumericBinary(Numeric{InfinityModifier: NegativeInfinity, Valid: true}, buf)
   360  	}
   361  	num, exp, err := parseNumericString(strconv.FormatFloat(n.Float64, 'f', -1, 64))
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  
   366  	return encodeNumericBinary(Numeric{Int: num, Exp: exp, Valid: true}, buf)
   367  }
   368  
   369  type encodePlanNumericCodecBinaryInt64Valuer struct{}
   370  
   371  func (encodePlanNumericCodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   372  	n, err := value.(Int64Valuer).Int64Value()
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  
   377  	if !n.Valid {
   378  		return nil, nil
   379  	}
   380  
   381  	return encodeNumericBinary(Numeric{Int: big.NewInt(n.Int64), Valid: true}, buf)
   382  }
   383  
   384  func encodeNumericBinary(n Numeric, buf []byte) (newBuf []byte, err error) {
   385  	if !n.Valid {
   386  		return nil, nil
   387  	}
   388  
   389  	if n.NaN {
   390  		buf = pgio.AppendUint64(buf, pgNumericNaN)
   391  		return buf, nil
   392  	} else if n.InfinityModifier == Infinity {
   393  		buf = pgio.AppendUint64(buf, pgNumericPosInf)
   394  		return buf, nil
   395  	} else if n.InfinityModifier == NegativeInfinity {
   396  		buf = pgio.AppendUint64(buf, pgNumericNegInf)
   397  		return buf, nil
   398  	}
   399  
   400  	var sign int16
   401  	if n.Int.Cmp(big0) < 0 {
   402  		sign = 16384
   403  	}
   404  
   405  	absInt := &big.Int{}
   406  	wholePart := &big.Int{}
   407  	fracPart := &big.Int{}
   408  	remainder := &big.Int{}
   409  	absInt.Abs(n.Int)
   410  
   411  	// Normalize absInt and exp to where exp is always a multiple of 4. This makes
   412  	// converting to 16-bit base 10,000 digits easier.
   413  	var exp int32
   414  	switch n.Exp % 4 {
   415  	case 1, -3:
   416  		exp = n.Exp - 1
   417  		absInt.Mul(absInt, big10)
   418  	case 2, -2:
   419  		exp = n.Exp - 2
   420  		absInt.Mul(absInt, big100)
   421  	case 3, -1:
   422  		exp = n.Exp - 3
   423  		absInt.Mul(absInt, big1000)
   424  	default:
   425  		exp = n.Exp
   426  	}
   427  
   428  	if exp < 0 {
   429  		divisor := &big.Int{}
   430  		divisor.Exp(big10, big.NewInt(int64(-exp)), nil)
   431  		wholePart.DivMod(absInt, divisor, fracPart)
   432  		fracPart.Add(fracPart, divisor)
   433  	} else {
   434  		wholePart = absInt
   435  	}
   436  
   437  	var wholeDigits, fracDigits []int16
   438  
   439  	for wholePart.Cmp(big0) != 0 {
   440  		wholePart.DivMod(wholePart, bigNBase, remainder)
   441  		wholeDigits = append(wholeDigits, int16(remainder.Int64()))
   442  	}
   443  
   444  	if fracPart.Cmp(big0) != 0 {
   445  		for fracPart.Cmp(big1) != 0 {
   446  			fracPart.DivMod(fracPart, bigNBase, remainder)
   447  			fracDigits = append(fracDigits, int16(remainder.Int64()))
   448  		}
   449  	}
   450  
   451  	buf = pgio.AppendInt16(buf, int16(len(wholeDigits)+len(fracDigits)))
   452  
   453  	var weight int16
   454  	if len(wholeDigits) > 0 {
   455  		weight = int16(len(wholeDigits) - 1)
   456  		if exp > 0 {
   457  			weight += int16(exp / 4)
   458  		}
   459  	} else {
   460  		weight = int16(exp/4) - 1 + int16(len(fracDigits))
   461  	}
   462  	buf = pgio.AppendInt16(buf, weight)
   463  
   464  	buf = pgio.AppendInt16(buf, sign)
   465  
   466  	var dscale int16
   467  	if n.Exp < 0 {
   468  		dscale = int16(-n.Exp)
   469  	}
   470  	buf = pgio.AppendInt16(buf, dscale)
   471  
   472  	for i := len(wholeDigits) - 1; i >= 0; i-- {
   473  		buf = pgio.AppendInt16(buf, wholeDigits[i])
   474  	}
   475  
   476  	for i := len(fracDigits) - 1; i >= 0; i-- {
   477  		buf = pgio.AppendInt16(buf, fracDigits[i])
   478  	}
   479  
   480  	return buf, nil
   481  }
   482  
   483  type encodePlanNumericCodecTextNumericValuer struct{}
   484  
   485  func (encodePlanNumericCodecTextNumericValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   486  	n, err := value.(NumericValuer).NumericValue()
   487  	if err != nil {
   488  		return nil, err
   489  	}
   490  
   491  	return encodeNumericText(n, buf)
   492  }
   493  
   494  type encodePlanNumericCodecTextFloat64Valuer struct{}
   495  
   496  func (encodePlanNumericCodecTextFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   497  	n, err := value.(Float64Valuer).Float64Value()
   498  	if err != nil {
   499  		return nil, err
   500  	}
   501  
   502  	if !n.Valid {
   503  		return nil, nil
   504  	}
   505  
   506  	if math.IsNaN(n.Float64) {
   507  		buf = append(buf, "NaN"...)
   508  	} else if math.IsInf(n.Float64, 1) {
   509  		buf = append(buf, "Infinity"...)
   510  	} else if math.IsInf(n.Float64, -1) {
   511  		buf = append(buf, "-Infinity"...)
   512  	} else {
   513  		buf = append(buf, strconv.FormatFloat(n.Float64, 'f', -1, 64)...)
   514  	}
   515  	return buf, nil
   516  }
   517  
   518  type encodePlanNumericCodecTextInt64Valuer struct{}
   519  
   520  func (encodePlanNumericCodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   521  	n, err := value.(Int64Valuer).Int64Value()
   522  	if err != nil {
   523  		return nil, err
   524  	}
   525  
   526  	if !n.Valid {
   527  		return nil, nil
   528  	}
   529  
   530  	buf = append(buf, strconv.FormatInt(n.Int64, 10)...)
   531  	return buf, nil
   532  }
   533  
   534  func encodeNumericText(n Numeric, buf []byte) (newBuf []byte, err error) {
   535  	if !n.Valid {
   536  		return nil, nil
   537  	}
   538  
   539  	if n.NaN {
   540  		buf = append(buf, "NaN"...)
   541  		return buf, nil
   542  	} else if n.InfinityModifier == Infinity {
   543  		buf = append(buf, "Infinity"...)
   544  		return buf, nil
   545  	} else if n.InfinityModifier == NegativeInfinity {
   546  		buf = append(buf, "-Infinity"...)
   547  		return buf, nil
   548  	}
   549  
   550  	buf = append(buf, n.numberTextBytes()...)
   551  
   552  	return buf, nil
   553  }
   554  
   555  func (NumericCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
   556  
   557  	switch format {
   558  	case BinaryFormatCode:
   559  		switch target.(type) {
   560  		case NumericScanner:
   561  			return scanPlanBinaryNumericToNumericScanner{}
   562  		case Float64Scanner:
   563  			return scanPlanBinaryNumericToFloat64Scanner{}
   564  		case Int64Scanner:
   565  			return scanPlanBinaryNumericToInt64Scanner{}
   566  		case TextScanner:
   567  			return scanPlanBinaryNumericToTextScanner{}
   568  		}
   569  	case TextFormatCode:
   570  		switch target.(type) {
   571  		case NumericScanner:
   572  			return scanPlanTextAnyToNumericScanner{}
   573  		case Float64Scanner:
   574  			return scanPlanTextAnyToFloat64Scanner{}
   575  		case Int64Scanner:
   576  			return scanPlanTextAnyToInt64Scanner{}
   577  		}
   578  	}
   579  
   580  	return nil
   581  }
   582  
   583  type scanPlanBinaryNumericToNumericScanner struct{}
   584  
   585  func (scanPlanBinaryNumericToNumericScanner) Scan(src []byte, dst any) error {
   586  	scanner := (dst).(NumericScanner)
   587  
   588  	if src == nil {
   589  		return scanner.ScanNumeric(Numeric{})
   590  	}
   591  
   592  	if len(src) < 8 {
   593  		return fmt.Errorf("numeric incomplete %v", src)
   594  	}
   595  
   596  	rp := 0
   597  	ndigits := binary.BigEndian.Uint16(src[rp:])
   598  	rp += 2
   599  	weight := int16(binary.BigEndian.Uint16(src[rp:]))
   600  	rp += 2
   601  	sign := binary.BigEndian.Uint16(src[rp:])
   602  	rp += 2
   603  	dscale := int16(binary.BigEndian.Uint16(src[rp:]))
   604  	rp += 2
   605  
   606  	if sign == pgNumericNaNSign {
   607  		return scanner.ScanNumeric(Numeric{NaN: true, Valid: true})
   608  	} else if sign == pgNumericPosInfSign {
   609  		return scanner.ScanNumeric(Numeric{InfinityModifier: Infinity, Valid: true})
   610  	} else if sign == pgNumericNegInfSign {
   611  		return scanner.ScanNumeric(Numeric{InfinityModifier: NegativeInfinity, Valid: true})
   612  	}
   613  
   614  	if ndigits == 0 {
   615  		return scanner.ScanNumeric(Numeric{Int: big.NewInt(0), Valid: true})
   616  	}
   617  
   618  	if len(src[rp:]) < int(ndigits)*2 {
   619  		return fmt.Errorf("numeric incomplete %v", src)
   620  	}
   621  
   622  	accum := &big.Int{}
   623  
   624  	for i := 0; i < int(ndigits+3)/4; i++ {
   625  		int64accum, bytesRead, digitsRead := nbaseDigitsToInt64(src[rp:])
   626  		rp += bytesRead
   627  
   628  		if i > 0 {
   629  			var mul *big.Int
   630  			switch digitsRead {
   631  			case 1:
   632  				mul = bigNBase
   633  			case 2:
   634  				mul = bigNBaseX2
   635  			case 3:
   636  				mul = bigNBaseX3
   637  			case 4:
   638  				mul = bigNBaseX4
   639  			default:
   640  				return fmt.Errorf("invalid digitsRead: %d (this can't happen)", digitsRead)
   641  			}
   642  			accum.Mul(accum, mul)
   643  		}
   644  
   645  		accum.Add(accum, big.NewInt(int64accum))
   646  	}
   647  
   648  	exp := (int32(weight) - int32(ndigits) + 1) * 4
   649  
   650  	if dscale > 0 {
   651  		fracNBaseDigits := int16(int32(ndigits) - int32(weight) - 1)
   652  		fracDecimalDigits := fracNBaseDigits * 4
   653  
   654  		if dscale > fracDecimalDigits {
   655  			multCount := int(dscale - fracDecimalDigits)
   656  			for i := 0; i < multCount; i++ {
   657  				accum.Mul(accum, big10)
   658  				exp--
   659  			}
   660  		} else if dscale < fracDecimalDigits {
   661  			divCount := int(fracDecimalDigits - dscale)
   662  			for i := 0; i < divCount; i++ {
   663  				accum.Div(accum, big10)
   664  				exp++
   665  			}
   666  		}
   667  	}
   668  
   669  	reduced := &big.Int{}
   670  	remainder := &big.Int{}
   671  	if exp >= 0 {
   672  		for {
   673  			reduced.DivMod(accum, big10, remainder)
   674  			if remainder.Cmp(big0) != 0 {
   675  				break
   676  			}
   677  			accum.Set(reduced)
   678  			exp++
   679  		}
   680  	}
   681  
   682  	if sign != 0 {
   683  		accum.Neg(accum)
   684  	}
   685  
   686  	return scanner.ScanNumeric(Numeric{Int: accum, Exp: exp, Valid: true})
   687  }
   688  
   689  type scanPlanBinaryNumericToFloat64Scanner struct{}
   690  
   691  func (scanPlanBinaryNumericToFloat64Scanner) Scan(src []byte, dst any) error {
   692  	scanner := (dst).(Float64Scanner)
   693  
   694  	if src == nil {
   695  		return scanner.ScanFloat64(Float8{})
   696  	}
   697  
   698  	var n Numeric
   699  
   700  	err := scanPlanBinaryNumericToNumericScanner{}.Scan(src, &n)
   701  	if err != nil {
   702  		return err
   703  	}
   704  
   705  	f8, err := n.Float64Value()
   706  	if err != nil {
   707  		return err
   708  	}
   709  
   710  	return scanner.ScanFloat64(f8)
   711  }
   712  
   713  type scanPlanBinaryNumericToInt64Scanner struct{}
   714  
   715  func (scanPlanBinaryNumericToInt64Scanner) Scan(src []byte, dst any) error {
   716  	scanner := (dst).(Int64Scanner)
   717  
   718  	if src == nil {
   719  		return scanner.ScanInt64(Int8{})
   720  	}
   721  
   722  	var n Numeric
   723  
   724  	err := scanPlanBinaryNumericToNumericScanner{}.Scan(src, &n)
   725  	if err != nil {
   726  		return err
   727  	}
   728  
   729  	bigInt, err := n.toBigInt()
   730  	if err != nil {
   731  		return err
   732  	}
   733  
   734  	if !bigInt.IsInt64() {
   735  		return fmt.Errorf("%v is out of range for int64", bigInt)
   736  	}
   737  
   738  	return scanner.ScanInt64(Int8{Int64: bigInt.Int64(), Valid: true})
   739  }
   740  
   741  type scanPlanBinaryNumericToTextScanner struct{}
   742  
   743  func (scanPlanBinaryNumericToTextScanner) Scan(src []byte, dst any) error {
   744  	scanner := (dst).(TextScanner)
   745  
   746  	if src == nil {
   747  		return scanner.ScanText(Text{})
   748  	}
   749  
   750  	var n Numeric
   751  
   752  	err := scanPlanBinaryNumericToNumericScanner{}.Scan(src, &n)
   753  	if err != nil {
   754  		return err
   755  	}
   756  
   757  	sbuf, err := encodeNumericText(n, nil)
   758  	if err != nil {
   759  		return err
   760  	}
   761  
   762  	return scanner.ScanText(Text{String: string(sbuf), Valid: true})
   763  }
   764  
   765  type scanPlanTextAnyToNumericScanner struct{}
   766  
   767  func (scanPlanTextAnyToNumericScanner) Scan(src []byte, dst any) error {
   768  	scanner := (dst).(NumericScanner)
   769  
   770  	if src == nil {
   771  		return scanner.ScanNumeric(Numeric{})
   772  	}
   773  
   774  	if string(src) == "NaN" {
   775  		return scanner.ScanNumeric(Numeric{NaN: true, Valid: true})
   776  	} else if string(src) == "Infinity" {
   777  		return scanner.ScanNumeric(Numeric{InfinityModifier: Infinity, Valid: true})
   778  	} else if string(src) == "-Infinity" {
   779  		return scanner.ScanNumeric(Numeric{InfinityModifier: NegativeInfinity, Valid: true})
   780  	}
   781  
   782  	num, exp, err := parseNumericString(string(src))
   783  	if err != nil {
   784  		return err
   785  	}
   786  
   787  	return scanner.ScanNumeric(Numeric{Int: num, Exp: exp, Valid: true})
   788  }
   789  
   790  func (c NumericCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
   791  	if src == nil {
   792  		return nil, nil
   793  	}
   794  
   795  	if format == TextFormatCode {
   796  		return string(src), nil
   797  	}
   798  
   799  	var n Numeric
   800  	err := codecScan(c, m, oid, format, src, &n)
   801  	if err != nil {
   802  		return nil, err
   803  	}
   804  
   805  	buf, err := m.Encode(oid, TextFormatCode, n, nil)
   806  	if err != nil {
   807  		return nil, err
   808  	}
   809  	return string(buf), nil
   810  }
   811  
   812  func (c NumericCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
   813  	if src == nil {
   814  		return nil, nil
   815  	}
   816  
   817  	var n Numeric
   818  	err := codecScan(c, m, oid, format, src, &n)
   819  	if err != nil {
   820  		return nil, err
   821  	}
   822  	return n, nil
   823  }
   824  

View as plain text