func NewBindPacket(data []byte) (*BindPacket, error) {
	portal, data, err := readString(data)
	if err != nil {
		return nil, err
	}
	statement, data, err := readString(data)
	if err != nil {
		return nil, err
	}
	paramFormats, data, err := readUint16Array(data)
	if err != nil {
		return nil, err
	}
	paramValues, data, err := readParameterArray(data)
	if err != nil {
		return nil, err
	}
	resultFormats, _, err := readUint16Array(data)
	if err != nil {
		return nil, err
	}
	return &BindPacket{
		portal:        portal,
		statement:     statement,
		paramFormats:  paramFormats,
		paramValues:   paramValues,
		resultFormats: resultFormats,
	}, nil
}
NewBindPacket parses Bind packet from data.
package postgresql
import (
	"bytes"
	"encoding/binary"
	"errors"
	"math"
	"github.com/cossacklabs/acra/decryptor/base"
	"github.com/cossacklabs/acra/utils"
	log "github.com/sirupsen/logrus"
)
var terminator = []byte{0}
var ErrTerminatorNotFound = errors.New("invalid string, terminator not found")
var ErrPacketTruncated = errors.New("invalid packet, too short")
var ErrArrayTooBig = errors.New("array too big")
func FetchQueryFromParse(data []byte) ([]byte, error) {
	startIndex := bytes.Index(data, terminator)
	if startIndex == -1 {
		return nil, ErrTerminatorNotFound
	}
	startIndex++
	endIndex := bytes.Index(data[startIndex:], terminator)
	if endIndex == -1 {
		return nil, ErrTerminatorNotFound
	}
	endIndex += startIndex
	return data[startIndex : endIndex+1], nil
}
type objectID []byte
type paramsNum []byte
func (num paramsNum) ToInt() int {
	return int(binary.BigEndian.Uint16(num))
}
type ParsePacket struct {
	name  []byte
	query []byte
	paramsNum paramsNum
	params []objectID
}
func (packet *ParsePacket) Marshal() []byte {
	output := make([]byte, 0, packet.Length())
	output = append(output, packet.name...)
	output = append(output, packet.query...)
	output = append(output, packet.paramsNum...)
	for _, param := range packet.params {
		output = append(output, param...)
	}
	return output
}
func (packet *ParsePacket) Length() int {
	return len(packet.name) + len(packet.query) + len(packet.paramsNum) + (4 * len(packet.params))
}
func (packet *ParsePacket) Name() string {
	return string(packet.name[:len(packet.name)-1])
}
func (packet *ParsePacket) QueryString() string {
	return string(packet.query[:len(packet.query)-1])
}
func (packet *ParsePacket) ReplaceQuery(newQuery string) {
	packet.query = append([]byte(newQuery), 0)
}
func (packet *ParsePacket) Zeroize() {
	utils.ZeroizeBytes(packet.query)
}
func NewParsePacket(data []byte) (*ParsePacket, error) {
	startIndex := bytes.Index(data, terminator)
	if startIndex == -1 {
		return nil, ErrTerminatorNotFound
	}
	startIndex++
	name := data[:startIndex]
	endIndex := bytes.Index(data[startIndex:], terminator)
	if endIndex == -1 {
		return nil, ErrTerminatorNotFound
	}
	endIndex += startIndex + 1
	query := data[startIndex:endIndex]
	numParams := paramsNum(data[endIndex : endIndex+2])
	endIndex += 2
	var params []objectID
	if endIndex < len(data) {
		for i := 0; i < numParams.ToInt(); i++ {
			params = append(params, data[endIndex:endIndex+4])
			endIndex += 4
		}
	}
	return &ParsePacket{
		name:      name,
		query:     query,
		paramsNum: numParams,
		params:    params,
	}, nil
}
type BindPacket struct {
	portal        string
	statement     string
	paramFormats  []uint16
	paramValues   [][]byte
	resultFormats []uint16
}
var ErrUnknownFormat = errors.New("unknown Bind packet format")
var ErrNotEnoughFormats = errors.New("format index out of range")
const (
	bindFormatText   = 0
	bindFormatBinary = 1
)
func (p *BindPacket) PortalName() string {
	return p.portal
}
func (p *BindPacket) StatementName() string {
	return p.statement
}
func (p *BindPacket) Zeroize() {
	for _, value := range p.paramValues {
		utils.ZeroizeBytes(value)
	}
}
func (p *BindPacket) GetParameters() ([]base.BoundValue, error) {
	values := make([]base.BoundValue, len(p.paramValues))
	for i := range values {
		format, err := p.parameterFormatByIndex(i)
		if err != nil {
			return nil, err
		}
		values[i] = base.NewBoundValue(p.paramValues[i], format)
	}
	return values, nil
}
func (p *BindPacket) parameterFormatByIndex(i int) (base.BoundValueFormat, error) {
	if len(p.paramFormats) == 0 {
		return base.TextFormat, nil
	}
	var format uint16
	if len(p.paramFormats) == 1 {
		format = p.paramFormats[0]
	} else if i < len(p.paramFormats) {
		format = p.paramFormats[i]
	} else {
		log.WithField("index", i).WithField("max", len(p.paramFormats)).Debug("Bind format array too short")
		return base.TextFormat, ErrNotEnoughFormats
	}
	switch format {
	case bindFormatText:
		return base.TextFormat, nil
	case bindFormatBinary:
		return base.BinaryFormat, nil
	default:
		log.WithField("index", i).WithField("format", format).Debug("Unknown Bind format")
		return base.TextFormat, ErrUnknownFormat
	}
}
func (p *BindPacket) SetParameters(values []base.BoundValue) {
	if len(values) == 0 {
		p.paramFormats = nil
		return
	}
	allSame := true
	format := base.TextFormat
	if len(values) > 0 {
		format = values[0].Format()
		for _, value := range values[1:] {
			if value.Format() != format {
				allSame = false
				break
			}
		}
	}
	if allSame {
		p.paramFormats = make([]uint16, 1)
		switch format {
		case base.TextFormat:
			p.paramFormats[0] = bindFormatText
		case base.BinaryFormat:
			p.paramFormats[0] = bindFormatBinary
		}
	} else {
		p.paramFormats = make([]uint16, len(values))
		for i := range p.paramFormats {
			switch values[i].Format() {
			case base.TextFormat:
				p.paramFormats[i] = bindFormatText
			case base.BinaryFormat:
				p.paramFormats[i] = bindFormatBinary
			}
		}
	}
	if len(values) != len(p.paramValues) {
		p.paramValues = make([][]byte, len(values))
	}
	for i := range p.paramValues {
		p.paramValues[i] = values[i].Data()
	}
}
func (p *BindPacket) MarshalInto(buffer *bytes.Buffer) (int, error) {
	var total int
	oldLength := buffer.Len()
	n, err := writeString(buffer, p.portal)
	if err != nil {
		buffer.Truncate(oldLength)
		return 0, err
	}
	total += n
	n, err = writeString(buffer, p.statement)
	if err != nil {
		buffer.Truncate(oldLength)
		return 0, err
	}
	total += n
	n, err = writeUint16Array(buffer, p.paramFormats)
	if err != nil {
		buffer.Truncate(oldLength)
		return 0, err
	}
	total += n
	n, err = writeParameterArray(buffer, p.paramValues)
	if err != nil {
		buffer.Truncate(oldLength)
		return 0, err
	}
	total += n
	n, err = writeUint16Array(buffer, p.resultFormats)
	if err != nil {
		buffer.Truncate(oldLength)
		return 0, err
	}
	total += n
	return total, nil
}