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