mirror of https://github.com/jackc/pgx.git
Add timestamp support
But not to NullTime because of text vs binary encoding difficulties. You really should never use timestamp anyway.scan-io
parent
c108378973
commit
ed2b3b3b49
4
conn.go
4
conn.go
|
@ -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))
|
||||
}
|
||||
|
|
13
query.go
13
query.go
|
@ -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 {
|
||||
|
|
|
@ -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)}},
|
||||
}
|
||||
|
||||
|
|
44
values.go
44
values.go
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue