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