...

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

View as plain text