From ecd39239686d03ff57aae3152532f1bef4c51e7d Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Mon, 1 Jul 2013 16:40:53 -0500 Subject: [PATCH] Refactor prepared statement path to use ValueTranscoder --- connection.go | 43 ++++++---------------- value_transcoder.go | 89 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 93 insertions(+), 39 deletions(-) diff --git a/connection.go b/connection.go index e08ab281..9979d7ed 100644 --- a/connection.go +++ b/connection.go @@ -9,8 +9,6 @@ import ( "fmt" "io" "net" - "reflect" - "strconv" ) type ConnectionParameters struct { @@ -350,37 +348,20 @@ func (c *Connection) sendPreparedQuery(ps *PreparedStatement, arguments ...inter buf.WriteByte(0) buf.WriteString(ps.Name) buf.WriteByte(0) - binary.Write(buf, binary.BigEndian, int16(0)) - binary.Write(buf, binary.BigEndian, int16(len(arguments))) - for _, iArg := range arguments { - var s string - switch arg := iArg.(type) { - case string: - s = arg - case int16: - s = strconv.FormatInt(int64(arg), 10) - case int32: - s = strconv.FormatInt(int64(arg), 10) - case int64: - s = strconv.FormatInt(int64(arg), 10) - case float32: - s = strconv.FormatFloat(float64(arg), 'f', -1, 32) - case float64: - s = strconv.FormatFloat(arg, 'f', -1, 64) - case []byte: - s = `E'\\x` + hex.EncodeToString(arg) + `'` - default: - panic("Unable to encode type: " + reflect.TypeOf(arg).String()) + binary.Write(buf, binary.BigEndian, int16(len(ps.ParameterOids))) + for _, oid := range ps.ParameterOids { + transcoder := valueTranscoders[oid] + if transcoder == nil { + panic(fmt.Sprintf("can't encode %#v", oid)) } - binary.Write(buf, binary.BigEndian, int32(len(s))) - buf.WriteString(s) + binary.Write(buf, binary.BigEndian, transcoder.EncodeFormat) + } + + binary.Write(buf, binary.BigEndian, int16(len(arguments))) + for i, oid := range ps.ParameterOids { + transcoder := valueTranscoders[oid] + transcoder.EncodeTo(buf, arguments[i]) } - // for _, pd := range ps.ParameterOids { - // transcoder := valueTranscoders[pd] - // if transcoder == nil { - // return - // } - // } binary.Write(buf, binary.BigEndian, int16(0)) err = c.txMsg('B', buf) diff --git a/value_transcoder.go b/value_transcoder.go index ce9b3c90..94bd413b 100644 --- a/value_transcoder.go +++ b/value_transcoder.go @@ -1,15 +1,16 @@ package pgx import ( + "bytes" + "encoding/binary" "fmt" - "io" "strconv" ) type valueTranscoder struct { DecodeText func(*MessageReader, int32) interface{} DecodeBinary func(*MessageReader, int32) interface{} - EncodeTo func(io.Writer, interface{}) + EncodeTo func(*bytes.Buffer, interface{}) EncodeFormat int16 } @@ -19,22 +20,42 @@ func init() { valueTranscoders = make(map[oid]*valueTranscoder) // bool - valueTranscoders[oid(16)] = &valueTranscoder{DecodeText: decodeBoolFromText} + valueTranscoders[oid(16)] = &valueTranscoder{ + DecodeText: decodeBoolFromText, + EncodeTo: encodeBool} // int8 - valueTranscoders[oid(20)] = &valueTranscoder{DecodeText: decodeInt8FromText} + valueTranscoders[oid(20)] = &valueTranscoder{ + DecodeText: decodeInt8FromText, + EncodeTo: encodeInt8} // int2 - valueTranscoders[oid(21)] = &valueTranscoder{DecodeText: decodeInt2FromText} + valueTranscoders[oid(21)] = &valueTranscoder{ + DecodeText: decodeInt2FromText, + EncodeTo: encodeInt2} // int4 - valueTranscoders[oid(23)] = &valueTranscoder{DecodeText: decodeInt4FromText} + valueTranscoders[oid(23)] = &valueTranscoder{ + DecodeText: decodeInt4FromText, + EncodeTo: encodeInt4} + + // text + valueTranscoders[oid(25)] = &valueTranscoder{ + DecodeText: decodeTextFromText, + EncodeTo: encodeText} // float4 - valueTranscoders[oid(700)] = &valueTranscoder{DecodeText: decodeFloat4FromText} + valueTranscoders[oid(700)] = &valueTranscoder{ + DecodeText: decodeFloat4FromText, + EncodeTo: encodeFloat4} // float8 - valueTranscoders[oid(701)] = &valueTranscoder{DecodeText: decodeFloat8FromText} + valueTranscoders[oid(701)] = &valueTranscoder{ + DecodeText: decodeFloat8FromText, + EncodeTo: encodeFloat8} + + // varchar -- same as text + valueTranscoders[oid(1043)] = valueTranscoders[oid(25)] } func decodeBoolFromText(mr *MessageReader, size int32) interface{} { @@ -49,6 +70,13 @@ func decodeBoolFromText(mr *MessageReader, size int32) interface{} { } } +func encodeBool(buf *bytes.Buffer, value interface{}) { + v := value.(bool) + s := strconv.FormatBool(v) + binary.Write(buf, binary.BigEndian, int32(len(s))) + buf.WriteString(s) +} + func decodeInt8FromText(mr *MessageReader, size int32) interface{} { s := mr.ReadByteString(size) n, err := strconv.ParseInt(s, 10, 64) @@ -58,6 +86,13 @@ func decodeInt8FromText(mr *MessageReader, size int32) interface{} { return n } +func encodeInt8(buf *bytes.Buffer, value interface{}) { + v := value.(int64) + s := strconv.FormatInt(int64(v), 10) + binary.Write(buf, binary.BigEndian, int32(len(s))) + buf.WriteString(s) +} + func decodeInt2FromText(mr *MessageReader, size int32) interface{} { s := mr.ReadByteString(size) n, err := strconv.ParseInt(s, 10, 16) @@ -67,6 +102,13 @@ func decodeInt2FromText(mr *MessageReader, size int32) interface{} { return int16(n) } +func encodeInt2(buf *bytes.Buffer, value interface{}) { + v := value.(int16) + s := strconv.FormatInt(int64(v), 10) + binary.Write(buf, binary.BigEndian, int32(len(s))) + buf.WriteString(s) +} + func decodeInt4FromText(mr *MessageReader, size int32) interface{} { s := mr.ReadByteString(size) n, err := strconv.ParseInt(s, 10, 32) @@ -76,6 +118,13 @@ func decodeInt4FromText(mr *MessageReader, size int32) interface{} { return int32(n) } +func encodeInt4(buf *bytes.Buffer, value interface{}) { + v := value.(int32) + s := strconv.FormatInt(int64(v), 10) + binary.Write(buf, binary.BigEndian, int32(len(s))) + buf.WriteString(s) +} + func decodeFloat4FromText(mr *MessageReader, size int32) interface{} { s := mr.ReadByteString(size) n, err := strconv.ParseFloat(s, 32) @@ -85,6 +134,13 @@ func decodeFloat4FromText(mr *MessageReader, size int32) interface{} { return float32(n) } +func encodeFloat4(buf *bytes.Buffer, value interface{}) { + v := value.(float32) + s := strconv.FormatFloat(float64(v), 'e', -1, 32) + binary.Write(buf, binary.BigEndian, int32(len(s))) + buf.WriteString(s) +} + func decodeFloat8FromText(mr *MessageReader, size int32) interface{} { s := mr.ReadByteString(size) v, err := strconv.ParseFloat(s, 64) @@ -93,3 +149,20 @@ func decodeFloat8FromText(mr *MessageReader, size int32) interface{} { } return v } + +func encodeFloat8(buf *bytes.Buffer, value interface{}) { + v := value.(float64) + s := strconv.FormatFloat(float64(v), 'e', -1, 64) + binary.Write(buf, binary.BigEndian, int32(len(s))) + buf.WriteString(s) +} + +func decodeTextFromText(mr *MessageReader, size int32) interface{} { + return mr.ReadByteString(size) +} + +func encodeText(buf *bytes.Buffer, value interface{}) { + s := value.(string) + binary.Write(buf, binary.BigEndian, int32(len(s))) + buf.WriteString(s) +}