Add timestamp support

But not to NullTime because of text vs binary encoding difficulties.

You really should never use timestamp anyway.
scan-io
Jack Christensen 2014-07-12 09:33:49 -05:00
parent c108378973
commit ed2b3b3b49
4 changed files with 59 additions and 3 deletions

View File

@ -438,7 +438,7 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{}
switch oid {
case BoolOid, ByteaOid, Int2Oid, Int4Oid, Int8Oid, Float4Oid, Float8Oid, TimestampTzOid:
wbuf.WriteInt16(BinaryFormatCode)
case TextOid, VarcharOid, DateOid:
case TextOid, VarcharOid, DateOid, TimestampOid:
wbuf.WriteInt16(TextFormatCode)
default:
return SerializationError(fmt.Sprintf("Parameter %d oid %d is not a core type and argument type %T does not implement TextEncoder or BinaryEncoder", i, oid, arg))
@ -488,6 +488,8 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{}
err = encodeDate(wbuf, arguments[i])
case TimestampTzOid:
err = encodeTimestampTz(wbuf, arguments[i])
case TimestampOid:
err = encodeTimestamp(wbuf, arguments[i])
default:
return SerializationError(fmt.Sprintf("%T is not a core type and it does not implement TextEncoder or BinaryEncoder", arg))
}

View File

@ -199,10 +199,17 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
case *float64:
*d = decodeFloat8(rows, fd, size)
case *time.Time:
if fd.DataType == DateOid {
switch fd.DataType {
case DateOid:
*d = decodeDate(rows, fd, size)
} else {
case TimestampTzOid:
*d = decodeTimestampTz(rows, fd, size)
case TimestampOid:
*d = decodeTimestamp(rows, fd, size)
default:
err = fmt.Errorf("Can't convert OID %v to time.Time", fd.DataType)
rows.Fatal(err)
return err
}
case Scanner:
@ -254,6 +261,8 @@ func (rows *Rows) Values() ([]interface{}, error) {
values = append(values, decodeDate(rows, fd, size))
case TimestampTzOid:
values = append(values, decodeTimestampTz(rows, fd, size))
case TimestampOid:
values = append(values, decodeTimestamp(rows, fd, size))
default:
// if it is not an intrinsic type then return the text
switch fd.FormatCode {

View File

@ -387,6 +387,7 @@ func TestQueryRowCoreTypes(t *testing.T) {
{"select $1::float8", []interface{}{float64(1.23)}, []interface{}{&actual.f64}, allTypes{f64: 1.23}},
{"select $1::bool", []interface{}{true}, []interface{}{&actual.b}, allTypes{b: true}},
{"select $1::timestamptz", []interface{}{time.Unix(123, 5000)}, []interface{}{&actual.t}, allTypes{t: time.Unix(123, 5000)}},
{"select $1::timestamp", []interface{}{time.Date(2010, 1, 2, 3, 4, 5, 0, time.Local)}, []interface{}{&actual.t}, allTypes{t: time.Date(2010, 1, 2, 3, 4, 5, 0, time.Local)}},
{"select $1::date", []interface{}{time.Date(1987, 1, 2, 0, 0, 0, 0, time.Local)}, []interface{}{&actual.t}, allTypes{t: time.Date(1987, 1, 2, 0, 0, 0, 0, time.Local)}},
}

View File

@ -22,6 +22,7 @@ const (
Float8Oid = 701
VarcharOid = 1043
DateOid = 1082
TimestampOid = 1114
TimestampTzOid = 1184
)
@ -366,10 +367,15 @@ type NullTime struct {
}
func (n *NullTime) Scan(rows *Rows, fd *FieldDescription, size int32) error {
if fd.DataType != TimestampTzOid {
return SerializationError(fmt.Sprintf("NullTime.EncodeBinary cannot encode into OID %d", fd.DataType))
}
if size == -1 {
n.Time, n.Valid = time.Time{}, false
return nil
}
n.Valid = true
n.Time = decodeTimestampTz(rows, fd, size)
@ -962,3 +968,41 @@ func encodeTimestampTz(w *WriteBuf, value interface{}) error {
return nil
}
func decodeTimestamp(rows *Rows, fd *FieldDescription, size int32) time.Time {
var zeroTime time.Time
if fd.DataType != TimestampOid {
rows.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", TimestampOid, fd.DataType)))
return zeroTime
}
switch fd.FormatCode {
case TextFormatCode:
s := rows.mr.ReadString(size)
t, err := time.ParseInLocation("2006-01-02 15:04:05.999999", s, time.Local)
if err != nil {
rows.Fatal(ProtocolError(fmt.Sprintf("Can't decode timestamp: %v - %v", err, s)))
return zeroTime
}
return t
case BinaryFormatCode:
rows.Fatal(ProtocolError("Can't decode binary timestamp"))
return zeroTime
default:
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
return zeroTime
}
}
func encodeTimestamp(w *WriteBuf, value interface{}) error {
t, ok := value.(time.Time)
if !ok {
return fmt.Errorf("Expected time.Time, received %T", value)
}
s := t.Format("2006-01-02 15:04:05.999999")
return encodeText(w, s)
return nil
}