package pg

import (
	
	

	
	
	
	
)

var errStmtClosed = errors.New("pg: statement is closed")

// Stmt is a prepared statement. Stmt is safe for concurrent use by
// multiple goroutines.
type Stmt struct {
	db        *baseDB
	stickyErr error

	q       string
	name    string
	columns []types.ColumnInfo
}

func ( *baseDB,  string) (*Stmt, error) {
	 := &Stmt{
		db: ,

		q: ,
	}

	 := .prepare(context.TODO(), )
	if  != nil {
		_ = .Close()
		return nil, 
	}
	return , nil
}

func ( *Stmt) ( context.Context,  string) error {
	var  error
	for  := 0;  <= .db.opt.MaxRetries; ++ {
		if  > 0 {
			if  := internal.Sleep(, .db.retryBackoff(-1));  != nil {
				return 
			}

			 := .db.pool.(*pool.StickyConnPool).Reset()
			if  != nil {
				return 
			}
		}

		 = .withConn(, func( context.Context,  *pool.Conn) error {
			var  error
			.name, .columns,  = .db.prepare(, , )
			return 
		})
		if !.db.shouldRetry() {
			break
		}
	}
	return 
}

func ( *Stmt) ( context.Context,  func(context.Context, *pool.Conn) error) error {
	if .stickyErr != nil {
		return .stickyErr
	}
	 := .db.withConn(, )
	if  == pool.ErrClosed {
		return errStmtClosed
	}
	return 
}

// Exec executes a prepared statement with the given parameters.
func ( *Stmt) ( ...interface{}) (Result, error) {
	return .exec(context.TODO(), ...)
}

// ExecContext executes a prepared statement with the given parameters.
func ( *Stmt) ( context.Context,  ...interface{}) (Result, error) {
	return .exec(, ...)
}

func ( *Stmt) ( context.Context,  ...interface{}) (Result, error) {
	, ,  := .db.beforeQuery(, .db.db, nil, .q, , nil)
	if  != nil {
		return nil, 
	}

	var  Result
	var  error
	for  := 0;  <= .db.opt.MaxRetries; ++ {
		if  > 0 {
			 = internal.Sleep(, .db.retryBackoff(-1))
			if  != nil {
				break
			}
		}

		 = .withConn(, func( context.Context,  *pool.Conn) error {
			,  = .extQuery(, , .name, ...)
			return 
		})
		if !.db.shouldRetry() {
			break
		}
	}

	if  := .db.afterQuery(, , , );  != nil {
		return nil, 
	}
	return , 
}

// ExecOne acts like Exec, but query must affect only one row. It
// returns ErrNoRows error when query returns zero rows or
// ErrMultiRows when query returns multiple rows.
func ( *Stmt) ( ...interface{}) (Result, error) {
	return .execOne(context.Background(), ...)
}

// ExecOneContext acts like ExecOne but additionally receives a context.
func ( *Stmt) ( context.Context,  ...interface{}) (Result, error) {
	return .execOne(, ...)
}

func ( *Stmt) ( context.Context,  ...interface{}) (Result, error) {
	,  := .ExecContext(, ...)
	if  != nil {
		return nil, 
	}

	if  := internal.AssertOneRow(.RowsAffected());  != nil {
		return nil, 
	}
	return , nil
}

// Query executes a prepared query statement with the given parameters.
func ( *Stmt) ( interface{},  ...interface{}) (Result, error) {
	return .query(context.Background(), , ...)
}

// QueryContext acts like Query but additionally receives a context.
func ( *Stmt) ( context.Context,  interface{},  ...interface{}) (Result, error) {
	return .query(, , ...)
}

func ( *Stmt) ( context.Context,  interface{},  ...interface{}) (Result, error) {
	, ,  := .db.beforeQuery(, .db.db, , .q, , nil)
	if  != nil {
		return nil, 
	}

	var  Result
	var  error
	for  := 0;  <= .db.opt.MaxRetries; ++ {
		if  > 0 {
			 = internal.Sleep(, .db.retryBackoff(-1))
			if  != nil {
				break
			}
		}

		 = .withConn(, func( context.Context,  *pool.Conn) error {
			,  = .extQueryData(, , .name, , .columns, ...)
			return 
		})
		if !.db.shouldRetry() {
			break
		}
	}

	if  := .db.afterQuery(, , , );  != nil {
		return nil, 
	}
	return , 
}

// QueryOne acts like Query, but query must return only one row. It
// returns ErrNoRows error when query returns zero rows or
// ErrMultiRows when query returns multiple rows.
func ( *Stmt) ( interface{},  ...interface{}) (Result, error) {
	return .queryOne(context.Background(), , ...)
}

// QueryOneContext acts like QueryOne but additionally receives a context.
func ( *Stmt) ( context.Context,  interface{},  ...interface{}) (Result, error) {
	return .queryOne(, , ...)
}

func ( *Stmt) ( context.Context,  interface{},  ...interface{}) (Result, error) {
	,  := orm.NewModel()
	if  != nil {
		return nil, 
	}

	,  := .QueryContext(, , ...)
	if  != nil {
		return nil, 
	}

	if  := internal.AssertOneRow(.RowsAffected());  != nil {
		return nil, 
	}
	return , nil
}

// Close closes the statement.
func ( *Stmt) () error {
	var  error

	if .name != "" {
		 = .closeStmt()
	}

	 := .db.Close()
	if  != nil &&  == nil {
		 = 
	}

	return 
}

func ( *Stmt) (
	 context.Context,  *pool.Conn,  string,  ...interface{},
) (Result, error) {
	 := .WithWriter(, .db.opt.WriteTimeout, func( *pool.WriteBuffer) error {
		return writeBindExecuteMsg(, , ...)
	})
	if  != nil {
		return nil, 
	}

	var  Result
	 = .WithReader(, .db.opt.ReadTimeout, func( *pool.ReaderContext) error {
		,  = readExtQuery()
		return 
	})
	if  != nil {
		return nil, 
	}

	return , nil
}

func ( *Stmt) (
	 context.Context,
	 *pool.Conn,
	 string,
	 interface{},
	 []types.ColumnInfo,
	 ...interface{},
) (Result, error) {
	 := .WithWriter(, .db.opt.WriteTimeout, func( *pool.WriteBuffer) error {
		return writeBindExecuteMsg(, , ...)
	})
	if  != nil {
		return nil, 
	}

	var  *result
	 = .WithReader(, .db.opt.ReadTimeout, func( *pool.ReaderContext) error {
		,  = readExtQueryData(, , , )
		return 
	})
	if  != nil {
		return nil, 
	}

	return , nil
}

func ( *Stmt) () error {
	return .withConn(context.TODO(), func( context.Context,  *pool.Conn) error {
		return .db.closeStmt(, , .name)
	})
}