Merge branch 'manniwood-add-char'

This commit is contained in:
Jack Christensen 2016-09-24 11:42:17 -05:00
commit 01afb57c8a
2 changed files with 87 additions and 1 deletions

View File

@ -18,6 +18,7 @@ import (
const (
BoolOid = 16
ByteaOid = 17
CharOid = 18
Int8Oid = 20
Int2Oid = 21
Int4Oid = 23
@ -89,6 +90,7 @@ func init() {
"_varchar": BinaryFormatCode,
"bool": BinaryFormatCode,
"bytea": BinaryFormatCode,
"char": BinaryFormatCode,
"cidr": BinaryFormatCode,
"date": BinaryFormatCode,
"float4": BinaryFormatCode,
@ -257,7 +259,53 @@ func (n NullString) Encode(w *WriteBuf, oid Oid) error {
return encodeString(w, oid, n.String)
}
// NullInt16 represents an smallint that may be null. NullInt16 implements the
// The pgx.Char type is for PostgreSQL's special 8-bit-only
// "char" type more akin to the C language's char type, or Go's byte type.
// (Note that the name in PostgreSQL itself is "char", in double-quotes,
// and not char.) It gets used a lot in PostgreSQL's system tables to hold
// a single ASCII character value (eg pg_class.relkind).
type Char byte
// NullChar represents a pgx.Char that may be null. NullChar implements the
// Scanner and Encoder 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 NullChar struct {
Char Char
Valid bool // Valid is true if Char is not NULL
}
func (n *NullChar) Scan(vr *ValueReader) error {
if vr.Type().DataType != CharOid {
return SerializationError(fmt.Sprintf("NullChar.Scan cannot decode OID %d", vr.Type().DataType))
}
if vr.Len() == -1 {
n.Char, n.Valid = 0, false
return nil
}
n.Valid = true
n.Char = decodeChar(vr)
return vr.Err()
}
func (n NullChar) FormatCode() int16 { return BinaryFormatCode }
func (n NullChar) Encode(w *WriteBuf, oid Oid) error {
if oid != CharOid {
return SerializationError(fmt.Sprintf("NullChar.Encode cannot encode into OID %d", oid))
}
if !n.Valid {
w.WriteInt32(-1)
return nil
}
return encodeChar(w, oid, n.Char)
}
// NullInt16 represents a smallint that may be null. NullInt16 implements the
// Scanner and Encoder interfaces so it may be used both as an argument to
// Query[Row] and a destination for Scan for prepared and unprepared queries.
//
@ -811,6 +859,8 @@ func Encode(wbuf *WriteBuf, oid Oid, arg interface{}) error {
return encodeInt(wbuf, oid, arg)
case uint:
return encodeUInt(wbuf, oid, arg)
case Char:
return encodeChar(wbuf, oid, arg)
case int8:
return encodeInt8(wbuf, oid, arg)
case uint8:
@ -987,6 +1037,8 @@ func Decode(vr *ValueReader, d interface{}) error {
return fmt.Errorf("%d is less than zero for uint64", n)
}
*v = uint64(n)
case *Char:
*v = decodeChar(vr)
case *Oid:
*v = decodeOid(vr)
case *Xid:
@ -1186,6 +1238,30 @@ func decodeInt8(vr *ValueReader) int64 {
return vr.ReadInt64()
}
func decodeChar(vr *ValueReader) Char {
if vr.Len() == -1 {
vr.Fatal(ProtocolError("Cannot decode null into char"))
return Char(0)
}
if vr.Type().DataType != CharOid {
vr.Fatal(ProtocolError(fmt.Sprintf("Cannot decode oid %v into char", vr.Type().DataType)))
return Char(0)
}
if vr.Type().FormatCode != BinaryFormatCode {
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
return Char(0)
}
if vr.Len() != 1 {
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for a char: %d", vr.Len())))
return Char(0)
}
return Char(vr.ReadByte())
}
func decodeInt2(vr *ValueReader) int16 {
if vr.Len() == -1 {
vr.Fatal(ProtocolError("Cannot decode null into int16"))
@ -1271,6 +1347,12 @@ func encodeUInt(w *WriteBuf, oid Oid, value uint) error {
return nil
}
func encodeChar(w *WriteBuf, oid Oid, value Char) error {
w.WriteInt32(1)
w.WriteByte(byte(value))
return nil
}
func encodeInt8(w *WriteBuf, oid Oid, value int8) error {
switch oid {
case Int2Oid:

View File

@ -594,6 +594,7 @@ func TestNullX(t *testing.T) {
s pgx.NullString
i16 pgx.NullInt16
i32 pgx.NullInt32
c pgx.NullChar
xid pgx.NullXid
cid pgx.NullCid
tid pgx.NullTid
@ -621,6 +622,9 @@ func TestNullX(t *testing.T) {
{"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}}},
{"select $1::\"char\"", []interface{}{pgx.NullChar{Char: 1, Valid: true}}, []interface{}{&actual.c}, allTypes{c: pgx.NullChar{Char: 1, Valid: true}}},
{"select $1::\"char\"", []interface{}{pgx.NullChar{Char: 1, Valid: false}}, []interface{}{&actual.c}, allTypes{c: pgx.NullChar{Char: 0, Valid: false}}},
{"select $1::\"char\"", []interface{}{pgx.NullChar{Char: 255, Valid: true}}, []interface{}{&actual.c}, allTypes{c: pgx.NullChar{Char: 255, Valid: true}}},
{"select $1::cid", []interface{}{pgx.NullCid{Cid: 1, Valid: true}}, []interface{}{&actual.cid}, allTypes{cid: pgx.NullCid{Cid: 1, Valid: true}}},
{"select $1::cid", []interface{}{pgx.NullCid{Cid: 1, Valid: false}}, []interface{}{&actual.cid}, allTypes{cid: pgx.NullCid{Cid: 0, Valid: false}}},
{"select $1::cid", []interface{}{pgx.NullCid{Cid: 4294967295, Valid: true}}, []interface{}{&actual.cid}, allTypes{cid: pgx.NullCid{Cid: 4294967295, Valid: true}}},