...

Source file src/github.com/jackc/pgx/v5/pgproto3/pgproto3.go

Documentation: github.com/jackc/pgx/v5/pgproto3

     1  package pgproto3
     2  
     3  import (
     4  	"encoding/hex"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/jackc/pgx/v5/internal/pgio"
     9  )
    10  
    11  // maxMessageBodyLen is the maximum length of a message body in bytes. See PG_LARGE_MESSAGE_LIMIT in the PostgreSQL
    12  // source. It is defined as (MaxAllocSize - 1). MaxAllocSize is defined as 0x3fffffff.
    13  const maxMessageBodyLen = (0x3fffffff - 1)
    14  
    15  // Message is the interface implemented by an object that can decode and encode
    16  // a particular PostgreSQL message.
    17  type Message interface {
    18  	// Decode is allowed and expected to retain a reference to data after
    19  	// returning (unlike encoding.BinaryUnmarshaler).
    20  	Decode(data []byte) error
    21  
    22  	// Encode appends itself to dst and returns the new buffer.
    23  	Encode(dst []byte) ([]byte, error)
    24  }
    25  
    26  // FrontendMessage is a message sent by the frontend (i.e. the client).
    27  type FrontendMessage interface {
    28  	Message
    29  	Frontend() // no-op method to distinguish frontend from backend methods
    30  }
    31  
    32  // BackendMessage is a message sent by the backend (i.e. the server).
    33  type BackendMessage interface {
    34  	Message
    35  	Backend() // no-op method to distinguish frontend from backend methods
    36  }
    37  
    38  type AuthenticationResponseMessage interface {
    39  	BackendMessage
    40  	AuthenticationResponse() // no-op method to distinguish authentication responses
    41  }
    42  
    43  type invalidMessageLenErr struct {
    44  	messageType string
    45  	expectedLen int
    46  	actualLen   int
    47  }
    48  
    49  func (e *invalidMessageLenErr) Error() string {
    50  	return fmt.Sprintf("%s body must have length of %d, but it is %d", e.messageType, e.expectedLen, e.actualLen)
    51  }
    52  
    53  type invalidMessageFormatErr struct {
    54  	messageType string
    55  	details     string
    56  }
    57  
    58  func (e *invalidMessageFormatErr) Error() string {
    59  	return fmt.Sprintf("%s body is invalid %s", e.messageType, e.details)
    60  }
    61  
    62  type writeError struct {
    63  	err         error
    64  	safeToRetry bool
    65  }
    66  
    67  func (e *writeError) Error() string {
    68  	return fmt.Sprintf("write failed: %s", e.err.Error())
    69  }
    70  
    71  func (e *writeError) SafeToRetry() bool {
    72  	return e.safeToRetry
    73  }
    74  
    75  func (e *writeError) Unwrap() error {
    76  	return e.err
    77  }
    78  
    79  type ExceededMaxBodyLenErr struct {
    80  	MaxExpectedBodyLen int
    81  	ActualBodyLen      int
    82  }
    83  
    84  func (e *ExceededMaxBodyLenErr) Error() string {
    85  	return fmt.Sprintf("invalid body length: expected at most %d, but got %d", e.MaxExpectedBodyLen, e.ActualBodyLen)
    86  }
    87  
    88  // getValueFromJSON gets the value from a protocol message representation in JSON.
    89  func getValueFromJSON(v map[string]string) ([]byte, error) {
    90  	if v == nil {
    91  		return nil, nil
    92  	}
    93  	if text, ok := v["text"]; ok {
    94  		return []byte(text), nil
    95  	}
    96  	if binary, ok := v["binary"]; ok {
    97  		return hex.DecodeString(binary)
    98  	}
    99  	return nil, errors.New("unknown protocol representation")
   100  }
   101  
   102  // beginMessage begines a new message of type t. It appends the message type and a placeholder for the message length to
   103  // dst. It returns the new buffer and the position of the message length placeholder.
   104  func beginMessage(dst []byte, t byte) ([]byte, int) {
   105  	dst = append(dst, t)
   106  	sp := len(dst)
   107  	dst = pgio.AppendInt32(dst, -1)
   108  	return dst, sp
   109  }
   110  
   111  // finishMessage finishes a message that was started with beginMessage. It computes the message length and writes it to
   112  // dst[sp]. If the message length is too large it returns an error. Otherwise it returns the final message buffer.
   113  func finishMessage(dst []byte, sp int) ([]byte, error) {
   114  	messageBodyLen := len(dst[sp:])
   115  	if messageBodyLen > maxMessageBodyLen {
   116  		return nil, errors.New("message body too large")
   117  	}
   118  	pgio.SetInt32(dst[sp:], int32(messageBodyLen))
   119  	return dst, nil
   120  }
   121  

View as plain text