Adds NullOid type

Oids are rarely null, but they can be: on the right hand
side of a left join, for instance.

This commit takes moves the Oid type def from
messages.go to values.go, so it can live along side the
other types. It removes the special case for testing Oid
and now leverages the TestNullX test instead.
pull/188/head
Manni Wood 2016-09-20 21:11:30 -04:00
parent 256cbf0010
commit cc1ad69c32
3 changed files with 52 additions and 42 deletions

View File

@ -53,12 +53,6 @@ func (s *startupMessage) Bytes() (buf []byte) {
return buf
}
// Oid (Object Identifier Type) is, according to https://www.postgresql.org/docs/current/static/datatype-oid.html,
// used internally by PostgreSQL as a primary key for various system tables. It is currently implemented
// as an unsigned four-byte integer. Its definition can be found in src/include/postgres_ext.h
// in the PostgreSQL sources.
type Oid uint32
type FieldDescription struct {
Name string
Table Oid

View File

@ -383,6 +383,51 @@ func (n NullInt32) Encode(w *WriteBuf, oid Oid) error {
return encodeInt32(w, oid, n.Int32)
}
// Oid (Object Identifier Type) is, according to https://www.postgresql.org/docs/current/static/datatype-oid.html,
// used internally by PostgreSQL as a primary key for various system tables. It is currently implemented
// as an unsigned four-byte integer. Its definition can be found in src/include/postgres_ext.h
// in the PostgreSQL sources.
type Oid uint32
// NullOid represents a Command Identifier (Oid) that may be null. NullOid implements the
// Scanner and Encoder interfaces so it may be used both as an argument to
// Query[Row] and a destination for Scan.
//
// If Valid is false then the value is NULL.
type NullOid struct {
Oid Oid
Valid bool // Valid is true if Oid is not NULL
}
func (n *NullOid) Scan(vr *ValueReader) error {
if vr.Type().DataType != OidOid {
return SerializationError(fmt.Sprintf("NullOid.Scan cannot decode OID %d", vr.Type().DataType))
}
if vr.Len() == -1 {
n.Oid, n.Valid = 0, false
return nil
}
n.Valid = true
n.Oid = decodeOid(vr)
return vr.Err()
}
func (n NullOid) FormatCode() int16 { return BinaryFormatCode }
func (n NullOid) Encode(w *WriteBuf, oid Oid) error {
if oid != OidOid {
return SerializationError(fmt.Sprintf("NullOid.Encode cannot encode into OID %d", oid))
}
if !n.Valid {
w.WriteInt32(-1)
return nil
}
return encodeOid(w, oid, n.Oid)
}
// Xid is PostgreSQL's Transaction ID type.
//
// In later versions of PostgreSQL, it is the type used for the backend_xid
@ -406,7 +451,7 @@ type Xid uint32
// If Valid is false then the value is NULL.
type NullXid struct {
Xid Xid
Valid bool // Valid is true if Int32 is not NULL
Valid bool // Valid is true if Xid is not NULL
}
func (n *NullXid) Scan(vr *ValueReader) error {
@ -458,7 +503,7 @@ type Cid uint32
// If Valid is false then the value is NULL.
type NullCid struct {
Cid Cid
Valid bool // Valid is true if Int32 is not NULL
Valid bool // Valid is true if Cid is not NULL
}
func (n *NullCid) Scan(vr *ValueReader) error {
@ -513,7 +558,7 @@ type Tid struct {
// If Valid is false then the value is NULL.
type NullTid struct {
Tid Tid
Valid bool // Valid is true if Int32 is not NULL
Valid bool // Valid is true if Tid is not NULL
}
func (n *NullTid) Scan(vr *ValueReader) error {

View File

@ -551,39 +551,6 @@ func TestInetCidrTranscodeWithJustIP(t *testing.T) {
}
}
func TestOid(t *testing.T) {
t.Parallel()
conn := mustConnect(t, *defaultConnConfig)
defer closeConn(t, conn)
tests := []struct {
sql string
value pgx.Oid
}{
{"select $1::oid", 0},
{"select $1::oid", 1},
{"select $1::oid", 4294967295},
}
for i, tt := range tests {
expected := tt.value
var actual pgx.Oid
err := conn.QueryRow(tt.sql, expected).Scan(&actual)
if err != nil {
t.Errorf("%d. Unexpected failure: %v (sql -> %v, value -> %v)", i, err, tt.sql, expected)
continue
}
if actual != expected {
t.Errorf("%d. Expected %v, got %v (sql -> %v)", i, expected, actual, tt.sql)
}
ensureConnValid(t, conn)
}
}
func TestNullX(t *testing.T) {
t.Parallel()
@ -595,6 +562,7 @@ func TestNullX(t *testing.T) {
i16 pgx.NullInt16
i32 pgx.NullInt32
c pgx.NullChar
oid pgx.NullOid
xid pgx.NullXid
cid pgx.NullCid
tid pgx.NullTid
@ -619,6 +587,9 @@ func TestNullX(t *testing.T) {
{"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::oid", []interface{}{pgx.NullOid{Oid: 1, Valid: true}}, []interface{}{&actual.oid}, allTypes{oid: pgx.NullOid{Oid: 1, Valid: true}}},
{"select $1::oid", []interface{}{pgx.NullOid{Oid: 1, Valid: false}}, []interface{}{&actual.oid}, allTypes{oid: pgx.NullOid{Oid: 0, Valid: false}}},
{"select $1::oid", []interface{}{pgx.NullOid{Oid: 4294967295, Valid: true}}, []interface{}{&actual.oid}, allTypes{oid: pgx.NullOid{Oid: 4294967295, Valid: true}}},
{"select $1::xid", []interface{}{pgx.NullXid{Xid: 1, Valid: true}}, []interface{}{&actual.xid}, allTypes{xid: pgx.NullXid{Xid: 1, Valid: true}}},
{"select $1::xid", []interface{}{pgx.NullXid{Xid: 1, Valid: false}}, []interface{}{&actual.xid}, allTypes{xid: pgx.NullXid{Xid: 0, Valid: false}}},
{"select $1::xid", []interface{}{pgx.NullXid{Xid: 4294967295, Valid: true}}, []interface{}{&actual.xid}, allTypes{xid: pgx.NullXid{Xid: 4294967295, Valid: true}}},