347 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			347 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // +build go1.8
 | |
| 
 | |
| package sqlx
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"database/sql"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"path/filepath"
 | |
| 	"reflect"
 | |
| )
 | |
| 
 | |
| // ConnectContext to a database and verify with a ping.
 | |
| func ConnectContext(ctx context.Context, driverName, dataSourceName string) (*DB, error) {
 | |
| 	db, err := Open(driverName, dataSourceName)
 | |
| 	if err != nil {
 | |
| 		return db, err
 | |
| 	}
 | |
| 	err = db.PingContext(ctx)
 | |
| 	return db, err
 | |
| }
 | |
| 
 | |
| // QueryerContext is an interface used by GetContext and SelectContext
 | |
| type QueryerContext interface {
 | |
| 	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
 | |
| 	QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
 | |
| 	QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row
 | |
| }
 | |
| 
 | |
| // PreparerContext is an interface used by PreparexContext.
 | |
| type PreparerContext interface {
 | |
| 	PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
 | |
| }
 | |
| 
 | |
| // ExecerContext is an interface used by MustExecContext and LoadFileContext
 | |
| type ExecerContext interface {
 | |
| 	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
 | |
| }
 | |
| 
 | |
| // ExtContext is a union interface which can bind, query, and exec, with Context
 | |
| // used by NamedQueryContext and NamedExecContext.
 | |
| type ExtContext interface {
 | |
| 	binder
 | |
| 	QueryerContext
 | |
| 	ExecerContext
 | |
| }
 | |
| 
 | |
| // SelectContext executes a query using the provided Queryer, and StructScans
 | |
| // each row into dest, which must be a slice.  If the slice elements are
 | |
| // scannable, then the result set must have only one column.  Otherwise,
 | |
| // StructScan is used. The *sql.Rows are closed automatically.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func SelectContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
 | |
| 	rows, err := q.QueryxContext(ctx, query, args...)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	// if something happens here, we want to make sure the rows are Closed
 | |
| 	defer rows.Close()
 | |
| 	return scanAll(rows, dest, false)
 | |
| }
 | |
| 
 | |
| // PreparexContext prepares a statement.
 | |
| //
 | |
| // The provided context is used for the preparation of the statement, not for
 | |
| // the execution of the statement.
 | |
| func PreparexContext(ctx context.Context, p PreparerContext, query string) (*Stmt, error) {
 | |
| 	s, err := p.PrepareContext(ctx, query)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return &Stmt{Stmt: s, unsafe: isUnsafe(p), Mapper: mapperFor(p)}, err
 | |
| }
 | |
| 
 | |
| // GetContext does a QueryRow using the provided Queryer, and scans the
 | |
| // resulting row to dest.  If dest is scannable, the result must only have one
 | |
| // column. Otherwise, StructScan is used.  Get will return sql.ErrNoRows like
 | |
| // row.Scan would. Any placeholder parameters are replaced with supplied args.
 | |
| // An error is returned if the result set is empty.
 | |
| func GetContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
 | |
| 	r := q.QueryRowxContext(ctx, query, args...)
 | |
| 	return r.scanAny(dest, false)
 | |
| }
 | |
| 
 | |
| // LoadFileContext exec's every statement in a file (as a single call to Exec).
 | |
| // LoadFileContext may return a nil *sql.Result if errors are encountered
 | |
| // locating or reading the file at path.  LoadFile reads the entire file into
 | |
| // memory, so it is not suitable for loading large data dumps, but can be useful
 | |
| // for initializing schemas or loading indexes.
 | |
| //
 | |
| // FIXME: this does not really work with multi-statement files for mattn/go-sqlite3
 | |
| // or the go-mysql-driver/mysql drivers;  pq seems to be an exception here.  Detecting
 | |
| // this by requiring something with DriverName() and then attempting to split the
 | |
| // queries will be difficult to get right, and its current driver-specific behavior
 | |
| // is deemed at least not complex in its incorrectness.
 | |
| func LoadFileContext(ctx context.Context, e ExecerContext, path string) (*sql.Result, error) {
 | |
| 	realpath, err := filepath.Abs(path)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	contents, err := ioutil.ReadFile(realpath)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	res, err := e.ExecContext(ctx, string(contents))
 | |
| 	return &res, err
 | |
| }
 | |
| 
 | |
| // MustExecContext execs the query using e and panics if there was an error.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func MustExecContext(ctx context.Context, e ExecerContext, query string, args ...interface{}) sql.Result {
 | |
| 	res, err := e.ExecContext(ctx, query, args...)
 | |
| 	if err != nil {
 | |
| 		panic(err)
 | |
| 	}
 | |
| 	return res
 | |
| }
 | |
| 
 | |
| // PrepareNamedContext returns an sqlx.NamedStmt
 | |
| func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) {
 | |
| 	return prepareNamedContext(ctx, db, query)
 | |
| }
 | |
| 
 | |
| // NamedQueryContext using this DB.
 | |
| // Any named placeholder parameters are replaced with fields from arg.
 | |
| func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*Rows, error) {
 | |
| 	return NamedQueryContext(ctx, db, query, arg)
 | |
| }
 | |
| 
 | |
| // NamedExecContext using this DB.
 | |
| // Any named placeholder parameters are replaced with fields from arg.
 | |
| func (db *DB) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) {
 | |
| 	return NamedExecContext(ctx, db, query, arg)
 | |
| }
 | |
| 
 | |
| // SelectContext using this DB.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
 | |
| 	return SelectContext(ctx, db, dest, query, args...)
 | |
| }
 | |
| 
 | |
| // GetContext using this DB.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| // An error is returned if the result set is empty.
 | |
| func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
 | |
| 	return GetContext(ctx, db, dest, query, args...)
 | |
| }
 | |
| 
 | |
| // PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
 | |
| //
 | |
| // The provided context is used for the preparation of the statement, not for
 | |
| // the execution of the statement.
 | |
| func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
 | |
| 	return PreparexContext(ctx, db, query)
 | |
| }
 | |
| 
 | |
| // QueryxContext queries the database and returns an *sqlx.Rows.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
 | |
| 	r, err := db.DB.QueryContext(ctx, query, args...)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return &Rows{Rows: r, unsafe: db.unsafe, Mapper: db.Mapper}, err
 | |
| }
 | |
| 
 | |
| // QueryRowxContext queries the database and returns an *sqlx.Row.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
 | |
| 	rows, err := db.DB.QueryContext(ctx, query, args...)
 | |
| 	return &Row{rows: rows, err: err, unsafe: db.unsafe, Mapper: db.Mapper}
 | |
| }
 | |
| 
 | |
| // MustBeginTx starts a transaction, and panics on error.  Returns an *sqlx.Tx instead
 | |
| // of an *sql.Tx.
 | |
| //
 | |
| // The provided context is used until the transaction is committed or rolled
 | |
| // back. If the context is canceled, the sql package will roll back the
 | |
| // transaction. Tx.Commit will return an error if the context provided to
 | |
| // MustBeginContext is canceled.
 | |
| func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx {
 | |
| 	tx, err := db.BeginTxx(ctx, opts)
 | |
| 	if err != nil {
 | |
| 		panic(err)
 | |
| 	}
 | |
| 	return tx
 | |
| }
 | |
| 
 | |
| // MustExecContext (panic) runs MustExec using this database.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (db *DB) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result {
 | |
| 	return MustExecContext(ctx, db, query, args...)
 | |
| }
 | |
| 
 | |
| // BeginTxx begins a transaction and returns an *sqlx.Tx instead of an
 | |
| // *sql.Tx.
 | |
| //
 | |
| // The provided context is used until the transaction is committed or rolled
 | |
| // back. If the context is canceled, the sql package will roll back the
 | |
| // transaction. Tx.Commit will return an error if the context provided to
 | |
| // BeginxContext is canceled.
 | |
| func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
 | |
| 	tx, err := db.DB.BeginTx(ctx, opts)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err
 | |
| }
 | |
| 
 | |
| // StmtxContext returns a version of the prepared statement which runs within a
 | |
| // transaction. Provided stmt can be either *sql.Stmt or *sqlx.Stmt.
 | |
| func (tx *Tx) StmtxContext(ctx context.Context, stmt interface{}) *Stmt {
 | |
| 	var s *sql.Stmt
 | |
| 	switch v := stmt.(type) {
 | |
| 	case Stmt:
 | |
| 		s = v.Stmt
 | |
| 	case *Stmt:
 | |
| 		s = v.Stmt
 | |
| 	case *sql.Stmt:
 | |
| 		s = v
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("non-statement type %v passed to Stmtx", reflect.ValueOf(stmt).Type()))
 | |
| 	}
 | |
| 	return &Stmt{Stmt: tx.StmtContext(ctx, s), Mapper: tx.Mapper}
 | |
| }
 | |
| 
 | |
| // NamedStmtContext returns a version of the prepared statement which runs
 | |
| // within a transaction.
 | |
| func (tx *Tx) NamedStmtContext(ctx context.Context, stmt *NamedStmt) *NamedStmt {
 | |
| 	return &NamedStmt{
 | |
| 		QueryString: stmt.QueryString,
 | |
| 		Params:      stmt.Params,
 | |
| 		Stmt:        tx.StmtxContext(ctx, stmt.Stmt),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
 | |
| //
 | |
| // The provided context is used for the preparation of the statement, not for
 | |
| // the execution of the statement.
 | |
| func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
 | |
| 	return PreparexContext(ctx, tx, query)
 | |
| }
 | |
| 
 | |
| // PrepareNamedContext returns an sqlx.NamedStmt
 | |
| func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) {
 | |
| 	return prepareNamedContext(ctx, tx, query)
 | |
| }
 | |
| 
 | |
| // MustExecContext runs MustExecContext within a transaction.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result {
 | |
| 	return MustExecContext(ctx, tx, query, args...)
 | |
| }
 | |
| 
 | |
| // QueryxContext within a transaction and context.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
 | |
| 	r, err := tx.Tx.QueryContext(ctx, query, args...)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return &Rows{Rows: r, unsafe: tx.unsafe, Mapper: tx.Mapper}, err
 | |
| }
 | |
| 
 | |
| // SelectContext within a transaction and context.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
 | |
| 	return SelectContext(ctx, tx, dest, query, args...)
 | |
| }
 | |
| 
 | |
| // GetContext within a transaction and context.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| // An error is returned if the result set is empty.
 | |
| func (tx *Tx) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
 | |
| 	return GetContext(ctx, tx, dest, query, args...)
 | |
| }
 | |
| 
 | |
| // QueryRowxContext within a transaction and context.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
 | |
| 	rows, err := tx.Tx.QueryContext(ctx, query, args...)
 | |
| 	return &Row{rows: rows, err: err, unsafe: tx.unsafe, Mapper: tx.Mapper}
 | |
| }
 | |
| 
 | |
| // NamedExecContext using this Tx.
 | |
| // Any named placeholder parameters are replaced with fields from arg.
 | |
| func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) {
 | |
| 	return NamedExecContext(ctx, tx, query, arg)
 | |
| }
 | |
| 
 | |
| // SelectContext using the prepared statement.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error {
 | |
| 	return SelectContext(ctx, &qStmt{s}, dest, "", args...)
 | |
| }
 | |
| 
 | |
| // GetContext using the prepared statement.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| // An error is returned if the result set is empty.
 | |
| func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error {
 | |
| 	return GetContext(ctx, &qStmt{s}, dest, "", args...)
 | |
| }
 | |
| 
 | |
| // MustExecContext (panic) using this statement.  Note that the query portion of
 | |
| // the error output will be blank, as Stmt does not expose its query.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Result {
 | |
| 	return MustExecContext(ctx, &qStmt{s}, "", args...)
 | |
| }
 | |
| 
 | |
| // QueryRowxContext using this statement.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *Row {
 | |
| 	qs := &qStmt{s}
 | |
| 	return qs.QueryRowxContext(ctx, "", args...)
 | |
| }
 | |
| 
 | |
| // QueryxContext using this statement.
 | |
| // Any placeholder parameters are replaced with supplied args.
 | |
| func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) {
 | |
| 	qs := &qStmt{s}
 | |
| 	return qs.QueryxContext(ctx, "", args...)
 | |
| }
 | |
| 
 | |
| func (q *qStmt) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
 | |
| 	return q.Stmt.QueryContext(ctx, args...)
 | |
| }
 | |
| 
 | |
| func (q *qStmt) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
 | |
| 	r, err := q.Stmt.QueryContext(ctx, args...)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return &Rows{Rows: r, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}, err
 | |
| }
 | |
| 
 | |
| func (q *qStmt) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
 | |
| 	rows, err := q.Stmt.QueryContext(ctx, args...)
 | |
| 	return &Row{rows: rows, err: err, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}
 | |
| }
 | |
| 
 | |
| func (q *qStmt) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
 | |
| 	return q.Stmt.ExecContext(ctx, args...)
 | |
| }
 |