@@ -11,13 +11,32 @@ import (
1111 "time"
1212)
1313
14+ // Pre-allocated error sentinels for NULL scans (hot path optimization)
15+ var (
16+ errNullInt8 = errors .New ("cannot scan NULL into *int8" )
17+ errNullInt16 = errors .New ("cannot scan NULL into *int16" )
18+ errNullInt32 = errors .New ("cannot scan NULL into *int32" )
19+ errNullInt64 = errors .New ("cannot scan NULL into *int64" )
20+ errNullInt = errors .New ("cannot scan NULL into *int" )
21+ errNullUint8 = errors .New ("cannot scan NULL into *uint8" )
22+ errNullUint16 = errors .New ("cannot scan NULL into *uint16" )
23+ errNullUint32 = errors .New ("cannot scan NULL into *uint32" )
24+ errNullUint64 = errors .New ("cannot scan NULL into *uint64" )
25+ errNullUint = errors .New ("cannot scan NULL into *uint" )
26+ errNullFloat32 = errors .New ("cannot scan NULL into *float32" )
27+ errNullFloat64 = errors .New ("cannot scan NULL into *float64" )
28+ errNullString = errors .New ("cannot scan NULL into *string" )
29+ errNullTime = errors .New ("cannot scan NULL into *time.Time" )
30+ errNullBytes = errors .New ("cannot scan NULL into *[16]byte" )
31+ )
32+
1433type int8Wrapper int8
1534
1635func (w int8Wrapper ) SkipUnderlyingTypePlan () {}
1736
1837func (w * int8Wrapper ) ScanInt64 (v Int8 ) error {
1938 if ! v .Valid {
20- return fmt . Errorf ( "cannot scan NULL into *int8" )
39+ return errNullInt8
2140 }
2241
2342 if v .Int64 < math .MinInt8 {
@@ -41,7 +60,7 @@ func (w int16Wrapper) SkipUnderlyingTypePlan() {}
4160
4261func (w * int16Wrapper ) ScanInt64 (v Int8 ) error {
4362 if ! v .Valid {
44- return fmt . Errorf ( "cannot scan NULL into *int16" )
63+ return errNullInt16
4564 }
4665
4766 if v .Int64 < math .MinInt16 {
@@ -65,7 +84,7 @@ func (w int32Wrapper) SkipUnderlyingTypePlan() {}
6584
6685func (w * int32Wrapper ) ScanInt64 (v Int8 ) error {
6786 if ! v .Valid {
68- return fmt . Errorf ( "cannot scan NULL into *int32" )
87+ return errNullInt32
6988 }
7089
7190 if v .Int64 < math .MinInt32 {
@@ -89,7 +108,7 @@ func (w int64Wrapper) SkipUnderlyingTypePlan() {}
89108
90109func (w * int64Wrapper ) ScanInt64 (v Int8 ) error {
91110 if ! v .Valid {
92- return fmt . Errorf ( "cannot scan NULL into *int64" )
111+ return errNullInt64
93112 }
94113
95114 * w = int64Wrapper (v .Int64 )
@@ -107,7 +126,7 @@ func (w intWrapper) SkipUnderlyingTypePlan() {}
107126
108127func (w * intWrapper ) ScanInt64 (v Int8 ) error {
109128 if ! v .Valid {
110- return fmt . Errorf ( "cannot scan NULL into *int" )
129+ return errNullInt
111130 }
112131
113132 if v .Int64 < math .MinInt {
@@ -132,7 +151,7 @@ func (w uint8Wrapper) SkipUnderlyingTypePlan() {}
132151
133152func (w * uint8Wrapper ) ScanInt64 (v Int8 ) error {
134153 if ! v .Valid {
135- return fmt . Errorf ( "cannot scan NULL into *uint8" )
154+ return errNullUint8
136155 }
137156
138157 if v .Int64 < 0 {
@@ -156,7 +175,7 @@ func (w uint16Wrapper) SkipUnderlyingTypePlan() {}
156175
157176func (w * uint16Wrapper ) ScanInt64 (v Int8 ) error {
158177 if ! v .Valid {
159- return fmt . Errorf ( "cannot scan NULL into *uint16" )
178+ return errNullUint16
160179 }
161180
162181 if v .Int64 < 0 {
@@ -180,7 +199,7 @@ func (w uint32Wrapper) SkipUnderlyingTypePlan() {}
180199
181200func (w * uint32Wrapper ) ScanInt64 (v Int8 ) error {
182201 if ! v .Valid {
183- return fmt . Errorf ( "cannot scan NULL into *uint32" )
202+ return errNullUint32
184203 }
185204
186205 if v .Int64 < 0 {
@@ -204,7 +223,7 @@ func (w uint64Wrapper) SkipUnderlyingTypePlan() {}
204223
205224func (w * uint64Wrapper ) ScanInt64 (v Int8 ) error {
206225 if ! v .Valid {
207- return fmt . Errorf ( "cannot scan NULL into *uint64" )
226+ return errNullUint64
208227 }
209228
210229 if v .Int64 < 0 {
@@ -226,7 +245,7 @@ func (w uint64Wrapper) Int64Value() (Int8, error) {
226245
227246func (w * uint64Wrapper ) ScanNumeric (v Numeric ) error {
228247 if ! v .Valid {
229- return fmt . Errorf ( "cannot scan NULL into *uint64" )
248+ return errNullUint64
230249 }
231250
232251 bi , err := v .toBigInt ()
@@ -253,7 +272,7 @@ func (w uintWrapper) SkipUnderlyingTypePlan() {}
253272
254273func (w * uintWrapper ) ScanInt64 (v Int8 ) error {
255274 if ! v .Valid {
256- return fmt . Errorf ( "cannot scan NULL into *uint64" )
275+ return errNullUint
257276 }
258277
259278 if v .Int64 < 0 {
@@ -279,7 +298,7 @@ func (w uintWrapper) Int64Value() (Int8, error) {
279298
280299func (w * uintWrapper ) ScanNumeric (v Numeric ) error {
281300 if ! v .Valid {
282- return fmt . Errorf ( "cannot scan NULL into *uint" )
301+ return errNullUint
283302 }
284303
285304 bi , err := v .toBigInt ()
@@ -312,7 +331,7 @@ func (w float32Wrapper) SkipUnderlyingTypePlan() {}
312331
313332func (w * float32Wrapper ) ScanInt64 (v Int8 ) error {
314333 if ! v .Valid {
315- return fmt . Errorf ( "cannot scan NULL into *float32" )
334+ return errNullFloat32
316335 }
317336
318337 * w = float32Wrapper (v .Int64 )
@@ -330,7 +349,7 @@ func (w float32Wrapper) Int64Value() (Int8, error) {
330349
331350func (w * float32Wrapper ) ScanFloat64 (v Float8 ) error {
332351 if ! v .Valid {
333- return fmt . Errorf ( "cannot scan NULL into *float32" )
352+ return errNullFloat32
334353 }
335354
336355 * w = float32Wrapper (v .Float64 )
@@ -348,7 +367,7 @@ func (w float64Wrapper) SkipUnderlyingTypePlan() {}
348367
349368func (w * float64Wrapper ) ScanInt64 (v Int8 ) error {
350369 if ! v .Valid {
351- return fmt . Errorf ( "cannot scan NULL into *float64" )
370+ return errNullFloat64
352371 }
353372
354373 * w = float64Wrapper (v .Int64 )
@@ -366,7 +385,7 @@ func (w float64Wrapper) Int64Value() (Int8, error) {
366385
367386func (w * float64Wrapper ) ScanFloat64 (v Float8 ) error {
368387 if ! v .Valid {
369- return fmt . Errorf ( "cannot scan NULL into *float64" )
388+ return errNullFloat64
370389 }
371390
372391 * w = float64Wrapper (v .Float64 )
@@ -384,7 +403,7 @@ func (w stringWrapper) SkipUnderlyingTypePlan() {}
384403
385404func (w * stringWrapper ) ScanText (v Text ) error {
386405 if ! v .Valid {
387- return fmt . Errorf ( "cannot scan NULL into *string" )
406+ return errNullString
388407 }
389408
390409 * w = stringWrapper (v .String )
@@ -399,7 +418,7 @@ type timeWrapper time.Time
399418
400419func (w * timeWrapper ) ScanDate (v Date ) error {
401420 if ! v .Valid {
402- return fmt . Errorf ( "cannot scan NULL into *time.Time" )
421+ return errNullTime
403422 }
404423
405424 switch v .InfinityModifier {
@@ -421,7 +440,7 @@ func (w timeWrapper) DateValue() (Date, error) {
421440
422441func (w * timeWrapper ) ScanTimestamp (v Timestamp ) error {
423442 if ! v .Valid {
424- return fmt . Errorf ( "cannot scan NULL into *time.Time" )
443+ return errNullTime
425444 }
426445
427446 switch v .InfinityModifier {
@@ -443,7 +462,7 @@ func (w timeWrapper) TimestampValue() (Timestamp, error) {
443462
444463func (w * timeWrapper ) ScanTimestamptz (v Timestamptz ) error {
445464 if ! v .Valid {
446- return fmt . Errorf ( "cannot scan NULL into *time.Time" )
465+ return errNullTime
447466 }
448467
449468 switch v .InfinityModifier {
@@ -465,7 +484,7 @@ func (w timeWrapper) TimestamptzValue() (Timestamptz, error) {
465484
466485func (w * timeWrapper ) ScanTime (v Time ) error {
467486 if ! v .Valid {
468- return fmt . Errorf ( "cannot scan NULL into *time.Time" )
487+ return errNullTime
469488 }
470489
471490 // 24:00:00 is max allowed time in PostgreSQL, but time.Time will normalize that to 00:00:00 the next day.
@@ -531,7 +550,7 @@ func (w *netIPNetWrapper) ScanNetipPrefix(v netip.Prefix) error {
531550func (w netIPNetWrapper ) NetipPrefixValue () (netip.Prefix , error ) {
532551 ip , ok := netip .AddrFromSlice (w .IP )
533552 if ! ok {
534- return netip.Prefix {}, errors . New ("invalid net.IPNet" )
553+ return netip.Prefix {}, fmt . Errorf ("invalid net.IPNet" )
535554 }
536555
537556 ones , _ := w .Mask .Size ()
@@ -564,7 +583,7 @@ func (w netIPWrapper) NetipPrefixValue() (netip.Prefix, error) {
564583
565584 addr , ok := netip .AddrFromSlice ([]byte (w ))
566585 if ! ok {
567- return netip.Prefix {}, errors . New ("invalid net.IP" )
586+ return netip.Prefix {}, fmt . Errorf ("invalid net.IP" )
568587 }
569588
570589 return netip .PrefixFrom (addr , addr .BitLen ()), nil
@@ -656,7 +675,7 @@ type byte16Wrapper [16]byte
656675
657676func (w * byte16Wrapper ) ScanUUID (v UUID ) error {
658677 if ! v .Valid {
659- return fmt . Errorf ( "cannot scan NULL into *[16]byte" )
678+ return errNullBytes
660679 }
661680 * w = byte16Wrapper (v .Bytes )
662681 return nil
0 commit comments