diff --git a/messages.go b/messages.go index 8eb4b8ef..317ba273 100644 --- a/messages.go +++ b/messages.go @@ -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 diff --git a/values.go b/values.go index f8991f88..545f1031 100644 --- a/values.go +++ b/values.go @@ -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 { diff --git a/values_test.go b/values_test.go index 10ef5de4..7de4e0c2 100644 --- a/values_test.go +++ b/values_test.go @@ -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}}},