github.com/jackc/pgx/v5@v5.5.5/pgtype/numeric.go (about) 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 }