mirror of https://github.com/jackc/pgx.git
Use Go casing convention for OID
parent
73f496d7de
commit
27ab289096
18
batch.go
18
batch.go
|
@ -10,7 +10,7 @@ import (
|
||||||
type batchItem struct {
|
type batchItem struct {
|
||||||
query string
|
query string
|
||||||
arguments []interface{}
|
arguments []interface{}
|
||||||
parameterOids []pgtype.Oid
|
parameterOIDs []pgtype.OID
|
||||||
resultFormatCodes []int16
|
resultFormatCodes []int16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,14 +36,14 @@ func (b *Batch) Conn() *Conn {
|
||||||
return b.conn
|
return b.conn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue queues a query to batch b. parameterOids are required if there are
|
// Queue queues a query to batch b. parameterOIDs are required if there are
|
||||||
// parameters and query is not the name of a prepared statement.
|
// parameters and query is not the name of a prepared statement.
|
||||||
// resultFormatCodes are required if there is a result.
|
// resultFormatCodes are required if there is a result.
|
||||||
func (b *Batch) Queue(query string, arguments []interface{}, parameterOids []pgtype.Oid, resultFormatCodes []int16) {
|
func (b *Batch) Queue(query string, arguments []interface{}, parameterOIDs []pgtype.OID, resultFormatCodes []int16) {
|
||||||
b.items = append(b.items, &batchItem{
|
b.items = append(b.items, &batchItem{
|
||||||
query: query,
|
query: query,
|
||||||
arguments: arguments,
|
arguments: arguments,
|
||||||
parameterOids: parameterOids,
|
parameterOIDs: parameterOIDs,
|
||||||
resultFormatCodes: resultFormatCodes,
|
resultFormatCodes: resultFormatCodes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -76,18 +76,18 @@ func (b *Batch) Send(ctx context.Context, txOptions *TxOptions) error {
|
||||||
|
|
||||||
for _, bi := range b.items {
|
for _, bi := range b.items {
|
||||||
var psName string
|
var psName string
|
||||||
var psParameterOids []pgtype.Oid
|
var psParameterOIDs []pgtype.OID
|
||||||
|
|
||||||
if ps, ok := b.conn.preparedStatements[bi.query]; ok {
|
if ps, ok := b.conn.preparedStatements[bi.query]; ok {
|
||||||
psName = ps.Name
|
psName = ps.Name
|
||||||
psParameterOids = ps.ParameterOids
|
psParameterOIDs = ps.ParameterOIDs
|
||||||
} else {
|
} else {
|
||||||
psParameterOids = bi.parameterOids
|
psParameterOIDs = bi.parameterOIDs
|
||||||
buf = appendParse(buf, "", bi.query, psParameterOids)
|
buf = appendParse(buf, "", bi.query, psParameterOIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
buf, err = appendBind(buf, "", psName, b.conn.ConnInfo, psParameterOids, bi.arguments, bi.resultFormatCodes)
|
buf, err = appendBind(buf, "", psName, b.conn.ConnInfo, psParameterOIDs, bi.arguments, bi.resultFormatCodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,17 +24,17 @@ func TestConnBeginBatch(t *testing.T) {
|
||||||
batch := conn.BeginBatch()
|
batch := conn.BeginBatch()
|
||||||
batch.Queue("insert into ledger(description, amount) values($1, $2)",
|
batch.Queue("insert into ledger(description, amount) values($1, $2)",
|
||||||
[]interface{}{"q1", 1},
|
[]interface{}{"q1", 1},
|
||||||
[]pgtype.Oid{pgtype.VarcharOid, pgtype.Int4Oid},
|
[]pgtype.OID{pgtype.VarcharOID, pgtype.Int4OID},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
batch.Queue("insert into ledger(description, amount) values($1, $2)",
|
batch.Queue("insert into ledger(description, amount) values($1, $2)",
|
||||||
[]interface{}{"q2", 2},
|
[]interface{}{"q2", 2},
|
||||||
[]pgtype.Oid{pgtype.VarcharOid, pgtype.Int4Oid},
|
[]pgtype.OID{pgtype.VarcharOID, pgtype.Int4OID},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
batch.Queue("insert into ledger(description, amount) values($1, $2)",
|
batch.Queue("insert into ledger(description, amount) values($1, $2)",
|
||||||
[]interface{}{"q3", 3},
|
[]interface{}{"q3", 3},
|
||||||
[]pgtype.Oid{pgtype.VarcharOid, pgtype.Int4Oid},
|
[]pgtype.OID{pgtype.VarcharOID, pgtype.Int4OID},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
batch.Queue("select id, description, amount from ledger order by id",
|
batch.Queue("select id, description, amount from ledger order by id",
|
||||||
|
@ -220,7 +220,7 @@ func TestConnBeginBatchContextCancelBeforeExecResults(t *testing.T) {
|
||||||
batch := conn.BeginBatch()
|
batch := conn.BeginBatch()
|
||||||
batch.Queue("insert into ledger(description, amount) values($1, $2)",
|
batch.Queue("insert into ledger(description, amount) values($1, $2)",
|
||||||
[]interface{}{"q1", 1},
|
[]interface{}{"q1", 1},
|
||||||
[]pgtype.Oid{pgtype.VarcharOid, pgtype.Int4Oid},
|
[]pgtype.OID{pgtype.VarcharOID, pgtype.Int4OID},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
batch.Queue("select pg_sleep(2)",
|
batch.Queue("select pg_sleep(2)",
|
||||||
|
|
68
conn.go
68
conn.go
|
@ -39,11 +39,11 @@ var minimalConnInfo *pgtype.ConnInfo
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
minimalConnInfo = pgtype.NewConnInfo()
|
minimalConnInfo = pgtype.NewConnInfo()
|
||||||
minimalConnInfo.InitializeDataTypes(map[string]pgtype.Oid{
|
minimalConnInfo.InitializeDataTypes(map[string]pgtype.OID{
|
||||||
"int4": pgtype.Int4Oid,
|
"int4": pgtype.Int4OID,
|
||||||
"name": pgtype.NameOid,
|
"name": pgtype.NameOID,
|
||||||
"oid": pgtype.OidOid,
|
"oid": pgtype.OIDOID,
|
||||||
"text": pgtype.TextOid,
|
"text": pgtype.TextOID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,12 +126,12 @@ type PreparedStatement struct {
|
||||||
Name string
|
Name string
|
||||||
SQL string
|
SQL string
|
||||||
FieldDescriptions []FieldDescription
|
FieldDescriptions []FieldDescription
|
||||||
ParameterOids []pgtype.Oid
|
ParameterOIDs []pgtype.OID
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareExOptions is an option struct that can be passed to PrepareEx
|
// PrepareExOptions is an option struct that can be passed to PrepareEx
|
||||||
type PrepareExOptions struct {
|
type PrepareExOptions struct {
|
||||||
ParameterOids []pgtype.Oid
|
ParameterOIDs []pgtype.OID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notification is a message received from the PostgreSQL LISTEN/NOTIFY system
|
// Notification is a message received from the PostgreSQL LISTEN/NOTIFY system
|
||||||
|
@ -373,7 +373,7 @@ func (c *Conn) connect(config ConnConfig, network, address string, tlsConfig *tl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) initConnInfo() error {
|
func (c *Conn) initConnInfo() error {
|
||||||
nameOids := make(map[string]pgtype.Oid, 256)
|
nameOIDs := make(map[string]pgtype.OID, 256)
|
||||||
|
|
||||||
rows, err := c.Query(`select t.oid, t.typname
|
rows, err := c.Query(`select t.oid, t.typname
|
||||||
from pg_type t
|
from pg_type t
|
||||||
|
@ -387,13 +387,13 @@ where (
|
||||||
}
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var oid pgtype.Oid
|
var oid pgtype.OID
|
||||||
var name pgtype.Text
|
var name pgtype.Text
|
||||||
if err := rows.Scan(&oid, &name); err != nil {
|
if err := rows.Scan(&oid, &name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nameOids[name.String] = oid
|
nameOIDs[name.String] = oid
|
||||||
}
|
}
|
||||||
|
|
||||||
if rows.Err() != nil {
|
if rows.Err() != nil {
|
||||||
|
@ -401,7 +401,7 @@ where (
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ConnInfo = pgtype.NewConnInfo()
|
c.ConnInfo = pgtype.NewConnInfo()
|
||||||
c.ConnInfo.InitializeDataTypes(nameOids)
|
c.ConnInfo.InitializeDataTypes(nameOIDs)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -725,7 +725,7 @@ func (c *Conn) Prepare(name, sql string) (ps *PreparedStatement, err error) {
|
||||||
|
|
||||||
// PrepareEx creates a prepared statement with name and sql. sql can contain placeholders
|
// PrepareEx creates a prepared statement with name and sql. sql can contain placeholders
|
||||||
// for bound parameters. These placeholders are referenced positional as $1, $2, etc.
|
// for bound parameters. These placeholders are referenced positional as $1, $2, etc.
|
||||||
// It defers from Prepare as it allows additional options (such as parameter Oids) to be passed via struct
|
// It defers from Prepare as it allows additional options (such as parameter OIDs) to be passed via struct
|
||||||
//
|
//
|
||||||
// PrepareEx is idempotent; i.e. it is safe to call PrepareEx multiple times with the same
|
// PrepareEx is idempotent; i.e. it is safe to call PrepareEx multiple times with the same
|
||||||
// name and sql arguments. This allows a code path to PrepareEx and Query/Exec without
|
// name and sql arguments. This allows a code path to PrepareEx and Query/Exec without
|
||||||
|
@ -769,11 +769,11 @@ func (c *Conn) prepareEx(name, sql string, opts *PrepareExOptions) (ps *Prepared
|
||||||
opts = &PrepareExOptions{}
|
opts = &PrepareExOptions{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.ParameterOids) > 65535 {
|
if len(opts.ParameterOIDs) > 65535 {
|
||||||
return nil, fmt.Errorf("Number of PrepareExOptions ParameterOids must be between 0 and 65535, received %d", len(opts.ParameterOids))
|
return nil, fmt.Errorf("Number of PrepareExOptions ParameterOIDs must be between 0 and 65535, received %d", len(opts.ParameterOIDs))
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := appendParse(c.wbuf, name, sql, opts.ParameterOids)
|
buf := appendParse(c.wbuf, name, sql, opts.ParameterOIDs)
|
||||||
buf = appendDescribe(buf, 'S', name)
|
buf = appendDescribe(buf, 'S', name)
|
||||||
buf = appendSync(buf)
|
buf = appendSync(buf)
|
||||||
|
|
||||||
|
@ -798,15 +798,15 @@ func (c *Conn) prepareEx(name, sql string, opts *PrepareExOptions) (ps *Prepared
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case *pgproto3.ParameterDescription:
|
case *pgproto3.ParameterDescription:
|
||||||
ps.ParameterOids = c.rxParameterDescription(msg)
|
ps.ParameterOIDs = c.rxParameterDescription(msg)
|
||||||
|
|
||||||
if len(ps.ParameterOids) > 65535 && softErr == nil {
|
if len(ps.ParameterOIDs) > 65535 && softErr == nil {
|
||||||
softErr = fmt.Errorf("PostgreSQL supports maximum of 65535 parameters, received %d", len(ps.ParameterOids))
|
softErr = fmt.Errorf("PostgreSQL supports maximum of 65535 parameters, received %d", len(ps.ParameterOIDs))
|
||||||
}
|
}
|
||||||
case *pgproto3.RowDescription:
|
case *pgproto3.RowDescription:
|
||||||
ps.FieldDescriptions = c.rxRowDescription(msg)
|
ps.FieldDescriptions = c.rxRowDescription(msg)
|
||||||
for i := range ps.FieldDescriptions {
|
for i := range ps.FieldDescriptions {
|
||||||
if dt, ok := c.ConnInfo.DataTypeForOid(ps.FieldDescriptions[i].DataType); ok {
|
if dt, ok := c.ConnInfo.DataTypeForOID(ps.FieldDescriptions[i].DataType); ok {
|
||||||
ps.FieldDescriptions[i].DataTypeName = dt.Name
|
ps.FieldDescriptions[i].DataTypeName = dt.Name
|
||||||
if _, ok := dt.Value.(pgtype.BinaryDecoder); ok {
|
if _, ok := dt.Value.(pgtype.BinaryDecoder); ok {
|
||||||
ps.FieldDescriptions[i].FormatCode = BinaryFormatCode
|
ps.FieldDescriptions[i].FormatCode = BinaryFormatCode
|
||||||
|
@ -1020,8 +1020,8 @@ func (c *Conn) sendSimpleQuery(sql string, args ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{}) (err error) {
|
func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{}) (err error) {
|
||||||
if len(ps.ParameterOids) != len(arguments) {
|
if len(ps.ParameterOIDs) != len(arguments) {
|
||||||
return fmt.Errorf("Prepared statement \"%v\" requires %d parameters, but %d were provided", ps.Name, len(ps.ParameterOids), len(arguments))
|
return fmt.Errorf("Prepared statement \"%v\" requires %d parameters, but %d were provided", ps.Name, len(ps.ParameterOIDs), len(arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.ensureConnectionReadyForQuery(); err != nil {
|
if err := c.ensureConnectionReadyForQuery(); err != nil {
|
||||||
|
@ -1032,7 +1032,7 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{}
|
||||||
for i, fd := range ps.FieldDescriptions {
|
for i, fd := range ps.FieldDescriptions {
|
||||||
resultFormatCodes[i] = fd.FormatCode
|
resultFormatCodes[i] = fd.FormatCode
|
||||||
}
|
}
|
||||||
buf, err := appendBind(c.wbuf, "", ps.Name, c.ConnInfo, ps.ParameterOids, arguments, resultFormatCodes)
|
buf, err := appendBind(c.wbuf, "", ps.Name, c.ConnInfo, ps.ParameterOIDs, arguments, resultFormatCodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1177,9 +1177,9 @@ func (c *Conn) rxRowDescription(msg *pgproto3.RowDescription) []FieldDescription
|
||||||
fields := make([]FieldDescription, len(msg.Fields))
|
fields := make([]FieldDescription, len(msg.Fields))
|
||||||
for i := 0; i < len(fields); i++ {
|
for i := 0; i < len(fields); i++ {
|
||||||
fields[i].Name = msg.Fields[i].Name
|
fields[i].Name = msg.Fields[i].Name
|
||||||
fields[i].Table = pgtype.Oid(msg.Fields[i].TableOID)
|
fields[i].Table = pgtype.OID(msg.Fields[i].TableOID)
|
||||||
fields[i].AttributeNumber = msg.Fields[i].TableAttributeNumber
|
fields[i].AttributeNumber = msg.Fields[i].TableAttributeNumber
|
||||||
fields[i].DataType = pgtype.Oid(msg.Fields[i].DataTypeOID)
|
fields[i].DataType = pgtype.OID(msg.Fields[i].DataTypeOID)
|
||||||
fields[i].DataTypeSize = msg.Fields[i].DataTypeSize
|
fields[i].DataTypeSize = msg.Fields[i].DataTypeSize
|
||||||
fields[i].Modifier = msg.Fields[i].TypeModifier
|
fields[i].Modifier = msg.Fields[i].TypeModifier
|
||||||
fields[i].FormatCode = msg.Fields[i].Format
|
fields[i].FormatCode = msg.Fields[i].Format
|
||||||
|
@ -1187,10 +1187,10 @@ func (c *Conn) rxRowDescription(msg *pgproto3.RowDescription) []FieldDescription
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) rxParameterDescription(msg *pgproto3.ParameterDescription) []pgtype.Oid {
|
func (c *Conn) rxParameterDescription(msg *pgproto3.ParameterDescription) []pgtype.OID {
|
||||||
parameters := make([]pgtype.Oid, len(msg.ParameterOIDs))
|
parameters := make([]pgtype.OID, len(msg.ParameterOIDs))
|
||||||
for i := 0; i < len(parameters); i++ {
|
for i := 0; i < len(parameters); i++ {
|
||||||
parameters[i] = pgtype.Oid(msg.ParameterOIDs[i])
|
parameters[i] = pgtype.OID(msg.ParameterOIDs[i])
|
||||||
}
|
}
|
||||||
return parameters
|
return parameters
|
||||||
}
|
}
|
||||||
|
@ -1418,7 +1418,7 @@ func (c *Conn) execEx(ctx context.Context, sql string, options *QueryExOptions,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
} else if options != nil && len(options.ParameterOids) > 0 {
|
} else if options != nil && len(options.ParameterOIDs) > 0 {
|
||||||
buf, err := c.buildOneRoundTripExec(c.wbuf, sql, options, arguments)
|
buf, err := c.buildOneRoundTripExec(c.wbuf, sql, options, arguments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -1477,16 +1477,16 @@ func (c *Conn) execEx(ctx context.Context, sql string, options *QueryExOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) buildOneRoundTripExec(buf []byte, sql string, options *QueryExOptions, arguments []interface{}) ([]byte, error) {
|
func (c *Conn) buildOneRoundTripExec(buf []byte, sql string, options *QueryExOptions, arguments []interface{}) ([]byte, error) {
|
||||||
if len(arguments) != len(options.ParameterOids) {
|
if len(arguments) != len(options.ParameterOIDs) {
|
||||||
return nil, fmt.Errorf("mismatched number of arguments (%d) and options.ParameterOids (%d)", len(arguments), len(options.ParameterOids))
|
return nil, fmt.Errorf("mismatched number of arguments (%d) and options.ParameterOIDs (%d)", len(arguments), len(options.ParameterOIDs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(options.ParameterOids) > 65535 {
|
if len(options.ParameterOIDs) > 65535 {
|
||||||
return nil, fmt.Errorf("Number of QueryExOptions ParameterOids must be between 0 and 65535, received %d", len(options.ParameterOids))
|
return nil, fmt.Errorf("Number of QueryExOptions ParameterOIDs must be between 0 and 65535, received %d", len(options.ParameterOIDs))
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = appendParse(buf, "", sql, options.ParameterOids)
|
buf = appendParse(buf, "", sql, options.ParameterOIDs)
|
||||||
buf, err := appendBind(buf, "", "", c.ConnInfo, options.ParameterOids, arguments, nil)
|
buf, err := appendBind(buf, "", "", c.ConnInfo, options.ParameterOIDs, arguments, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -434,7 +434,7 @@ func (p *ConnPool) Prepare(name, sql string) (*PreparedStatement, error) {
|
||||||
//
|
//
|
||||||
// PrepareEx creates a prepared statement with name and sql. sql can contain placeholders
|
// PrepareEx creates a prepared statement with name and sql. sql can contain placeholders
|
||||||
// for bound parameters. These placeholders are referenced positional as $1, $2, etc.
|
// for bound parameters. These placeholders are referenced positional as $1, $2, etc.
|
||||||
// It defers from Prepare as it allows additional options (such as parameter Oids) to be passed via struct
|
// It defers from Prepare as it allows additional options (such as parameter OIDs) to be passed via struct
|
||||||
//
|
//
|
||||||
// PrepareEx is idempotent; i.e. it is safe to call PrepareEx multiple times with the same
|
// PrepareEx is idempotent; i.e. it is safe to call PrepareEx multiple times with the same
|
||||||
// name and sql arguments. This allows a code path to PrepareEx and Query/Exec/Prepare without
|
// name and sql arguments. This allows a code path to PrepareEx and Query/Exec/Prepare without
|
||||||
|
|
|
@ -1166,7 +1166,7 @@ func TestConnExecExSuppliedCorrectParameterOIDs(t *testing.T) {
|
||||||
commandTag, err := conn.ExecEx(
|
commandTag, err := conn.ExecEx(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
"insert into foo(name) values($1);",
|
"insert into foo(name) values($1);",
|
||||||
&pgx.QueryExOptions{ParameterOids: []pgtype.Oid{pgtype.VarcharOid}},
|
&pgx.QueryExOptions{ParameterOIDs: []pgtype.OID{pgtype.VarcharOID}},
|
||||||
"bar'; drop table foo;--",
|
"bar'; drop table foo;--",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1188,7 +1188,7 @@ func TestConnExecExSuppliedIncorrectParameterOIDs(t *testing.T) {
|
||||||
_, err := conn.ExecEx(
|
_, err := conn.ExecEx(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
"insert into foo(name) values($1);",
|
"insert into foo(name) values($1);",
|
||||||
&pgx.QueryExOptions{ParameterOids: []pgtype.Oid{pgtype.Int4Oid}},
|
&pgx.QueryExOptions{ParameterOIDs: []pgtype.OID{pgtype.Int4OID}},
|
||||||
"bar'; drop table foo;--",
|
"bar'; drop table foo;--",
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -1367,7 +1367,7 @@ func TestPrepareEx(t *testing.T) {
|
||||||
conn := mustConnect(t, *defaultConnConfig)
|
conn := mustConnect(t, *defaultConnConfig)
|
||||||
defer closeConn(t, conn)
|
defer closeConn(t, conn)
|
||||||
|
|
||||||
_, err := conn.PrepareEx(context.Background(), "test", "select $1", &pgx.PrepareExOptions{ParameterOids: []pgtype.Oid{pgtype.TextOid}})
|
_, err := conn.PrepareEx(context.Background(), "test", "select $1", &pgx.PrepareExOptions{ParameterOIDs: []pgtype.OID{pgtype.TextOID}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unable to prepare statement: %v", err)
|
t.Errorf("Unable to prepare statement: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -81,7 +81,7 @@ func Example_CustomType() {
|
||||||
conn.ConnInfo.RegisterDataType(pgtype.DataType{
|
conn.ConnInfo.RegisterDataType(pgtype.DataType{
|
||||||
Value: &Point{},
|
Value: &Point{},
|
||||||
Name: "point",
|
Name: "point",
|
||||||
Oid: 600,
|
OID: 600,
|
||||||
})
|
})
|
||||||
|
|
||||||
p := &Point{}
|
p := &Point{}
|
||||||
|
|
14
fastpath.go
14
fastpath.go
|
@ -9,26 +9,26 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func newFastpath(cn *Conn) *fastpath {
|
func newFastpath(cn *Conn) *fastpath {
|
||||||
return &fastpath{cn: cn, fns: make(map[string]pgtype.Oid)}
|
return &fastpath{cn: cn, fns: make(map[string]pgtype.OID)}
|
||||||
}
|
}
|
||||||
|
|
||||||
type fastpath struct {
|
type fastpath struct {
|
||||||
cn *Conn
|
cn *Conn
|
||||||
fns map[string]pgtype.Oid
|
fns map[string]pgtype.OID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fastpath) functionOid(name string) pgtype.Oid {
|
func (f *fastpath) functionOID(name string) pgtype.OID {
|
||||||
return f.fns[name]
|
return f.fns[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fastpath) addFunction(name string, oid pgtype.Oid) {
|
func (f *fastpath) addFunction(name string, oid pgtype.OID) {
|
||||||
f.fns[name] = oid
|
f.fns[name] = oid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fastpath) addFunctions(rows *Rows) error {
|
func (f *fastpath) addFunctions(rows *Rows) error {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var name string
|
var name string
|
||||||
var oid pgtype.Oid
|
var oid pgtype.OID
|
||||||
if err := rows.Scan(&name, &oid); err != nil {
|
if err := rows.Scan(&name, &oid); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func fpInt64Arg(n int64) fpArg {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fastpath) Call(oid pgtype.Oid, args []fpArg) (res []byte, err error) {
|
func (f *fastpath) Call(oid pgtype.OID, args []fpArg) (res []byte, err error) {
|
||||||
if err := f.cn.ensureConnectionReadyForQuery(); err != nil {
|
if err := f.cn.ensureConnectionReadyForQuery(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ func (f *fastpath) Call(oid pgtype.Oid, args []fpArg) (res []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fastpath) CallFn(fn string, args []fpArg) ([]byte, error) {
|
func (f *fastpath) CallFn(fn string, args []fpArg) ([]byte, error) {
|
||||||
return f.Call(f.functionOid(fn), args)
|
return f.Call(f.functionOID(fn), args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fpInt32(data []byte, err error) (int32, error) {
|
func fpInt32(data []byte, err error) (int32, error) {
|
||||||
|
|
|
@ -61,20 +61,20 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create creates a new large object. If id is zero, the server assigns an
|
// Create creates a new large object. If id is zero, the server assigns an
|
||||||
// unused Oid.
|
// unused OID.
|
||||||
func (o *LargeObjects) Create(id pgtype.Oid) (pgtype.Oid, error) {
|
func (o *LargeObjects) Create(id pgtype.OID) (pgtype.OID, error) {
|
||||||
newOid, err := fpInt32(o.fp.CallFn("lo_create", []fpArg{fpIntArg(int32(id))}))
|
newOID, err := fpInt32(o.fp.CallFn("lo_create", []fpArg{fpIntArg(int32(id))}))
|
||||||
return pgtype.Oid(newOid), err
|
return pgtype.OID(newOID), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens an existing large object with the given mode.
|
// Open opens an existing large object with the given mode.
|
||||||
func (o *LargeObjects) Open(oid pgtype.Oid, mode LargeObjectMode) (*LargeObject, error) {
|
func (o *LargeObjects) Open(oid pgtype.OID, mode LargeObjectMode) (*LargeObject, error) {
|
||||||
fd, err := fpInt32(o.fp.CallFn("lo_open", []fpArg{fpIntArg(int32(oid)), fpIntArg(int32(mode))}))
|
fd, err := fpInt32(o.fp.CallFn("lo_open", []fpArg{fpIntArg(int32(oid)), fpIntArg(int32(mode))}))
|
||||||
return &LargeObject{fd: fd, lo: o}, err
|
return &LargeObject{fd: fd, lo: o}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlink removes a large object from the database.
|
// Unlink removes a large object from the database.
|
||||||
func (o *LargeObjects) Unlink(oid pgtype.Oid) error {
|
func (o *LargeObjects) Unlink(oid pgtype.OID) error {
|
||||||
_, err := o.fp.CallFn("lo_unlink", []fpArg{fpIntArg(int32(oid))})
|
_, err := o.fp.CallFn("lo_unlink", []fpArg{fpIntArg(int32(oid))})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ const (
|
||||||
|
|
||||||
type FieldDescription struct {
|
type FieldDescription struct {
|
||||||
Name string
|
Name string
|
||||||
Table pgtype.Oid
|
Table pgtype.OID
|
||||||
AttributeNumber uint16
|
AttributeNumber uint16
|
||||||
DataType pgtype.Oid
|
DataType pgtype.OID
|
||||||
DataTypeSize int16
|
DataTypeSize int16
|
||||||
DataTypeName string
|
DataTypeName string
|
||||||
Modifier uint32
|
Modifier uint32
|
||||||
|
@ -50,7 +50,7 @@ func (pe PgError) Error() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendParse appends a PostgreSQL wire protocol parse message to buf and returns it.
|
// appendParse appends a PostgreSQL wire protocol parse message to buf and returns it.
|
||||||
func appendParse(buf []byte, name string, query string, parameterOIDs []pgtype.Oid) []byte {
|
func appendParse(buf []byte, name string, query string, parameterOIDs []pgtype.OID) []byte {
|
||||||
buf = append(buf, 'P')
|
buf = append(buf, 'P')
|
||||||
sp := len(buf)
|
sp := len(buf)
|
||||||
buf = pgio.AppendInt32(buf, -1)
|
buf = pgio.AppendInt32(buf, -1)
|
||||||
|
@ -95,7 +95,7 @@ func appendBind(
|
||||||
destinationPortal,
|
destinationPortal,
|
||||||
preparedStatement string,
|
preparedStatement string,
|
||||||
connInfo *pgtype.ConnInfo,
|
connInfo *pgtype.ConnInfo,
|
||||||
parameterOIDs []pgtype.Oid,
|
parameterOIDs []pgtype.OID,
|
||||||
arguments []interface{},
|
arguments []interface{},
|
||||||
resultFormatCodes []int16,
|
resultFormatCodes []int16,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
|
|
|
@ -242,7 +242,7 @@ func PgxInitSteps() []Step {
|
||||||
}
|
}
|
||||||
|
|
||||||
rowVals := []struct {
|
rowVals := []struct {
|
||||||
oid pgtype.Oid
|
oid pgtype.OID
|
||||||
name string
|
name string
|
||||||
}{
|
}{
|
||||||
{16, "bool"},
|
{16, "bool"},
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
type ArrayHeader struct {
|
type ArrayHeader struct {
|
||||||
ContainsNull bool
|
ContainsNull bool
|
||||||
ElementOid int32
|
ElementOID int32
|
||||||
Dimensions []ArrayDimension
|
Dimensions []ArrayDimension
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ func (dst *ArrayHeader) DecodeBinary(ci *ConnInfo, src []byte) (int, error) {
|
||||||
dst.ContainsNull = binary.BigEndian.Uint32(src[rp:]) == 1
|
dst.ContainsNull = binary.BigEndian.Uint32(src[rp:]) == 1
|
||||||
rp += 4
|
rp += 4
|
||||||
|
|
||||||
dst.ElementOid = int32(binary.BigEndian.Uint32(src[rp:]))
|
dst.ElementOID = int32(binary.BigEndian.Uint32(src[rp:]))
|
||||||
rp += 4
|
rp += 4
|
||||||
|
|
||||||
if numDims > 0 {
|
if numDims > 0 {
|
||||||
|
@ -69,7 +69,7 @@ func (src *ArrayHeader) EncodeBinary(ci *ConnInfo, buf []byte) []byte {
|
||||||
}
|
}
|
||||||
buf = pgio.AppendInt32(buf, containsNull)
|
buf = pgio.AppendInt32(buf, containsNull)
|
||||||
|
|
||||||
buf = pgio.AppendInt32(buf, src.ElementOid)
|
buf = pgio.AppendInt32(buf, src.ElementOID)
|
||||||
|
|
||||||
for i := range src.Dimensions {
|
for i := range src.Dimensions {
|
||||||
buf = pgio.AppendInt32(buf, src.Dimensions[i].Length)
|
buf = pgio.AppendInt32(buf, src.Dimensions[i].Length)
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (src *BoolArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("bool"); ok {
|
if dt, ok := ci.DataTypeForName("bool"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "bool")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "bool")
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (src *ByteaArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("bytea"); ok {
|
if dt, ok := ci.DataTypeForName("bytea"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "bytea")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "bytea")
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,7 +260,7 @@ func (src *CidrArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("cidr"); ok {
|
if dt, ok := ci.DataTypeForName("cidr"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "cidr")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "cidr")
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,7 +232,7 @@ func (src *DateArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("date"); ok {
|
if dt, ok := ci.DataTypeForName("date"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "date")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "date")
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (src *Float4Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("float4"); ok {
|
if dt, ok := ci.DataTypeForName("float4"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "float4")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "float4")
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (src *Float8Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("float8"); ok {
|
if dt, ok := ci.DataTypeForName("float8"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "float8")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "float8")
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (src *HstoreArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("hstore"); ok {
|
if dt, ok := ci.DataTypeForName("hstore"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "hstore")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "hstore")
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,7 +260,7 @@ func (src *InetArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("inet"); ok {
|
if dt, ok := ci.DataTypeForName("inet"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "inet")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "inet")
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ func (src *Int2Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("int2"); ok {
|
if dt, ok := ci.DataTypeForName("int2"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "int2")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "int2")
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ func (src *Int4Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("int4"); ok {
|
if dt, ok := ci.DataTypeForName("int4"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "int4")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "int4")
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ func (src *Int8Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("int8"); ok {
|
if dt, ok := ci.DataTypeForName("int8"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "int8")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "int8")
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ func (src *NumericArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("numeric"); ok {
|
if dt, ok := ci.DataTypeForName("numeric"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "numeric")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "numeric")
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,18 @@ import (
|
||||||
"github.com/jackc/pgx/pgio"
|
"github.com/jackc/pgx/pgio"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Oid (Object Identifier Type) is, according to
|
// OID (Object Identifier Type) is, according to
|
||||||
// https://www.postgresql.org/docs/current/static/datatype-oid.html, used
|
// https://www.postgresql.org/docs/current/static/datatype-oid.html, used
|
||||||
// internally by PostgreSQL as a primary key for various system tables. It is
|
// internally by PostgreSQL as a primary key for various system tables. It is
|
||||||
// currently implemented as an unsigned four-byte integer. Its definition can be
|
// currently implemented as an unsigned four-byte integer. Its definition can be
|
||||||
// found in src/include/postgres_ext.h in the PostgreSQL sources. Because it is
|
// found in src/include/postgres_ext.h in the PostgreSQL sources. Because it is
|
||||||
// so frequently required to be in a NOT NULL condition Oid cannot be NULL. To
|
// so frequently required to be in a NOT NULL condition OID cannot be NULL. To
|
||||||
// allow for NULL Oids use OidValue.
|
// allow for NULL OIDs use OIDValue.
|
||||||
type Oid uint32
|
type OID uint32
|
||||||
|
|
||||||
func (dst *Oid) DecodeText(ci *ConnInfo, src []byte) error {
|
func (dst *OID) DecodeText(ci *ConnInfo, src []byte) error {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
return fmt.Errorf("cannot decode nil into Oid")
|
return fmt.Errorf("cannot decode nil into OID")
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := strconv.ParseUint(string(src), 10, 32)
|
n, err := strconv.ParseUint(string(src), 10, 32)
|
||||||
|
@ -28,13 +28,13 @@ func (dst *Oid) DecodeText(ci *ConnInfo, src []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst = Oid(n)
|
*dst = OID(n)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dst *Oid) DecodeBinary(ci *ConnInfo, src []byte) error {
|
func (dst *OID) DecodeBinary(ci *ConnInfo, src []byte) error {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
return fmt.Errorf("cannot decode nil into Oid")
|
return fmt.Errorf("cannot decode nil into OID")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src) != 4 {
|
if len(src) != 4 {
|
||||||
|
@ -42,27 +42,27 @@ func (dst *Oid) DecodeBinary(ci *ConnInfo, src []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
n := binary.BigEndian.Uint32(src)
|
n := binary.BigEndian.Uint32(src)
|
||||||
*dst = Oid(n)
|
*dst = OID(n)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Oid) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
|
func (src OID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
return append(buf, strconv.FormatUint(uint64(src), 10)...), nil
|
return append(buf, strconv.FormatUint(uint64(src), 10)...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src Oid) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
func (src OID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
return pgio.AppendUint32(buf, uint32(src)), nil
|
return pgio.AppendUint32(buf, uint32(src)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan implements the database/sql Scanner interface.
|
// Scan implements the database/sql Scanner interface.
|
||||||
func (dst *Oid) Scan(src interface{}) error {
|
func (dst *OID) Scan(src interface{}) error {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
return fmt.Errorf("cannot scan NULL into %T", src)
|
return fmt.Errorf("cannot scan NULL into %T", src)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch src := src.(type) {
|
switch src := src.(type) {
|
||||||
case int64:
|
case int64:
|
||||||
*dst = Oid(src)
|
*dst = OID(src)
|
||||||
return nil
|
return nil
|
||||||
case string:
|
case string:
|
||||||
return dst.DecodeText(nil, []byte(src))
|
return dst.DecodeText(nil, []byte(src))
|
||||||
|
@ -76,6 +76,6 @@ func (dst *Oid) Scan(src interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value implements the database/sql/driver Valuer interface.
|
// Value implements the database/sql/driver Valuer interface.
|
||||||
func (src Oid) Value() (driver.Value, error) {
|
func (src OID) Value() (driver.Value, error) {
|
||||||
return int64(src), nil
|
return int64(src), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,52 +4,52 @@ import (
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OidValue (Object Identifier Type) is, according to
|
// OIDValue (Object Identifier Type) is, according to
|
||||||
// https://www.postgresql.org/docs/current/static/datatype-OidValue.html, used
|
// https://www.postgresql.org/docs/current/static/datatype-OIDValue.html, used
|
||||||
// internally by PostgreSQL as a primary key for various system tables. It is
|
// internally by PostgreSQL as a primary key for various system tables. It is
|
||||||
// currently implemented as an unsigned four-byte integer. Its definition can be
|
// currently implemented as an unsigned four-byte integer. Its definition can be
|
||||||
// found in src/include/postgres_ext.h in the PostgreSQL sources.
|
// found in src/include/postgres_ext.h in the PostgreSQL sources.
|
||||||
type OidValue pguint32
|
type OIDValue pguint32
|
||||||
|
|
||||||
// Set converts from src to dst. Note that as OidValue is not a general
|
// Set converts from src to dst. Note that as OIDValue is not a general
|
||||||
// number type Set does not do automatic type conversion as other number
|
// number type Set does not do automatic type conversion as other number
|
||||||
// types do.
|
// types do.
|
||||||
func (dst *OidValue) Set(src interface{}) error {
|
func (dst *OIDValue) Set(src interface{}) error {
|
||||||
return (*pguint32)(dst).Set(src)
|
return (*pguint32)(dst).Set(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dst *OidValue) Get() interface{} {
|
func (dst *OIDValue) Get() interface{} {
|
||||||
return (*pguint32)(dst).Get()
|
return (*pguint32)(dst).Get()
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssignTo assigns from src to dst. Note that as OidValue is not a general number
|
// AssignTo assigns from src to dst. Note that as OIDValue is not a general number
|
||||||
// type AssignTo does not do automatic type conversion as other number types do.
|
// type AssignTo does not do automatic type conversion as other number types do.
|
||||||
func (src *OidValue) AssignTo(dst interface{}) error {
|
func (src *OIDValue) AssignTo(dst interface{}) error {
|
||||||
return (*pguint32)(src).AssignTo(dst)
|
return (*pguint32)(src).AssignTo(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dst *OidValue) DecodeText(ci *ConnInfo, src []byte) error {
|
func (dst *OIDValue) DecodeText(ci *ConnInfo, src []byte) error {
|
||||||
return (*pguint32)(dst).DecodeText(ci, src)
|
return (*pguint32)(dst).DecodeText(ci, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dst *OidValue) DecodeBinary(ci *ConnInfo, src []byte) error {
|
func (dst *OIDValue) DecodeBinary(ci *ConnInfo, src []byte) error {
|
||||||
return (*pguint32)(dst).DecodeBinary(ci, src)
|
return (*pguint32)(dst).DecodeBinary(ci, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *OidValue) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
|
func (src *OIDValue) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
return (*pguint32)(src).EncodeText(ci, buf)
|
return (*pguint32)(src).EncodeText(ci, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *OidValue) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
func (src *OIDValue) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
return (*pguint32)(src).EncodeBinary(ci, buf)
|
return (*pguint32)(src).EncodeBinary(ci, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan implements the database/sql Scanner interface.
|
// Scan implements the database/sql Scanner interface.
|
||||||
func (dst *OidValue) Scan(src interface{}) error {
|
func (dst *OIDValue) Scan(src interface{}) error {
|
||||||
return (*pguint32)(dst).Scan(src)
|
return (*pguint32)(dst).Scan(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value implements the database/sql/driver Valuer interface.
|
// Value implements the database/sql/driver Valuer interface.
|
||||||
func (src *OidValue) Value() (driver.Value, error) {
|
func (src *OIDValue) Value() (driver.Value, error) {
|
||||||
return (*pguint32)(src).Value()
|
return (*pguint32)(src).Value()
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,23 +8,23 @@ import (
|
||||||
"github.com/jackc/pgx/pgtype/testutil"
|
"github.com/jackc/pgx/pgtype/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOidValueTranscode(t *testing.T) {
|
func TestOIDValueTranscode(t *testing.T) {
|
||||||
testutil.TestSuccessfulTranscode(t, "oid", []interface{}{
|
testutil.TestSuccessfulTranscode(t, "oid", []interface{}{
|
||||||
&pgtype.OidValue{Uint: 42, Status: pgtype.Present},
|
&pgtype.OIDValue{Uint: 42, Status: pgtype.Present},
|
||||||
&pgtype.OidValue{Status: pgtype.Null},
|
&pgtype.OIDValue{Status: pgtype.Null},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOidValueSet(t *testing.T) {
|
func TestOIDValueSet(t *testing.T) {
|
||||||
successfulTests := []struct {
|
successfulTests := []struct {
|
||||||
source interface{}
|
source interface{}
|
||||||
result pgtype.OidValue
|
result pgtype.OIDValue
|
||||||
}{
|
}{
|
||||||
{source: uint32(1), result: pgtype.OidValue{Uint: 1, Status: pgtype.Present}},
|
{source: uint32(1), result: pgtype.OIDValue{Uint: 1, Status: pgtype.Present}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range successfulTests {
|
for i, tt := range successfulTests {
|
||||||
var r pgtype.OidValue
|
var r pgtype.OIDValue
|
||||||
err := r.Set(tt.source)
|
err := r.Set(tt.source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d: %v", i, err)
|
t.Errorf("%d: %v", i, err)
|
||||||
|
@ -36,17 +36,17 @@ func TestOidValueSet(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOidValueAssignTo(t *testing.T) {
|
func TestOIDValueAssignTo(t *testing.T) {
|
||||||
var ui32 uint32
|
var ui32 uint32
|
||||||
var pui32 *uint32
|
var pui32 *uint32
|
||||||
|
|
||||||
simpleTests := []struct {
|
simpleTests := []struct {
|
||||||
src pgtype.OidValue
|
src pgtype.OIDValue
|
||||||
dst interface{}
|
dst interface{}
|
||||||
expected interface{}
|
expected interface{}
|
||||||
}{
|
}{
|
||||||
{src: pgtype.OidValue{Uint: 42, Status: pgtype.Present}, dst: &ui32, expected: uint32(42)},
|
{src: pgtype.OIDValue{Uint: 42, Status: pgtype.Present}, dst: &ui32, expected: uint32(42)},
|
||||||
{src: pgtype.OidValue{Status: pgtype.Null}, dst: &pui32, expected: ((*uint32)(nil))},
|
{src: pgtype.OIDValue{Status: pgtype.Null}, dst: &pui32, expected: ((*uint32)(nil))},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range simpleTests {
|
for i, tt := range simpleTests {
|
||||||
|
@ -61,11 +61,11 @@ func TestOidValueAssignTo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pointerAllocTests := []struct {
|
pointerAllocTests := []struct {
|
||||||
src pgtype.OidValue
|
src pgtype.OIDValue
|
||||||
dst interface{}
|
dst interface{}
|
||||||
expected interface{}
|
expected interface{}
|
||||||
}{
|
}{
|
||||||
{src: pgtype.OidValue{Uint: 42, Status: pgtype.Present}, dst: &pui32, expected: uint32(42)},
|
{src: pgtype.OIDValue{Uint: 42, Status: pgtype.Present}, dst: &pui32, expected: uint32(42)},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range pointerAllocTests {
|
for i, tt := range pointerAllocTests {
|
||||||
|
@ -80,10 +80,10 @@ func TestOidValueAssignTo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
errorTests := []struct {
|
errorTests := []struct {
|
||||||
src pgtype.OidValue
|
src pgtype.OIDValue
|
||||||
dst interface{}
|
dst interface{}
|
||||||
}{
|
}{
|
||||||
{src: pgtype.OidValue{Status: pgtype.Null}, dst: &ui32},
|
{src: pgtype.OIDValue{Status: pgtype.Null}, dst: &ui32},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range errorTests {
|
for i, tt := range errorTests {
|
||||||
|
|
104
pgtype/pgtype.go
104
pgtype/pgtype.go
|
@ -7,47 +7,47 @@ import (
|
||||||
|
|
||||||
// PostgreSQL oids for common types
|
// PostgreSQL oids for common types
|
||||||
const (
|
const (
|
||||||
BoolOid = 16
|
BoolOID = 16
|
||||||
ByteaOid = 17
|
ByteaOID = 17
|
||||||
CharOid = 18
|
CharOID = 18
|
||||||
NameOid = 19
|
NameOID = 19
|
||||||
Int8Oid = 20
|
Int8OID = 20
|
||||||
Int2Oid = 21
|
Int2OID = 21
|
||||||
Int4Oid = 23
|
Int4OID = 23
|
||||||
TextOid = 25
|
TextOID = 25
|
||||||
OidOid = 26
|
OIDOID = 26
|
||||||
TidOid = 27
|
TidOID = 27
|
||||||
XidOid = 28
|
XidOID = 28
|
||||||
CidOid = 29
|
CidOID = 29
|
||||||
JsonOid = 114
|
JsonOID = 114
|
||||||
CidrOid = 650
|
CidrOID = 650
|
||||||
CidrArrayOid = 651
|
CidrArrayOID = 651
|
||||||
Float4Oid = 700
|
Float4OID = 700
|
||||||
Float8Oid = 701
|
Float8OID = 701
|
||||||
UnknownOid = 705
|
UnknownOID = 705
|
||||||
InetOid = 869
|
InetOID = 869
|
||||||
BoolArrayOid = 1000
|
BoolArrayOID = 1000
|
||||||
Int2ArrayOid = 1005
|
Int2ArrayOID = 1005
|
||||||
Int4ArrayOid = 1007
|
Int4ArrayOID = 1007
|
||||||
TextArrayOid = 1009
|
TextArrayOID = 1009
|
||||||
ByteaArrayOid = 1001
|
ByteaArrayOID = 1001
|
||||||
VarcharArrayOid = 1015
|
VarcharArrayOID = 1015
|
||||||
Int8ArrayOid = 1016
|
Int8ArrayOID = 1016
|
||||||
Float4ArrayOid = 1021
|
Float4ArrayOID = 1021
|
||||||
Float8ArrayOid = 1022
|
Float8ArrayOID = 1022
|
||||||
AclitemOid = 1033
|
AclitemOID = 1033
|
||||||
AclitemArrayOid = 1034
|
AclitemArrayOID = 1034
|
||||||
InetArrayOid = 1041
|
InetArrayOID = 1041
|
||||||
VarcharOid = 1043
|
VarcharOID = 1043
|
||||||
DateOid = 1082
|
DateOID = 1082
|
||||||
TimestampOid = 1114
|
TimestampOID = 1114
|
||||||
TimestampArrayOid = 1115
|
TimestampArrayOID = 1115
|
||||||
DateArrayOid = 1182
|
DateArrayOID = 1182
|
||||||
TimestamptzOid = 1184
|
TimestamptzOID = 1184
|
||||||
TimestamptzArrayOid = 1185
|
TimestamptzArrayOID = 1185
|
||||||
RecordOid = 2249
|
RecordOID = 2249
|
||||||
UuidOid = 2950
|
UuidOID = 2950
|
||||||
JsonbOid = 3802
|
JsonbOID = 3802
|
||||||
)
|
)
|
||||||
|
|
||||||
type Status byte
|
type Status byte
|
||||||
|
@ -133,42 +133,42 @@ var errBadStatus = errors.New("invalid status")
|
||||||
type DataType struct {
|
type DataType struct {
|
||||||
Value Value
|
Value Value
|
||||||
Name string
|
Name string
|
||||||
Oid Oid
|
OID OID
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnInfo struct {
|
type ConnInfo struct {
|
||||||
oidToDataType map[Oid]*DataType
|
oidToDataType map[OID]*DataType
|
||||||
nameToDataType map[string]*DataType
|
nameToDataType map[string]*DataType
|
||||||
reflectTypeToDataType map[reflect.Type]*DataType
|
reflectTypeToDataType map[reflect.Type]*DataType
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConnInfo() *ConnInfo {
|
func NewConnInfo() *ConnInfo {
|
||||||
return &ConnInfo{
|
return &ConnInfo{
|
||||||
oidToDataType: make(map[Oid]*DataType, 256),
|
oidToDataType: make(map[OID]*DataType, 256),
|
||||||
nameToDataType: make(map[string]*DataType, 256),
|
nameToDataType: make(map[string]*DataType, 256),
|
||||||
reflectTypeToDataType: make(map[reflect.Type]*DataType, 256),
|
reflectTypeToDataType: make(map[reflect.Type]*DataType, 256),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ci *ConnInfo) InitializeDataTypes(nameOids map[string]Oid) {
|
func (ci *ConnInfo) InitializeDataTypes(nameOIDs map[string]OID) {
|
||||||
for name, oid := range nameOids {
|
for name, oid := range nameOIDs {
|
||||||
var value Value
|
var value Value
|
||||||
if t, ok := nameValues[name]; ok {
|
if t, ok := nameValues[name]; ok {
|
||||||
value = reflect.New(reflect.ValueOf(t).Elem().Type()).Interface().(Value)
|
value = reflect.New(reflect.ValueOf(t).Elem().Type()).Interface().(Value)
|
||||||
} else {
|
} else {
|
||||||
value = &GenericText{}
|
value = &GenericText{}
|
||||||
}
|
}
|
||||||
ci.RegisterDataType(DataType{Value: value, Name: name, Oid: oid})
|
ci.RegisterDataType(DataType{Value: value, Name: name, OID: oid})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ci *ConnInfo) RegisterDataType(t DataType) {
|
func (ci *ConnInfo) RegisterDataType(t DataType) {
|
||||||
ci.oidToDataType[t.Oid] = &t
|
ci.oidToDataType[t.OID] = &t
|
||||||
ci.nameToDataType[t.Name] = &t
|
ci.nameToDataType[t.Name] = &t
|
||||||
ci.reflectTypeToDataType[reflect.ValueOf(t.Value).Type()] = &t
|
ci.reflectTypeToDataType[reflect.ValueOf(t.Value).Type()] = &t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ci *ConnInfo) DataTypeForOid(oid Oid) (*DataType, bool) {
|
func (ci *ConnInfo) DataTypeForOID(oid OID) (*DataType, bool) {
|
||||||
dt, ok := ci.oidToDataType[oid]
|
dt, ok := ci.oidToDataType[oid]
|
||||||
return dt, ok
|
return dt, ok
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ func (ci *ConnInfo) DataTypeForValue(v Value) (*DataType, bool) {
|
||||||
// DeepCopy makes a deep copy of the ConnInfo.
|
// DeepCopy makes a deep copy of the ConnInfo.
|
||||||
func (ci *ConnInfo) DeepCopy() *ConnInfo {
|
func (ci *ConnInfo) DeepCopy() *ConnInfo {
|
||||||
ci2 := &ConnInfo{
|
ci2 := &ConnInfo{
|
||||||
oidToDataType: make(map[Oid]*DataType, len(ci.oidToDataType)),
|
oidToDataType: make(map[OID]*DataType, len(ci.oidToDataType)),
|
||||||
nameToDataType: make(map[string]*DataType, len(ci.nameToDataType)),
|
nameToDataType: make(map[string]*DataType, len(ci.nameToDataType)),
|
||||||
reflectTypeToDataType: make(map[reflect.Type]*DataType, len(ci.reflectTypeToDataType)),
|
reflectTypeToDataType: make(map[reflect.Type]*DataType, len(ci.reflectTypeToDataType)),
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ func (ci *ConnInfo) DeepCopy() *ConnInfo {
|
||||||
ci2.RegisterDataType(DataType{
|
ci2.RegisterDataType(DataType{
|
||||||
Value: reflect.New(reflect.ValueOf(dt.Value).Elem().Type()).Interface().(Value),
|
Value: reflect.New(reflect.ValueOf(dt.Value).Elem().Type()).Interface().(Value),
|
||||||
Name: dt.Name,
|
Name: dt.Name,
|
||||||
Oid: dt.Oid,
|
OID: dt.OID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ func init() {
|
||||||
"name": &Name{},
|
"name": &Name{},
|
||||||
"numeric": &Numeric{},
|
"numeric": &Numeric{},
|
||||||
"numrange": &Numrange{},
|
"numrange": &Numrange{},
|
||||||
"oid": &OidValue{},
|
"oid": &OIDValue{},
|
||||||
"path": &Path{},
|
"path": &Path{},
|
||||||
"point": &Point{},
|
"point": &Point{},
|
||||||
"polygon": &Polygon{},
|
"polygon": &Polygon{},
|
||||||
|
|
|
@ -88,16 +88,16 @@ func (dst *Record) DecodeBinary(ci *ConnInfo, src []byte) error {
|
||||||
if len(src[rp:]) < 8 {
|
if len(src[rp:]) < 8 {
|
||||||
return fmt.Errorf("Record incomplete %v", src)
|
return fmt.Errorf("Record incomplete %v", src)
|
||||||
}
|
}
|
||||||
fieldOid := Oid(binary.BigEndian.Uint32(src[rp:]))
|
fieldOID := OID(binary.BigEndian.Uint32(src[rp:]))
|
||||||
rp += 4
|
rp += 4
|
||||||
|
|
||||||
fieldLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
|
fieldLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
|
||||||
rp += 4
|
rp += 4
|
||||||
|
|
||||||
var binaryDecoder BinaryDecoder
|
var binaryDecoder BinaryDecoder
|
||||||
if dt, ok := ci.DataTypeForOid(fieldOid); ok {
|
if dt, ok := ci.DataTypeForOID(fieldOID); ok {
|
||||||
if binaryDecoder, ok = dt.Value.(BinaryDecoder); !ok {
|
if binaryDecoder, ok = dt.Value.(BinaryDecoder); !ok {
|
||||||
return fmt.Errorf("unknown oid while decoding record: %v", fieldOid)
|
return fmt.Errorf("unknown oid while decoding record: %v", fieldOID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (src *TextArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("text"); ok {
|
if dt, ok := ci.DataTypeForName("text"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "text")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "text")
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,7 +232,7 @@ func (src *TimestampArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("timestamp"); ok {
|
if dt, ok := ci.DataTypeForName("timestamp"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "timestamp")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "timestamp")
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,7 +232,7 @@ func (src *TimestamptzArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("timestamptz"); ok {
|
if dt, ok := ci.DataTypeForName("timestamptz"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "timestamptz")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "timestamptz")
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,7 +234,7 @@ func (src *<%= pgtype_array_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byt
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("<%= element_type_name %>"); ok {
|
if dt, ok := ci.DataTypeForName("<%= element_type_name %>"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "<%= element_type_name %>")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "<%= element_type_name %>")
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (src *VarcharArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForName("varchar"); ok {
|
if dt, ok := ci.DataTypeForName("varchar"); ok {
|
||||||
arrayHeader.ElementOid = int32(dt.Oid)
|
arrayHeader.ElementOID = int32(dt.OID)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unable to find oid for type name %v", "varchar")
|
return nil, fmt.Errorf("unable to find oid for type name %v", "varchar")
|
||||||
}
|
}
|
||||||
|
|
28
query.go
28
query.go
|
@ -131,7 +131,7 @@ func (rows *Rows) Next() bool {
|
||||||
case *pgproto3.RowDescription:
|
case *pgproto3.RowDescription:
|
||||||
rows.fields = rows.conn.rxRowDescription(msg)
|
rows.fields = rows.conn.rxRowDescription(msg)
|
||||||
for i := range rows.fields {
|
for i := range rows.fields {
|
||||||
if dt, ok := rows.conn.ConnInfo.DataTypeForOid(rows.fields[i].DataType); ok {
|
if dt, ok := rows.conn.ConnInfo.DataTypeForOID(rows.fields[i].DataType); ok {
|
||||||
rows.fields[i].DataTypeName = dt.Name
|
rows.fields[i].DataTypeName = dt.Name
|
||||||
rows.fields[i].FormatCode = TextFormatCode
|
rows.fields[i].FormatCode = TextFormatCode
|
||||||
} else {
|
} else {
|
||||||
|
@ -214,7 +214,7 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
|
||||||
rows.fatal(scanArgError{col: i, err: err})
|
rows.fatal(scanArgError{col: i, err: err})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if dt, ok := rows.conn.ConnInfo.DataTypeForOid(fd.DataType); ok {
|
if dt, ok := rows.conn.ConnInfo.DataTypeForOID(fd.DataType); ok {
|
||||||
value := dt.Value
|
value := dt.Value
|
||||||
switch fd.FormatCode {
|
switch fd.FormatCode {
|
||||||
case TextFormatCode:
|
case TextFormatCode:
|
||||||
|
@ -282,7 +282,7 @@ func (rows *Rows) Values() ([]interface{}, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := rows.conn.ConnInfo.DataTypeForOid(fd.DataType); ok {
|
if dt, ok := rows.conn.ConnInfo.DataTypeForOID(fd.DataType); ok {
|
||||||
value := dt.Value
|
value := dt.Value
|
||||||
|
|
||||||
switch fd.FormatCode {
|
switch fd.FormatCode {
|
||||||
|
@ -353,10 +353,10 @@ func (c *Conn) QueryRow(sql string, args ...interface{}) *Row {
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryExOptions struct {
|
type QueryExOptions struct {
|
||||||
// When ParameterOids are present and the query is not a prepared statement,
|
// When ParameterOIDs are present and the query is not a prepared statement,
|
||||||
// then ParameterOids and ResultFormatCodes will be used to avoid an extra
|
// then ParameterOIDs and ResultFormatCodes will be used to avoid an extra
|
||||||
// network round-trip.
|
// network round-trip.
|
||||||
ParameterOids []pgtype.Oid
|
ParameterOIDs []pgtype.OID
|
||||||
ResultFormatCodes []int16
|
ResultFormatCodes []int16
|
||||||
|
|
||||||
SimpleProtocol bool
|
SimpleProtocol bool
|
||||||
|
@ -398,7 +398,7 @@ func (c *Conn) QueryEx(ctx context.Context, sql string, options *QueryExOptions,
|
||||||
return rows, nil
|
return rows, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if options != nil && len(options.ParameterOids) > 0 {
|
if options != nil && len(options.ParameterOIDs) > 0 {
|
||||||
|
|
||||||
buf, err := c.buildOneRoundTripQueryEx(c.wbuf, sql, options, args)
|
buf, err := c.buildOneRoundTripQueryEx(c.wbuf, sql, options, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -463,17 +463,17 @@ func (c *Conn) QueryEx(ctx context.Context, sql string, options *QueryExOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) buildOneRoundTripQueryEx(buf []byte, sql string, options *QueryExOptions, arguments []interface{}) ([]byte, error) {
|
func (c *Conn) buildOneRoundTripQueryEx(buf []byte, sql string, options *QueryExOptions, arguments []interface{}) ([]byte, error) {
|
||||||
if len(arguments) != len(options.ParameterOids) {
|
if len(arguments) != len(options.ParameterOIDs) {
|
||||||
return nil, fmt.Errorf("mismatched number of arguments (%d) and options.ParameterOids (%d)", len(arguments), len(options.ParameterOids))
|
return nil, fmt.Errorf("mismatched number of arguments (%d) and options.ParameterOIDs (%d)", len(arguments), len(options.ParameterOIDs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(options.ParameterOids) > 65535 {
|
if len(options.ParameterOIDs) > 65535 {
|
||||||
return nil, fmt.Errorf("Number of QueryExOptions ParameterOids must be between 0 and 65535, received %d", len(options.ParameterOids))
|
return nil, fmt.Errorf("Number of QueryExOptions ParameterOIDs must be between 0 and 65535, received %d", len(options.ParameterOIDs))
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = appendParse(buf, "", sql, options.ParameterOids)
|
buf = appendParse(buf, "", sql, options.ParameterOIDs)
|
||||||
buf = appendDescribe(buf, 'S', "")
|
buf = appendDescribe(buf, 'S', "")
|
||||||
buf, err := appendBind(buf, "", "", c.ConnInfo, options.ParameterOids, arguments, options.ResultFormatCodes)
|
buf, err := appendBind(buf, "", "", c.ConnInfo, options.ParameterOIDs, arguments, options.ResultFormatCodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -494,7 +494,7 @@ func (c *Conn) readUntilRowDescription() ([]FieldDescription, error) {
|
||||||
case *pgproto3.RowDescription:
|
case *pgproto3.RowDescription:
|
||||||
fieldDescriptions := c.rxRowDescription(msg)
|
fieldDescriptions := c.rxRowDescription(msg)
|
||||||
for i := range fieldDescriptions {
|
for i := range fieldDescriptions {
|
||||||
if dt, ok := c.ConnInfo.DataTypeForOid(fieldDescriptions[i].DataType); ok {
|
if dt, ok := c.ConnInfo.DataTypeForOID(fieldDescriptions[i].DataType); ok {
|
||||||
fieldDescriptions[i].DataTypeName = dt.Name
|
fieldDescriptions[i].DataTypeName = dt.Name
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unknown oid: %d", fieldDescriptions[i].DataType)
|
return nil, fmt.Errorf("unknown oid: %d", fieldDescriptions[i].DataType)
|
||||||
|
|
|
@ -251,7 +251,7 @@ func TestConnQueryReadWrongTypeError(t *testing.T) {
|
||||||
t.Fatal("Expected Rows to have an error after an improper read but it didn't")
|
t.Fatal("Expected Rows to have an error after an improper read but it didn't")
|
||||||
}
|
}
|
||||||
|
|
||||||
if rows.Err().Error() != "can't scan into dest[0]: Can't convert Oid 23 to time.Time" && !strings.Contains(rows.Err().Error(), "cannot assign") {
|
if rows.Err().Error() != "can't scan into dest[0]: Can't convert OID 23 to time.Time" && !strings.Contains(rows.Err().Error(), "cannot assign") {
|
||||||
t.Fatalf("Expected different Rows.Err(): %v", rows.Err())
|
t.Fatalf("Expected different Rows.Err(): %v", rows.Err())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +389,7 @@ func TestQueryRowCoreTypes(t *testing.T) {
|
||||||
f64 float64
|
f64 float64
|
||||||
b bool
|
b bool
|
||||||
t time.Time
|
t time.Time
|
||||||
oid pgtype.Oid
|
oid pgtype.OID
|
||||||
}
|
}
|
||||||
|
|
||||||
var actual, zero allTypes
|
var actual, zero allTypes
|
||||||
|
@ -407,7 +407,7 @@ func TestQueryRowCoreTypes(t *testing.T) {
|
||||||
{"select $1::timestamptz", []interface{}{time.Unix(123, 5000)}, []interface{}{&actual.t}, allTypes{t: time.Unix(123, 5000)}},
|
{"select $1::timestamptz", []interface{}{time.Unix(123, 5000)}, []interface{}{&actual.t}, allTypes{t: time.Unix(123, 5000)}},
|
||||||
{"select $1::timestamp", []interface{}{time.Date(2010, 1, 2, 3, 4, 5, 0, time.UTC)}, []interface{}{&actual.t}, allTypes{t: time.Date(2010, 1, 2, 3, 4, 5, 0, time.UTC)}},
|
{"select $1::timestamp", []interface{}{time.Date(2010, 1, 2, 3, 4, 5, 0, time.UTC)}, []interface{}{&actual.t}, allTypes{t: time.Date(2010, 1, 2, 3, 4, 5, 0, time.UTC)}},
|
||||||
{"select $1::date", []interface{}{time.Date(1987, 1, 2, 0, 0, 0, 0, time.UTC)}, []interface{}{&actual.t}, allTypes{t: time.Date(1987, 1, 2, 0, 0, 0, 0, time.UTC)}},
|
{"select $1::date", []interface{}{time.Date(1987, 1, 2, 0, 0, 0, 0, time.UTC)}, []interface{}{&actual.t}, allTypes{t: time.Date(1987, 1, 2, 0, 0, 0, 0, time.UTC)}},
|
||||||
{"select $1::oid", []interface{}{pgtype.Oid(42)}, []interface{}{&actual.oid}, allTypes{oid: 42}},
|
{"select $1::oid", []interface{}{pgtype.OID(42)}, []interface{}{&actual.oid}, allTypes{oid: 42}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
|
@ -768,12 +768,12 @@ func TestQueryRowUnknownType(t *testing.T) {
|
||||||
conn.ConnInfo.RegisterDataType(pgtype.DataType{
|
conn.ConnInfo.RegisterDataType(pgtype.DataType{
|
||||||
Value: &pgtype.GenericText{},
|
Value: &pgtype.GenericText{},
|
||||||
Name: "point",
|
Name: "point",
|
||||||
Oid: 600,
|
OID: 600,
|
||||||
})
|
})
|
||||||
conn.ConnInfo.RegisterDataType(pgtype.DataType{
|
conn.ConnInfo.RegisterDataType(pgtype.DataType{
|
||||||
Value: &pgtype.Int4{},
|
Value: &pgtype.Int4{},
|
||||||
Name: "int4",
|
Name: "int4",
|
||||||
Oid: pgtype.Int4Oid,
|
OID: pgtype.Int4OID,
|
||||||
})
|
})
|
||||||
|
|
||||||
sql := "select $1::point"
|
sql := "select $1::point"
|
||||||
|
@ -1193,7 +1193,7 @@ func TestConnQueryRowExSingleRoundTrip(t *testing.T) {
|
||||||
context.Background(),
|
context.Background(),
|
||||||
"select $1 + $2",
|
"select $1 + $2",
|
||||||
&pgx.QueryExOptions{
|
&pgx.QueryExOptions{
|
||||||
ParameterOids: []pgtype.Oid{pgtype.Int4Oid, pgtype.Int4Oid},
|
ParameterOIDs: []pgtype.OID{pgtype.Int4OID, pgtype.Int4OID},
|
||||||
ResultFormatCodes: []int16{pgx.BinaryFormatCode},
|
ResultFormatCodes: []int16{pgx.BinaryFormatCode},
|
||||||
},
|
},
|
||||||
1, 2,
|
1, 2,
|
||||||
|
|
|
@ -348,7 +348,7 @@ func (rc *ReplicationConn) sendReplicationModeQuery(sql string) (*Rows, error) {
|
||||||
rows.fields = rc.c.rxRowDescription(msg)
|
rows.fields = rc.c.rxRowDescription(msg)
|
||||||
// We don't have c.PgTypes here because we're a replication
|
// We don't have c.PgTypes here because we're a replication
|
||||||
// connection. This means the field descriptions will have
|
// connection. This means the field descriptions will have
|
||||||
// only Oids. Not much we can do about this.
|
// only OIDs. Not much we can do about this.
|
||||||
default:
|
default:
|
||||||
if e := rc.c.processContextFreeMsg(msg); e != nil {
|
if e := rc.c.processContextFreeMsg(msg); e != nil {
|
||||||
rows.fatal(e)
|
rows.fatal(e)
|
||||||
|
@ -368,7 +368,7 @@ func (rc *ReplicationConn) sendReplicationModeQuery(sql string) (*Rows, error) {
|
||||||
//
|
//
|
||||||
// NOTE: Because this is a replication mode connection, we don't have
|
// NOTE: Because this is a replication mode connection, we don't have
|
||||||
// type names, so the field descriptions in the result will have only
|
// type names, so the field descriptions in the result will have only
|
||||||
// Oids and no DataTypeName values
|
// OIDs and no DataTypeName values
|
||||||
func (rc *ReplicationConn) IdentifySystem() (r *Rows, err error) {
|
func (rc *ReplicationConn) IdentifySystem() (r *Rows, err error) {
|
||||||
return rc.sendReplicationModeQuery("IDENTIFY_SYSTEM")
|
return rc.sendReplicationModeQuery("IDENTIFY_SYSTEM")
|
||||||
}
|
}
|
||||||
|
@ -383,7 +383,7 @@ func (rc *ReplicationConn) IdentifySystem() (r *Rows, err error) {
|
||||||
//
|
//
|
||||||
// NOTE: Because this is a replication mode connection, we don't have
|
// NOTE: Because this is a replication mode connection, we don't have
|
||||||
// type names, so the field descriptions in the result will have only
|
// type names, so the field descriptions in the result will have only
|
||||||
// Oids and no DataTypeName values
|
// OIDs and no DataTypeName values
|
||||||
func (rc *ReplicationConn) TimelineHistory(timeline int) (r *Rows, err error) {
|
func (rc *ReplicationConn) TimelineHistory(timeline int) (r *Rows, err error) {
|
||||||
return rc.sendReplicationModeQuery(fmt.Sprintf("TIMELINE_HISTORY %d", timeline))
|
return rc.sendReplicationModeQuery(fmt.Sprintf("TIMELINE_HISTORY %d", timeline))
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ import (
|
||||||
|
|
||||||
// oids that map to intrinsic database/sql types. These will be allowed to be
|
// oids that map to intrinsic database/sql types. These will be allowed to be
|
||||||
// binary, anything else will be forced to text format
|
// binary, anything else will be forced to text format
|
||||||
var databaseSqlOids map[pgtype.Oid]bool
|
var databaseSqlOIDs map[pgtype.OID]bool
|
||||||
|
|
||||||
var pgxDriver *Driver
|
var pgxDriver *Driver
|
||||||
|
|
||||||
|
@ -97,20 +97,20 @@ func init() {
|
||||||
}
|
}
|
||||||
sql.Register("pgx", pgxDriver)
|
sql.Register("pgx", pgxDriver)
|
||||||
|
|
||||||
databaseSqlOids = make(map[pgtype.Oid]bool)
|
databaseSqlOIDs = make(map[pgtype.OID]bool)
|
||||||
databaseSqlOids[pgtype.BoolOid] = true
|
databaseSqlOIDs[pgtype.BoolOID] = true
|
||||||
databaseSqlOids[pgtype.ByteaOid] = true
|
databaseSqlOIDs[pgtype.ByteaOID] = true
|
||||||
databaseSqlOids[pgtype.CidOid] = true
|
databaseSqlOIDs[pgtype.CidOID] = true
|
||||||
databaseSqlOids[pgtype.DateOid] = true
|
databaseSqlOIDs[pgtype.DateOID] = true
|
||||||
databaseSqlOids[pgtype.Float4Oid] = true
|
databaseSqlOIDs[pgtype.Float4OID] = true
|
||||||
databaseSqlOids[pgtype.Float8Oid] = true
|
databaseSqlOIDs[pgtype.Float8OID] = true
|
||||||
databaseSqlOids[pgtype.Int2Oid] = true
|
databaseSqlOIDs[pgtype.Int2OID] = true
|
||||||
databaseSqlOids[pgtype.Int4Oid] = true
|
databaseSqlOIDs[pgtype.Int4OID] = true
|
||||||
databaseSqlOids[pgtype.Int8Oid] = true
|
databaseSqlOIDs[pgtype.Int8OID] = true
|
||||||
databaseSqlOids[pgtype.OidOid] = true
|
databaseSqlOIDs[pgtype.OIDOID] = true
|
||||||
databaseSqlOids[pgtype.TimestampOid] = true
|
databaseSqlOIDs[pgtype.TimestampOID] = true
|
||||||
databaseSqlOids[pgtype.TimestamptzOid] = true
|
databaseSqlOIDs[pgtype.TimestamptzOID] = true
|
||||||
databaseSqlOids[pgtype.XidOid] = true
|
databaseSqlOIDs[pgtype.XidOID] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
|
@ -364,7 +364,7 @@ func (c *Conn) Ping(ctx context.Context) error {
|
||||||
// (e.g. []int32)
|
// (e.g. []int32)
|
||||||
func restrictBinaryToDatabaseSqlTypes(ps *pgx.PreparedStatement) {
|
func restrictBinaryToDatabaseSqlTypes(ps *pgx.PreparedStatement) {
|
||||||
for i, _ := range ps.FieldDescriptions {
|
for i, _ := range ps.FieldDescriptions {
|
||||||
intrinsic, _ := databaseSqlOids[ps.FieldDescriptions[i].DataType]
|
intrinsic, _ := databaseSqlOIDs[ps.FieldDescriptions[i].DataType]
|
||||||
if !intrinsic {
|
if !intrinsic {
|
||||||
ps.FieldDescriptions[i].FormatCode = pgx.TextFormatCode
|
ps.FieldDescriptions[i].FormatCode = pgx.TextFormatCode
|
||||||
}
|
}
|
||||||
|
@ -381,7 +381,7 @@ func (s *Stmt) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stmt) NumInput() int {
|
func (s *Stmt) NumInput() int {
|
||||||
return len(s.ps.ParameterOids)
|
return len(s.ps.ParameterOIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stmt) Exec(argsV []driver.Value) (driver.Result, error) {
|
func (s *Stmt) Exec(argsV []driver.Value) (driver.Result, error) {
|
||||||
|
@ -428,31 +428,31 @@ func (r *Rows) Next(dest []driver.Value) error {
|
||||||
r.values = make([]interface{}, len(r.rows.FieldDescriptions()))
|
r.values = make([]interface{}, len(r.rows.FieldDescriptions()))
|
||||||
for i, fd := range r.rows.FieldDescriptions() {
|
for i, fd := range r.rows.FieldDescriptions() {
|
||||||
switch fd.DataType {
|
switch fd.DataType {
|
||||||
case pgtype.BoolOid:
|
case pgtype.BoolOID:
|
||||||
r.values[i] = &pgtype.Bool{}
|
r.values[i] = &pgtype.Bool{}
|
||||||
case pgtype.ByteaOid:
|
case pgtype.ByteaOID:
|
||||||
r.values[i] = &pgtype.Bytea{}
|
r.values[i] = &pgtype.Bytea{}
|
||||||
case pgtype.CidOid:
|
case pgtype.CidOID:
|
||||||
r.values[i] = &pgtype.Cid{}
|
r.values[i] = &pgtype.Cid{}
|
||||||
case pgtype.DateOid:
|
case pgtype.DateOID:
|
||||||
r.values[i] = &pgtype.Date{}
|
r.values[i] = &pgtype.Date{}
|
||||||
case pgtype.Float4Oid:
|
case pgtype.Float4OID:
|
||||||
r.values[i] = &pgtype.Float4{}
|
r.values[i] = &pgtype.Float4{}
|
||||||
case pgtype.Float8Oid:
|
case pgtype.Float8OID:
|
||||||
r.values[i] = &pgtype.Float8{}
|
r.values[i] = &pgtype.Float8{}
|
||||||
case pgtype.Int2Oid:
|
case pgtype.Int2OID:
|
||||||
r.values[i] = &pgtype.Int2{}
|
r.values[i] = &pgtype.Int2{}
|
||||||
case pgtype.Int4Oid:
|
case pgtype.Int4OID:
|
||||||
r.values[i] = &pgtype.Int4{}
|
r.values[i] = &pgtype.Int4{}
|
||||||
case pgtype.Int8Oid:
|
case pgtype.Int8OID:
|
||||||
r.values[i] = &pgtype.Int8{}
|
r.values[i] = &pgtype.Int8{}
|
||||||
case pgtype.OidOid:
|
case pgtype.OIDOID:
|
||||||
r.values[i] = &pgtype.OidValue{}
|
r.values[i] = &pgtype.OIDValue{}
|
||||||
case pgtype.TimestampOid:
|
case pgtype.TimestampOID:
|
||||||
r.values[i] = &pgtype.Timestamp{}
|
r.values[i] = &pgtype.Timestamp{}
|
||||||
case pgtype.TimestamptzOid:
|
case pgtype.TimestamptzOID:
|
||||||
r.values[i] = &pgtype.Timestamptz{}
|
r.values[i] = &pgtype.Timestamptz{}
|
||||||
case pgtype.XidOid:
|
case pgtype.XidOID:
|
||||||
r.values[i] = &pgtype.Xid{}
|
r.values[i] = &pgtype.Xid{}
|
||||||
default:
|
default:
|
||||||
r.values[i] = &pgtype.GenericText{}
|
r.values[i] = &pgtype.GenericText{}
|
||||||
|
|
|
@ -97,7 +97,7 @@ func convertSimpleArgument(ci *pgtype.ConnInfo, arg interface{}) (interface{}, e
|
||||||
return nil, SerializationError(fmt.Sprintf("Cannot encode %T in simple protocol - %T must implement driver.Valuer, pgtype.TextEncoder, or be a native type", arg, arg))
|
return nil, SerializationError(fmt.Sprintf("Cannot encode %T in simple protocol - %T must implement driver.Valuer, pgtype.TextEncoder, or be a native type", arg, arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodePreparedStatementArgument(ci *pgtype.ConnInfo, buf []byte, oid pgtype.Oid, arg interface{}) ([]byte, error) {
|
func encodePreparedStatementArgument(ci *pgtype.ConnInfo, buf []byte, oid pgtype.OID, arg interface{}) ([]byte, error) {
|
||||||
if arg == nil {
|
if arg == nil {
|
||||||
return pgio.AppendInt32(buf, -1), nil
|
return pgio.AppendInt32(buf, -1), nil
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ func encodePreparedStatementArgument(ci *pgtype.ConnInfo, buf []byte, oid pgtype
|
||||||
return encodePreparedStatementArgument(ci, buf, oid, arg)
|
return encodePreparedStatementArgument(ci, buf, oid, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForOid(oid); ok {
|
if dt, ok := ci.DataTypeForOID(oid); ok {
|
||||||
value := dt.Value
|
value := dt.Value
|
||||||
err := value.Set(arg)
|
err := value.Set(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -178,7 +178,7 @@ func encodePreparedStatementArgument(ci *pgtype.ConnInfo, buf []byte, oid pgtype
|
||||||
// chooseParameterFormatCode determines the correct format code for an
|
// chooseParameterFormatCode determines the correct format code for an
|
||||||
// argument to a prepared statement. It defaults to TextFormatCode if no
|
// argument to a prepared statement. It defaults to TextFormatCode if no
|
||||||
// determination can be made.
|
// determination can be made.
|
||||||
func chooseParameterFormatCode(ci *pgtype.ConnInfo, oid pgtype.Oid, arg interface{}) int16 {
|
func chooseParameterFormatCode(ci *pgtype.ConnInfo, oid pgtype.OID, arg interface{}) int16 {
|
||||||
switch arg.(type) {
|
switch arg.(type) {
|
||||||
case pgtype.BinaryEncoder:
|
case pgtype.BinaryEncoder:
|
||||||
return BinaryFormatCode
|
return BinaryFormatCode
|
||||||
|
@ -186,7 +186,7 @@ func chooseParameterFormatCode(ci *pgtype.ConnInfo, oid pgtype.Oid, arg interfac
|
||||||
return TextFormatCode
|
return TextFormatCode
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForOid(oid); ok {
|
if dt, ok := ci.DataTypeForOID(oid); ok {
|
||||||
if _, ok := dt.Value.(pgtype.BinaryEncoder); ok {
|
if _, ok := dt.Value.(pgtype.BinaryEncoder); ok {
|
||||||
if arg, ok := arg.(driver.Valuer); ok {
|
if arg, ok := arg.(driver.Valuer); ok {
|
||||||
if err := dt.Value.Set(arg); err != nil {
|
if err := dt.Value.Set(arg); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue