package pgx

import (
	
	
	
	
	
	

	
	
	
	
	
)

// ConnConfig contains all the options used to establish a connection. It must be created by ParseConfig and
// then it can be modified. A manually initialized ConnConfig will cause ConnectConfig to panic.
type ConnConfig struct {
	pgconn.Config

	Tracer QueryTracer

	// Original connection string that was parsed into config.
	connString string

	// StatementCacheCapacity is maximum size of the statement cache used when executing a query with "cache_statement"
	// query exec mode.
	StatementCacheCapacity int

	// DescriptionCacheCapacity is the maximum size of the description cache used when executing a query with
	// "cache_describe" query exec mode.
	DescriptionCacheCapacity int

	// 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
	// functionality can be controlled on a per query basis by passing a QueryExecMode as the first query argument.
	DefaultQueryExecMode QueryExecMode

	createdByParseConfig bool // Used to enforce created by ParseConfig rule.
}

// ParseConfigOptions contains options that control how a config is built such as getsslpassword.
type ParseConfigOptions struct {
	pgconn.ParseConfigOptions
}

// Copy returns a deep copy of the config that is safe to use and modify.
// The only exception is the tls.Config:
// according to the tls.Config docs it must not be modified after creation.
func ( *ConnConfig) () *ConnConfig {
	 := new(ConnConfig)
	* = *
	.Config = *.Config.Copy()
	return 
}

// ConnString returns the connection string as parsed by pgx.ParseConfig into pgx.ConnConfig.
func ( *ConnConfig) () string { return .connString }

// Conn is a PostgreSQL connection handle. It is not safe for concurrent usage. Use a connection pool to manage access
// to multiple database connections from multiple goroutines.
type Conn struct {
	pgConn             *pgconn.PgConn
	config             *ConnConfig // config used when establishing this connection
	preparedStatements map[string]*pgconn.StatementDescription
	statementCache     stmtcache.Cache
	descriptionCache   stmtcache.Cache

	queryTracer    QueryTracer
	batchTracer    BatchTracer
	copyFromTracer CopyFromTracer
	prepareTracer  PrepareTracer

	notifications []*pgconn.Notification

	doneChan   chan struct{}
	closedChan chan error

	typeMap *pgtype.Map

	wbuf []byte
	eqb  ExtendedQueryBuilder
}

// Identifier a PostgreSQL identifier or name. Identifiers can be composed of
// multiple parts such as ["schema", "table"] or ["table", "column"].
type Identifier []string

// Sanitize returns a sanitized string safe for SQL interpolation.
func ( Identifier) () string {
	 := make([]string, len())
	for  := range  {
		 := strings.ReplaceAll([], string([]byte{0}), "")
		[] = `"` + strings.ReplaceAll(, `"`, `""`) + `"`
	}
	return strings.Join(, ".")
}

// ErrNoRows occurs when rows are expected but none are returned.
var ErrNoRows = errors.New("no 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")

// Connect establishes a connection with a PostgreSQL server with a connection string. See
// pgconn.Connect for details.
func ( context.Context,  string) (*Conn, error) {
	,  := ParseConfig()
	if  != nil {
		return nil, 
	}
	return connect(, )
}

// ConnectWithOptions behaves exactly like Connect with the addition of options. At the present options is only used to
// provide a GetSSLPassword function.
func ( context.Context,  string,  ParseConfigOptions) (*Conn, error) {
	,  := ParseConfigWithOptions(, )
	if  != nil {
		return nil, 
	}
	return connect(, )
}

// ConnectConfig establishes a connection with a PostgreSQL server with a configuration struct.
// connConfig must have been created by ParseConfig.
func ( context.Context,  *ConnConfig) (*Conn, error) {
	// In general this improves safety. In particular avoid the config.Config.OnNotification mutation from affecting other
	// connections with the same config. See https://github.com/jackc/pgx/issues/618.
	 = .Copy()

	return connect(, )
}

// ParseConfigWithOptions behaves exactly as ParseConfig does with the addition of options. At the present options is
// only used to provide a GetSSLPassword function.
func ( string,  ParseConfigOptions) (*ConnConfig, error) {
	,  := pgconn.ParseConfigWithOptions(, .ParseConfigOptions)
	if  != nil {
		return nil, 
	}

	 := 512
	if ,  := .RuntimeParams["statement_cache_capacity"];  {
		delete(.RuntimeParams, "statement_cache_capacity")
		,  := strconv.ParseInt(, 10, 32)
		if  != nil {
			return nil, fmt.Errorf("cannot parse statement_cache_capacity: %w", )
		}
		 = int()
	}

	 := 512
	if ,  := .RuntimeParams["description_cache_capacity"];  {
		delete(.RuntimeParams, "description_cache_capacity")
		,  := strconv.ParseInt(, 10, 32)
		if  != nil {
			return nil, fmt.Errorf("cannot parse description_cache_capacity: %w", )
		}
		 = int()
	}

	 := QueryExecModeCacheStatement
	if ,  := .RuntimeParams["default_query_exec_mode"];  {
		delete(.RuntimeParams, "default_query_exec_mode")
		switch  {
		case "cache_statement":
			 = QueryExecModeCacheStatement
		case "cache_describe":
			 = QueryExecModeCacheDescribe
		case "describe_exec":
			 = QueryExecModeDescribeExec
		case "exec":
			 = QueryExecModeExec
		case "simple_protocol":
			 = QueryExecModeSimpleProtocol
		default:
			return nil, fmt.Errorf("invalid default_query_exec_mode: %s", )
		}
	}

	 := &ConnConfig{
		Config:                   *,
		createdByParseConfig:     true,
		StatementCacheCapacity:   ,
		DescriptionCacheCapacity: ,
		DefaultQueryExecMode:     ,
		connString:               ,
	}

	return , nil
}

// ParseConfig creates a ConnConfig from a connection string. ParseConfig handles all options that [pgconn.ParseConfig]
// does. In addition, it accepts the following options:
//
//   - default_query_exec_mode.
//     Possible values: "cache_statement", "cache_describe", "describe_exec", "exec", and "simple_protocol". See
//     QueryExecMode constant documentation for the meaning of these values. Default: "cache_statement".
//
//   - statement_cache_capacity.
//     The maximum size of the statement cache used when executing a query with "cache_statement" query exec mode.
//     Default: 512.
//
//   - description_cache_capacity.
//     The maximum size of the description cache used when executing a query with "cache_describe" query exec mode.
//     Default: 512.
func ( string) (*ConnConfig, error) {
	return ParseConfigWithOptions(, ParseConfigOptions{})
}

// connect connects to a database. connect takes ownership of config. The caller must not use or access it again.
func connect( context.Context,  *ConnConfig) ( *Conn,  error) {
	if ,  := .Tracer.(ConnectTracer);  {
		 = .TraceConnectStart(, TraceConnectStartData{ConnConfig: })
		defer func() {
			.TraceConnectEnd(, TraceConnectEndData{Conn: , Err: })
		}()
	}

	// Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from
	// zero values.
	if !.createdByParseConfig {
		panic("config must be created by ParseConfig")
	}

	 = &Conn{
		config:      ,
		typeMap:     pgtype.NewMap(),
		queryTracer: .Tracer,
	}

	if ,  := .queryTracer.(BatchTracer);  {
		.batchTracer = 
	}
	if ,  := .queryTracer.(CopyFromTracer);  {
		.copyFromTracer = 
	}
	if ,  := .queryTracer.(PrepareTracer);  {
		.prepareTracer = 
	}

	// Only install pgx notification system if no other callback handler is present.
	if .Config.OnNotification == nil {
		.Config.OnNotification = .bufferNotifications
	}

	.pgConn,  = pgconn.ConnectConfig(, &.Config)
	if  != nil {
		return nil, 
	}

	.preparedStatements = make(map[string]*pgconn.StatementDescription)
	.doneChan = make(chan struct{})
	.closedChan = make(chan error)
	.wbuf = make([]byte, 0, 1024)

	if .config.StatementCacheCapacity > 0 {
		.statementCache = stmtcache.NewLRUCache(.config.StatementCacheCapacity)
	}

	if .config.DescriptionCacheCapacity > 0 {
		.descriptionCache = stmtcache.NewLRUCache(.config.DescriptionCacheCapacity)
	}

	return , nil
}

// Close closes a connection. It is safe to call Close on a already closed
// connection.
func ( *Conn) ( context.Context) error {
	if .IsClosed() {
		return nil
	}

	 := .pgConn.Close()
	return 
}

// 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 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 ( *Conn) ( context.Context, ,  string) ( *pgconn.StatementDescription,  error) {
	if .prepareTracer != nil {
		 = .prepareTracer.TracePrepareStart(, , TracePrepareStartData{Name: , SQL: })
	}

	if  != "" {
		var  bool
		if ,  = .preparedStatements[];  && .SQL ==  {
			if .prepareTracer != nil {
				.prepareTracer.TracePrepareEnd(, , TracePrepareEndData{AlreadyPrepared: true})
			}
			return , nil
		}
	}

	if .prepareTracer != nil {
		defer func() {
			.prepareTracer.TracePrepareEnd(, , TracePrepareEndData{Err: })
		}()
	}

	,  = .pgConn.Prepare(, , , nil)
	if  != nil {
		return nil, 
	}

	if  != "" {
		.preparedStatements[] = 
	}

	return , nil
}

// Deallocate released a prepared statement
func ( *Conn) ( context.Context,  string) error {
	delete(.preparedStatements, )
	,  := .pgConn.Exec(, "deallocate "+quoteIdentifier()).ReadAll()
	return 
}

// DeallocateAll releases all previously prepared statements from the server and client, where it also resets the statement and description cache.
func ( *Conn) ( context.Context) error {
	.preparedStatements = map[string]*pgconn.StatementDescription{}
	if .config.StatementCacheCapacity > 0 {
		.statementCache = stmtcache.NewLRUCache(.config.StatementCacheCapacity)
	}
	if .config.DescriptionCacheCapacity > 0 {
		.descriptionCache = stmtcache.NewLRUCache(.config.DescriptionCacheCapacity)
	}
	,  := .pgConn.Exec(, "deallocate all").ReadAll()
	return 
}

func ( *Conn) ( *pgconn.PgConn,  *pgconn.Notification) {
	.notifications = append(.notifications, )
}

// WaitForNotification waits for a PostgreSQL notification. It wraps the underlying pgconn notification system in a
// slightly more convenient form.
func ( *Conn) ( context.Context) (*pgconn.Notification, error) {
	var  *pgconn.Notification

	// Return already received notification immediately
	if len(.notifications) > 0 {
		 = .notifications[0]
		.notifications = .notifications[1:]
		return , nil
	}

	 := .pgConn.WaitForNotification()
	if len(.notifications) > 0 {
		 = .notifications[0]
		.notifications = .notifications[1:]
	}
	return , 
}

// IsClosed reports if the connection has been closed.
func ( *Conn) () bool {
	return .pgConn.IsClosed()
}

func ( *Conn) ( error) {
	if .IsClosed() {
		return
	}

	,  := context.WithCancel(context.Background())
	() // force immediate hard cancel
	.pgConn.Close()
}

func quoteIdentifier( string) string {
	return `"` + strings.ReplaceAll(, `"`, `""`) + `"`
}

// Ping delegates to the underlying *pgconn.PgConn.Ping.
func ( *Conn) ( context.Context) error {
	return .pgConn.Ping()
}

// PgConn returns the underlying *pgconn.PgConn. This is an escape hatch method that allows lower level access to the
// PostgreSQL connection than pgx exposes.
//
// It is strongly recommended that the connection be idle (no in-progress queries) before the underlying *pgconn.PgConn
// is used and the connection must be returned to the same state before any *pgx.Conn methods are again used.
func ( *Conn) () *pgconn.PgConn { return .pgConn }

// TypeMap returns the connection info used for this connection.
func ( *Conn) () *pgtype.Map { return .typeMap }

// Config returns a copy of config that was used to establish this connection.
func ( *Conn) () *ConnConfig { return .config.Copy() }

// Exec executes sql. sql can be either a prepared statement name or an SQL string. arguments should be referenced
// positionally from the sql string as $1, $2, etc.
func ( *Conn) ( context.Context,  string,  ...any) (pgconn.CommandTag, error) {
	if .queryTracer != nil {
		 = .queryTracer.TraceQueryStart(, , TraceQueryStartData{SQL: , Args: })
	}

	if  := .deallocateInvalidatedCachedStatements();  != nil {
		return pgconn.CommandTag{}, 
	}

	,  := .exec(, , ...)

	if .queryTracer != nil {
		.queryTracer.TraceQueryEnd(, , TraceQueryEndData{CommandTag: , Err: })
	}

	return , 
}

func ( *Conn) ( context.Context,  string,  ...any) ( pgconn.CommandTag,  error) {
	 := .config.DefaultQueryExecMode
	var  QueryRewriter

:
	for len() > 0 {
		switch arg := [0].(type) {
		case QueryExecMode:
			 = 
			 = [1:]
		case QueryRewriter:
			 = 
			 = [1:]
		default:
			break 
		}
	}

	if  != nil {
		, ,  = .RewriteQuery(, , , )
		if  != nil {
			return pgconn.CommandTag{}, fmt.Errorf("rewrite query failed: %v", )
		}
	}

	// Always use simple protocol when there are no arguments.
	if len() == 0 {
		 = QueryExecModeSimpleProtocol
	}

	if ,  := .preparedStatements[];  {
		return .execPrepared(, , )
	}

	switch  {
	case QueryExecModeCacheStatement:
		if .statementCache == nil {
			return pgconn.CommandTag{}, errDisabledStatementCache
		}
		 := .statementCache.Get()
		if  == nil {
			,  = .Prepare(, stmtcache.NextStatementName(), )
			if  != nil {
				return pgconn.CommandTag{}, 
			}
			.statementCache.Put()
		}

		return .execPrepared(, , )
	case QueryExecModeCacheDescribe:
		if .descriptionCache == nil {
			return pgconn.CommandTag{}, errDisabledDescriptionCache
		}
		 := .descriptionCache.Get()
		if  == nil {
			,  = .Prepare(, "", )
			if  != nil {
				return pgconn.CommandTag{}, 
			}
		}

		return .execParams(, , )
	case QueryExecModeDescribeExec:
		,  := .Prepare(, "", )
		if  != nil {
			return pgconn.CommandTag{}, 
		}
		return .execPrepared(, , )
	case QueryExecModeExec:
		return .execSQLParams(, , )
	case QueryExecModeSimpleProtocol:
		return .execSimpleProtocol(, , )
	default:
		return pgconn.CommandTag{}, fmt.Errorf("unknown QueryExecMode: %v", )
	}
}

func ( *Conn) ( context.Context,  string,  []any) ( pgconn.CommandTag,  error) {
	if len() > 0 {
		,  = .sanitizeForSimpleQuery(, ...)
		if  != nil {
			return pgconn.CommandTag{}, 
		}
	}

	 := .pgConn.Exec(, )
	for .NextResult() {
		, _ = .ResultReader().Close()
	}
	 = .Close()
	return , 
}

func ( *Conn) ( context.Context,  *pgconn.StatementDescription,  []any) (pgconn.CommandTag, error) {
	 := .eqb.Build(.typeMap, , )
	if  != nil {
		return pgconn.CommandTag{}, 
	}

	 := .pgConn.ExecParams(, .SQL, .eqb.ParamValues, .ParamOIDs, .eqb.ParamFormats, .eqb.ResultFormats).Read()
	.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.
	return .CommandTag, .Err
}

func ( *Conn) ( context.Context,  *pgconn.StatementDescription,  []any) (pgconn.CommandTag, error) {
	 := .eqb.Build(.typeMap, , )
	if  != nil {
		return pgconn.CommandTag{}, 
	}

	 := .pgConn.ExecPrepared(, .Name, .eqb.ParamValues, .eqb.ParamFormats, .eqb.ResultFormats).Read()
	.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.
	return .CommandTag, .Err
}

type unknownArgumentTypeQueryExecModeExecError struct {
	arg any
}

func ( *unknownArgumentTypeQueryExecModeExecError) () string {
	return fmt.Sprintf("cannot use unregistered type %T as query argument in QueryExecModeExec", .arg)
}

func ( *Conn) ( context.Context,  string,  []any) (pgconn.CommandTag, error) {
	 := .eqb.Build(.typeMap, nil, )
	if  != nil {
		return pgconn.CommandTag{}, 
	}

	 := .pgConn.ExecParams(, , .eqb.ParamValues, nil, .eqb.ParamFormats, .eqb.ResultFormats).Read()
	.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.
	return .CommandTag, .Err
}

func ( *Conn) ( context.Context,  string,  []any) *baseRows {
	 := &baseRows{}

	.ctx = 
	.queryTracer = .queryTracer
	.typeMap = .typeMap
	.startTime = time.Now()
	.sql = 
	.args = 
	.conn = 

	return 
}

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.
	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.
	QueryExecModeCacheDescribe

	// Get the statement description on every execution. This uses the extended protocol. Queries require two round trips
	// to execute. It does not use named prepared statements. But it does use the unnamed prepared statement to get the
	// statement description on the first round trip and then uses it to execute the query on the second round trip. This
	// may cause problems with connection poolers that switch the underlying connection between round trips. It is safe
	// even when the the database schema is modified concurrently.
	QueryExecModeDescribeExec

	// 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
	// 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.
	// 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.
	//
	// QueryExecModeSimpleProtocol should have the user application visible behavior as QueryExecModeExec with minor
	// exceptions such as behavior when multiple result returning queries are erroneously sent in a single string.
	//
	// QueryExecModeSimpleProtocol uses client side parameter interpolation. All values are quoted and escaped. Prefer
	// QueryExecModeExec over QueryExecModeSimpleProtocol whenever possible. In general QueryExecModeSimpleProtocol
	// should only be used if connecting to a proxy server, connection pool server, or non-PostgreSQL server that does
	// not support the extended protocol.
	QueryExecModeSimpleProtocol
)

func ( QueryExecMode) () string {
	switch  {
	case QueryExecModeCacheStatement:
		return "cache statement"
	case QueryExecModeCacheDescribe:
		return "cache describe"
	case QueryExecModeDescribeExec:
		return "describe exec"
	case QueryExecModeExec:
		return "exec"
	case QueryExecModeSimpleProtocol:
		return "simple protocol"
	default:
		return "invalid"
	}
}

// QueryResultFormats controls the result format (text=0, binary=1) of a query by result column position.
type QueryResultFormats []int16

// QueryResultFormatsByOID controls the result format (text=0, binary=1) of a query by the result column OID.
type QueryResultFormatsByOID map[uint32]int16

// QueryRewriter rewrites a query when used as the first arguments to a query method.
type QueryRewriter interface {
	RewriteQuery(ctx context.Context, conn *Conn, sql string, args []any) (newSQL string, newArgs []any, err error)
}

// Query sends a query to the server and returns a Rows to read the results. Only errors encountered sending the query
// and initializing Rows will be returned. Err() on the returned Rows must be checked after the Rows is closed to
// determine if the query executed successfully.
//
// The returned Rows must be closed before the connection can be used again. It is safe to attempt to read from the
// returned Rows even if an error is returned. The error will be the available in rows.Err() after rows are closed. It
// is allowed to ignore the error returned from Query and handle it in Rows.
//
// It is possible for a call of FieldDescriptions on the returned Rows to return nil even if the Query call did not
// return an error.
//
// It is possible for a query to return one or more rows before encountering an error. In most cases the rows should be
// collected before processing rather than processed while receiving each row. This avoids the possibility of the
// application processing rows from a query that the server rejected. The CollectRows function is useful here.
//
// An implementor of QueryRewriter may be passed as the first element of args. It can rewrite the sql and change or
// replace args. For example, NamedArgs is QueryRewriter that implements named arguments.
//
// For extra control over how the query is executed, the types QueryExecMode, QueryResultFormats, and
// QueryResultFormatsByOID may be used as the first args to control exactly how the query is executed. This is rarely
// needed. See the documentation for those types for details.
func ( *Conn) ( context.Context,  string,  ...any) (Rows, error) {
	if .queryTracer != nil {
		 = .queryTracer.TraceQueryStart(, , TraceQueryStartData{SQL: , Args: })
	}

	if  := .deallocateInvalidatedCachedStatements();  != nil {
		if .queryTracer != nil {
			.queryTracer.TraceQueryEnd(, , TraceQueryEndData{Err: })
		}
		return &baseRows{err: , closed: true}, 
	}

	var  QueryResultFormats
	var  QueryResultFormatsByOID
	 := .config.DefaultQueryExecMode
	var  QueryRewriter

:
	for len() > 0 {
		switch arg := [0].(type) {
		case QueryResultFormats:
			 = 
			 = [1:]
		case QueryResultFormatsByOID:
			 = 
			 = [1:]
		case QueryExecMode:
			 = 
			 = [1:]
		case QueryRewriter:
			 = 
			 = [1:]
		default:
			break 
		}
	}

	if  != nil {
		var  error
		 := 
		 := 
		, ,  = .RewriteQuery(, , , )
		if  != nil {
			 := .getRows(, , )
			 = fmt.Errorf("rewrite query failed: %v", )
			.fatal()
			return , 
		}
	}

	// Bypass any statement caching.
	if  == "" {
		 = QueryExecModeSimpleProtocol
	}

	.eqb.reset()
	anynil.NormalizeSlice()
	 := .getRows(, , )

	var  error
	,  := .preparedStatements[]
	if  != nil ||  == QueryExecModeCacheStatement ||  == QueryExecModeCacheDescribe ||  == QueryExecModeDescribeExec {
		if  == nil {
			,  = .getStatementDescription(, , )
			if  != nil {
				.fatal()
				return , 
			}
		}

		if len(.ParamOIDs) != len() {
			.fatal(fmt.Errorf("expected %d arguments, got %d", len(.ParamOIDs), len()))
			return , .err
		}

		.sql = .SQL

		 = .eqb.Build(.typeMap, , )
		if  != nil {
			.fatal()
			return , .err
		}

		if  != nil {
			 = make([]int16, len(.Fields))
			for  := range  {
				[] = [uint32(.Fields[].DataTypeOID)]
			}
		}

		if  == nil {
			 = .eqb.ResultFormats
		}

		if ! &&  == QueryExecModeCacheDescribe {
			.resultReader = .pgConn.ExecParams(, , .eqb.ParamValues, .ParamOIDs, .eqb.ParamFormats, )
		} else {
			.resultReader = .pgConn.ExecPrepared(, .Name, .eqb.ParamValues, .eqb.ParamFormats, )
		}
	} else if  == QueryExecModeExec {
		 := .eqb.Build(.typeMap, nil, )
		if  != nil {
			.fatal()
			return , .err
		}

		.resultReader = .pgConn.ExecParams(, , .eqb.ParamValues, nil, .eqb.ParamFormats, .eqb.ResultFormats)
	} else if  == QueryExecModeSimpleProtocol {
		,  = .sanitizeForSimpleQuery(, ...)
		if  != nil {
			.fatal()
			return , 
		}

		 := .pgConn.Exec(, )
		if .NextResult() {
			.resultReader = .ResultReader()
			.multiResultReader = 
		} else {
			 = .Close()
			.fatal()
			return , 
		}

		return , nil
	} else {
		 = fmt.Errorf("unknown QueryExecMode: %v", )
		.fatal()
		return , .err
	}

	.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.

	return , .err
}

// getStatementDescription returns the statement description of the sql query
// according to the given mode.
//
// If the mode is one that doesn't require to know the param and result OIDs
// then nil is returned without error.
func ( *Conn) (
	 context.Context,
	 QueryExecMode,
	 string,
) ( *pgconn.StatementDescription,  error) {

	switch  {
	case QueryExecModeCacheStatement:
		if .statementCache == nil {
			return nil, errDisabledStatementCache
		}
		 = .statementCache.Get()
		if  == nil {
			,  = .Prepare(, stmtcache.NextStatementName(), )
			if  != nil {
				return nil, 
			}
			.statementCache.Put()
		}
	case QueryExecModeCacheDescribe:
		if .descriptionCache == nil {
			return nil, errDisabledDescriptionCache
		}
		 = .descriptionCache.Get()
		if  == nil {
			,  = .Prepare(, "", )
			if  != nil {
				return nil, 
			}
			.descriptionCache.Put()
		}
	case QueryExecModeDescribeExec:
		return .Prepare(, "", )
	}
	return , 
}

// QueryRow is a convenience wrapper over Query. Any error that occurs while
// querying is deferred until calling Scan on the returned Row. That Row will
// error with ErrNoRows if no rows are returned.
func ( *Conn) ( context.Context,  string,  ...any) Row {
	,  := .Query(, , ...)
	return (*connRow)(.(*baseRows))
}

// SendBatch sends all queued queries to the server at once. All queries are run in an implicit transaction unless
// explicit transaction control statements are executed. The returned BatchResults must be closed before the connection
// is used again.
func ( *Conn) ( context.Context,  *Batch) ( BatchResults) {
	if .batchTracer != nil {
		 = .batchTracer.TraceBatchStart(, , TraceBatchStartData{Batch: })
		defer func() {
			 := .(interface{ () error }).()
			if  != nil {
				.batchTracer.TraceBatchEnd(, , TraceBatchEndData{Err: })
			}
		}()
	}

	if  := .deallocateInvalidatedCachedStatements();  != nil {
		return &batchResults{ctx: , conn: , err: }
	}

	 := .config.DefaultQueryExecMode

	for ,  := range .queuedQueries {
		var  QueryRewriter
		 := .query
		 := .arguments

	:
		for len() > 0 {
			switch arg := [0].(type) {
			case QueryRewriter:
				 = 
				 = [1:]
			default:
				break 
			}
		}

		if  != nil {
			var  error
			, ,  = .RewriteQuery(, , , )
			if  != nil {
				return &batchResults{ctx: , conn: , err: fmt.Errorf("rewrite query failed: %v", )}
			}
		}

		.query = 
		.arguments = 
	}

	if  == QueryExecModeSimpleProtocol {
		return .sendBatchQueryExecModeSimpleProtocol(, )
	}

	// All other modes use extended protocol and thus can use prepared statements.
	for ,  := range .queuedQueries {
		if ,  := .preparedStatements[.query];  {
			.sd = 
		}
	}

	switch  {
	case QueryExecModeExec:
		return .sendBatchQueryExecModeExec(, )
	case QueryExecModeCacheStatement:
		return .sendBatchQueryExecModeCacheStatement(, )
	case QueryExecModeCacheDescribe:
		return .sendBatchQueryExecModeCacheDescribe(, )
	case QueryExecModeDescribeExec:
		return .sendBatchQueryExecModeDescribeExec(, )
	default:
		panic("unknown QueryExecMode")
	}
}

func ( *Conn) ( context.Context,  *Batch) *batchResults {
	var  strings.Builder
	for ,  := range .queuedQueries {
		if  > 0 {
			.WriteByte(';')
		}
		,  := .sanitizeForSimpleQuery(.query, .arguments...)
		if  != nil {
			return &batchResults{ctx: , conn: , err: }
		}
		.WriteString()
	}
	 := .pgConn.Exec(, .String())
	return &batchResults{
		ctx:   ,
		conn:  ,
		mrr:   ,
		b:     ,
		qqIdx: 0,
	}
}

func ( *Conn) ( context.Context,  *Batch) *batchResults {
	 := &pgconn.Batch{}

	for ,  := range .queuedQueries {
		 := .sd
		if  != nil {
			 := .eqb.Build(.typeMap, , .arguments)
			if  != nil {
				return &batchResults{ctx: , conn: , err: }
			}

			.ExecPrepared(.Name, .eqb.ParamValues, .eqb.ParamFormats, .eqb.ResultFormats)
		} else {
			 := .eqb.Build(.typeMap, nil, .arguments)
			if  != nil {
				return &batchResults{ctx: , conn: , err: }
			}
			.ExecParams(.query, .eqb.ParamValues, nil, .eqb.ParamFormats, .eqb.ResultFormats)
		}
	}

	.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.

	 := .pgConn.ExecBatch(, )

	return &batchResults{
		ctx:   ,
		conn:  ,
		mrr:   ,
		b:     ,
		qqIdx: 0,
	}
}

func ( *Conn) ( context.Context,  *Batch) ( *pipelineBatchResults) {
	if .statementCache == nil {
		return &pipelineBatchResults{ctx: , conn: , err: errDisabledStatementCache, closed: true}
	}

	 := []*pgconn.StatementDescription{}
	 := make(map[string]int)

	for ,  := range .queuedQueries {
		if .sd == nil {
			 := .statementCache.Get(.query)
			if  != nil {
				.sd = 
			} else {
				if ,  := [.query];  {
					.sd = []
				} else {
					 = &pgconn.StatementDescription{
						Name: stmtcache.NextStatementName(),
						SQL:  .query,
					}
					[.SQL] = len()
					 = append(, )
					.sd = 
				}
			}
		}
	}

	return .sendBatchExtendedWithDescription(, , , .statementCache)
}

func ( *Conn) ( context.Context,  *Batch) ( *pipelineBatchResults) {
	if .descriptionCache == nil {
		return &pipelineBatchResults{ctx: , conn: , err: errDisabledDescriptionCache, closed: true}
	}

	 := []*pgconn.StatementDescription{}
	 := make(map[string]int)

	for ,  := range .queuedQueries {
		if .sd == nil {
			 := .descriptionCache.Get(.query)
			if  != nil {
				.sd = 
			} else {
				if ,  := [.query];  {
					.sd = []
				} else {
					 = &pgconn.StatementDescription{
						SQL: .query,
					}
					[.SQL] = len()
					 = append(, )
					.sd = 
				}
			}
		}
	}

	return .sendBatchExtendedWithDescription(, , , .descriptionCache)
}

func ( *Conn) ( context.Context,  *Batch) ( *pipelineBatchResults) {
	 := []*pgconn.StatementDescription{}
	 := make(map[string]int)

	for ,  := range .queuedQueries {
		if .sd == nil {
			if ,  := [.query];  {
				.sd = []
			} else {
				 := &pgconn.StatementDescription{
					SQL: .query,
				}
				[.SQL] = len()
				 = append(, )
				.sd = 
			}
		}
	}

	return .sendBatchExtendedWithDescription(, , , nil)
}

func ( *Conn) ( context.Context,  *Batch,  []*pgconn.StatementDescription,  stmtcache.Cache) ( *pipelineBatchResults) {
	 := .pgConn.StartPipeline(context.Background())
	defer func() {
		if  != nil && .err != nil {
			.Close()
		}
	}()

	// Prepare any needed queries
	if len() > 0 {
		for ,  := range  {
			.SendPrepare(.Name, .SQL, nil)
		}

		 := .Sync()
		if  != nil {
			return &pipelineBatchResults{ctx: , conn: , err: , closed: true}
		}

		for ,  := range  {
			,  := .GetResults()
			if  != nil {
				return &pipelineBatchResults{ctx: , conn: , err: , closed: true}
			}

			,  := .(*pgconn.StatementDescription)
			if ! {
				return &pipelineBatchResults{ctx: , conn: , err: fmt.Errorf("expected statement description, got %T", ), closed: true}
			}

			// Fill in the previously empty / pending statement descriptions.
			.ParamOIDs = .ParamOIDs
			.Fields = .Fields
		}

		,  := .GetResults()
		if  != nil {
			return &pipelineBatchResults{ctx: , conn: , err: , closed: true}
		}

		,  := .(*pgconn.PipelineSync)
		if ! {
			return &pipelineBatchResults{ctx: , conn: , err: fmt.Errorf("expected sync, got %T", ), closed: true}
		}
	}

	// Put all statements into the cache. It's fine if it overflows because HandleInvalidated will clean them up later.
	if  != nil {
		for ,  := range  {
			.Put()
		}
	}

	// Queue the queries.
	for ,  := range .queuedQueries {
		 := .eqb.Build(.typeMap, .sd, .arguments)
		if  != nil {
			// we wrap the error so we the user can understand which query failed inside the batch
			 = fmt.Errorf("error building query %s: %w", .query, )
			return &pipelineBatchResults{ctx: , conn: , err: , closed: true}
		}

		if .sd.Name == "" {
			.SendQueryParams(.sd.SQL, .eqb.ParamValues, .sd.ParamOIDs, .eqb.ParamFormats, .eqb.ResultFormats)
		} else {
			.SendQueryPrepared(.sd.Name, .eqb.ParamValues, .eqb.ParamFormats, .eqb.ResultFormats)
		}
	}

	 := .Sync()
	if  != nil {
		return &pipelineBatchResults{ctx: , conn: , err: , closed: true}
	}

	return &pipelineBatchResults{
		ctx:      ,
		conn:     ,
		pipeline: ,
		b:        ,
	}
}

func ( *Conn) ( string,  ...any) (string, error) {
	if .pgConn.ParameterStatus("standard_conforming_strings") != "on" {
		return "", errors.New("simple protocol queries must be run with standard_conforming_strings=on")
	}

	if .pgConn.ParameterStatus("client_encoding") != "UTF8" {
		return "", errors.New("simple protocol queries must be run with client_encoding=UTF8")
	}

	var  error
	 := make([]any, len())
	for ,  := range  {
		[],  = convertSimpleArgument(.typeMap, )
		if  != nil {
			return "", 
		}
	}

	return sanitize.SanitizeSQL(, ...)
}

// LoadType inspects the database for typeName and produces a pgtype.Type suitable for registration.
func ( *Conn) ( context.Context,  string) (*pgtype.Type, error) {
	var  uint32

	 := .QueryRow(, "select $1::text::regtype::oid;", ).Scan(&)
	if  != nil {
		return nil, 
	}

	var  string
	var  uint32

	 = .QueryRow(, "select typtype::text, typbasetype from pg_type where oid=$1", ).Scan(&, &)
	if  != nil {
		return nil, 
	}

	switch  {
	case "b": // array
		,  := .getArrayElementOID(, )
		if  != nil {
			return nil, 
		}

		,  := .TypeMap().TypeForOID()
		if ! {
			return nil, errors.New("array element OID not registered")
		}

		return &pgtype.Type{Name: , OID: , Codec: &pgtype.ArrayCodec{ElementType: }}, nil
	case "c": // composite
		,  := .getCompositeFields(, )
		if  != nil {
			return nil, 
		}

		return &pgtype.Type{Name: , OID: , Codec: &pgtype.CompositeCodec{Fields: }}, nil
	case "d": // domain
		,  := .TypeMap().TypeForOID()
		if ! {
			return nil, errors.New("domain base type OID not registered")
		}

		return &pgtype.Type{Name: , OID: , Codec: .Codec}, nil
	case "e": // enum
		return &pgtype.Type{Name: , OID: , Codec: &pgtype.EnumCodec{}}, nil
	case "r": // range
		,  := .getRangeElementOID(, )
		if  != nil {
			return nil, 
		}

		,  := .TypeMap().TypeForOID()
		if ! {
			return nil, errors.New("range element OID not registered")
		}

		return &pgtype.Type{Name: , OID: , Codec: &pgtype.RangeCodec{ElementType: }}, nil
	case "m": // multirange
		,  := .getMultiRangeElementOID(, )
		if  != nil {
			return nil, 
		}

		,  := .TypeMap().TypeForOID()
		if ! {
			return nil, errors.New("multirange element OID not registered")
		}

		return &pgtype.Type{Name: , OID: , Codec: &pgtype.MultirangeCodec{ElementType: }}, nil
	default:
		return &pgtype.Type{}, errors.New("unknown typtype")
	}
}

func ( *Conn) ( context.Context,  uint32) (uint32, error) {
	var  uint32

	 := .QueryRow(, "select typelem from pg_type where oid=$1", ).Scan(&)
	if  != nil {
		return 0, 
	}

	return , nil
}

func ( *Conn) ( context.Context,  uint32) (uint32, error) {
	var  uint32

	 := .QueryRow(, "select rngsubtype from pg_range where rngtypid=$1", ).Scan(&)
	if  != nil {
		return 0, 
	}

	return , nil
}

func ( *Conn) ( context.Context,  uint32) (uint32, error) {
	var  uint32

	 := .QueryRow(, "select rngtypid from pg_range where rngmultitypid=$1", ).Scan(&)
	if  != nil {
		return 0, 
	}

	return , nil
}

func ( *Conn) ( context.Context,  uint32) ([]pgtype.CompositeCodecField, error) {
	var  uint32

	 := .QueryRow(, "select typrelid from pg_type where oid=$1", ).Scan(&)
	if  != nil {
		return nil, 
	}

	var  []pgtype.CompositeCodecField
	var  string
	var  uint32
	,  := .Query(, `select attname, atttypid
from pg_attribute
where attrelid=$1
	and not attisdropped
	and attnum > 0
order by attnum`,
		,
	)
	_,  = ForEachRow(, []any{&, &}, func() error {
		,  := .TypeMap().TypeForOID()
		if ! {
			return fmt.Errorf("unknown composite type field OID: %v", )
		}
		 = append(, pgtype.CompositeCodecField{Name: , Type: })
		return nil
	})
	if  != nil {
		return nil, 
	}

	return , nil
}

func ( *Conn) ( context.Context) error {
	if .pgConn.TxStatus() != 'I' {
		return nil
	}

	if .descriptionCache != nil {
		.descriptionCache.HandleInvalidated()
	}

	var  []*pgconn.StatementDescription
	if .statementCache != nil {
		 = .statementCache.HandleInvalidated()
	}

	if len() == 0 {
		return nil
	}

	 := .pgConn.StartPipeline()
	defer .Close()

	for ,  := range  {
		.SendDeallocate(.Name)
		delete(.preparedStatements, .Name)
	}

	 := .Sync()
	if  != nil {
		return fmt.Errorf("failed to deallocate cached statement(s): %w", )
	}

	 = .Close()
	if  != nil {
		return fmt.Errorf("failed to deallocate cached statement(s): %w", )
	}

	return nil
}