diff --git a/authentication.go b/authentication.go index 54f4978f..c04ee448 100644 --- a/authentication.go +++ b/authentication.go @@ -1,9 +1,10 @@ package pgproto3 import ( - "bytes" "encoding/binary" "fmt" + + "github.com/jackc/pgx/pgio" ) const ( @@ -36,19 +37,18 @@ func (dst *Authentication) Decode(src []byte) error { return nil } -func (src *Authentication) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - buf.WriteByte('R') - buf.Write(bigEndian.Uint32(0)) - buf.Write(bigEndian.Uint32(src.Type)) +func (src *Authentication) Encode(dst []byte) []byte { + dst = append(dst, 'R') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) + dst = pgio.AppendUint32(dst, src.Type) switch src.Type { case AuthTypeMD5Password: - buf.Write(src.Salt[:]) + dst = append(dst, src.Salt[:]...) } - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - return buf.Bytes(), nil + return dst } diff --git a/backend.go b/backend.go index df66a799..bf96ba95 100644 --- a/backend.go +++ b/backend.go @@ -32,12 +32,7 @@ func NewBackend(r io.Reader, w io.Writer) (*Backend, error) { } func (b *Backend) Send(msg BackendMessage) error { - buf, err := msg.MarshalBinary() - if err != nil { - return nil - } - - _, err = b.w.Write(buf) + _, err := b.w.Write(msg.Encode(nil)) return err } diff --git a/backend_key_data.go b/backend_key_data.go index 04f31aec..5a478f10 100644 --- a/backend_key_data.go +++ b/backend_key_data.go @@ -1,9 +1,10 @@ package pgproto3 import ( - "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type BackendKeyData struct { @@ -24,14 +25,12 @@ func (dst *BackendKeyData) Decode(src []byte) error { return nil } -func (src *BackendKeyData) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - buf.WriteByte('K') - buf.Write(bigEndian.Uint32(12)) - buf.Write(bigEndian.Uint32(src.ProcessID)) - buf.Write(bigEndian.Uint32(src.SecretKey)) - return buf.Bytes(), nil +func (src *BackendKeyData) Encode(dst []byte) []byte { + dst = append(dst, 'K') + dst = pgio.AppendUint32(dst, 12) + dst = pgio.AppendUint32(dst, src.ProcessID) + dst = pgio.AppendUint32(dst, src.SecretKey) + return dst } func (src *BackendKeyData) MarshalJSON() ([]byte, error) { diff --git a/bind.go b/bind.go index 79fb4503..cceee6ab 100644 --- a/bind.go +++ b/bind.go @@ -5,6 +5,8 @@ import ( "encoding/binary" "encoding/hex" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type Bind struct { @@ -101,45 +103,40 @@ func (dst *Bind) Decode(src []byte) error { return nil } -func (src *Bind) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} +func (src *Bind) Encode(dst []byte) []byte { + dst = append(dst, 'B') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) - buf.WriteByte('B') - buf.Write(bigEndian.Uint32(0)) - - buf.WriteString(src.DestinationPortal) - buf.WriteByte(0) - buf.WriteString(src.PreparedStatement) - buf.WriteByte(0) - - buf.Write(bigEndian.Uint16(uint16(len(src.ParameterFormatCodes)))) + dst = append(dst, src.DestinationPortal...) + dst = append(dst, 0) + dst = append(dst, src.PreparedStatement...) + dst = append(dst, 0) + dst = pgio.AppendUint16(dst, uint16(len(src.ParameterFormatCodes))) for _, fc := range src.ParameterFormatCodes { - buf.Write(bigEndian.Int16(fc)) + dst = pgio.AppendInt16(dst, fc) } - buf.Write(bigEndian.Uint16(uint16(len(src.Parameters)))) - + dst = pgio.AppendUint16(dst, uint16(len(src.Parameters))) for _, p := range src.Parameters { if p == nil { - buf.Write(bigEndian.Int32(-1)) + dst = pgio.AppendInt32(dst, -1) continue } - buf.Write(bigEndian.Int32(int32(len(p)))) - buf.Write(p) + dst = pgio.AppendInt32(dst, int32(len(p))) + dst = append(dst, p...) } - buf.Write(bigEndian.Uint16(uint16(len(src.ResultFormatCodes)))) - + dst = pgio.AppendUint16(dst, uint16(len(src.ResultFormatCodes))) for _, fc := range src.ResultFormatCodes { - buf.Write(bigEndian.Int16(fc)) + dst = pgio.AppendInt16(dst, fc) } - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - return buf.Bytes(), nil + return dst } func (src *Bind) MarshalJSON() ([]byte, error) { diff --git a/bind_complete.go b/bind_complete.go index 4f1c44b8..60360519 100644 --- a/bind_complete.go +++ b/bind_complete.go @@ -16,8 +16,8 @@ func (dst *BindComplete) Decode(src []byte) error { return nil } -func (src *BindComplete) MarshalBinary() ([]byte, error) { - return []byte{'2', 0, 0, 0, 4}, nil +func (src *BindComplete) Encode(dst []byte) []byte { + return append(dst, '2', 0, 0, 0, 4) } func (src *BindComplete) MarshalJSON() ([]byte, error) { diff --git a/close.go b/close.go index 454ef68e..5ff4c886 100644 --- a/close.go +++ b/close.go @@ -2,8 +2,9 @@ package pgproto3 import ( "bytes" - "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type Close struct { @@ -31,20 +32,18 @@ func (dst *Close) Decode(src []byte) error { return nil } -func (src *Close) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} +func (src *Close) Encode(dst []byte) []byte { + dst = append(dst, 'C') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) - buf.WriteByte('C') - buf.Write(bigEndian.Uint32(0)) + dst = append(dst, src.ObjectType) + dst = append(dst, src.Name...) + dst = append(dst, 0) - buf.WriteByte(src.ObjectType) - buf.WriteString(src.Name) - buf.WriteByte(0) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) - - return buf.Bytes(), nil + return dst } func (src *Close) MarshalJSON() ([]byte, error) { diff --git a/close_complete.go b/close_complete.go index 9bab3e8c..db793c94 100644 --- a/close_complete.go +++ b/close_complete.go @@ -16,8 +16,8 @@ func (dst *CloseComplete) Decode(src []byte) error { return nil } -func (src *CloseComplete) MarshalBinary() ([]byte, error) { - return []byte{'3', 0, 0, 0, 4}, nil +func (src *CloseComplete) Encode(dst []byte) []byte { + return append(dst, '3', 0, 0, 0, 4) } func (src *CloseComplete) MarshalJSON() ([]byte, error) { diff --git a/command_complete.go b/command_complete.go index 86653804..85848532 100644 --- a/command_complete.go +++ b/command_complete.go @@ -3,6 +3,8 @@ package pgproto3 import ( "bytes" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type CommandComplete struct { @@ -22,17 +24,17 @@ func (dst *CommandComplete) Decode(src []byte) error { return nil } -func (src *CommandComplete) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} +func (src *CommandComplete) Encode(dst []byte) []byte { + dst = append(dst, 'C') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) - buf.WriteByte('C') - buf.Write(bigEndian.Uint32(uint32(4 + len(src.CommandTag) + 1))) + dst = append(dst, src.CommandTag...) + dst = append(dst, 0) - buf.WriteString(src.CommandTag) - buf.WriteByte(0) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - return buf.Bytes(), nil + return dst } func (src *CommandComplete) MarshalJSON() ([]byte, error) { diff --git a/copy_both_response.go b/copy_both_response.go index 3857c187..2862a34f 100644 --- a/copy_both_response.go +++ b/copy_both_response.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type CopyBothResponse struct { @@ -37,20 +39,19 @@ func (dst *CopyBothResponse) Decode(src []byte) error { return nil } -func (src *CopyBothResponse) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - - buf.WriteByte('W') - buf.Write(bigEndian.Uint32(uint32(4 + 1 + 2 + 2*len(src.ColumnFormatCodes)))) - - buf.Write(bigEndian.Uint16(uint16(len(src.ColumnFormatCodes)))) +func (src *CopyBothResponse) Encode(dst []byte) []byte { + dst = append(dst, 'W') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) + dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes))) for _, fc := range src.ColumnFormatCodes { - buf.Write(bigEndian.Uint16(fc)) + dst = pgio.AppendUint16(dst, fc) } - return buf.Bytes(), nil + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) + + return dst } func (src *CopyBothResponse) MarshalJSON() ([]byte, error) { diff --git a/copy_data.go b/copy_data.go index de7ab4ff..fab139e6 100644 --- a/copy_data.go +++ b/copy_data.go @@ -1,9 +1,10 @@ package pgproto3 import ( - "bytes" "encoding/hex" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type CopyData struct { @@ -18,15 +19,11 @@ func (dst *CopyData) Decode(src []byte) error { return nil } -func (src *CopyData) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - - buf.WriteByte('d') - buf.Write(bigEndian.Uint32(uint32(4 + len(src.Data)))) - buf.Write(src.Data) - - return buf.Bytes(), nil +func (src *CopyData) Encode(dst []byte) []byte { + dst = append(dst, 'd') + dst = pgio.AppendInt32(dst, int32(4+len(src.Data))) + dst = append(dst, src.Data...) + return dst } func (src *CopyData) MarshalJSON() ([]byte, error) { diff --git a/copy_in_response.go b/copy_in_response.go index 9854d665..54083cd6 100644 --- a/copy_in_response.go +++ b/copy_in_response.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type CopyInResponse struct { @@ -37,20 +39,19 @@ func (dst *CopyInResponse) Decode(src []byte) error { return nil } -func (src *CopyInResponse) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - - buf.WriteByte('G') - buf.Write(bigEndian.Uint32(uint32(4 + 1 + 2 + 2*len(src.ColumnFormatCodes)))) - - buf.Write(bigEndian.Uint16(uint16(len(src.ColumnFormatCodes)))) +func (src *CopyInResponse) Encode(dst []byte) []byte { + dst = append(dst, 'G') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) + dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes))) for _, fc := range src.ColumnFormatCodes { - buf.Write(bigEndian.Uint16(fc)) + dst = pgio.AppendUint16(dst, fc) } - return buf.Bytes(), nil + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) + + return dst } func (src *CopyInResponse) MarshalJSON() ([]byte, error) { diff --git a/copy_out_response.go b/copy_out_response.go index 5ef6e4c1..eaa33b8b 100644 --- a/copy_out_response.go +++ b/copy_out_response.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type CopyOutResponse struct { @@ -37,20 +39,19 @@ func (dst *CopyOutResponse) Decode(src []byte) error { return nil } -func (src *CopyOutResponse) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - - buf.WriteByte('H') - buf.Write(bigEndian.Uint32(uint32(4 + 1 + 2 + 2*len(src.ColumnFormatCodes)))) - - buf.Write(bigEndian.Uint16(uint16(len(src.ColumnFormatCodes)))) +func (src *CopyOutResponse) Encode(dst []byte) []byte { + dst = append(dst, 'H') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) + dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes))) for _, fc := range src.ColumnFormatCodes { - buf.Write(bigEndian.Uint16(fc)) + dst = pgio.AppendUint16(dst, fc) } - return buf.Bytes(), nil + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) + + return dst } func (src *CopyOutResponse) MarshalJSON() ([]byte, error) { diff --git a/data_row.go b/data_row.go index 3e600e84..e46d3cc0 100644 --- a/data_row.go +++ b/data_row.go @@ -1,10 +1,11 @@ package pgproto3 import ( - "bytes" "encoding/binary" "encoding/hex" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type DataRow struct { @@ -58,28 +59,25 @@ func (dst *DataRow) Decode(src []byte) error { return nil } -func (src *DataRow) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - - buf.WriteByte('D') - buf.Write(bigEndian.Uint32(0)) - - buf.Write(bigEndian.Uint16(uint16(len(src.Values)))) +func (src *DataRow) Encode(dst []byte) []byte { + dst = append(dst, 'D') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) + dst = pgio.AppendUint16(dst, uint16(len(src.Values))) for _, v := range src.Values { if v == nil { - buf.Write(bigEndian.Int32(-1)) + dst = pgio.AppendInt32(dst, -1) continue } - buf.Write(bigEndian.Int32(int32(len(v)))) - buf.Write(v) + dst = pgio.AppendInt32(dst, int32(len(v))) + dst = append(dst, v...) } - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - return buf.Bytes(), nil + return dst } func (src *DataRow) MarshalJSON() ([]byte, error) { diff --git a/describe.go b/describe.go index ea55ed9d..bb7bc056 100644 --- a/describe.go +++ b/describe.go @@ -2,8 +2,9 @@ package pgproto3 import ( "bytes" - "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type Describe struct { @@ -31,20 +32,18 @@ func (dst *Describe) Decode(src []byte) error { return nil } -func (src *Describe) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} +func (src *Describe) Encode(dst []byte) []byte { + dst = append(dst, 'D') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) - buf.WriteByte('D') - buf.Write(bigEndian.Uint32(0)) + dst = append(dst, src.ObjectType) + dst = append(dst, src.Name...) + dst = append(dst, 0) - buf.WriteByte(src.ObjectType) - buf.WriteString(src.Name) - buf.WriteByte(0) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) - - return buf.Bytes(), nil + return dst } func (src *Describe) MarshalJSON() ([]byte, error) { diff --git a/empty_query_response.go b/empty_query_response.go index 13ed1886..d283b06d 100644 --- a/empty_query_response.go +++ b/empty_query_response.go @@ -16,8 +16,8 @@ func (dst *EmptyQueryResponse) Decode(src []byte) error { return nil } -func (src *EmptyQueryResponse) MarshalBinary() ([]byte, error) { - return []byte{'I', 0, 0, 0, 4}, nil +func (src *EmptyQueryResponse) Encode(dst []byte) []byte { + return append(dst, 'I', 0, 0, 0, 4) } func (src *EmptyQueryResponse) MarshalJSON() ([]byte, error) { diff --git a/error_response.go b/error_response.go index 602dd2a1..160234f2 100644 --- a/error_response.go +++ b/error_response.go @@ -103,11 +103,11 @@ func (dst *ErrorResponse) Decode(src []byte) error { return nil } -func (src *ErrorResponse) MarshalBinary() ([]byte, error) { - return src.marshalBinary('E') +func (src *ErrorResponse) Encode(dst []byte) []byte { + return append(dst, src.marshalBinary('E')...) } -func (src *ErrorResponse) marshalBinary(typeByte byte) ([]byte, error) { +func (src *ErrorResponse) marshalBinary(typeByte byte) []byte { var bigEndian BigEndianBuf buf := &bytes.Buffer{} @@ -193,5 +193,5 @@ func (src *ErrorResponse) marshalBinary(typeByte byte) ([]byte, error) { binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) - return buf.Bytes(), nil + return buf.Bytes() } diff --git a/execute.go b/execute.go index 4892e7b3..76da9943 100644 --- a/execute.go +++ b/execute.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type Execute struct { @@ -30,21 +32,19 @@ func (dst *Execute) Decode(src []byte) error { return nil } -func (src *Execute) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} +func (src *Execute) Encode(dst []byte) []byte { + dst = append(dst, 'E') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) - buf.WriteByte('E') - buf.Write(bigEndian.Uint32(0)) + dst = append(dst, src.Portal...) + dst = append(dst, 0) - buf.WriteString(src.Portal) - buf.WriteByte(0) + dst = pgio.AppendUint32(dst, src.MaxRows) - buf.Write(bigEndian.Uint32(src.MaxRows)) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) - - return buf.Bytes(), nil + return dst } func (src *Execute) MarshalJSON() ([]byte, error) { diff --git a/flush.go b/flush.go index d26f5c0c..7fd5e987 100644 --- a/flush.go +++ b/flush.go @@ -16,8 +16,8 @@ func (dst *Flush) Decode(src []byte) error { return nil } -func (src *Flush) MarshalBinary() ([]byte, error) { - return []byte{'H', 0, 0, 0, 4}, nil +func (src *Flush) Encode(dst []byte) []byte { + return append(dst, 'H', 0, 0, 0, 4) } func (src *Flush) MarshalJSON() ([]byte, error) { diff --git a/frontend.go b/frontend.go index 27a9890a..630a5cba 100644 --- a/frontend.go +++ b/frontend.go @@ -42,12 +42,7 @@ func NewFrontend(r io.Reader, w io.Writer) (*Frontend, error) { } func (b *Frontend) Send(msg FrontendMessage) error { - buf, err := msg.MarshalBinary() - if err != nil { - return nil - } - - _, err = b.w.Write(buf) + _, err := b.w.Write(msg.Encode(nil)) return err } diff --git a/function_call_response.go b/function_call_response.go index 1e0f16af..bb325b69 100644 --- a/function_call_response.go +++ b/function_call_response.go @@ -1,10 +1,11 @@ package pgproto3 import ( - "bytes" "encoding/binary" "encoding/hex" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type FunctionCallResponse struct { @@ -34,21 +35,21 @@ func (dst *FunctionCallResponse) Decode(src []byte) error { return nil } -func (src *FunctionCallResponse) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - - buf.WriteByte('V') - buf.Write(bigEndian.Uint32(uint32(4 + 4 + len(src.Result)))) +func (src *FunctionCallResponse) Encode(dst []byte) []byte { + dst = append(dst, 'V') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) if src.Result == nil { - buf.Write(bigEndian.Int32(-1)) + dst = pgio.AppendInt32(dst, -1) } else { - buf.Write(bigEndian.Int32(int32(len(src.Result)))) - buf.Write(src.Result) + dst = pgio.AppendInt32(dst, int32(len(src.Result))) + dst = append(dst, src.Result...) } - return buf.Bytes(), nil + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) + + return dst } func (src *FunctionCallResponse) MarshalJSON() ([]byte, error) { diff --git a/no_data.go b/no_data.go index 3adec4ad..1fb47c2a 100644 --- a/no_data.go +++ b/no_data.go @@ -16,8 +16,8 @@ func (dst *NoData) Decode(src []byte) error { return nil } -func (src *NoData) MarshalBinary() ([]byte, error) { - return []byte{'n', 0, 0, 0, 4}, nil +func (src *NoData) Encode(dst []byte) []byte { + return append(dst, 'n', 0, 0, 0, 4) } func (src *NoData) MarshalJSON() ([]byte, error) { diff --git a/notice_response.go b/notice_response.go index 8af55baf..e4595aa5 100644 --- a/notice_response.go +++ b/notice_response.go @@ -8,6 +8,6 @@ func (dst *NoticeResponse) Decode(src []byte) error { return (*ErrorResponse)(dst).Decode(src) } -func (src *NoticeResponse) MarshalBinary() ([]byte, error) { - return (*ErrorResponse)(src).marshalBinary('N') +func (src *NoticeResponse) Encode(dst []byte) []byte { + return append(dst, (*ErrorResponse)(src).marshalBinary('N')...) } diff --git a/notification_response.go b/notification_response.go index 7262844e..b14007b4 100644 --- a/notification_response.go +++ b/notification_response.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type NotificationResponse struct { @@ -35,19 +37,19 @@ func (dst *NotificationResponse) Decode(src []byte) error { return nil } -func (src *NotificationResponse) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} +func (src *NotificationResponse) Encode(dst []byte) []byte { + dst = append(dst, 'A') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) - buf.WriteByte('A') - buf.Write(bigEndian.Uint32(uint32(4 + 4 + len(src.Channel) + len(src.Payload)))) + dst = append(dst, src.Channel...) + dst = append(dst, 0) + dst = append(dst, src.Payload...) + dst = append(dst, 0) - buf.WriteString(src.Channel) - buf.WriteByte(0) - buf.WriteString(src.Payload) - buf.WriteByte(0) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - return buf.Bytes(), nil + return dst } func (src *NotificationResponse) MarshalJSON() ([]byte, error) { diff --git a/parameter_description.go b/parameter_description.go index 32b6e1c1..1fa3c927 100644 --- a/parameter_description.go +++ b/parameter_description.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type ParameterDescription struct { @@ -33,20 +35,19 @@ func (dst *ParameterDescription) Decode(src []byte) error { return nil } -func (src *ParameterDescription) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - - buf.WriteByte('t') - buf.Write(bigEndian.Uint32(uint32(4 + 2 + 4*len(src.ParameterOIDs)))) - - buf.Write(bigEndian.Uint16(uint16(len(src.ParameterOIDs)))) +func (src *ParameterDescription) Encode(dst []byte) []byte { + dst = append(dst, 't') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) + dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs))) for _, oid := range src.ParameterOIDs { - buf.Write(bigEndian.Uint32(oid)) + dst = pgio.AppendUint32(dst, oid) } - return buf.Bytes(), nil + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) + + return dst } func (src *ParameterDescription) MarshalJSON() ([]byte, error) { diff --git a/parameter_status.go b/parameter_status.go index 9b10824c..b3bac33f 100644 --- a/parameter_status.go +++ b/parameter_status.go @@ -2,8 +2,9 @@ package pgproto3 import ( "bytes" - "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type ParameterStatus struct { @@ -32,21 +33,19 @@ func (dst *ParameterStatus) Decode(src []byte) error { return nil } -func (src *ParameterStatus) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} +func (src *ParameterStatus) Encode(dst []byte) []byte { + dst = append(dst, 'S') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) - buf.WriteByte('S') - buf.Write(bigEndian.Uint32(0)) + dst = append(dst, src.Name...) + dst = append(dst, 0) + dst = append(dst, src.Value...) + dst = append(dst, 0) - buf.WriteString(src.Name) - buf.WriteByte(0) - buf.WriteString(src.Value) - buf.WriteByte(0) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) - - return buf.Bytes(), nil + return dst } func (ps *ParameterStatus) MarshalJSON() ([]byte, error) { diff --git a/parse.go b/parse.go index 5d17ed11..b8775547 100644 --- a/parse.go +++ b/parse.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type Parse struct { @@ -44,27 +46,24 @@ func (dst *Parse) Decode(src []byte) error { return nil } -func (src *Parse) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} +func (src *Parse) Encode(dst []byte) []byte { + dst = append(dst, 'P') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) - buf.WriteByte('P') - buf.Write(bigEndian.Uint32(0)) + dst = append(dst, src.Name...) + dst = append(dst, 0) + dst = append(dst, src.Query...) + dst = append(dst, 0) - buf.WriteString(src.Name) - buf.WriteByte(0) - buf.WriteString(src.Query) - buf.WriteByte(0) - - buf.Write(bigEndian.Uint16(uint16(len(src.ParameterOIDs)))) - - for _, v := range src.ParameterOIDs { - buf.Write(bigEndian.Uint32(v)) + dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs))) + for _, oid := range src.ParameterOIDs { + dst = pgio.AppendUint32(dst, oid) } - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - return buf.Bytes(), nil + return dst } func (src *Parse) MarshalJSON() ([]byte, error) { diff --git a/parse_complete.go b/parse_complete.go index e949c14c..462a89ba 100644 --- a/parse_complete.go +++ b/parse_complete.go @@ -16,8 +16,8 @@ func (dst *ParseComplete) Decode(src []byte) error { return nil } -func (src *ParseComplete) MarshalBinary() ([]byte, error) { - return []byte{'1', 0, 0, 0, 4}, nil +func (src *ParseComplete) Encode(dst []byte) []byte { + return append(dst, '1', 0, 0, 0, 4) } func (src *ParseComplete) MarshalJSON() ([]byte, error) { diff --git a/password_message.go b/password_message.go index 69df6362..2ad3fe4a 100644 --- a/password_message.go +++ b/password_message.go @@ -3,6 +3,8 @@ package pgproto3 import ( "bytes" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type PasswordMessage struct { @@ -23,14 +25,14 @@ func (dst *PasswordMessage) Decode(src []byte) error { return nil } -func (src *PasswordMessage) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - buf.WriteByte('p') - buf.Write(bigEndian.Uint32(uint32(4 + len(src.Password) + 1))) - buf.WriteString(src.Password) - buf.WriteByte(0) - return buf.Bytes(), nil +func (src *PasswordMessage) Encode(dst []byte) []byte { + dst = append(dst, 'p') + dst = pgio.AppendInt32(dst, int32(4+len(src.Password)+1)) + + dst = append(dst, src.Password...) + dst = append(dst, 0) + + return dst } func (src *PasswordMessage) MarshalJSON() ([]byte, error) { diff --git a/pgproto3.go b/pgproto3.go index 3fe8fc93..fe7b085b 100644 --- a/pgproto3.go +++ b/pgproto3.go @@ -4,12 +4,13 @@ import "fmt" // Message is the interface implemented by an object that can decode and encode // a particular PostgreSQL message. -// -// Decode is allowed and expected to retain a reference to data after -// returning (unlike encoding.BinaryUnmarshaler). type Message interface { + // Decode is allowed and expected to retain a reference to data after + // returning (unlike encoding.BinaryUnmarshaler). Decode(data []byte) error - MarshalBinary() (data []byte, err error) + + // Encode appends itself to dst and returns the new buffer. + Encode(dst []byte) []byte } type FrontendMessage interface { diff --git a/query.go b/query.go index b5fc2dbc..d80c0fb4 100644 --- a/query.go +++ b/query.go @@ -3,6 +3,8 @@ package pgproto3 import ( "bytes" "encoding/json" + + "github.com/jackc/pgx/pgio" ) type Query struct { @@ -22,14 +24,14 @@ func (dst *Query) Decode(src []byte) error { return nil } -func (src *Query) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - buf.WriteByte('Q') - buf.Write(bigEndian.Uint32(uint32(4 + len(src.String) + 1))) - buf.WriteString(src.String) - buf.WriteByte(0) - return buf.Bytes(), nil +func (src *Query) Encode(dst []byte) []byte { + dst = append(dst, 'Q') + dst = pgio.AppendInt32(dst, int32(4+len(src.String)+1)) + + dst = append(dst, src.String...) + dst = append(dst, 0) + + return dst } func (src *Query) MarshalJSON() ([]byte, error) { diff --git a/ready_for_query.go b/ready_for_query.go index e0e4707a..63b902bd 100644 --- a/ready_for_query.go +++ b/ready_for_query.go @@ -20,8 +20,8 @@ func (dst *ReadyForQuery) Decode(src []byte) error { return nil } -func (src *ReadyForQuery) MarshalBinary() ([]byte, error) { - return []byte{'Z', 0, 0, 0, 5, src.TxStatus}, nil +func (src *ReadyForQuery) Encode(dst []byte) []byte { + return append(dst, 'Z', 0, 0, 0, 5, src.TxStatus) } func (src *ReadyForQuery) MarshalJSON() ([]byte, error) { diff --git a/row_description.go b/row_description.go index b1110290..d0df11b0 100644 --- a/row_description.go +++ b/row_description.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" + + "github.com/jackc/pgx/pgio" ) const ( @@ -64,30 +66,27 @@ func (dst *RowDescription) Decode(src []byte) error { return nil } -func (src *RowDescription) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - - buf.WriteByte('T') - buf.Write(bigEndian.Uint32(0)) - - buf.Write(bigEndian.Uint16(uint16(len(src.Fields)))) +func (src *RowDescription) Encode(dst []byte) []byte { + dst = append(dst, 'T') + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) + dst = pgio.AppendUint16(dst, uint16(len(src.Fields))) for _, fd := range src.Fields { - buf.WriteString(fd.Name) - buf.WriteByte(0) + dst = append(dst, fd.Name...) + dst = append(dst, 0) - buf.Write(bigEndian.Uint32(fd.TableOID)) - buf.Write(bigEndian.Uint16(fd.TableAttributeNumber)) - buf.Write(bigEndian.Uint32(fd.DataTypeOID)) - buf.Write(bigEndian.Uint16(uint16(fd.DataTypeSize))) - buf.Write(bigEndian.Uint32(fd.TypeModifier)) - buf.Write(bigEndian.Uint16(uint16(fd.Format))) + dst = pgio.AppendUint32(dst, fd.TableOID) + dst = pgio.AppendUint16(dst, fd.TableAttributeNumber) + dst = pgio.AppendUint32(dst, fd.DataTypeOID) + dst = pgio.AppendInt16(dst, fd.DataTypeSize) + dst = pgio.AppendUint32(dst, fd.TypeModifier) + dst = pgio.AppendInt16(dst, fd.Format) } - binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - return buf.Bytes(), nil + return dst } func (src *RowDescription) MarshalJSON() ([]byte, error) { diff --git a/startup_message.go b/startup_message.go index 4847d629..4e2df27d 100644 --- a/startup_message.go +++ b/startup_message.go @@ -5,6 +5,8 @@ import ( "encoding/binary" "encoding/json" "fmt" + + "github.com/jackc/pgx/pgio" ) const ( @@ -64,22 +66,22 @@ func (dst *StartupMessage) Decode(src []byte) error { return nil } -func (src *StartupMessage) MarshalBinary() ([]byte, error) { - var bigEndian BigEndianBuf - buf := &bytes.Buffer{} - buf.Write(bigEndian.Uint32(0)) - buf.Write(bigEndian.Uint32(src.ProtocolVersion)) +func (src *StartupMessage) Encode(dst []byte) []byte { + sp := len(dst) + dst = pgio.AppendInt32(dst, -1) + + dst = pgio.AppendUint32(dst, src.ProtocolVersion) for k, v := range src.Parameters { - buf.WriteString(k) - buf.WriteByte(0) - buf.WriteString(v) - buf.WriteByte(0) + dst = append(dst, k...) + dst = append(dst, 0) + dst = append(dst, v...) + dst = append(dst, 0) } - buf.WriteByte(0) + dst = append(dst, 0) - binary.BigEndian.PutUint32(buf.Bytes()[0:4], uint32(buf.Len())) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) - return buf.Bytes(), nil + return dst } func (src *StartupMessage) MarshalJSON() ([]byte, error) { diff --git a/sync.go b/sync.go index da3fa727..85f4749a 100644 --- a/sync.go +++ b/sync.go @@ -16,8 +16,8 @@ func (dst *Sync) Decode(src []byte) error { return nil } -func (src *Sync) MarshalBinary() ([]byte, error) { - return []byte{'S', 0, 0, 0, 4}, nil +func (src *Sync) Encode(dst []byte) []byte { + return append(dst, 'S', 0, 0, 0, 4) } func (src *Sync) MarshalJSON() ([]byte, error) { diff --git a/terminate.go b/terminate.go index 77977f20..0a3310da 100644 --- a/terminate.go +++ b/terminate.go @@ -16,8 +16,8 @@ func (dst *Terminate) Decode(src []byte) error { return nil } -func (src *Terminate) MarshalBinary() ([]byte, error) { - return []byte{'X', 0, 0, 0, 4}, nil +func (src *Terminate) Encode(dst []byte) []byte { + return append(dst, 'X', 0, 0, 0, 4) } func (src *Terminate) MarshalJSON() ([]byte, error) {