gotosocial/vendor/github.com/jackc/pgx/v5/pgtype/float8.go
dependabot[bot] 9b76afc851
[chore]: Bump github.com/jackc/pgx/v5 from 5.4.3 to 5.5.0 (#2336)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-06 14:44:53 +00:00

366 lines
7.8 KiB
Go

package pgtype
import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"fmt"
"math"
"strconv"
"github.com/jackc/pgx/v5/internal/pgio"
)
type Float64Scanner interface {
ScanFloat64(Float8) error
}
type Float64Valuer interface {
Float64Value() (Float8, error)
}
type Float8 struct {
Float64 float64
Valid bool
}
// ScanFloat64 implements the Float64Scanner interface.
func (f *Float8) ScanFloat64(n Float8) error {
*f = n
return nil
}
func (f Float8) Float64Value() (Float8, error) {
return f, nil
}
func (f *Float8) ScanInt64(n Int8) error {
*f = Float8{Float64: float64(n.Int64), Valid: n.Valid}
return nil
}
func (f Float8) Int64Value() (Int8, error) {
return Int8{Int64: int64(f.Float64), Valid: f.Valid}, nil
}
// Scan implements the database/sql Scanner interface.
func (f *Float8) Scan(src any) error {
if src == nil {
*f = Float8{}
return nil
}
switch src := src.(type) {
case float64:
*f = Float8{Float64: src, Valid: true}
return nil
case string:
n, err := strconv.ParseFloat(string(src), 64)
if err != nil {
return err
}
*f = Float8{Float64: n, Valid: true}
return nil
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (f Float8) Value() (driver.Value, error) {
if !f.Valid {
return nil, nil
}
return f.Float64, nil
}
func (f Float8) MarshalJSON() ([]byte, error) {
if !f.Valid {
return []byte("null"), nil
}
return json.Marshal(f.Float64)
}
func (f *Float8) UnmarshalJSON(b []byte) error {
var n *float64
err := json.Unmarshal(b, &n)
if err != nil {
return err
}
if n == nil {
*f = Float8{}
} else {
*f = Float8{Float64: *n, Valid: true}
}
return nil
}
type Float8Codec struct{}
func (Float8Codec) FormatSupported(format int16) bool {
return format == TextFormatCode || format == BinaryFormatCode
}
func (Float8Codec) PreferredFormat() int16 {
return BinaryFormatCode
}
func (Float8Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
switch format {
case BinaryFormatCode:
switch value.(type) {
case float64:
return encodePlanFloat8CodecBinaryFloat64{}
case Float64Valuer:
return encodePlanFloat8CodecBinaryFloat64Valuer{}
case Int64Valuer:
return encodePlanFloat8CodecBinaryInt64Valuer{}
}
case TextFormatCode:
switch value.(type) {
case float64:
return encodePlanTextFloat64{}
case Float64Valuer:
return encodePlanTextFloat64Valuer{}
case Int64Valuer:
return encodePlanTextInt64Valuer{}
}
}
return nil
}
type encodePlanFloat8CodecBinaryFloat64 struct{}
func (encodePlanFloat8CodecBinaryFloat64) Encode(value any, buf []byte) (newBuf []byte, err error) {
n := value.(float64)
return pgio.AppendUint64(buf, math.Float64bits(n)), nil
}
type encodePlanTextFloat64 struct{}
func (encodePlanTextFloat64) Encode(value any, buf []byte) (newBuf []byte, err error) {
n := value.(float64)
return append(buf, strconv.FormatFloat(n, 'f', -1, 64)...), nil
}
type encodePlanFloat8CodecBinaryFloat64Valuer struct{}
func (encodePlanFloat8CodecBinaryFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
n, err := value.(Float64Valuer).Float64Value()
if err != nil {
return nil, err
}
if !n.Valid {
return nil, nil
}
return pgio.AppendUint64(buf, math.Float64bits(n.Float64)), nil
}
type encodePlanTextFloat64Valuer struct{}
func (encodePlanTextFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
n, err := value.(Float64Valuer).Float64Value()
if err != nil {
return nil, err
}
if !n.Valid {
return nil, nil
}
return append(buf, strconv.FormatFloat(n.Float64, 'f', -1, 64)...), nil
}
type encodePlanFloat8CodecBinaryInt64Valuer struct{}
func (encodePlanFloat8CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
n, err := value.(Int64Valuer).Int64Value()
if err != nil {
return nil, err
}
if !n.Valid {
return nil, nil
}
f := float64(n.Int64)
return pgio.AppendUint64(buf, math.Float64bits(f)), nil
}
type encodePlanTextInt64Valuer struct{}
func (encodePlanTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
n, err := value.(Int64Valuer).Int64Value()
if err != nil {
return nil, err
}
if !n.Valid {
return nil, nil
}
return append(buf, strconv.FormatInt(n.Int64, 10)...), nil
}
func (Float8Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
switch format {
case BinaryFormatCode:
switch target.(type) {
case *float64:
return scanPlanBinaryFloat8ToFloat64{}
case Float64Scanner:
return scanPlanBinaryFloat8ToFloat64Scanner{}
case Int64Scanner:
return scanPlanBinaryFloat8ToInt64Scanner{}
case TextScanner:
return scanPlanBinaryFloat8ToTextScanner{}
}
case TextFormatCode:
switch target.(type) {
case *float64:
return scanPlanTextAnyToFloat64{}
case Float64Scanner:
return scanPlanTextAnyToFloat64Scanner{}
case Int64Scanner:
return scanPlanTextAnyToInt64Scanner{}
}
}
return nil
}
type scanPlanBinaryFloat8ToFloat64 struct{}
func (scanPlanBinaryFloat8ToFloat64) Scan(src []byte, dst any) error {
if src == nil {
return fmt.Errorf("cannot scan NULL into %T", dst)
}
if len(src) != 8 {
return fmt.Errorf("invalid length for float8: %v", len(src))
}
n := int64(binary.BigEndian.Uint64(src))
f := (dst).(*float64)
*f = math.Float64frombits(uint64(n))
return nil
}
type scanPlanBinaryFloat8ToFloat64Scanner struct{}
func (scanPlanBinaryFloat8ToFloat64Scanner) Scan(src []byte, dst any) error {
s := (dst).(Float64Scanner)
if src == nil {
return s.ScanFloat64(Float8{})
}
if len(src) != 8 {
return fmt.Errorf("invalid length for float8: %v", len(src))
}
n := int64(binary.BigEndian.Uint64(src))
return s.ScanFloat64(Float8{Float64: math.Float64frombits(uint64(n)), Valid: true})
}
type scanPlanBinaryFloat8ToInt64Scanner struct{}
func (scanPlanBinaryFloat8ToInt64Scanner) Scan(src []byte, dst any) error {
s := (dst).(Int64Scanner)
if src == nil {
return s.ScanInt64(Int8{})
}
if len(src) != 8 {
return fmt.Errorf("invalid length for float8: %v", len(src))
}
ui64 := int64(binary.BigEndian.Uint64(src))
f64 := math.Float64frombits(uint64(ui64))
i64 := int64(f64)
if f64 != float64(i64) {
return fmt.Errorf("cannot losslessly convert %v to int64", f64)
}
return s.ScanInt64(Int8{Int64: i64, Valid: true})
}
type scanPlanBinaryFloat8ToTextScanner struct{}
func (scanPlanBinaryFloat8ToTextScanner) Scan(src []byte, dst any) error {
s := (dst).(TextScanner)
if src == nil {
return s.ScanText(Text{})
}
if len(src) != 8 {
return fmt.Errorf("invalid length for float8: %v", len(src))
}
ui64 := int64(binary.BigEndian.Uint64(src))
f64 := math.Float64frombits(uint64(ui64))
return s.ScanText(Text{String: strconv.FormatFloat(f64, 'f', -1, 64), Valid: true})
}
type scanPlanTextAnyToFloat64 struct{}
func (scanPlanTextAnyToFloat64) Scan(src []byte, dst any) error {
if src == nil {
return fmt.Errorf("cannot scan NULL into %T", dst)
}
n, err := strconv.ParseFloat(string(src), 64)
if err != nil {
return err
}
f := (dst).(*float64)
*f = n
return nil
}
type scanPlanTextAnyToFloat64Scanner struct{}
func (scanPlanTextAnyToFloat64Scanner) Scan(src []byte, dst any) error {
s := (dst).(Float64Scanner)
if src == nil {
return s.ScanFloat64(Float8{})
}
n, err := strconv.ParseFloat(string(src), 64)
if err != nil {
return err
}
return s.ScanFloat64(Float8{Float64: n, Valid: true})
}
func (c Float8Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
return c.DecodeValue(m, oid, format, src)
}
func (c Float8Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
if src == nil {
return nil, nil
}
var n float64
err := codecScan(c, m, oid, format, src, &n)
if err != nil {
return nil, err
}
return n, nil
}