From 32a368a75bf939c2674d2889267af0312bc77d8c Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Fri, 11 Jul 2014 11:41:32 -0500 Subject: [PATCH] Add more Null* types * NullFloat32 * NullFloat64 * NullInteger16 * NullInteger32 --- values.go | 158 +++++++++++++++++++++++++++++++++++++++++++++++++ values_test.go | 12 ++++ 2 files changed, 170 insertions(+) diff --git a/values.go b/values.go index 603a7731..7de38edb 100644 --- a/values.go +++ b/values.go @@ -60,6 +60,164 @@ type BinaryEncoder interface { EncodeBinary(w *WriteBuf) error } +// NullFloat32 represents an smallint that may be null. +// NullFloat32 implements the Scanner, TextEncoder, and BinaryEncoder interfaces +// so it may be used both as an argument to Query[Row] and a destination for +// Scan for prepared and unprepared queries. +// +// If Valid is false then the value is NULL. +type NullFloat32 struct { + Float32 float32 + Valid bool // Valid is true if Float32 is not NULL +} + +func (n *NullFloat32) Scan(rows *Rows, fd *FieldDescription, size int32) error { + if size == -1 { + n.Float32, n.Valid = 0, false + return nil + } + n.Valid = true + n.Float32 = decodeFloat4(rows, fd, size) + return rows.Err() +} + +func (n *NullFloat32) EncodeText() (string, error) { + if n.Valid { + return strconv.FormatFloat(float64(n.Float32), 'f', -1, 32), nil + } else { + return "null", nil + } +} + +func (n *NullFloat32) EncodeBinary(w *WriteBuf) error { + if !n.Valid { + w.WriteInt32(-1) + return nil + } + + return encodeFloat4(w, n.Float32) +} + +// NullFloat64 represents an smallint that may be null. +// NullFloat64 implements the Scanner, TextEncoder, and BinaryEncoder interfaces +// so it may be used both as an argument to Query[Row] and a destination for +// Scan for prepared and unprepared queries. +// +// If Valid is false then the value is NULL. +type NullFloat64 struct { + Float64 float64 + Valid bool // Valid is true if Float64 is not NULL +} + +func (n *NullFloat64) Scan(rows *Rows, fd *FieldDescription, size int32) error { + if size == -1 { + n.Float64, n.Valid = 0, false + return nil + } + n.Valid = true + n.Float64 = decodeFloat8(rows, fd, size) + return rows.Err() +} + +func (n *NullFloat64) EncodeText() (string, error) { + if n.Valid { + return strconv.FormatFloat(n.Float64, 'f', -1, 64), nil + } else { + return "null", nil + } +} + +func (n *NullFloat64) EncodeBinary(w *WriteBuf) error { + if !n.Valid { + w.WriteInt32(-1) + return nil + } + + return encodeFloat8(w, n.Float64) +} + +// NullInt16 represents an smallint that may be null. +// NullInt16 implements the Scanner, TextEncoder, and BinaryEncoder interfaces +// so it may be used both as an argument to Query[Row] and a destination for +// Scan for prepared and unprepared queries. +// +// If Valid is false then the value is NULL. +type NullInt16 struct { + Int16 int16 + Valid bool // Valid is true if Int16 is not NULL +} + +func (n *NullInt16) Scan(rows *Rows, fd *FieldDescription, size int32) error { + if size == -1 { + n.Int16, n.Valid = 0, false + return nil + } + n.Valid = true + n.Int16 = decodeInt2(rows, fd, size) + return rows.Err() +} + +func (n *NullInt16) EncodeText() (string, error) { + if n.Valid { + return strconv.FormatInt(int64(n.Int16), 10), nil + } else { + return "null", nil + } +} + +func (n *NullInt16) EncodeBinary(w *WriteBuf) error { + if !n.Valid { + w.WriteInt32(-1) + return nil + } + + return encodeInt2(w, n.Int16) +} + +// NullInt32 represents an integer that may be null. +// NullInt32 implements the Scanner, TextEncoder, and BinaryEncoder interfaces +// so it may be used both as an argument to Query[Row] and a destination for +// Scan for prepared and unprepared queries. +// +// If Valid is false then the value is NULL. +type NullInt32 struct { + Int32 int32 + Valid bool // Valid is true if Int64 is not NULL +} + +func (n *NullInt32) Scan(rows *Rows, fd *FieldDescription, size int32) error { + if size == -1 { + n.Int32, n.Valid = 0, false + return nil + } + n.Valid = true + n.Int32 = decodeInt4(rows, fd, size) + return rows.Err() +} + +func (n *NullInt32) EncodeText() (string, error) { + if n.Valid { + return strconv.FormatInt(int64(n.Int32), 10), nil + } else { + return "null", nil + } +} + +func (n *NullInt32) EncodeBinary(w *WriteBuf) error { + if !n.Valid { + w.WriteInt32(-1) + return nil + } + + return encodeInt4(w, n.Int32) +} + +// NullInt64 represents an bigint that may be null. +// NullInt64 implements the Scanner, TextEncoder, and BinaryEncoder interfaces +// so it may be used both as an argument to Query[Row] and a destination for +// Scan for prepared and unprepared queries. +// +// If Valid is false then the value is NULL. type NullInt64 struct { Int64 int64 Valid bool // Valid is true if Int64 is not NULL diff --git a/values_test.go b/values_test.go index f36cef33..da009a7b 100644 --- a/values_test.go +++ b/values_test.go @@ -194,7 +194,11 @@ func TestNullX(t *testing.T) { defer closeConn(t, conn) type allTypes struct { + i16 pgx.NullInt16 + i32 pgx.NullInt32 i64 pgx.NullInt64 + f32 pgx.NullFloat32 + f64 pgx.NullFloat64 } var actual, zero allTypes @@ -205,8 +209,16 @@ func TestNullX(t *testing.T) { scanArgs []interface{} expected allTypes }{ + {"select $1::int2", []interface{}{&pgx.NullInt16{Int16: 1, Valid: true}}, []interface{}{&actual.i16}, allTypes{i16: pgx.NullInt16{Int16: 1, Valid: true}}}, + {"select $1::int2", []interface{}{&pgx.NullInt16{Int16: 1, Valid: false}}, []interface{}{&actual.i16}, allTypes{i16: pgx.NullInt16{Int16: 0, Valid: false}}}, + {"select $1::int4", []interface{}{&pgx.NullInt32{Int32: 1, Valid: true}}, []interface{}{&actual.i32}, allTypes{i32: pgx.NullInt32{Int32: 1, Valid: true}}}, + {"select $1::int4", []interface{}{&pgx.NullInt32{Int32: 1, Valid: false}}, []interface{}{&actual.i32}, allTypes{i32: pgx.NullInt32{Int32: 0, Valid: false}}}, {"select $1::int8", []interface{}{&pgx.NullInt64{Int64: 1, Valid: true}}, []interface{}{&actual.i64}, allTypes{i64: pgx.NullInt64{Int64: 1, Valid: true}}}, {"select $1::int8", []interface{}{&pgx.NullInt64{Int64: 1, Valid: false}}, []interface{}{&actual.i64}, allTypes{i64: pgx.NullInt64{Int64: 0, Valid: false}}}, + {"select $1::float4", []interface{}{&pgx.NullFloat32{Float32: 1.23, Valid: true}}, []interface{}{&actual.f32}, allTypes{f32: pgx.NullFloat32{Float32: 1.23, Valid: true}}}, + {"select $1::float4", []interface{}{&pgx.NullFloat32{Float32: 1.23, Valid: false}}, []interface{}{&actual.f32}, allTypes{f32: pgx.NullFloat32{Float32: 0, Valid: false}}}, + {"select $1::float8", []interface{}{&pgx.NullFloat64{Float64: 1.23, Valid: true}}, []interface{}{&actual.f64}, allTypes{f64: pgx.NullFloat64{Float64: 1.23, Valid: true}}}, + {"select $1::float8", []interface{}{&pgx.NullFloat64{Float64: 1.23, Valid: false}}, []interface{}{&actual.f64}, allTypes{f64: pgx.NullFloat64{Float64: 0, Valid: false}}}, } for i, tt := range tests {