CVE-2024-27304 (Go, published 2024-03-06T19:15Z)
Description: value: pgx is a PostgreSQL driver and toolkit for Go. SQL injection can occur if an attacker can cause a single query or bind message to exceed 4 GB in size. An integer overflow in the calculated message size can cause the one large message to be sent as multiple messages under the attacker's control. The problem is resolved in v4.18.2 and v5.5.4. As a workaround, reject user input large enough to cause a single query or bind message to exceed 4 GB in size.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/jackc/pgproto3
Files changed:
authentication_cleartext_password.go
authentication_gss.go
authentication_gss_continue.go
authentication_md5_password.go
authentication_ok.go
authentication_sasl.go
authentication_sasl_continue.go
authentication_sasl_final.go
backend.go
backend_key_data.go
backend_test.go
bind.go
bind_complete.go
bind_test.go
cancel_request.go
close.go
close_complete.go
command_complete.go
copy_both_response.go
copy_both_response_test.go
copy_data.go
copy_done.go
copy_fail.go
copy_in_response.go
copy_out_response.go
data_row.go
describe.go
empty_query_response.go
error_response.go
example/pgfortune/server.go
execute.go
flush.go
frontend.go
function_call.go
function_call_response.go
function_call_test.go
gss_enc_request.go
gss_response.go
no_data.go
notice_response.go
notification_response.go
parameter_description.go
parameter_status.go
parse.go
parse_complete.go
password_message.go
pgproto3.go
pgproto3_private_test.go
portal_suspended.go
query.go
query_test.go
ready_for_query.go
row_description.go
sasl_initial_response.go
sasl_response.go
ssl_request.go
startup_message.go
sync.go
terminate.go
Commit message: Backport fixes from pgx v5

Check for overflow on uint16 sizes in pgproto3

Do not allow protocol messages larger than ~1GB

The PostgreSQL server will reject messages greater than ~1 GB anyway.
However, worse than that is that a message that is larger than 4 GB
could wrap the 32-bit integer message size and be interpreted by the
server as multiple messages. This could allow a malicious client to
inject arbitrary protocol messages.

https://github.com/jackc/pgx/security/advisories/GHSA-mrww-27vc-gghv


Vulnerable code:
func (src *AuthenticationCleartextPassword) Encode(dst []byte) []byte {
	dst = append(dst, 'R')
	dst = pgio.AppendInt32(dst, 8)
	return dst
func (a *AuthenticationGSS) Encode(dst []byte) []byte {
	dst = append(dst, 'R')
	dst = pgio.AppendInt32(dst, 4)
	return dst
func (a *AuthenticationGSSContinue) Encode(dst []byte) []byte {
	dst = append(dst, 'R')
	dst = pgio.AppendInt32(dst, int32(len(a.Data))+8)
	return dst
func (src *AuthenticationMD5Password) Encode(dst []byte) []byte {
	dst = append(dst, 'R')
	dst = pgio.AppendInt32(dst, 12)
	return dst
func (src *AuthenticationOk) Encode(dst []byte) []byte {
	dst = append(dst, 'R')
	dst = pgio.AppendInt32(dst, 8)
	return dst
func (src *AuthenticationSASL) Encode(dst []byte) []byte {
	dst = append(dst, 'R')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *AuthenticationSASLContinue) Encode(dst []byte) []byte {
	dst = append(dst, 'R')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)


	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *AuthenticationSASLFinal) Encode(dst []byte) []byte {
	dst = append(dst, 'R')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)


	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
	_, err := b.w.Write(msg.Encode(nil))
// 		Byte1('p')
//      Identifies the message as a password response. Note that this is also used for
//		GSSAPI, SSPI and SASL response messages. The exact message type can be deduced from
//		the context.
func (src *BackendKeyData) Encode(dst []byte) []byte {
	dst = append(dst, 'K')
	dst = pgio.AppendUint32(dst, 12)
	return dst
		dst := []byte{}
		dst = want.Encode(dst)
func (src *Bind) Encode(dst []byte) []byte {
	dst = append(dst, 'B')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *BindComplete) Encode(dst []byte) []byte {
	return append(dst, '2', 0, 0, 0, 4)
func (src *CancelRequest) Encode(dst []byte) []byte {
	return dst

	"github.com/jackc/pgio"
func (src *Close) Encode(dst []byte) []byte {
	dst = append(dst, 'C')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)


	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *CloseComplete) Encode(dst []byte) []byte {
	return append(dst, '3', 0, 0, 0, 4)

	"github.com/jackc/pgio"
func (src *CommandComplete) Encode(dst []byte) []byte {
	dst = append(dst, 'C')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)


	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *CopyBothResponse) Encode(dst []byte) []byte {
	dst = append(dst, 'W')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
	dstBytes = dstResp.Encode(dstBytes)

	"github.com/jackc/pgio"
func (src *CopyData) Encode(dst []byte) []byte {
	dst = append(dst, 'd')
	dst = pgio.AppendInt32(dst, int32(4+len(src.Data)))
	return dst
func (src *CopyDone) Encode(dst []byte) []byte {
	return append(dst, 'c', 0, 0, 0, 4)

	"github.com/jackc/pgio"
func (src *CopyFail) Encode(dst []byte) []byte {
	dst = append(dst, 'f')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)


	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *CopyInResponse) Encode(dst []byte) []byte {
	dst = append(dst, 'G')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *CopyOutResponse) Encode(dst []byte) []byte {
	dst = append(dst, 'H')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *DataRow) Encode(dst []byte) []byte {
	dst = append(dst, 'D')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst

	"github.com/jackc/pgio"
func (src *Describe) Encode(dst []byte) []byte {
	dst = append(dst, 'D')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)


	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *EmptyQueryResponse) Encode(dst []byte) []byte {
	return append(dst, 'I', 0, 0, 0, 4)
	"encoding/binary"
func (src *ErrorResponse) Encode(dst []byte) []byte {
	return append(dst, src.marshalBinary('E')...)
func (src *ErrorResponse) marshalBinary(typeByte byte) []byte {
	var bigEndian BigEndianBuf
	buf := &bytes.Buffer{}

	buf.WriteByte(typeByte)
	buf.Write(bigEndian.Uint32(0))

		buf.WriteByte('S')
		buf.WriteString(src.Severity)
		buf.WriteByte(0)
		buf.WriteByte('V')
		buf.WriteString(src.SeverityUnlocalized)
		buf.WriteByte(0)
		buf.WriteByte('C')
		buf.WriteString(src.Code)
		buf.WriteByte(0)
		buf.WriteByte('M')
		buf.WriteString(src.Message)
		buf.WriteByte(0)
		buf.WriteByte('D')
		buf.WriteString(src.Detail)
		buf.WriteByte(0)
		buf.WriteByte('H')
		buf.WriteString(src.Hint)
		buf.WriteByte(0)
		buf.WriteByte('P')
		buf.WriteString(strconv.Itoa(int(src.Position)))
		buf.WriteByte(0)
		buf.WriteByte('p')
		buf.WriteString(strconv.Itoa(int(src.InternalPosition)))
		buf.WriteByte(0)
		buf.WriteByte('q')
		buf.WriteString(src.InternalQuery)
		buf.WriteByte(0)
		buf.WriteByte('W')
		buf.WriteString(src.Where)
		buf.WriteByte(0)
		buf.WriteByte('s')
		buf.WriteString(src.SchemaName)
		buf.WriteByte(0)
		buf.WriteByte('t')
		buf.WriteString(src.TableName)
		buf.WriteByte(0)
		buf.WriteByte('c')
		buf.WriteString(src.ColumnName)
		buf.WriteByte(0)
		buf.WriteByte('d')
		buf.WriteString(src.DataTypeName)
		buf.WriteByte(0)
		buf.WriteByte('n')
		buf.WriteString(src.ConstraintName)
		buf.WriteByte(0)
		buf.WriteByte('F')
		buf.WriteString(src.File)
		buf.WriteByte(0)
		buf.WriteByte('L')
		buf.WriteString(strconv.Itoa(int(src.Line)))
		buf.WriteByte(0)
		buf.WriteByte('R')
		buf.WriteString(src.Routine)
		buf.WriteByte(0)
		buf.WriteByte(k)
		buf.WriteByte(0)
		buf.WriteString(v)
		buf.WriteByte(0)
	buf.WriteByte(0)

	binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1))
	return buf.Bytes()
			buf := (&pgproto3.RowDescription{Fields: []pgproto3.FieldDescription{
			}}).Encode(nil)
			buf = (&pgproto3.DataRow{Values: [][]byte{response}}).Encode(buf)
			buf = (&pgproto3.CommandComplete{CommandTag: []byte("SELECT 1")}).Encode(buf)
			buf = (&pgproto3.ReadyForQuery{TxStatus: 'I'}).Encode(buf)
		buf := (&pgproto3.AuthenticationOk{}).Encode(nil)
		buf = (&pgproto3.ReadyForQuery{TxStatus: 'I'}).Encode(buf)
func (src *Execute) Encode(dst []byte) []byte {
	dst = append(dst, 'E')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)



	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *Flush) Encode(dst []byte) []byte {
	return append(dst, 'H', 0, 0, 0, 4)
	_, err := f.w.Write(msg.Encode(nil))
func (src *FunctionCall) Encode(dst []byte) []byte {
	dst = append(dst, 'F')
	sp := len(dst)
	dst = pgio.AppendUint32(dst, 0) // Unknown length, set it at the end
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
	return dst
func (src *FunctionCallResponse) Encode(dst []byte) []byte {
	dst = append(dst, 'V')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
			encoded := src.Encode([]byte{})
			err := dst.Decode(encoded[5:])
func (src *GSSEncRequest) Encode(dst []byte) []byte {
	return dst
	"github.com/jackc/pgio"
func (g *GSSResponse) Encode(dst []byte) []byte {
	dst = append(dst, 'p')
	dst = pgio.AppendInt32(dst, int32(4+len(g.Data)))
	return dst
func (src *NoData) Encode(dst []byte) []byte {
	return append(dst, 'n', 0, 0, 0, 4)
func (src *NoticeResponse) Encode(dst []byte) []byte {
	return append(dst, (*ErrorResponse)(src).marshalBinary('N')...)
func (src *NotificationResponse) Encode(dst []byte) []byte {
	dst = append(dst, 'A')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)


	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *ParameterDescription) Encode(dst []byte) []byte {
	dst = append(dst, 't')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst

	"github.com/jackc/pgio"
func (src *ParameterStatus) Encode(dst []byte) []byte {
	dst = append(dst, 'S')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)


	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *Parse) Encode(dst []byte) []byte {
	dst = append(dst, 'P')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *ParseComplete) Encode(dst []byte) []byte {
	return append(dst, '1', 0, 0, 0, 4)

	"github.com/jackc/pgio"
func (src *PasswordMessage) Encode(dst []byte) []byte {
	dst = append(dst, 'p')
	dst = pgio.AppendInt32(dst, int32(4+len(src.Password)+1))


	return dst
	Encode(dst []byte) []byte
func (src *PortalSuspended) Encode(dst []byte) []byte {
	return append(dst, 's', 0, 0, 0, 4)

	"github.com/jackc/pgio"
func (src *Query) Encode(dst []byte) []byte {
	dst = append(dst, 'Q')
	dst = pgio.AppendInt32(dst, int32(4+len(src.String)+1))


	return dst
func (src *ReadyForQuery) Encode(dst []byte) []byte {
	return append(dst, 'Z', 0, 0, 0, 5, src.TxStatus)
func (src *RowDescription) Encode(dst []byte) []byte {
	dst = append(dst, 'T')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *SASLInitialResponse) Encode(dst []byte) []byte {
	dst = append(dst, 'p')
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst

	"github.com/jackc/pgio"
func (src *SASLResponse) Encode(dst []byte) []byte {
	dst = append(dst, 'p')
	dst = pgio.AppendInt32(dst, int32(4+len(src.Data)))


	return dst
func (src *SSLRequest) Encode(dst []byte) []byte {
	return dst
func (src *StartupMessage) Encode(dst []byte) []byte {
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))

	return dst
func (src *Sync) Encode(dst []byte) []byte {
	return append(dst, 'S', 0, 0, 0, 4)
func (src *Terminate) Encode(dst []byte) []byte {
	return append(dst, 'X', 0, 0, 0, 4)

Fixed code:
func (src *AuthenticationCleartextPassword) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'R')
	return finishMessage(dst, sp)

func (a *AuthenticationGSS) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'R')
	return finishMessage(dst, sp)

func (a *AuthenticationGSSContinue) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'R')
	return finishMessage(dst, sp)
func (src *AuthenticationMD5Password) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'R')
	return finishMessage(dst, sp)
func (src *AuthenticationOk) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'R')
	return finishMessage(dst, sp)
func (src *AuthenticationSASL) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'R')
	return finishMessage(dst, sp)
func (src *AuthenticationSASLContinue) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'R')
	return finishMessage(dst, sp)
func (src *AuthenticationSASLFinal) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'R')
	return finishMessage(dst, sp)
	buf, err := msg.Encode(nil)
	if err != nil {
		return err
	}

	_, err = b.w.Write(buf)
//			Byte1('p')
//	     Identifies the message as a password response. Note that this is also used for
//			GSSAPI, SSPI and SASL response messages. The exact message type can be deduced from
//			the context.
func (src *BackendKeyData) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'K')
	return finishMessage(dst, sp)
		dst, err := want.Encode([]byte{})
		require.NoError(t, err)
	"errors"
	"math"
func (src *Bind) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'B')
	if len(src.ParameterFormatCodes) > math.MaxUint16 {
		return nil, errors.New("too many parameter format codes")
	}
	if len(src.Parameters) > math.MaxUint16 {
		return nil, errors.New("too many parameters")
	}
	if len(src.ResultFormatCodes) > math.MaxUint16 {
		return nil, errors.New("too many result format codes")
	}
	return finishMessage(dst, sp)
func (src *BindComplete) Encode(dst []byte) ([]byte, error) {
	return append(dst, '2', 0, 0, 0, 4), nil
package pgproto3_test

import (
	"testing"

	"github.com/jackc/pgproto3/v2"
	"github.com/stretchr/testify/require"
)

func TestBindBiggerThanMaxMessageBodyLen(t *testing.T) {
	t.Parallel()

	// Maximum allowed size.
	_, err := (&pgproto3.Bind{Parameters: [][]byte{make([]byte, pgproto3.MaxMessageBodyLen-16)}}).Encode(nil)
	require.NoError(t, err)

	// 1 byte too big
	_, err = (&pgproto3.Bind{Parameters: [][]byte{make([]byte, pgproto3.MaxMessageBodyLen-15)}}).Encode(nil)
	require.Error(t, err)
}
func (src *CancelRequest) Encode(dst []byte) ([]byte, error) {
	return dst, nil
func (src *Close) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'C')
	return finishMessage(dst, sp)
func (src *CloseComplete) Encode(dst []byte) ([]byte, error) {
	return append(dst, '3', 0, 0, 0, 4), nil
func (src *CommandComplete) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'C')
	return finishMessage(dst, sp)
	"math"
func (src *CopyBothResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'W')
	if len(src.ColumnFormatCodes) > math.MaxUint16 {
		return nil, errors.New("too many column format codes")
	}
	return finishMessage(dst, sp)
	"github.com/stretchr/testify/require"
	dstBytes, err = dstResp.Encode(dstBytes)
	require.NoError(t, err)
func (src *CopyData) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'd')
	return finishMessage(dst, sp)
func (src *CopyDone) Encode(dst []byte) ([]byte, error) {
	return append(dst, 'c', 0, 0, 0, 4), nil
func (src *CopyFail) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'f')
	return finishMessage(dst, sp)
	"math"
func (src *CopyInResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'G')
	if len(src.ColumnFormatCodes) > math.MaxUint16 {
		return nil, errors.New("too many column format codes")
	}
	return finishMessage(dst, sp)
	"math"
func (src *CopyOutResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'H')
	if len(src.ColumnFormatCodes) > math.MaxUint16 {
		return nil, errors.New("too many column format codes")
	}
	return finishMessage(dst, sp)
	"errors"
	"math"
func (src *DataRow) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'D')
	if len(src.Values) > math.MaxUint16 {
		return nil, errors.New("too many values")
	}
	return finishMessage(dst, sp)
func (src *Describe) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'D')
	return finishMessage(dst, sp)
func (src *EmptyQueryResponse) Encode(dst []byte) ([]byte, error) {
	return append(dst, 'I', 0, 0, 0, 4), nil
func (src *ErrorResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'E')
	dst = src.appendFields(dst)
	return finishMessage(dst, sp)
func (src *ErrorResponse) appendFields(dst []byte) []byte {
		dst = append(dst, 'S')
		dst = append(dst, src.Severity...)
		dst = append(dst, 0)
		dst = append(dst, 'V')
		dst = append(dst, src.SeverityUnlocalized...)
		dst = append(dst, 0)
		dst = append(dst, 'C')
		dst = append(dst, src.Code...)
		dst = append(dst, 0)
		dst = append(dst, 'M')
		dst = append(dst, src.Message...)
		dst = append(dst, 0)
		dst = append(dst, 'D')
		dst = append(dst, src.Detail...)
		dst = append(dst, 0)
		dst = append(dst, 'H')
		dst = append(dst, src.Hint...)
		dst = append(dst, 0)
		dst = append(dst, 'P')
		dst = append(dst, strconv.Itoa(int(src.Position))...)
		dst = append(dst, 0)
		dst = append(dst, 'p')
		dst = append(dst, strconv.Itoa(int(src.InternalPosition))...)
		dst = append(dst, 0)
		dst = append(dst, 'q')
		dst = append(dst, src.InternalQuery...)
		dst = append(dst, 0)
		dst = append(dst, 'W')
		dst = append(dst, src.Where...)
		dst = append(dst, 0)
		dst = append(dst, 's')
		dst = append(dst, src.SchemaName...)
		dst = append(dst, 0)
		dst = append(dst, 't')
		dst = append(dst, src.TableName...)
		dst = append(dst, 0)
		dst = append(dst, 'c')
		dst = append(dst, src.ColumnName...)
		dst = append(dst, 0)
		dst = append(dst, 'd')
		dst = append(dst, src.DataTypeName...)
		dst = append(dst, 0)
		dst = append(dst, 'n')
		dst = append(dst, src.ConstraintName...)
		dst = append(dst, 0)
		dst = append(dst, 'F')
		dst = append(dst, src.File...)
		dst = append(dst, 0)
		dst = append(dst, 'L')
		dst = append(dst, strconv.Itoa(int(src.Line))...)
		dst = append(dst, 0)
		dst = append(dst, 'R')
		dst = append(dst, src.Routine...)
		dst = append(dst, 0)
		dst = append(dst, k)
		dst = append(dst, v...)
		dst = append(dst, 0)
	dst = append(dst, 0)
	return dst
			buf := mustEncode((&pgproto3.RowDescription{Fields: []pgproto3.FieldDescription{
			}}).Encode(nil))
			buf = mustEncode((&pgproto3.DataRow{Values: [][]byte{response}}).Encode(buf))
			buf = mustEncode((&pgproto3.CommandComplete{CommandTag: []byte("SELECT 1")}).Encode(buf))
			buf = mustEncode((&pgproto3.ReadyForQuery{TxStatus: 'I'}).Encode(buf))
		buf := mustEncode((&pgproto3.AuthenticationOk{}).Encode(nil))
		buf = mustEncode((&pgproto3.ReadyForQuery{TxStatus: 'I'}).Encode(buf))

func mustEncode(buf []byte, err error) []byte {
	if err != nil {
		panic(err)
	}
	return buf
}
func (src *Execute) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'E')
	return finishMessage(dst, sp)
func (src *Flush) Encode(dst []byte) ([]byte, error) {
	return append(dst, 'H', 0, 0, 0, 4), nil
	buf, err := msg.Encode(nil)
	if err != nil {
		return err
	}
	_, err = f.w.Write(buf)
	"errors"
	"math"

func (src *FunctionCall) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'F')

	if len(src.ArgFormatCodes) > math.MaxUint16 {
		return nil, errors.New("too many arg format codes")
	}

	if len(src.Arguments) > math.MaxUint16 {
		return nil, errors.New("too many arguments")
	}
	return finishMessage(dst, sp)
func (src *FunctionCallResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'V')
	return finishMessage(dst, sp)

	"github.com/stretchr/testify/require"
			encoded, err := src.Encode([]byte{})
			require.NoError(t, err)
			err = dst.Decode(encoded[5:])
func (src *GSSEncRequest) Encode(dst []byte) ([]byte, error) {
	return dst, nil
func (g *GSSResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'p')
	return finishMessage(dst, sp)
func (src *NoData) Encode(dst []byte) ([]byte, error) {
	return append(dst, 'n', 0, 0, 0, 4), nil
func (src *NoticeResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'N')
	dst = (*ErrorResponse)(src).appendFields(dst)
	return finishMessage(dst, sp)
func (src *NotificationResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'A')
	return finishMessage(dst, sp)
	"errors"
	"math"
func (src *ParameterDescription) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 't')
	if len(src.ParameterOIDs) > math.MaxUint16 {
		return nil, errors.New("too many parameter oids")
	}
	return finishMessage(dst, sp)
func (src *ParameterStatus) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'S')
	return finishMessage(dst, sp)
	"errors"
	"math"
func (src *Parse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'P')
	if len(src.ParameterOIDs) > math.MaxUint16 {
		return nil, errors.New("too many parameter oids")
	}
	return finishMessage(dst, sp)
func (src *ParseComplete) Encode(dst []byte) ([]byte, error) {
	return append(dst, '1', 0, 0, 0, 4), nil
func (src *PasswordMessage) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'p')
	return finishMessage(dst, sp)

	"github.com/jackc/pgio"
// maxMessageBodyLen is the maximum length of a message body in bytes. See PG_LARGE_MESSAGE_LIMIT in the PostgreSQL
// source. It is defined as (MaxAllocSize - 1). MaxAllocSize is defined as 0x3fffffff.
const maxMessageBodyLen = (0x3fffffff - 1)

	Encode(dst []byte) ([]byte, error)

// beginMessage begines a new message of type t. It appends the message type and a placeholder for the message length to
// dst. It returns the new buffer and the position of the message length placeholder.
func beginMessage(dst []byte, t byte) ([]byte, int) {
	dst = append(dst, t)
	sp := len(dst)
	dst = pgio.AppendInt32(dst, -1)
	return dst, sp
}

// finishMessage finishes a message that was started with beginMessage. It computes the message length and writes it to
// dst[sp]. If the message length is too large it returns an error. Otherwise it returns the final message buffer.
func finishMessage(dst []byte, sp int) ([]byte, error) {
	messageBodyLen := len(dst[sp:])
	if messageBodyLen > maxMessageBodyLen {
		return nil, errors.New("message body too large")
	}
	pgio.SetInt32(dst[sp:], int32(messageBodyLen))
	return dst, nil
}
package pgproto3

const MaxMessageBodyLen = maxMessageBodyLen
func (src *PortalSuspended) Encode(dst []byte) ([]byte, error) {
	return append(dst, 's', 0, 0, 0, 4), nil
func (src *Query) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'Q')
	return finishMessage(dst, sp)
package pgproto3_test

import (
	"testing"

	"github.com/jackc/pgproto3/v2"
	"github.com/stretchr/testify/require"
)

func TestQueryBiggerThanMaxMessageBodyLen(t *testing.T) {
	t.Parallel()

	// Maximum allowed size. 4 bytes for size and 1 byte for 0 terminated string.
	_, err := (&pgproto3.Query{String: string(make([]byte, pgproto3.MaxMessageBodyLen-5))}).Encode(nil)
	require.NoError(t, err)

	// 1 byte too big
	_, err = (&pgproto3.Query{String: string(make([]byte, pgproto3.MaxMessageBodyLen-4))}).Encode(nil)
	require.Error(t, err)
}
func (src *ReadyForQuery) Encode(dst []byte) ([]byte, error) {
	return append(dst, 'Z', 0, 0, 0, 5, src.TxStatus), nil
	"errors"
	"math"
func (src *RowDescription) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'T')
	if len(src.Fields) > math.MaxUint16 {
		return nil, errors.New("too many fields")
	}
	return finishMessage(dst, sp)
func (src *SASLInitialResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'p')
	return finishMessage(dst, sp)
func (src *SASLResponse) Encode(dst []byte) ([]byte, error) {
	dst, sp := beginMessage(dst, 'p')
	return finishMessage(dst, sp)
func (src *SSLRequest) Encode(dst []byte) ([]byte, error) {
	return dst, nil
func (src *StartupMessage) Encode(dst []byte) ([]byte, error) {
	return finishMessage(dst, sp)
func (src *Sync) Encode(dst []byte) ([]byte, error) {
	return append(dst, 'S', 0, 0, 0, 4), nil
func (src *Terminate) Encode(dst []byte) ([]byte, error) {
	return append(dst, 'X', 0, 0, 0, 4), nil