...

Source file src/github.com/jackc/pgproto3/v2/function_call.go

Documentation: github.com/jackc/pgproto3/v2

     1  package pgproto3
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"math"
     7  
     8  	"github.com/jackc/pgio"
     9  )
    10  
    11  type FunctionCall struct {
    12  	Function         uint32
    13  	ArgFormatCodes   []uint16
    14  	Arguments        [][]byte
    15  	ResultFormatCode uint16
    16  }
    17  
    18  // Frontend identifies this message as sendable by a PostgreSQL frontend.
    19  func (*FunctionCall) Frontend() {}
    20  
    21  // Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
    22  // type identifier and 4 byte message length.
    23  func (dst *FunctionCall) Decode(src []byte) error {
    24  	*dst = FunctionCall{}
    25  	rp := 0
    26  	// Specifies the object ID of the function to call.
    27  	dst.Function = binary.BigEndian.Uint32(src[rp:])
    28  	rp += 4
    29  	// The number of argument format codes that follow (denoted C below).
    30  	// This can be zero to indicate that there are no arguments or that the arguments all use the default format (text);
    31  	// or one, in which case the specified format code is applied to all arguments;
    32  	// or it can equal the actual number of arguments.
    33  	nArgumentCodes := int(binary.BigEndian.Uint16(src[rp:]))
    34  	rp += 2
    35  	argumentCodes := make([]uint16, nArgumentCodes)
    36  	for i := 0; i < nArgumentCodes; i++ {
    37  		// The argument format codes. Each must presently be zero (text) or one (binary).
    38  		ac := binary.BigEndian.Uint16(src[rp:])
    39  		if ac != 0 && ac != 1 {
    40  			return &invalidMessageFormatErr{messageType: "FunctionCall"}
    41  		}
    42  		argumentCodes[i] = ac
    43  		rp += 2
    44  	}
    45  	dst.ArgFormatCodes = argumentCodes
    46  
    47  	// Specifies the number of arguments being supplied to the function.
    48  	nArguments := int(binary.BigEndian.Uint16(src[rp:]))
    49  	rp += 2
    50  	arguments := make([][]byte, nArguments)
    51  	for i := 0; i < nArguments; i++ {
    52  		// The length of the argument value, in bytes (this count does not include itself). Can be zero.
    53  		// As a special case, -1 indicates a NULL argument value. No value bytes follow in the NULL case.
    54  		argumentLength := int(binary.BigEndian.Uint32(src[rp:]))
    55  		rp += 4
    56  		if argumentLength == -1 {
    57  			arguments[i] = nil
    58  		} else {
    59  			// The value of the argument, in the format indicated by the associated format code. n is the above length.
    60  			argumentValue := src[rp : rp+argumentLength]
    61  			rp += argumentLength
    62  			arguments[i] = argumentValue
    63  		}
    64  	}
    65  	dst.Arguments = arguments
    66  	// The format code for the function result. Must presently be zero (text) or one (binary).
    67  	resultFormatCode := binary.BigEndian.Uint16(src[rp:])
    68  	if resultFormatCode != 0 && resultFormatCode != 1 {
    69  		return &invalidMessageFormatErr{messageType: "FunctionCall"}
    70  	}
    71  	dst.ResultFormatCode = resultFormatCode
    72  	return nil
    73  }
    74  
    75  // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
    76  func (src *FunctionCall) Encode(dst []byte) ([]byte, error) {
    77  	dst, sp := beginMessage(dst, 'F')
    78  	dst = pgio.AppendUint32(dst, src.Function)
    79  
    80  	if len(src.ArgFormatCodes) > math.MaxUint16 {
    81  		return nil, errors.New("too many arg format codes")
    82  	}
    83  	dst = pgio.AppendUint16(dst, uint16(len(src.ArgFormatCodes)))
    84  	for _, argFormatCode := range src.ArgFormatCodes {
    85  		dst = pgio.AppendUint16(dst, argFormatCode)
    86  	}
    87  
    88  	if len(src.Arguments) > math.MaxUint16 {
    89  		return nil, errors.New("too many arguments")
    90  	}
    91  	dst = pgio.AppendUint16(dst, uint16(len(src.Arguments)))
    92  	for _, argument := range src.Arguments {
    93  		if argument == nil {
    94  			dst = pgio.AppendInt32(dst, -1)
    95  		} else {
    96  			dst = pgio.AppendInt32(dst, int32(len(argument)))
    97  			dst = append(dst, argument...)
    98  		}
    99  	}
   100  	dst = pgio.AppendUint16(dst, src.ResultFormatCode)
   101  	return finishMessage(dst, sp)
   102  }
   103  

View as plain text