From 1516a0d8db88d11410bdb1948a11d5d533603bd1 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Fri, 31 Dec 2021 17:51:18 -0600 Subject: [PATCH] pgtype tests pass --- pgtype/int2.go | 18 ++++++++++++ pgtype/int2_codec.go | 8 ++++++ pgtype/int_scan_plans.go | 46 ++++++++++++++++++++++++++++++ pgtype/int_scan_plans.go.erb | 54 ++++++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) diff --git a/pgtype/int2.go b/pgtype/int2.go index b7b7243f..309fe6b6 100644 --- a/pgtype/int2.go +++ b/pgtype/int2.go @@ -12,6 +12,24 @@ type Int2 struct { Valid bool } +// ScanInt64 implements the Int64Scanner interface. +func (dst *Int2) ScanInt64(n int64, valid bool) error { + if !valid { + *dst = Int2{} + return nil + } + + if n < math.MinInt16 { + return fmt.Errorf("%d is greater than maximum value for Int2", n) + } + if n > math.MaxInt16 { + return fmt.Errorf("%d is greater than maximum value for Int2", n) + } + *dst = Int2{Int: int16(n), Valid: true} + + return nil +} + // Scan implements the database/sql Scanner interface. func (dst *Int2) Scan(src interface{}) error { if src == nil { diff --git a/pgtype/int2_codec.go b/pgtype/int2_codec.go index d436346c..55fd7a12 100644 --- a/pgtype/int2_codec.go +++ b/pgtype/int2_codec.go @@ -70,6 +70,8 @@ func (Int2Codec) PlanScan(ci *ConnInfo, oid uint32, format int16, target interfa return scanPlanBinaryInt2ToUint64{} case *uint: return scanPlanBinaryInt2ToUint{} + case Int64Scanner: + return scanPlanBinaryInt2ToInt64Scanner{} } case TextFormatCode: switch target.(type) { @@ -93,6 +95,8 @@ func (Int2Codec) PlanScan(ci *ConnInfo, oid uint32, format int16, target interfa return scanPlanTextAnyToUint64{} case *uint: return scanPlanTextAnyToUint{} + case Int64Scanner: + return scanPlanTextAnyToInt64Scanner{} } } @@ -132,3 +136,7 @@ func (c Int2Codec) DecodeValue(ci *ConnInfo, oid uint32, format int16, src []byt } return n, nil } + +type Int64Scanner interface { + ScanInt64(v int64, valid bool) error +} diff --git a/pgtype/int_scan_plans.go b/pgtype/int_scan_plans.go index 1694e021..13b61c4a 100644 --- a/pgtype/int_scan_plans.go +++ b/pgtype/int_scan_plans.go @@ -462,3 +462,49 @@ func (scanPlanBinaryInt2ToUint) Scan(ci *ConnInfo, oid uint32, formatCode int16, return nil } + +type scanPlanBinaryInt2ToInt64Scanner struct{} + +func (scanPlanBinaryInt2ToInt64Scanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + s, ok := (dst).(Int64Scanner) + if !ok { + return ErrScanTargetTypeChanged + } + + if src == nil { + return s.ScanInt64(0, false) + } + + if len(src) != 2 { + return fmt.Errorf("invalid length for int2: %v", len(src)) + } + + n := int64(binary.BigEndian.Uint16(src)) + + return s.ScanInt64(n, true) +} + +type scanPlanTextAnyToInt64Scanner struct{} + +func (scanPlanTextAnyToInt64Scanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + s, ok := (dst).(Int64Scanner) + if !ok { + return ErrScanTargetTypeChanged + } + + if src == nil { + return s.ScanInt64(0, false) + } + + n, err := strconv.ParseInt(string(src), 10, 64) + if err != nil { + return err + } + + err = s.ScanInt64(n, true) + if err != nil { + return err + } + + return nil +} diff --git a/pgtype/int_scan_plans.go.erb b/pgtype/int_scan_plans.go.erb index 448453f1..67bfa3f4 100644 --- a/pgtype/int_scan_plans.go.erb +++ b/pgtype/int_scan_plans.go.erb @@ -5,6 +5,7 @@ import ( "strconv" ) +<%# Any text to all integer types %> <% [ ["8", 8], ["16", 16], @@ -55,6 +56,7 @@ func (scanPlanTextAnyToUint<%= type_suffix %>) Scan(ci *ConnInfo, oid uint32, fo } <% end %> +<%# PostgreSQL binary integers to fixed size Go integers %> <% [ [16, 8], [16, 16], @@ -125,6 +127,7 @@ func (scanPlanBinaryInt<%= src_byte_size %>ToUint<%= dst_bit_size %>) Scan(ci *C } <% end %> +<%# PostgreSQL binary integers to Go machine integers %> <% [16].each do |src_bit_size| %> <% src_byte_size = src_bit_size / 8 %> type scanPlanBinaryInt<%= src_byte_size %>ToInt struct{} @@ -189,3 +192,54 @@ func (scanPlanBinaryInt<%= src_byte_size %>ToUint) Scan(ci *ConnInfo, oid uint32 return nil } <% end %> + +<%# PostgreSQL binary integers to Go Int64Scanner %> +<% [16].each do |src_bit_size| %> +<% src_byte_size = src_bit_size / 8 %> +type scanPlanBinaryInt<%= src_byte_size %>ToInt64Scanner struct{} + +func (scanPlanBinaryInt<%= src_byte_size %>ToInt64Scanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + s, ok := (dst).(Int64Scanner) + if !ok { + return ErrScanTargetTypeChanged + } + + if src == nil { + return s.ScanInt64(0, false) + } + + if len(src) != <%= src_byte_size %> { + return fmt.Errorf("invalid length for int<%= src_byte_size %>: %v", len(src)) + } + + + n := int64(binary.BigEndian.Uint<%= src_bit_size %>(src)) + + return s.ScanInt64(n, true) +} +<% end %> + +type scanPlanTextAnyToInt64Scanner struct{} + +func (scanPlanTextAnyToInt64Scanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + s, ok := (dst).(Int64Scanner) + if !ok { + return ErrScanTargetTypeChanged + } + + if src == nil { + return s.ScanInt64(0, false) + } + + n, err := strconv.ParseInt(string(src), 10, 64) + if err != nil { + return err + } + + err = s.ScanInt64(n, true) + if err != nil { + return err + } + + return nil +}