...

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

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

     1  package pgtype
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"encoding/binary"
     6  	"encoding/json"
     7  	"fmt"
     8  	"math"
     9  	"strconv"
    10  
    11  	"github.com/jackc/pgx/v5/internal/pgio"
    12  )
    13  
    14  type Float64Scanner interface {
    15  	ScanFloat64(Float8) error
    16  }
    17  
    18  type Float64Valuer interface {
    19  	Float64Value() (Float8, error)
    20  }
    21  
    22  type Float8 struct {
    23  	Float64 float64
    24  	Valid   bool
    25  }
    26  
    27  // ScanFloat64 implements the Float64Scanner interface.
    28  func (f *Float8) ScanFloat64(n Float8) error {
    29  	*f = n
    30  	return nil
    31  }
    32  
    33  func (f Float8) Float64Value() (Float8, error) {
    34  	return f, nil
    35  }
    36  
    37  func (f *Float8) ScanInt64(n Int8) error {
    38  	*f = Float8{Float64: float64(n.Int64), Valid: n.Valid}
    39  	return nil
    40  }
    41  
    42  func (f Float8) Int64Value() (Int8, error) {
    43  	return Int8{Int64: int64(f.Float64), Valid: f.Valid}, nil
    44  }
    45  
    46  // Scan implements the database/sql Scanner interface.
    47  func (f *Float8) Scan(src any) error {
    48  	if src == nil {
    49  		*f = Float8{}
    50  		return nil
    51  	}
    52  
    53  	switch src := src.(type) {
    54  	case float64:
    55  		*f = Float8{Float64: src, Valid: true}
    56  		return nil
    57  	case string:
    58  		n, err := strconv.ParseFloat(string(src), 64)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		*f = Float8{Float64: n, Valid: true}
    63  		return nil
    64  	}
    65  
    66  	return fmt.Errorf("cannot scan %T", src)
    67  }
    68  
    69  // Value implements the database/sql/driver Valuer interface.
    70  func (f Float8) Value() (driver.Value, error) {
    71  	if !f.Valid {
    72  		return nil, nil
    73  	}
    74  	return f.Float64, nil
    75  }
    76  
    77  func (f Float8) MarshalJSON() ([]byte, error) {
    78  	if !f.Valid {
    79  		return []byte("null"), nil
    80  	}
    81  	return json.Marshal(f.Float64)
    82  }
    83  
    84  func (f *Float8) UnmarshalJSON(b []byte) error {
    85  	var n *float64
    86  	err := json.Unmarshal(b, &n)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	if n == nil {
    92  		*f = Float8{}
    93  	} else {
    94  		*f = Float8{Float64: *n, Valid: true}
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  type Float8Codec struct{}
   101  
   102  func (Float8Codec) FormatSupported(format int16) bool {
   103  	return format == TextFormatCode || format == BinaryFormatCode
   104  }
   105  
   106  func (Float8Codec) PreferredFormat() int16 {
   107  	return BinaryFormatCode
   108  }
   109  
   110  func (Float8Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
   111  	switch format {
   112  	case BinaryFormatCode:
   113  		switch value.(type) {
   114  		case float64:
   115  			return encodePlanFloat8CodecBinaryFloat64{}
   116  		case Float64Valuer:
   117  			return encodePlanFloat8CodecBinaryFloat64Valuer{}
   118  		case Int64Valuer:
   119  			return encodePlanFloat8CodecBinaryInt64Valuer{}
   120  		}
   121  	case TextFormatCode:
   122  		switch value.(type) {
   123  		case float64:
   124  			return encodePlanTextFloat64{}
   125  		case Float64Valuer:
   126  			return encodePlanTextFloat64Valuer{}
   127  		case Int64Valuer:
   128  			return encodePlanTextInt64Valuer{}
   129  		}
   130  	}
   131  
   132  	return nil
   133  }
   134  
   135  type encodePlanFloat8CodecBinaryFloat64 struct{}
   136  
   137  func (encodePlanFloat8CodecBinaryFloat64) Encode(value any, buf []byte) (newBuf []byte, err error) {
   138  	n := value.(float64)
   139  	return pgio.AppendUint64(buf, math.Float64bits(n)), nil
   140  }
   141  
   142  type encodePlanTextFloat64 struct{}
   143  
   144  func (encodePlanTextFloat64) Encode(value any, buf []byte) (newBuf []byte, err error) {
   145  	n := value.(float64)
   146  	return append(buf, strconv.FormatFloat(n, 'f', -1, 64)...), nil
   147  }
   148  
   149  type encodePlanFloat8CodecBinaryFloat64Valuer struct{}
   150  
   151  func (encodePlanFloat8CodecBinaryFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   152  	n, err := value.(Float64Valuer).Float64Value()
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	if !n.Valid {
   158  		return nil, nil
   159  	}
   160  
   161  	return pgio.AppendUint64(buf, math.Float64bits(n.Float64)), nil
   162  }
   163  
   164  type encodePlanTextFloat64Valuer struct{}
   165  
   166  func (encodePlanTextFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   167  	n, err := value.(Float64Valuer).Float64Value()
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	if !n.Valid {
   173  		return nil, nil
   174  	}
   175  
   176  	return append(buf, strconv.FormatFloat(n.Float64, 'f', -1, 64)...), nil
   177  }
   178  
   179  type encodePlanFloat8CodecBinaryInt64Valuer struct{}
   180  
   181  func (encodePlanFloat8CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   182  	n, err := value.(Int64Valuer).Int64Value()
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	if !n.Valid {
   188  		return nil, nil
   189  	}
   190  
   191  	f := float64(n.Int64)
   192  	return pgio.AppendUint64(buf, math.Float64bits(f)), nil
   193  }
   194  
   195  type encodePlanTextInt64Valuer struct{}
   196  
   197  func (encodePlanTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
   198  	n, err := value.(Int64Valuer).Int64Value()
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  
   203  	if !n.Valid {
   204  		return nil, nil
   205  	}
   206  
   207  	return append(buf, strconv.FormatInt(n.Int64, 10)...), nil
   208  }
   209  
   210  func (Float8Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
   211  
   212  	switch format {
   213  	case BinaryFormatCode:
   214  		switch target.(type) {
   215  		case *float64:
   216  			return scanPlanBinaryFloat8ToFloat64{}
   217  		case Float64Scanner:
   218  			return scanPlanBinaryFloat8ToFloat64Scanner{}
   219  		case Int64Scanner:
   220  			return scanPlanBinaryFloat8ToInt64Scanner{}
   221  		case TextScanner:
   222  			return scanPlanBinaryFloat8ToTextScanner{}
   223  		}
   224  	case TextFormatCode:
   225  		switch target.(type) {
   226  		case *float64:
   227  			return scanPlanTextAnyToFloat64{}
   228  		case Float64Scanner:
   229  			return scanPlanTextAnyToFloat64Scanner{}
   230  		case Int64Scanner:
   231  			return scanPlanTextAnyToInt64Scanner{}
   232  		}
   233  	}
   234  
   235  	return nil
   236  }
   237  
   238  type scanPlanBinaryFloat8ToFloat64 struct{}
   239  
   240  func (scanPlanBinaryFloat8ToFloat64) Scan(src []byte, dst any) error {
   241  	if src == nil {
   242  		return fmt.Errorf("cannot scan NULL into %T", dst)
   243  	}
   244  
   245  	if len(src) != 8 {
   246  		return fmt.Errorf("invalid length for float8: %v", len(src))
   247  	}
   248  
   249  	n := int64(binary.BigEndian.Uint64(src))
   250  	f := (dst).(*float64)
   251  	*f = math.Float64frombits(uint64(n))
   252  
   253  	return nil
   254  }
   255  
   256  type scanPlanBinaryFloat8ToFloat64Scanner struct{}
   257  
   258  func (scanPlanBinaryFloat8ToFloat64Scanner) Scan(src []byte, dst any) error {
   259  	s := (dst).(Float64Scanner)
   260  
   261  	if src == nil {
   262  		return s.ScanFloat64(Float8{})
   263  	}
   264  
   265  	if len(src) != 8 {
   266  		return fmt.Errorf("invalid length for float8: %v", len(src))
   267  	}
   268  
   269  	n := int64(binary.BigEndian.Uint64(src))
   270  	return s.ScanFloat64(Float8{Float64: math.Float64frombits(uint64(n)), Valid: true})
   271  }
   272  
   273  type scanPlanBinaryFloat8ToInt64Scanner struct{}
   274  
   275  func (scanPlanBinaryFloat8ToInt64Scanner) Scan(src []byte, dst any) error {
   276  	s := (dst).(Int64Scanner)
   277  
   278  	if src == nil {
   279  		return s.ScanInt64(Int8{})
   280  	}
   281  
   282  	if len(src) != 8 {
   283  		return fmt.Errorf("invalid length for float8: %v", len(src))
   284  	}
   285  
   286  	ui64 := int64(binary.BigEndian.Uint64(src))
   287  	f64 := math.Float64frombits(uint64(ui64))
   288  	i64 := int64(f64)
   289  	if f64 != float64(i64) {
   290  		return fmt.Errorf("cannot losslessly convert %v to int64", f64)
   291  	}
   292  
   293  	return s.ScanInt64(Int8{Int64: i64, Valid: true})
   294  }
   295  
   296  type scanPlanBinaryFloat8ToTextScanner struct{}
   297  
   298  func (scanPlanBinaryFloat8ToTextScanner) Scan(src []byte, dst any) error {
   299  	s := (dst).(TextScanner)
   300  
   301  	if src == nil {
   302  		return s.ScanText(Text{})
   303  	}
   304  
   305  	if len(src) != 8 {
   306  		return fmt.Errorf("invalid length for float8: %v", len(src))
   307  	}
   308  
   309  	ui64 := int64(binary.BigEndian.Uint64(src))
   310  	f64 := math.Float64frombits(uint64(ui64))
   311  
   312  	return s.ScanText(Text{String: strconv.FormatFloat(f64, 'f', -1, 64), Valid: true})
   313  }
   314  
   315  type scanPlanTextAnyToFloat64 struct{}
   316  
   317  func (scanPlanTextAnyToFloat64) Scan(src []byte, dst any) error {
   318  	if src == nil {
   319  		return fmt.Errorf("cannot scan NULL into %T", dst)
   320  	}
   321  
   322  	n, err := strconv.ParseFloat(string(src), 64)
   323  	if err != nil {
   324  		return err
   325  	}
   326  
   327  	f := (dst).(*float64)
   328  	*f = n
   329  
   330  	return nil
   331  }
   332  
   333  type scanPlanTextAnyToFloat64Scanner struct{}
   334  
   335  func (scanPlanTextAnyToFloat64Scanner) Scan(src []byte, dst any) error {
   336  	s := (dst).(Float64Scanner)
   337  
   338  	if src == nil {
   339  		return s.ScanFloat64(Float8{})
   340  	}
   341  
   342  	n, err := strconv.ParseFloat(string(src), 64)
   343  	if err != nil {
   344  		return err
   345  	}
   346  
   347  	return s.ScanFloat64(Float8{Float64: n, Valid: true})
   348  }
   349  
   350  func (c Float8Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
   351  	return c.DecodeValue(m, oid, format, src)
   352  }
   353  
   354  func (c Float8Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
   355  	if src == nil {
   356  		return nil, nil
   357  	}
   358  
   359  	var n float64
   360  	err := codecScan(c, m, oid, format, src, &n)
   361  	if err != nil {
   362  		return nil, err
   363  	}
   364  	return n, nil
   365  }
   366  

View as plain text