package pgx
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgx/v5/internal/anynil"
"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5/pgtype"
)
type ExtendedQueryBuilder struct {
ParamValues [][]byte
paramValueBytes []byte
ParamFormats []int16
ResultFormats []int16
}
func (eqb *ExtendedQueryBuilder ) Build (m *pgtype .Map , sd *pgconn .StatementDescription , args []any ) error {
eqb .reset ()
anynil .NormalizeSlice (args )
if sd == nil {
return eqb .appendParamsForQueryExecModeExec (m , args )
}
if len (sd .ParamOIDs ) != len (args ) {
return fmt .Errorf ("mismatched param and argument count" )
}
for i := range args {
err := eqb .appendParam (m , sd .ParamOIDs [i ], -1 , args [i ])
if err != nil {
err = fmt .Errorf ("failed to encode args[%d]: %v" , i , err )
return err
}
}
for i := range sd .Fields {
eqb .appendResultFormat (m .FormatCodeForOID (sd .Fields [i ].DataTypeOID ))
}
return nil
}
func (eqb *ExtendedQueryBuilder ) appendParam (m *pgtype .Map , oid uint32 , format int16 , arg any ) error {
if format == -1 {
preferredFormat := eqb .chooseParameterFormatCode (m , oid , arg )
preferredErr := eqb .appendParam (m , oid , preferredFormat , arg )
if preferredErr == nil {
return nil
}
var otherFormat int16
if preferredFormat == TextFormatCode {
otherFormat = BinaryFormatCode
} else {
otherFormat = TextFormatCode
}
otherErr := eqb .appendParam (m , oid , otherFormat , arg )
if otherErr == nil {
return nil
}
return preferredErr
}
v , err := eqb .encodeExtendedParamValue (m , oid , format , arg )
if err != nil {
return err
}
eqb .ParamFormats = append (eqb .ParamFormats , format )
eqb .ParamValues = append (eqb .ParamValues , v )
return nil
}
func (eqb *ExtendedQueryBuilder ) appendResultFormat (format int16 ) {
eqb .ResultFormats = append (eqb .ResultFormats , format )
}
func (eqb *ExtendedQueryBuilder ) reset () {
eqb .ParamValues = eqb .ParamValues [0 :0 ]
eqb .paramValueBytes = eqb .paramValueBytes [0 :0 ]
eqb .ParamFormats = eqb .ParamFormats [0 :0 ]
eqb .ResultFormats = eqb .ResultFormats [0 :0 ]
if cap (eqb .ParamValues ) > 64 {
eqb .ParamValues = make ([][]byte , 0 , 64 )
}
if cap (eqb .paramValueBytes ) > 256 {
eqb .paramValueBytes = make ([]byte , 0 , 256 )
}
if cap (eqb .ParamFormats ) > 64 {
eqb .ParamFormats = make ([]int16 , 0 , 64 )
}
if cap (eqb .ResultFormats ) > 64 {
eqb .ResultFormats = make ([]int16 , 0 , 64 )
}
}
func (eqb *ExtendedQueryBuilder ) encodeExtendedParamValue (m *pgtype .Map , oid uint32 , formatCode int16 , arg any ) ([]byte , error ) {
if anynil .Is (arg ) {
return nil , nil
}
if eqb .paramValueBytes == nil {
eqb .paramValueBytes = make ([]byte , 0 , 128 )
}
pos := len (eqb .paramValueBytes )
buf , err := m .Encode (oid , formatCode , arg , eqb .paramValueBytes )
if err != nil {
return nil , err
}
if buf == nil {
return nil , nil
}
eqb .paramValueBytes = buf
return eqb .paramValueBytes [pos :], nil
}
func (eqb *ExtendedQueryBuilder ) chooseParameterFormatCode (m *pgtype .Map , oid uint32 , arg any ) int16 {
switch arg .(type ) {
case string , *string :
return TextFormatCode
}
return m .FormatCodeForOID (oid )
}
func (eqb *ExtendedQueryBuilder ) appendParamsForQueryExecModeExec (m *pgtype .Map , args []any ) error {
for _ , arg := range args {
if arg == nil {
err := eqb .appendParam (m , 0 , TextFormatCode , arg )
if err != nil {
return err
}
} else {
dt , ok := m .TypeForValue (arg )
if !ok {
var tv pgtype .TextValuer
if tv , ok = arg .(pgtype .TextValuer ); ok {
t , err := tv .TextValue ()
if err != nil {
return err
}
dt , ok = m .TypeForOID (pgtype .TextOID )
if ok {
arg = t
}
}
}
if !ok {
var dv driver .Valuer
if dv , ok = arg .(driver .Valuer ); ok {
v , err := dv .Value ()
if err != nil {
return err
}
dt , ok = m .TypeForValue (v )
if ok {
arg = v
}
}
}
if !ok {
var str fmt .Stringer
if str , ok = arg .(fmt .Stringer ); ok {
dt , ok = m .TypeForOID (pgtype .TextOID )
if ok {
arg = str .String ()
}
}
}
if !ok {
return &unknownArgumentTypeQueryExecModeExecError {arg : arg }
}
err := eqb .appendParam (m , dt .OID , TextFormatCode , arg )
if err != nil {
return err
}
}
}
return nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .