mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-24 20:56:39 +00:00
103 lines
3.5 KiB
Go
103 lines
3.5 KiB
Go
package pgproto3
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"math"
|
|
|
|
"github.com/jackc/pgx/v5/internal/pgio"
|
|
)
|
|
|
|
type FunctionCall struct {
|
|
Function uint32
|
|
ArgFormatCodes []uint16
|
|
Arguments [][]byte
|
|
ResultFormatCode uint16
|
|
}
|
|
|
|
// Frontend identifies this message as sendable by a PostgreSQL frontend.
|
|
func (*FunctionCall) Frontend() {}
|
|
|
|
// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
|
|
// type identifier and 4 byte message length.
|
|
func (dst *FunctionCall) Decode(src []byte) error {
|
|
*dst = FunctionCall{}
|
|
rp := 0
|
|
// Specifies the object ID of the function to call.
|
|
dst.Function = binary.BigEndian.Uint32(src[rp:])
|
|
rp += 4
|
|
// The number of argument format codes that follow (denoted C below).
|
|
// This can be zero to indicate that there are no arguments or that the arguments all use the default format (text);
|
|
// or one, in which case the specified format code is applied to all arguments;
|
|
// or it can equal the actual number of arguments.
|
|
nArgumentCodes := int(binary.BigEndian.Uint16(src[rp:]))
|
|
rp += 2
|
|
argumentCodes := make([]uint16, nArgumentCodes)
|
|
for i := 0; i < nArgumentCodes; i++ {
|
|
// The argument format codes. Each must presently be zero (text) or one (binary).
|
|
ac := binary.BigEndian.Uint16(src[rp:])
|
|
if ac != 0 && ac != 1 {
|
|
return &invalidMessageFormatErr{messageType: "FunctionCall"}
|
|
}
|
|
argumentCodes[i] = ac
|
|
rp += 2
|
|
}
|
|
dst.ArgFormatCodes = argumentCodes
|
|
|
|
// Specifies the number of arguments being supplied to the function.
|
|
nArguments := int(binary.BigEndian.Uint16(src[rp:]))
|
|
rp += 2
|
|
arguments := make([][]byte, nArguments)
|
|
for i := 0; i < nArguments; i++ {
|
|
// The length of the argument value, in bytes (this count does not include itself). Can be zero.
|
|
// As a special case, -1 indicates a NULL argument value. No value bytes follow in the NULL case.
|
|
argumentLength := int(binary.BigEndian.Uint32(src[rp:]))
|
|
rp += 4
|
|
if argumentLength == -1 {
|
|
arguments[i] = nil
|
|
} else {
|
|
// The value of the argument, in the format indicated by the associated format code. n is the above length.
|
|
argumentValue := src[rp : rp+argumentLength]
|
|
rp += argumentLength
|
|
arguments[i] = argumentValue
|
|
}
|
|
}
|
|
dst.Arguments = arguments
|
|
// The format code for the function result. Must presently be zero (text) or one (binary).
|
|
resultFormatCode := binary.BigEndian.Uint16(src[rp:])
|
|
if resultFormatCode != 0 && resultFormatCode != 1 {
|
|
return &invalidMessageFormatErr{messageType: "FunctionCall"}
|
|
}
|
|
dst.ResultFormatCode = resultFormatCode
|
|
return nil
|
|
}
|
|
|
|
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
|
|
func (src *FunctionCall) Encode(dst []byte) ([]byte, error) {
|
|
dst, sp := beginMessage(dst, 'F')
|
|
dst = pgio.AppendUint32(dst, src.Function)
|
|
|
|
if len(src.ArgFormatCodes) > math.MaxUint16 {
|
|
return nil, errors.New("too many arg format codes")
|
|
}
|
|
dst = pgio.AppendUint16(dst, uint16(len(src.ArgFormatCodes)))
|
|
for _, argFormatCode := range src.ArgFormatCodes {
|
|
dst = pgio.AppendUint16(dst, argFormatCode)
|
|
}
|
|
|
|
if len(src.Arguments) > math.MaxUint16 {
|
|
return nil, errors.New("too many arguments")
|
|
}
|
|
dst = pgio.AppendUint16(dst, uint16(len(src.Arguments)))
|
|
for _, argument := range src.Arguments {
|
|
if argument == nil {
|
|
dst = pgio.AppendInt32(dst, -1)
|
|
} else {
|
|
dst = pgio.AppendInt32(dst, int32(len(argument)))
|
|
dst = append(dst, argument...)
|
|
}
|
|
}
|
|
dst = pgio.AppendUint16(dst, src.ResultFormatCode)
|
|
return finishMessage(dst, sp)
|
|
}
|