diff --git a/bench_test.go b/bench_test.go index 75da9016..80d332e5 100644 --- a/bench_test.go +++ b/bench_test.go @@ -15,6 +15,7 @@ var int8TextVsBinaryTestDataLoaded bool var float4TextVsBinaryTestDataLoaded bool var float8TextVsBinaryTestDataLoaded bool var boolTextVsBinaryTestDataLoaded bool +var timestampTzTextVsBinaryTestDataLoaded bool func createNarrowTestData(b *testing.B, conn *pgx.Connection) { if narrowTestDataLoaded { @@ -544,3 +545,60 @@ func BenchmarkBoolBinary(b *testing.B) { mustSelectRows(b, conn, "selectBool") } } + +func createTimestampTzTextVsBinaryTestData(b *testing.B, conn *pgx.Connection) { + if timestampTzTextVsBinaryTestDataLoaded { + return + } + + mustExecute(b, conn, ` + drop table if exists t; + + create temporary table t( + a timestamptz not null, + b timestamptz not null, + c timestamptz not null, + d timestamptz not null, + e timestamptz not null + ); + + insert into t(a, b, c, d, e) + select + now() - '10 years'::interval * random(), + now() - '10 years'::interval * random(), + now() - '10 years'::interval * random(), + now() - '10 years'::interval * random(), + now() - '10 years'::interval * random() + from generate_series(1, 10); + `) + + timestampTzTextVsBinaryTestDataLoaded = true +} + +func BenchmarkTimestampTzText(b *testing.B) { + conn := getSharedConnection() + createTimestampTzTextVsBinaryTestData(b, conn) + + encoders := removeBinaryEncoders() + defer func() { restoreBinaryEncoders(encoders) }() + + mustPrepare(b, conn, "selectTimestampTz", "select * from t") + defer func() { conn.Deallocate("selectTimestampTz") }() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + mustSelectRows(b, conn, "selectTimestampTz") + } +} + +func BenchmarkTimestampTzBinary(b *testing.B) { + conn := getSharedConnection() + createTimestampTzTextVsBinaryTestData(b, conn) + mustPrepare(b, conn, "selectTimestampTz", "select * from t") + defer func() { conn.Deallocate("selectTimestampTz") }() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + mustSelectRows(b, conn, "selectTimestampTz") + } +} diff --git a/value_transcoder.go b/value_transcoder.go index bf17e737..40419356 100644 --- a/value_transcoder.go +++ b/value_transcoder.go @@ -96,8 +96,9 @@ func init() { // timestamptz ValueTranscoders[Oid(1184)] = &ValueTranscoder{ - DecodeText: decodeTimestampTzFromText, - EncodeTo: encodeTimestampTz} + DecodeText: decodeTimestampTzFromText, + DecodeBinary: decodeTimestampTzFromBinary, + EncodeTo: encodeTimestampTz} // use text transcoder for anything we don't understand defaultTranscoder = ValueTranscoders[Oid(25)] @@ -299,6 +300,20 @@ func decodeTimestampTzFromText(mr *MessageReader, size int32) interface{} { return t } +func decodeTimestampTzFromBinary(mr *MessageReader, size int32) interface{} { + if size != 8 { + panic("Received an invalid size for an int8") + } + microsecFromUnixEpochToY2K := int64(946684800 * 1000000) + microsecSinceY2K := mr.ReadInt64() + microsecSinceUnixEpoch := microsecFromUnixEpochToY2K + microsecSinceY2K + return time.Unix(microsecSinceUnixEpoch/1000000, (microsecSinceUnixEpoch%1000000)*1000) + + // 2000-01-01 00:00:00 in 946684800 + // 946684800 * 1000000 + +} + func encodeTimestampTz(w *MessageWriter, value interface{}) { t := value.(time.Time) s := t.Format("2006-01-02 15:04:05.999999 -0700")