summaryrefslogtreecommitdiff
path: root/vendor/github.com/jackc/pgx/v5/conn.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/jackc/pgx/v5/conn.go')
-rw-r--r--vendor/github.com/jackc/pgx/v5/conn.go80
1 files changed, 54 insertions, 26 deletions
diff --git a/vendor/github.com/jackc/pgx/v5/conn.go b/vendor/github.com/jackc/pgx/v5/conn.go
index 7c7081b48..0426873c2 100644
--- a/vendor/github.com/jackc/pgx/v5/conn.go
+++ b/vendor/github.com/jackc/pgx/v5/conn.go
@@ -2,6 +2,8 @@ package pgx
import (
"context"
+ "crypto/sha256"
+ "encoding/hex"
"errors"
"fmt"
"strconv"
@@ -35,7 +37,7 @@ type ConnConfig struct {
// DefaultQueryExecMode controls the default mode for executing queries. By default pgx uses the extended protocol
// and automatically prepares and caches prepared statements. However, this may be incompatible with proxies such as
- // PGBouncer. In this case it may be preferrable to use QueryExecModeExec or QueryExecModeSimpleProtocol. The same
+ // PGBouncer. In this case it may be preferable to use QueryExecModeExec or QueryExecModeSimpleProtocol. The same
// functionality can be controlled on a per query basis by passing a QueryExecMode as the first query argument.
DefaultQueryExecMode QueryExecMode
@@ -99,8 +101,12 @@ func (ident Identifier) Sanitize() string {
return strings.Join(parts, ".")
}
-// ErrNoRows occurs when rows are expected but none are returned.
-var ErrNoRows = errors.New("no rows in result set")
+var (
+ // ErrNoRows occurs when rows are expected but none are returned.
+ ErrNoRows = errors.New("no rows in result set")
+ // ErrTooManyRows occurs when more rows than expected are returned.
+ ErrTooManyRows = errors.New("too many rows in result set")
+)
var errDisabledStatementCache = fmt.Errorf("cannot use QueryExecModeCacheStatement with disabled statement cache")
var errDisabledDescriptionCache = fmt.Errorf("cannot use QueryExecModeCacheDescribe with disabled description cache")
@@ -269,7 +275,7 @@ func connect(ctx context.Context, config *ConnConfig) (c *Conn, err error) {
return c, nil
}
-// Close closes a connection. It is safe to call Close on a already closed
+// Close closes a connection. It is safe to call Close on an already closed
// connection.
func (c *Conn) Close(ctx context.Context) error {
if c.IsClosed() {
@@ -280,12 +286,15 @@ func (c *Conn) Close(ctx context.Context) error {
return err
}
-// Prepare creates a prepared statement with name and sql. sql can contain placeholders
-// for bound parameters. These placeholders are referenced positional as $1, $2, etc.
+// Prepare creates a prepared statement with name and sql. sql can contain placeholders for bound parameters. These
+// placeholders are referenced positionally as $1, $2, etc. name can be used instead of sql with Query, QueryRow, and
+// Exec to execute the statement. It can also be used with Batch.Queue.
+//
+// The underlying PostgreSQL identifier for the prepared statement will be name if name != sql or a digest of sql if
+// name == sql.
//
-// Prepare is idempotent; i.e. it is safe to call Prepare multiple times with the same
-// name and sql arguments. This allows a code path to Prepare and Query/Exec without
-// concern for if the statement has already been prepared.
+// Prepare is idempotent; i.e. it is safe to call Prepare multiple times with the same name and sql arguments. This
+// allows a code path to Prepare and Query/Exec without concern for if the statement has already been prepared.
func (c *Conn) Prepare(ctx context.Context, name, sql string) (sd *pgconn.StatementDescription, err error) {
if c.prepareTracer != nil {
ctx = c.prepareTracer.TracePrepareStart(ctx, c, TracePrepareStartData{Name: name, SQL: sql})
@@ -307,22 +316,38 @@ func (c *Conn) Prepare(ctx context.Context, name, sql string) (sd *pgconn.Statem
}()
}
- sd, err = c.pgConn.Prepare(ctx, name, sql, nil)
+ var psName, psKey string
+ if name == sql {
+ digest := sha256.Sum256([]byte(sql))
+ psName = "stmt_" + hex.EncodeToString(digest[0:24])
+ psKey = sql
+ } else {
+ psName = name
+ psKey = name
+ }
+
+ sd, err = c.pgConn.Prepare(ctx, psName, sql, nil)
if err != nil {
return nil, err
}
- if name != "" {
- c.preparedStatements[name] = sd
+ if psKey != "" {
+ c.preparedStatements[psKey] = sd
}
return sd, nil
}
-// Deallocate released a prepared statement
+// Deallocate releases a prepared statement.
func (c *Conn) Deallocate(ctx context.Context, name string) error {
- delete(c.preparedStatements, name)
- _, err := c.pgConn.Exec(ctx, "deallocate "+quoteIdentifier(name)).ReadAll()
+ var psName string
+ if sd, ok := c.preparedStatements[name]; ok {
+ delete(c.preparedStatements, name)
+ psName = sd.Name
+ } else {
+ psName = name
+ }
+ _, err := c.pgConn.Exec(ctx, "deallocate "+quoteIdentifier(psName)).ReadAll()
return err
}
@@ -461,7 +486,7 @@ optionLoop:
}
sd := c.statementCache.Get(sql)
if sd == nil {
- sd, err = c.Prepare(ctx, stmtcache.NextStatementName(), sql)
+ sd, err = c.Prepare(ctx, stmtcache.StatementName(sql), sql)
if err != nil {
return pgconn.CommandTag{}, err
}
@@ -573,13 +598,16 @@ type QueryExecMode int32
const (
_ QueryExecMode = iota
- // Automatically prepare and cache statements. This uses the extended protocol. Queries are executed in a single
- // round trip after the statement is cached. This is the default.
+ // Automatically prepare and cache statements. This uses the extended protocol. Queries are executed in a single round
+ // trip after the statement is cached. This is the default. If the database schema is modified or the search_path is
+ // changed after a statement is cached then the first execution of a previously cached query may fail. e.g. If the
+ // number of columns returned by a "SELECT *" changes or the type of a column is changed.
QueryExecModeCacheStatement
- // Cache statement descriptions (i.e. argument and result types) and assume they do not change. This uses the
- // extended protocol. Queries are executed in a single round trip after the description is cached. If the database
- // schema is modified or the search_path is changed this may result in undetected result decoding errors.
+ // Cache statement descriptions (i.e. argument and result types) and assume they do not change. This uses the extended
+ // protocol. Queries are executed in a single round trip after the description is cached. If the database schema is
+ // modified or the search_path is changed after a statement is cached then the first execution of a previously cached
+ // query may fail. e.g. If the number of columns returned by a "SELECT *" changes or the type of a column is changed.
QueryExecModeCacheDescribe
// Get the statement description on every execution. This uses the extended protocol. Queries require two round trips
@@ -592,13 +620,13 @@ const (
// Assume the PostgreSQL query parameter types based on the Go type of the arguments. This uses the extended protocol
// with text formatted parameters and results. Queries are executed in a single round trip. Type mappings can be
// registered with pgtype.Map.RegisterDefaultPgType. Queries will be rejected that have arguments that are
- // unregistered or ambigious. e.g. A map[string]string may have the PostgreSQL type json or hstore. Modes that know
+ // unregistered or ambiguous. e.g. A map[string]string may have the PostgreSQL type json or hstore. Modes that know
// the PostgreSQL type can use a map[string]string directly as an argument. This mode cannot.
QueryExecModeExec
// Use the simple protocol. Assume the PostgreSQL query parameter types based on the Go type of the arguments.
// Queries are executed in a single round trip. Type mappings can be registered with
- // pgtype.Map.RegisterDefaultPgType. Queries will be rejected that have arguments that are unregistered or ambigious.
+ // pgtype.Map.RegisterDefaultPgType. Queries will be rejected that have arguments that are unregistered or ambiguous.
// e.g. A map[string]string may have the PostgreSQL type json or hstore. Modes that know the PostgreSQL type can use
// a map[string]string directly as an argument. This mode cannot.
//
@@ -815,7 +843,7 @@ func (c *Conn) getStatementDescription(
}
sd = c.statementCache.Get(sql)
if sd == nil {
- sd, err = c.Prepare(ctx, stmtcache.NextStatementName(), sql)
+ sd, err = c.Prepare(ctx, stmtcache.StatementName(sql), sql)
if err != nil {
return nil, err
}
@@ -994,7 +1022,7 @@ func (c *Conn) sendBatchQueryExecModeCacheStatement(ctx context.Context, b *Batc
bi.sd = distinctNewQueries[idx]
} else {
sd = &pgconn.StatementDescription{
- Name: stmtcache.NextStatementName(),
+ Name: stmtcache.StatementName(bi.query),
SQL: bi.query,
}
distinctNewQueriesIdxMap[sd.SQL] = len(distinctNewQueries)
@@ -1062,7 +1090,7 @@ func (c *Conn) sendBatchQueryExecModeDescribeExec(ctx context.Context, b *Batch)
}
func (c *Conn) sendBatchExtendedWithDescription(ctx context.Context, b *Batch, distinctNewQueries []*pgconn.StatementDescription, sdCache stmtcache.Cache) (pbr *pipelineBatchResults) {
- pipeline := c.pgConn.StartPipeline(context.Background())
+ pipeline := c.pgConn.StartPipeline(ctx)
defer func() {
if pbr != nil && pbr.err != nil {
pipeline.Close()