diff --git a/Rakefile b/Rakefile index 70b857de..275755bd 100644 --- a/Rakefile +++ b/Rakefile @@ -7,4 +7,4 @@ rule '.go' => '.go.erb' do |task| end desc "Generate code" -task generate: ["pgtype/int_scan_plans.go"] +task generate: ["pgtype/int.go"] diff --git a/pgtype/int_scan_plans.go b/pgtype/int.go similarity index 68% rename from pgtype/int_scan_plans.go rename to pgtype/int.go index 20cde1c2..4d7dea83 100644 --- a/pgtype/int_scan_plans.go +++ b/pgtype/int.go @@ -1,221 +1,223 @@ -// Do not edit. Generated from pgtype/int_scan_plans.go.erb +// Do not edit. Generated from pgtype/int.go.erb package pgtype import ( + "database/sql/driver" "encoding/binary" "fmt" "math" "strconv" + + "github.com/jackc/pgio" ) -type scanPlanTextAnyToInt8 struct{} +type Int64Scanner interface { + ScanInt64(v int64, valid bool) error +} -func (scanPlanTextAnyToInt8) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) +type Int2 struct { + Int int16 + Valid bool +} + +// ScanInt64 implements the Int64Scanner interface. +func (dst *Int2) ScanInt64(n int64, valid bool) error { + if !valid { + *dst = Int2{} + return nil } - p, ok := (dst).(*int8) - if !ok { - return ErrScanTargetTypeChanged + if n < math.MinInt16 { + return fmt.Errorf("%d is greater than maximum value for Int2", n) } - - n, err := strconv.ParseInt(string(src), 10, 8) - if err != nil { - return err + if n > math.MaxInt16 { + return fmt.Errorf("%d is greater than maximum value for Int2", n) } + *dst = Int2{Int: int16(n), Valid: true} - *p = int8(n) return nil } -type scanPlanTextAnyToUint8 struct{} - -func (scanPlanTextAnyToUint8) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { +// Scan implements the database/sql Scanner interface. +func (dst *Int2) Scan(src interface{}) error { if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) + *dst = Int2{} + return nil } - p, ok := (dst).(*uint8) - if !ok { - return ErrScanTargetTypeChanged + var n int64 + + switch src := src.(type) { + case int64: + n = src + case string: + var err error + n, err = strconv.ParseInt(src, 10, 16) + if err != nil { + return err + } + case []byte: + var err error + n, err = strconv.ParseInt(string(src), 10, 16) + if err != nil { + return err + } + default: + return fmt.Errorf("cannot scan %T", src) } - n, err := strconv.ParseUint(string(src), 10, 8) - if err != nil { - return err + 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} - *p = uint8(n) return nil } -type scanPlanTextAnyToInt16 struct{} - -func (scanPlanTextAnyToInt16) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) +// Value implements the database/sql/driver Valuer interface. +func (src Int2) Value() (driver.Value, error) { + if !src.Valid { + return nil, nil } + return int64(src.Int), nil +} - p, ok := (dst).(*int16) - if !ok { - return ErrScanTargetTypeChanged +func (src Int2) MarshalJSON() ([]byte, error) { + if !src.Valid { + return []byte("null"), nil } + return []byte(strconv.FormatInt(int64(src.Int), 10)), nil +} - n, err := strconv.ParseInt(string(src), 10, 16) +type Int2Codec struct{} + +func (Int2Codec) FormatSupported(format int16) bool { + return format == TextFormatCode || format == BinaryFormatCode +} + +func (Int2Codec) PreferredFormat() int16 { + return BinaryFormatCode +} + +func (Int2Codec) Encode(ci *ConnInfo, oid uint32, format int16, value interface{}, buf []byte) (newBuf []byte, err error) { + n, valid, err := convertToInt64ForEncode(value) if err != nil { - return err + return nil, fmt.Errorf("cannot convert %v to int2: %v", value, err) + } + if !valid { + return nil, nil + } + + if n > math.MaxInt16 { + return nil, fmt.Errorf("%d is greater than maximum value for int2", n) + } + if n < math.MinInt16 { + return nil, fmt.Errorf("%d is less than minimum value for int2", n) + } + + switch format { + case BinaryFormatCode: + return pgio.AppendInt16(buf, int16(n)), nil + case TextFormatCode: + return append(buf, strconv.FormatInt(n, 10)...), nil + default: + return nil, fmt.Errorf("unknown format code: %v", format) + } +} + +func (Int2Codec) PlanScan(ci *ConnInfo, oid uint32, format int16, target interface{}, actualTarget bool) ScanPlan { + + switch format { + case BinaryFormatCode: + switch target.(type) { + case *int8: + return scanPlanBinaryInt2ToInt8{} + case *int16: + return scanPlanBinaryInt2ToInt16{} + case *int32: + return scanPlanBinaryInt2ToInt32{} + case *int64: + return scanPlanBinaryInt2ToInt64{} + case *int: + return scanPlanBinaryInt2ToInt{} + case *uint8: + return scanPlanBinaryInt2ToUint8{} + case *uint16: + return scanPlanBinaryInt2ToUint16{} + case *uint32: + return scanPlanBinaryInt2ToUint32{} + case *uint64: + return scanPlanBinaryInt2ToUint64{} + case *uint: + return scanPlanBinaryInt2ToUint{} + case Int64Scanner: + return scanPlanBinaryInt2ToInt64Scanner{} + } + case TextFormatCode: + switch target.(type) { + case *int8: + return scanPlanTextAnyToInt8{} + case *int16: + return scanPlanTextAnyToInt16{} + case *int32: + return scanPlanTextAnyToInt32{} + case *int64: + return scanPlanTextAnyToInt64{} + case *int: + return scanPlanTextAnyToInt{} + case *uint8: + return scanPlanTextAnyToUint8{} + case *uint16: + return scanPlanTextAnyToUint16{} + case *uint32: + return scanPlanTextAnyToUint32{} + case *uint64: + return scanPlanTextAnyToUint64{} + case *uint: + return scanPlanTextAnyToUint{} + case Int64Scanner: + return scanPlanTextAnyToInt64Scanner{} + } } - *p = int16(n) return nil } -type scanPlanTextAnyToUint16 struct{} - -func (scanPlanTextAnyToUint16) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { +func (c Int2Codec) DecodeDatabaseSQLValue(ci *ConnInfo, oid uint32, format int16, src []byte) (driver.Value, error) { if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) + return nil, nil } - p, ok := (dst).(*uint16) - if !ok { - return ErrScanTargetTypeChanged + var n int64 + scanPlan := c.PlanScan(ci, oid, format, &n, true) + if scanPlan == nil { + return nil, fmt.Errorf("PlanScan did not find a plan") } - - n, err := strconv.ParseUint(string(src), 10, 16) + err := scanPlan.Scan(ci, oid, format, src, &n) if err != nil { - return err + return nil, err } - - *p = uint16(n) - return nil + return n, nil } -type scanPlanTextAnyToInt32 struct{} - -func (scanPlanTextAnyToInt32) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { +func (c Int2Codec) DecodeValue(ci *ConnInfo, oid uint32, format int16, src []byte) (interface{}, error) { if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) + return nil, nil } - p, ok := (dst).(*int32) - if !ok { - return ErrScanTargetTypeChanged + var n int16 + scanPlan := c.PlanScan(ci, oid, format, &n, true) + if scanPlan == nil { + return nil, fmt.Errorf("PlanScan did not find a plan") } - - n, err := strconv.ParseInt(string(src), 10, 32) + err := scanPlan.Scan(ci, oid, format, src, &n) if err != nil { - return err + return nil, err } - - *p = int32(n) - return nil -} - -type scanPlanTextAnyToUint32 struct{} - -func (scanPlanTextAnyToUint32) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - p, ok := (dst).(*uint32) - if !ok { - return ErrScanTargetTypeChanged - } - - n, err := strconv.ParseUint(string(src), 10, 32) - if err != nil { - return err - } - - *p = uint32(n) - return nil -} - -type scanPlanTextAnyToInt64 struct{} - -func (scanPlanTextAnyToInt64) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - p, ok := (dst).(*int64) - if !ok { - return ErrScanTargetTypeChanged - } - - n, err := strconv.ParseInt(string(src), 10, 64) - if err != nil { - return err - } - - *p = int64(n) - return nil -} - -type scanPlanTextAnyToUint64 struct{} - -func (scanPlanTextAnyToUint64) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - p, ok := (dst).(*uint64) - if !ok { - return ErrScanTargetTypeChanged - } - - n, err := strconv.ParseUint(string(src), 10, 64) - if err != nil { - return err - } - - *p = uint64(n) - return nil -} - -type scanPlanTextAnyToInt struct{} - -func (scanPlanTextAnyToInt) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - p, ok := (dst).(*int) - if !ok { - return ErrScanTargetTypeChanged - } - - n, err := strconv.ParseInt(string(src), 10, 0) - if err != nil { - return err - } - - *p = int(n) - return nil -} - -type scanPlanTextAnyToUint struct{} - -func (scanPlanTextAnyToUint) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - p, ok := (dst).(*uint) - if !ok { - return ErrScanTargetTypeChanged - } - - n, err := strconv.ParseUint(string(src), 10, 0) - if err != nil { - return err - } - - *p = uint(n) - return nil + return n, nil } type scanPlanBinaryInt2ToInt8 struct{} @@ -485,6 +487,216 @@ func (scanPlanBinaryInt2ToInt64Scanner) Scan(ci *ConnInfo, oid uint32, formatCod return s.ScanInt64(n, true) } +type scanPlanTextAnyToInt8 struct{} + +func (scanPlanTextAnyToInt8) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*int8) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseInt(string(src), 10, 8) + if err != nil { + return err + } + + *p = int8(n) + return nil +} + +type scanPlanTextAnyToUint8 struct{} + +func (scanPlanTextAnyToUint8) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*uint8) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseUint(string(src), 10, 8) + if err != nil { + return err + } + + *p = uint8(n) + return nil +} + +type scanPlanTextAnyToInt16 struct{} + +func (scanPlanTextAnyToInt16) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*int16) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseInt(string(src), 10, 16) + if err != nil { + return err + } + + *p = int16(n) + return nil +} + +type scanPlanTextAnyToUint16 struct{} + +func (scanPlanTextAnyToUint16) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*uint16) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseUint(string(src), 10, 16) + if err != nil { + return err + } + + *p = uint16(n) + return nil +} + +type scanPlanTextAnyToInt32 struct{} + +func (scanPlanTextAnyToInt32) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*int32) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseInt(string(src), 10, 32) + if err != nil { + return err + } + + *p = int32(n) + return nil +} + +type scanPlanTextAnyToUint32 struct{} + +func (scanPlanTextAnyToUint32) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*uint32) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseUint(string(src), 10, 32) + if err != nil { + return err + } + + *p = uint32(n) + return nil +} + +type scanPlanTextAnyToInt64 struct{} + +func (scanPlanTextAnyToInt64) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*int64) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseInt(string(src), 10, 64) + if err != nil { + return err + } + + *p = int64(n) + return nil +} + +type scanPlanTextAnyToUint64 struct{} + +func (scanPlanTextAnyToUint64) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*uint64) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseUint(string(src), 10, 64) + if err != nil { + return err + } + + *p = uint64(n) + return nil +} + +type scanPlanTextAnyToInt struct{} + +func (scanPlanTextAnyToInt) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*int) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseInt(string(src), 10, 0) + if err != nil { + return err + } + + *p = int(n) + return nil +} + +type scanPlanTextAnyToUint struct{} + +func (scanPlanTextAnyToUint) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*uint) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseUint(string(src), 10, 0) + if err != nil { + return err + } + + *p = uint(n) + return nil +} + type scanPlanTextAnyToInt64Scanner struct{} func (scanPlanTextAnyToInt64Scanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { diff --git a/pgtype/int.go.erb b/pgtype/int.go.erb new file mode 100644 index 00000000..152dabed --- /dev/null +++ b/pgtype/int.go.erb @@ -0,0 +1,451 @@ +package pgtype + +import ( + "database/sql/driver" + "encoding/binary" + "fmt" + "math" + "strconv" + + "github.com/jackc/pgio" +) + +type Int64Scanner interface { + ScanInt64(v int64, valid bool) error +} + + +<% [2].each do |pg_byte_size| %> +<% pg_bit_size = pg_byte_size * 8 %> +type Int<%= pg_byte_size %> struct { + Int int<%= pg_bit_size %> + Valid bool +} + +// ScanInt64 implements the Int64Scanner interface. +func (dst *Int<%= pg_byte_size %>) ScanInt64(n int64, valid bool) error { + if !valid { + *dst = Int<%= pg_byte_size %>{} + return nil + } + + if n < math.MinInt<%= pg_bit_size %> { + return fmt.Errorf("%d is greater than maximum value for Int<%= pg_byte_size %>", n) + } + if n > math.MaxInt<%= pg_bit_size %> { + return fmt.Errorf("%d is greater than maximum value for Int<%= pg_byte_size %>", n) + } + *dst = Int<%= pg_byte_size %>{Int: int<%= pg_bit_size %>(n), Valid: true} + + return nil +} + +// Scan implements the database/sql Scanner interface. +func (dst *Int<%= pg_byte_size %>) Scan(src interface{}) error { + if src == nil { + *dst = Int<%= pg_byte_size %>{} + return nil + } + + var n int64 + + switch src := src.(type) { + case int64: + n = src + case string: + var err error + n, err = strconv.ParseInt(src, 10, <%= pg_bit_size %>) + if err != nil { + return err + } + case []byte: + var err error + n, err = strconv.ParseInt(string(src), 10, <%= pg_bit_size %>) + if err != nil { + return err + } + default: + return fmt.Errorf("cannot scan %T", src) + } + + if n < math.MinInt<%= pg_bit_size %> { + return fmt.Errorf("%d is greater than maximum value for Int<%= pg_byte_size %>", n) + } + if n > math.MaxInt<%= pg_bit_size %> { + return fmt.Errorf("%d is greater than maximum value for Int<%= pg_byte_size %>", n) + } + *dst = Int<%= pg_byte_size %>{Int: int<%= pg_bit_size %>(n), Valid: true} + + return nil +} + +// Value implements the database/sql/driver Valuer interface. +func (src Int<%= pg_byte_size %>) Value() (driver.Value, error) { + if !src.Valid { + return nil, nil + } + return int64(src.Int), nil +} + +func (src Int<%= pg_byte_size %>) MarshalJSON() ([]byte, error) { + if !src.Valid { + return []byte("null"), nil + } + return []byte(strconv.FormatInt(int64(src.Int), 10)), nil +} + +type Int<%= pg_byte_size %>Codec struct{} + +func (Int<%= pg_byte_size %>Codec) FormatSupported(format int16) bool { + return format == TextFormatCode || format == BinaryFormatCode +} + +func (Int<%= pg_byte_size %>Codec) PreferredFormat() int16 { + return BinaryFormatCode +} + +func (Int<%= pg_byte_size %>Codec) Encode(ci *ConnInfo, oid uint32, format int16, value interface{}, buf []byte) (newBuf []byte, err error) { + n, valid, err := convertToInt64ForEncode(value) + if err != nil { + return nil, fmt.Errorf("cannot convert %v to int<%= pg_byte_size %>: %v", value, err) + } + if !valid { + return nil, nil + } + + if n > math.MaxInt<%= pg_bit_size %> { + return nil, fmt.Errorf("%d is greater than maximum value for int<%= pg_byte_size %>", n) + } + if n < math.MinInt<%= pg_bit_size %> { + return nil, fmt.Errorf("%d is less than minimum value for int<%= pg_byte_size %>", n) + } + + switch format { + case BinaryFormatCode: + return pgio.AppendInt<%= pg_bit_size %>(buf, int<%= pg_bit_size %>(n)), nil + case TextFormatCode: + return append(buf, strconv.FormatInt(n, 10)...), nil + default: + return nil, fmt.Errorf("unknown format code: %v", format) + } +} + +func (Int<%= pg_byte_size %>Codec) PlanScan(ci *ConnInfo, oid uint32, format int16, target interface{}, actualTarget bool) ScanPlan { + + switch format { + case BinaryFormatCode: + switch target.(type) { + case *int8: + return scanPlanBinaryInt<%= pg_byte_size %>ToInt8{} + case *int16: + return scanPlanBinaryInt<%= pg_byte_size %>ToInt16{} + case *int32: + return scanPlanBinaryInt<%= pg_byte_size %>ToInt32{} + case *int64: + return scanPlanBinaryInt<%= pg_byte_size %>ToInt64{} + case *int: + return scanPlanBinaryInt<%= pg_byte_size %>ToInt{} + case *uint8: + return scanPlanBinaryInt<%= pg_byte_size %>ToUint8{} + case *uint16: + return scanPlanBinaryInt<%= pg_byte_size %>ToUint16{} + case *uint32: + return scanPlanBinaryInt<%= pg_byte_size %>ToUint32{} + case *uint64: + return scanPlanBinaryInt<%= pg_byte_size %>ToUint64{} + case *uint: + return scanPlanBinaryInt<%= pg_byte_size %>ToUint{} + case Int64Scanner: + return scanPlanBinaryInt<%= pg_byte_size %>ToInt64Scanner{} + } + case TextFormatCode: + switch target.(type) { + case *int8: + return scanPlanTextAnyToInt8{} + case *int16: + return scanPlanTextAnyToInt16{} + case *int32: + return scanPlanTextAnyToInt32{} + case *int64: + return scanPlanTextAnyToInt64{} + case *int: + return scanPlanTextAnyToInt{} + case *uint8: + return scanPlanTextAnyToUint8{} + case *uint16: + return scanPlanTextAnyToUint16{} + case *uint32: + return scanPlanTextAnyToUint32{} + case *uint64: + return scanPlanTextAnyToUint64{} + case *uint: + return scanPlanTextAnyToUint{} + case Int64Scanner: + return scanPlanTextAnyToInt64Scanner{} + } + } + + return nil +} + +func (c Int<%= pg_byte_size %>Codec) DecodeDatabaseSQLValue(ci *ConnInfo, oid uint32, format int16, src []byte) (driver.Value, error) { + if src == nil { + return nil, nil + } + + var n int64 + scanPlan := c.PlanScan(ci, oid, format, &n, true) + if scanPlan == nil { + return nil, fmt.Errorf("PlanScan did not find a plan") + } + err := scanPlan.Scan(ci, oid, format, src, &n) + if err != nil { + return nil, err + } + return n, nil +} + +func (c Int<%= pg_byte_size %>Codec) DecodeValue(ci *ConnInfo, oid uint32, format int16, src []byte) (interface{}, error) { + if src == nil { + return nil, nil + } + + var n int<%= pg_bit_size %> + scanPlan := c.PlanScan(ci, oid, format, &n, true) + if scanPlan == nil { + return nil, fmt.Errorf("PlanScan did not find a plan") + } + err := scanPlan.Scan(ci, oid, format, src, &n) + if err != nil { + return nil, err + } + return n, nil +} + +<%# PostgreSQL binary format integer to fixed size Go integers %> +<% [8, 16, 32, 64].each do |dst_bit_size| %> +type scanPlanBinaryInt<%= pg_byte_size %>ToInt<%= dst_bit_size %> struct{} + +func (scanPlanBinaryInt<%= pg_byte_size %>ToInt<%= dst_bit_size %>) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + if len(src) != <%= pg_byte_size %> { + return fmt.Errorf("invalid length for int<%= pg_byte_size %>: %v", len(src)) + } + + p, ok := (dst).(*int<%= dst_bit_size %>) + if !ok { + return ErrScanTargetTypeChanged + } + + <% if dst_bit_size < pg_bit_size %> + n := int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src)) + if n < math.MinInt<%= dst_bit_size %> { + return fmt.Errorf("%d is less than minimum value for int<%= dst_bit_size %>", n) + } else if n > math.MaxInt<%= dst_bit_size %> { + return fmt.Errorf("%d is greater than maximum value for int<%= dst_bit_size %>", n) + } + + *p = int<%= dst_bit_size %>(n) + <% else %> + *p = int<%= dst_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src)) + <% end %> + + return nil +} + +type scanPlanBinaryInt<%= pg_byte_size %>ToUint<%= dst_bit_size %> struct{} + +func (scanPlanBinaryInt<%= pg_byte_size %>ToUint<%= dst_bit_size %>) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + if len(src) != <%= pg_byte_size %> { + return fmt.Errorf("invalid length for uint<%= pg_byte_size %>: %v", len(src)) + } + + p, ok := (dst).(*uint<%= dst_bit_size %>) + if !ok { + return ErrScanTargetTypeChanged + } + + n := int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src)) + if n < 0 { + return fmt.Errorf("%d is less than minimum value for uint<%= dst_bit_size %>", n) + } + <% if dst_bit_size < pg_bit_size %> + if n > math.MaxUint<%= dst_bit_size %> { + return fmt.Errorf("%d is greater than maximum value for uint<%= dst_bit_size %>", n) + } + <% end %> + *p = uint<%= dst_bit_size %>(n) + + return nil +} +<% end %> + +<%# PostgreSQL binary format integer to Go machine integers %> +type scanPlanBinaryInt<%= pg_byte_size %>ToInt struct{} + +func (scanPlanBinaryInt<%= pg_byte_size %>ToInt) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + if len(src) != <%= pg_byte_size %> { + return fmt.Errorf("invalid length for int<%= pg_byte_size %>: %v", len(src)) + } + + p, ok := (dst).(*int) + if !ok { + return ErrScanTargetTypeChanged + } + + <% if 32 < pg_bit_size %> + n := int64(binary.BigEndian.Uint<%= pg_bit_size %>(src)) + if n < math.MinInt { + return fmt.Errorf("%d is less than minimum value for int", n) + } else if n > math.MaxInt { + return fmt.Errorf("%d is greater than maximum value for int", n) + } + + *p = int(n) + <% else %> + *p = int(binary.BigEndian.Uint<%= pg_bit_size %>(src)) + <% end %> + + return nil +} + +type scanPlanBinaryInt<%= pg_byte_size %>ToUint struct{} + +func (scanPlanBinaryInt<%= pg_byte_size %>ToUint) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + if len(src) != <%= pg_byte_size %> { + return fmt.Errorf("invalid length for uint<%= pg_byte_size %>: %v", len(src)) + } + + p, ok := (dst).(*uint) + if !ok { + return ErrScanTargetTypeChanged + } + + n := int64(binary.BigEndian.Uint<%= pg_bit_size %>(src)) + if n < 0 { + return fmt.Errorf("%d is less than minimum value for uint", n) + } + <% if 32 < pg_bit_size %> + if uint64(n) > math.MaxUint { + return fmt.Errorf("%d is greater than maximum value for uint", n) + } + <% end %> + *p = uint(n) + + return nil +} + +<%# PostgreSQL binary format integer to Go Int64Scanner %> +type scanPlanBinaryInt<%= pg_byte_size %>ToInt64Scanner struct{} + +func (scanPlanBinaryInt<%= pg_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) != <%= pg_byte_size %> { + return fmt.Errorf("invalid length for int<%= pg_byte_size %>: %v", len(src)) + } + + + n := int64(binary.BigEndian.Uint<%= pg_bit_size %>(src)) + + return s.ScanInt64(n, true) +} +<% end %> + +<%# Any text to all integer types %> +<% [ + ["8", 8], + ["16", 16], + ["32", 32], + ["64", 64], + ["", 0] +].each do |type_suffix, bit_size| %> +type scanPlanTextAnyToInt<%= type_suffix %> struct{} + +func (scanPlanTextAnyToInt<%= type_suffix %>) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*int<%= type_suffix %>) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseInt(string(src), 10, <%= bit_size %>) + if err != nil { + return err + } + + *p = int<%= type_suffix %>(n) + return nil +} + +type scanPlanTextAnyToUint<%= type_suffix %> struct{} + +func (scanPlanTextAnyToUint<%= type_suffix %>) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { + if src == nil { + return fmt.Errorf("cannot scan null into %T", dst) + } + + p, ok := (dst).(*uint<%= type_suffix %>) + if !ok { + return ErrScanTargetTypeChanged + } + + n, err := strconv.ParseUint(string(src), 10, <%= bit_size %>) + if err != nil { + return err + } + + *p = uint<%= type_suffix %>(n) + return nil +} +<% 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 +} diff --git a/pgtype/int2.go b/pgtype/int2.go deleted file mode 100644 index 309fe6b6..00000000 --- a/pgtype/int2.go +++ /dev/null @@ -1,85 +0,0 @@ -package pgtype - -import ( - "database/sql/driver" - "fmt" - "math" - "strconv" -) - -type Int2 struct { - Int int16 - 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 { - *dst = Int2{} - return nil - } - - var n int64 - - switch src := src.(type) { - case int64: - n = src - case string: - var err error - n, err = strconv.ParseInt(src, 10, 16) - if err != nil { - return err - } - case []byte: - var err error - n, err = strconv.ParseInt(string(src), 10, 16) - if err != nil { - return err - } - default: - return fmt.Errorf("cannot scan %T", src) - } - - 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 -} - -// Value implements the database/sql/driver Valuer interface. -func (src Int2) Value() (driver.Value, error) { - if !src.Valid { - return nil, nil - } - return int64(src.Int), nil -} - -func (src Int2) MarshalJSON() ([]byte, error) { - if !src.Valid { - return []byte("null"), nil - } - return []byte(strconv.FormatInt(int64(src.Int), 10)), nil -} diff --git a/pgtype/int2_codec.go b/pgtype/int2_codec.go deleted file mode 100644 index 55fd7a12..00000000 --- a/pgtype/int2_codec.go +++ /dev/null @@ -1,142 +0,0 @@ -package pgtype - -import ( - "database/sql/driver" - "fmt" - "math" - "strconv" - - "github.com/jackc/pgio" -) - -type Int2Codec struct{} - -func (Int2Codec) FormatSupported(format int16) bool { - return format == TextFormatCode || format == BinaryFormatCode -} - -func (Int2Codec) PreferredFormat() int16 { - return BinaryFormatCode -} - -func (Int2Codec) Encode(ci *ConnInfo, oid uint32, format int16, value interface{}, buf []byte) (newBuf []byte, err error) { - n, valid, err := convertToInt64ForEncode(value) - if err != nil { - return nil, fmt.Errorf("cannot convert %v to int2: %v", value, err) - } - if !valid { - return nil, nil - } - - if n > math.MaxInt16 { - return nil, fmt.Errorf("%d is greater than maximum value for int2", n) - } - if n < math.MinInt16 { - return nil, fmt.Errorf("%d is less than minimum value for int2", n) - } - - switch format { - case BinaryFormatCode: - return pgio.AppendInt16(buf, int16(n)), nil - case TextFormatCode: - return append(buf, strconv.FormatInt(n, 10)...), nil - default: - return nil, fmt.Errorf("unknown format code: %v", format) - } -} - -func (Int2Codec) PlanScan(ci *ConnInfo, oid uint32, format int16, target interface{}, actualTarget bool) ScanPlan { - - switch format { - case BinaryFormatCode: - switch target.(type) { - case *int8: - return scanPlanBinaryInt2ToInt8{} - case *int16: - return scanPlanBinaryInt2ToInt16{} - case *int32: - return scanPlanBinaryInt2ToInt32{} - case *int64: - return scanPlanBinaryInt2ToInt64{} - case *int: - return scanPlanBinaryInt2ToInt{} - case *uint8: - return scanPlanBinaryInt2ToUint8{} - case *uint16: - return scanPlanBinaryInt2ToUint16{} - case *uint32: - return scanPlanBinaryInt2ToUint32{} - case *uint64: - return scanPlanBinaryInt2ToUint64{} - case *uint: - return scanPlanBinaryInt2ToUint{} - case Int64Scanner: - return scanPlanBinaryInt2ToInt64Scanner{} - } - case TextFormatCode: - switch target.(type) { - case *int8: - return scanPlanTextAnyToInt8{} - case *int16: - return scanPlanTextAnyToInt16{} - case *int32: - return scanPlanTextAnyToInt32{} - case *int64: - return scanPlanTextAnyToInt64{} - case *int: - return scanPlanTextAnyToInt{} - case *uint8: - return scanPlanTextAnyToUint8{} - case *uint16: - return scanPlanTextAnyToUint16{} - case *uint32: - return scanPlanTextAnyToUint32{} - case *uint64: - return scanPlanTextAnyToUint64{} - case *uint: - return scanPlanTextAnyToUint{} - case Int64Scanner: - return scanPlanTextAnyToInt64Scanner{} - } - } - - return nil -} - -func (c Int2Codec) DecodeDatabaseSQLValue(ci *ConnInfo, oid uint32, format int16, src []byte) (driver.Value, error) { - if src == nil { - return nil, nil - } - - var n int64 - scanPlan := c.PlanScan(ci, oid, format, &n, true) - if scanPlan == nil { - return nil, fmt.Errorf("PlanScan did not find a plan") - } - err := scanPlan.Scan(ci, oid, format, src, &n) - if err != nil { - return nil, err - } - return n, nil -} - -func (c Int2Codec) DecodeValue(ci *ConnInfo, oid uint32, format int16, src []byte) (interface{}, error) { - if src == nil { - return nil, nil - } - - var n int16 - scanPlan := c.PlanScan(ci, oid, format, &n, true) - if scanPlan == nil { - return nil, fmt.Errorf("PlanScan did not find a plan") - } - err := scanPlan.Scan(ci, oid, format, src, &n) - if err != nil { - return nil, err - } - return n, nil -} - -type Int64Scanner interface { - ScanInt64(v int64, valid bool) error -} diff --git a/pgtype/int_scan_plans.go.erb b/pgtype/int_scan_plans.go.erb deleted file mode 100644 index 67bfa3f4..00000000 --- a/pgtype/int_scan_plans.go.erb +++ /dev/null @@ -1,245 +0,0 @@ -package pgtype - -import ( - "fmt" - "strconv" -) - -<%# Any text to all integer types %> -<% [ - ["8", 8], - ["16", 16], - ["32", 32], - ["64", 64], - ["", 0] -].each do |type_suffix, bit_size| %> -type scanPlanTextAnyToInt<%= type_suffix %> struct{} - -func (scanPlanTextAnyToInt<%= type_suffix %>) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - p, ok := (dst).(*int<%= type_suffix %>) - if !ok { - return ErrScanTargetTypeChanged - } - - n, err := strconv.ParseInt(string(src), 10, <%= bit_size %>) - if err != nil { - return err - } - - *p = int<%= type_suffix %>(n) - return nil -} - -type scanPlanTextAnyToUint<%= type_suffix %> struct{} - -func (scanPlanTextAnyToUint<%= type_suffix %>) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - p, ok := (dst).(*uint<%= type_suffix %>) - if !ok { - return ErrScanTargetTypeChanged - } - - n, err := strconv.ParseUint(string(src), 10, <%= bit_size %>) - if err != nil { - return err - } - - *p = uint<%= type_suffix %>(n) - return nil -} -<% end %> - -<%# PostgreSQL binary integers to fixed size Go integers %> -<% [ - [16, 8], - [16, 16], - [16, 32], - [16, 64], -].each do |src_bit_size, dst_bit_size| %> -<% src_byte_size = src_bit_size / 8 %> -type scanPlanBinaryInt<%= src_byte_size %>ToInt<%= dst_bit_size %> struct{} - -func (scanPlanBinaryInt<%= src_byte_size %>ToInt<%= dst_bit_size %>) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - if len(src) != <%= src_byte_size %> { - return fmt.Errorf("invalid length for int<%= src_byte_size %>: %v", len(src)) - } - - p, ok := (dst).(*int<%= dst_bit_size %>) - if !ok { - return ErrScanTargetTypeChanged - } - - <% if dst_bit_size < src_bit_size %> - n := int<%= src_bit_size %>(binary.BigEndian.Uint<%= src_bit_size %>(src)) - if n < math.MinInt<%= dst_bit_size %> { - return fmt.Errorf("%d is less than minimum value for int<%= dst_bit_size %>", n) - } else if n > math.MaxInt<%= dst_bit_size %> { - return fmt.Errorf("%d is greater than maximum value for int<%= dst_bit_size %>", n) - } - - *p = int<%= dst_bit_size %>(n) - <% else %> - *p = int<%= dst_bit_size %>(binary.BigEndian.Uint<%= src_bit_size %>(src)) - <% end %> - - return nil -} - -type scanPlanBinaryInt<%= src_byte_size %>ToUint<%= dst_bit_size %> struct{} - -func (scanPlanBinaryInt<%= src_byte_size %>ToUint<%= dst_bit_size %>) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - if len(src) != <%= src_byte_size %> { - return fmt.Errorf("invalid length for uint<%= src_byte_size %>: %v", len(src)) - } - - p, ok := (dst).(*uint<%= dst_bit_size %>) - if !ok { - return ErrScanTargetTypeChanged - } - - n := int<%= src_bit_size %>(binary.BigEndian.Uint<%= src_bit_size %>(src)) - if n < 0 { - return fmt.Errorf("%d is less than minimum value for uint<%= dst_bit_size %>", n) - } - <% if dst_bit_size < src_bit_size %> - if n > math.MaxUint<%= dst_bit_size %> { - return fmt.Errorf("%d is greater than maximum value for uint<%= dst_bit_size %>", n) - } - <% end %> - *p = uint<%= dst_bit_size %>(n) - - return nil -} -<% 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{} - -func (scanPlanBinaryInt<%= src_byte_size %>ToInt) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - if len(src) != <%= src_byte_size %> { - return fmt.Errorf("invalid length for int<%= src_byte_size %>: %v", len(src)) - } - - p, ok := (dst).(*int) - if !ok { - return ErrScanTargetTypeChanged - } - - <% if 32 < src_bit_size %> - n := int64(binary.BigEndian.Uint<%= src_bit_size %>(src)) - if n < math.MinInt { - return fmt.Errorf("%d is less than minimum value for int", n) - } else if n > math.MaxInt { - return fmt.Errorf("%d is greater than maximum value for int", n) - } - - *p = int(n) - <% else %> - *p = int(binary.BigEndian.Uint<%= src_bit_size %>(src)) - <% end %> - - return nil -} - -type scanPlanBinaryInt<%= src_byte_size %>ToUint struct{} - -func (scanPlanBinaryInt<%= src_byte_size %>ToUint) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { - if src == nil { - return fmt.Errorf("cannot scan null into %T", dst) - } - - if len(src) != <%= src_byte_size %> { - return fmt.Errorf("invalid length for uint<%= src_byte_size %>: %v", len(src)) - } - - p, ok := (dst).(*uint) - if !ok { - return ErrScanTargetTypeChanged - } - - n := int64(binary.BigEndian.Uint<%= src_bit_size %>(src)) - if n < 0 { - return fmt.Errorf("%d is less than minimum value for uint", n) - } - <% if 32 < src_bit_size %> - if uint64(n) > math.MaxUint { - return fmt.Errorf("%d is greater than maximum value for uint", n) - } - <% end %> - *p = uint(n) - - 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 -}