Add binary decoding for floats

pgx-vs-pq
Jack Christensen 2013-07-11 12:42:17 -04:00
parent 01b7865abf
commit 8c7ea78485
2 changed files with 149 additions and 4 deletions

View File

@ -11,6 +11,8 @@ var narrowTestDataLoaded bool
var int2TextVsBinaryTestDataLoaded bool
var int4TextVsBinaryTestDataLoaded bool
var int8TextVsBinaryTestDataLoaded bool
var float4TextVsBinaryTestDataLoaded bool
var float8TextVsBinaryTestDataLoaded bool
func mustPrepare(b *testing.B, conn *Connection, name, sql string) {
if err := conn.Prepare(name, sql); err != nil {
@ -407,3 +409,123 @@ func BenchmarkInt8Binary(b *testing.B) {
}
}
}
func createFloat4TextVsBinaryTestData(b *testing.B, conn *Connection) {
if float4TextVsBinaryTestDataLoaded {
return
}
if _, err := conn.Execute(`
drop table if exists t;
create temporary table t(
a float4 not null,
b float4 not null,
c float4 not null,
d float4 not null,
e float4 not null
);
insert into t(a, b, c, d, e)
select
(random() * 1000000)::float4, (random() * 1000000)::float4, (random() * 1000000)::float4, (random() * 1000000)::float4, (random() * 1000000)::float4
from generate_series(1, 10);
`); err != nil {
b.Fatalf("Could not set up test data: %v", err)
}
float4TextVsBinaryTestDataLoaded = true
}
func BenchmarkFloat4Text(b *testing.B) {
conn := getSharedConnection()
createFloat4TextVsBinaryTestData(b, conn)
binaryDecoder := valueTranscoders[oid(700)].DecodeBinary
valueTranscoders[oid(700)].DecodeBinary = nil
defer func() { valueTranscoders[oid(700)].DecodeBinary = binaryDecoder }()
mustPrepare(b, conn, "selectFloat32", "select * from t")
defer func() { conn.Deallocate("selectFloat32") }()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("selectFloat32"); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkFloat4Binary(b *testing.B) {
conn := getSharedConnection()
createFloat4TextVsBinaryTestData(b, conn)
mustPrepare(b, conn, "selectFloat32", "select * from t")
defer func() { conn.Deallocate("selectFloat32") }()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("selectFloat32"); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func createFloat8TextVsBinaryTestData(b *testing.B, conn *Connection) {
if float8TextVsBinaryTestDataLoaded {
return
}
if _, err := conn.Execute(`
drop table if exists t;
create temporary table t(
a float8 not null,
b float8 not null,
c float8 not null,
d float8 not null,
e float8 not null
);
insert into t(a, b, c, d, e)
select
(random() * 1000000)::float8, (random() * 1000000)::float8, (random() * 1000000)::float8, (random() * 1000000)::float8, (random() * 1000000)::float8
from generate_series(1, 10);
`); err != nil {
b.Fatalf("Could not set up test data: %v", err)
}
float8TextVsBinaryTestDataLoaded = true
}
func BenchmarkFloat8Text(b *testing.B) {
conn := getSharedConnection()
createFloat8TextVsBinaryTestData(b, conn)
binaryDecoder := valueTranscoders[oid(701)].DecodeBinary
valueTranscoders[oid(701)].DecodeBinary = nil
defer func() { valueTranscoders[oid(701)].DecodeBinary = binaryDecoder }()
mustPrepare(b, conn, "selectFloat32", "select * from t")
defer func() { conn.Deallocate("selectFloat32") }()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("selectFloat32"); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}
func BenchmarkFloat8Binary(b *testing.B) {
conn := getSharedConnection()
createFloat8TextVsBinaryTestData(b, conn)
mustPrepare(b, conn, "selectFloat32", "select * from t")
defer func() { conn.Deallocate("selectFloat32") }()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := conn.SelectRows("selectFloat32"); err != nil {
b.Fatalf("Failure while benchmarking: %v", err)
}
}
}

View File

@ -4,6 +4,7 @@ import (
"encoding/hex"
"fmt"
"strconv"
"unsafe"
)
type valueTranscoder struct {
@ -58,13 +59,15 @@ func init() {
// float4
valueTranscoders[oid(700)] = &valueTranscoder{
DecodeText: decodeFloat4FromText,
EncodeTo: encodeFloat4}
DecodeText: decodeFloat4FromText,
DecodeBinary: decodeFloat4FromBinary,
EncodeTo: encodeFloat4}
// float8
valueTranscoders[oid(701)] = &valueTranscoder{
DecodeText: decodeFloat8FromText,
EncodeTo: encodeFloat8}
DecodeText: decodeFloat8FromText,
DecodeBinary: decodeFloat8FromBinary,
EncodeTo: encodeFloat8}
// varchar -- same as text
valueTranscoders[oid(1043)] = valueTranscoders[oid(25)]
@ -167,6 +170,16 @@ func decodeFloat4FromText(mr *MessageReader, size int32) interface{} {
return float32(n)
}
func decodeFloat4FromBinary(mr *MessageReader, size int32) interface{} {
if size != 4 {
panic("Received an invalid size for an float4")
}
i := mr.ReadInt32()
p := unsafe.Pointer(&i)
return *(*float32)(p)
}
func encodeFloat4(w *messageWriter, value interface{}) {
v := value.(float32)
s := strconv.FormatFloat(float64(v), 'e', -1, 32)
@ -183,6 +196,16 @@ func decodeFloat8FromText(mr *MessageReader, size int32) interface{} {
return v
}
func decodeFloat8FromBinary(mr *MessageReader, size int32) interface{} {
if size != 8 {
panic("Received an invalid size for an float4")
}
i := mr.ReadInt64()
p := unsafe.Pointer(&i)
return *(*float64)(p)
}
func encodeFloat8(w *messageWriter, value interface{}) {
v := value.(float64)
s := strconv.FormatFloat(float64(v), 'e', -1, 64)