Skip to content
Snippets Groups Projects
sql.go 83.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • // will run in the transaction context.
    func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
    
    	stmt, err := tx.db.prepareDC(ctx, dc, release, tx, query)
    
    	if err != nil {
    		return nil, err
    	}
    
    	tx.stmts.Lock()
    	tx.stmts.v = append(tx.stmts.v, stmt)
    	tx.stmts.Unlock()
    
    // Prepare creates a prepared statement for use within a transaction.
    //
    // The returned statement operates within the transaction and can no longer
    // be used once the transaction has been committed or rolled back.
    //
    // To use an existing prepared statement on this transaction, see Tx.Stmt.
    func (tx *Tx) Prepare(query string) (*Stmt, error) {
    
    	return tx.PrepareContext(context.Background(), query)
    
    }
    
    // StmtContext returns a transaction-specific prepared statement from
    
    // an existing statement.
    //
    // Example:
    //  updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")
    //  ...
    //  tx, err := db.Begin()
    //  ...
    
    //  res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203)
    
    // The provided context is used for the preparation of the statement, not for the
    // execution of the statement.
    //
    
    // The returned statement operates within the transaction and will be closed
    // when the transaction has been committed or rolled back.
    
    func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt {
    
    	dc, release, err := tx.grabConn(ctx)
    	if err != nil {
    		return &Stmt{stickyErr: err}
    	}
    	defer release(nil)
    
    	if tx.db != stmt.db {
    		return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
    	}
    
    	var parentStmt *Stmt
    	stmt.mu.Lock()
    
    		// If the statement has been closed or already belongs to a
    		// transaction, we can't reuse it in this connection.
    		// Since tx.StmtContext should never need to be called with a
    		// Stmt already belonging to tx, we ignore this edge case and
    		// re-prepare the statement in this case. No need to add
    		// code-complexity for this.
    		stmt.mu.Unlock()
    		withLock(dc, func() {
    			si, err = ctxDriverPrepare(ctx, dc.ci, stmt.query)
    		})
    		if err != nil {
    			return &Stmt{stickyErr: err}
    		}
    	} else {
    		stmt.removeClosedStmtLocked()
    		// See if the statement has already been prepared on this connection,
    		// and reuse it if possible.
    		for _, v := range stmt.css {
    			if v.dc == dc {
    				si = v.ds.si
    				break
    			}
    		}
    
    		stmt.mu.Unlock()
    
    		if si == nil {
    
    			withLock(dc, func() {
    				ds, err = stmt.prepareOnConnLocked(ctx, dc)
    			})
    
    			if err != nil {
    				return &Stmt{stickyErr: err}
    			}
    
    		parentStmt: parentStmt,
    		query:      stmt.query,
    	}
    	if parentStmt != nil {
    		tx.db.addDep(parentStmt, txs)
    
    	tx.stmts.Lock()
    	tx.stmts.v = append(tx.stmts.v, txs)
    	tx.stmts.Unlock()
    	return txs
    
    // Stmt returns a transaction-specific prepared statement from
    // an existing statement.
    //
    // Example:
    //  updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")
    //  ...
    //  tx, err := db.Begin()
    //  ...
    //  res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
    //
    
    // The returned statement operates within the transaction and will be closed
    // when the transaction has been committed or rolled back.
    
    func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
    
    	return tx.StmtContext(context.Background(), stmt)
    
    }
    
    // ExecContext executes a query that doesn't return rows.
    
    // For example: an INSERT and UPDATE.
    
    func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
    
    	if err != nil {
    		return nil, err
    	}
    
    	return tx.db.execDC(ctx, dc, release, query, args)
    
    // Exec executes a query that doesn't return rows.
    // For example: an INSERT and UPDATE.
    func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
    
    	return tx.ExecContext(context.Background(), query, args...)
    
    }
    
    // QueryContext executes a query that returns rows, typically a SELECT.
    func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
    
    	if err != nil {
    		return nil, err
    
    	return tx.db.queryDC(ctx, tx.ctx, dc, release, query, args)
    
    }
    
    // Query executes a query that returns rows, typically a SELECT.
    func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
    
    	return tx.QueryContext(context.Background(), query, args...)
    
    }
    
    // QueryRowContext executes a query that is expected to return at most one row.
    // QueryRowContext always returns a non-nil value. Errors are deferred until
    // Row's Scan method is called.
    
    // If the query selects no rows, the *Row's Scan will return ErrNoRows.
    // Otherwise, the *Row's Scan scans the first selected row and discards
    // the rest.
    
    func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row {
    	rows, err := tx.QueryContext(ctx, query, args...)
    	return &Row{rows: rows, err: err}
    
    }
    
    // QueryRow executes a query that is expected to return at most one row.
    
    Evan Shaw's avatar
    Evan Shaw committed
    // QueryRow always returns a non-nil value. Errors are deferred until
    
    // Row's Scan method is called.
    
    // If the query selects no rows, the *Row's Scan will return ErrNoRows.
    // Otherwise, the *Row's Scan scans the first selected row and discards
    // the rest.
    
    func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
    
    	return tx.QueryRowContext(context.Background(), query, args...)
    
    }
    
    // connStmt is a prepared statement on a particular connection.
    type connStmt struct {
    
    // stmtConnGrabber represents a Tx or Conn that will return the underlying
    // driverConn and release function.
    type stmtConnGrabber interface {
    	// grabConn returns the driverConn and the associated release function
    	// that must be called when the operation completes.
    	grabConn(context.Context) (*driverConn, releaseConn, error)
    
    	// txCtx returns the transaction context if available.
    	// The returned context should be selected on along with
    	// any query context when awaiting a cancel.
    	txCtx() context.Context
    }
    
    var (
    	_ stmtConnGrabber = &Tx{}
    	_ stmtConnGrabber = &Conn{}
    )
    
    
    // Stmt is a prepared statement.
    // A Stmt is safe for concurrent use by multiple goroutines.
    
    type Stmt struct {
    	// Immutable:
    
    	db        *DB    // where we came from
    	query     string // that created the Stmt
    	stickyErr error  // if non-nil, this error is returned for all operations
    
    	closemu sync.RWMutex // held exclusively during close, for read otherwise.
    
    
    	// If Stmt is prepared on a Tx or Conn then cg is present and will
    	// only ever grab a connection from cg.
    	// If cg is nil then the Stmt must grab an arbitrary connection
    	// from db and determine if it must prepare the stmt again by
    	// inspecting css.
    	cg   stmtConnGrabber
    	cgds *driverStmt
    
    	// parentStmt is set when a transaction-specific statement
    	// is requested from an identical statement prepared on the same
    	// conn. parentStmt is used to track the dependency of this statement
    	// on its originating ("parent") statement so that parentStmt may
    	// be closed by the user without them having to know whether or not
    	// any transactions are still using it.
    	parentStmt *Stmt
    
    
    	mu     sync.Mutex // protects the rest of the fields
    
    	// css is a list of underlying driver statement interfaces
    
    	// that are valid on particular connections. This is only
    
    	// used if cg == nil and one is found that has idle
    	// connections. If cg != nil, cgds is always used.
    
    
    	// lastNumClosed is copied from db.numClosed when Stmt is created
    	// without tx and closed connections in css are removed.
    	lastNumClosed uint64
    
    // ExecContext executes a prepared statement with the given arguments and
    
    // returns a Result summarizing the effect of the statement.
    
    func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, error) {
    
    	s.closemu.RLock()
    	defer s.closemu.RUnlock()
    
    	strategy := cachedOrNewConn
    	for i := 0; i < maxBadConnRetries+1; i++ {
    		if i == maxBadConnRetries {
    			strategy = alwaysNewConn
    		}
    		dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
    
    		if err != nil {
    			if err == driver.ErrBadConn {
    				continue
    			}
    			return nil, err
    		}
    
    
    		res, err = resultFromStatement(ctx, dc.ci, ds, args...)
    
    		releaseConn(err)
    		if err != driver.ErrBadConn {
    			return res, err
    		}
    	}
    	return nil, driver.ErrBadConn
    
    // Exec executes a prepared statement with the given arguments and
    // returns a Result summarizing the effect of the statement.
    func (s *Stmt) Exec(args ...interface{}) (Result, error) {
    	return s.ExecContext(context.Background(), args...)
    }
    
    
    func resultFromStatement(ctx context.Context, ci driver.Conn, ds *driverStmt, args ...interface{}) (Result, error) {
    
    	ds.Lock()
    	defer ds.Unlock()
    
    	dargs, err := driverArgsConnLocked(ci, ds, args)
    
    	resi, err := ctxDriverStmtExec(ctx, ds.si, dargs)
    
    	if err != nil {
    		return nil, err
    	}
    
    	return driverResult{ds.Locker, resi}, nil
    
    // removeClosedStmtLocked removes closed conns in s.css.
    //
    // To avoid lock contention on DB.mu, we do it only when
    // s.db.numClosed - s.lastNum is large enough.
    func (s *Stmt) removeClosedStmtLocked() {
    	t := len(s.css)/2 + 1
    	if t > 10 {
    		t = 10
    	}
    	dbClosed := atomic.LoadUint64(&s.db.numClosed)
    	if dbClosed-s.lastNumClosed < uint64(t) {
    		return
    	}
    
    	s.db.mu.Lock()
    	for i := 0; i < len(s.css); i++ {
    		if s.css[i].dc.dbmuClosed {
    			s.css[i] = s.css[len(s.css)-1]
    			s.css = s.css[:len(s.css)-1]
    			i--
    		}
    	}
    	s.db.mu.Unlock()
    	s.lastNumClosed = dbClosed
    }
    
    
    // connStmt returns a free driver connection on which to execute the
    // statement, a function to call to release the connection, and a
    // statement bound to that connection.
    
    func (s *Stmt) connStmt(ctx context.Context, strategy connReuseStrategy) (dc *driverConn, releaseConn func(error), ds *driverStmt, err error) {
    
    	if err = s.stickyErr; err != nil {
    		return
    
    	s.mu.Lock()
    	if s.closed {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		err = errors.New("sql: statement is closed")
    
    	// In a transaction or connection, we always use the connection that the
    
    	// stmt was created on.
    
    		dc, releaseConn, err = s.cg.grabConn(ctx) // blocks, waiting for the connection.
    
    	s.removeClosedStmtLocked()
    
    	if err != nil {
    		return nil, nil, nil, err
    	}
    
    	s.mu.Lock()
    	for _, v := range s.css {
    		if v.dc == dc {
    			s.mu.Unlock()
    
    			return dc, dc.releaseConn, v.ds, nil
    
    	s.mu.Unlock()
    
    	// No luck; we need to prepare the statement on this connection
    
    		ds, err = s.prepareOnConnLocked(ctx, dc)
    
    		dc.releaseConn(err)
    
    
    	return dc, dc.releaseConn, ds, nil
    }
    
    // prepareOnConnLocked prepares the query in Stmt s on dc and adds it to the list of
    // open connStmt on the statement. It assumes the caller is holding the lock on dc.
    func (s *Stmt) prepareOnConnLocked(ctx context.Context, dc *driverConn) (*driverStmt, error) {
    
    	si, err := dc.prepareLocked(ctx, s.cg, s.query)
    
    	if err != nil {
    		return nil, err
    	}
    	cs := connStmt{dc, si}
    
    	s.mu.Lock()
    	s.css = append(s.css, cs)
    	s.mu.Unlock()
    
    // QueryContext executes a prepared query statement with the given arguments
    
    // and returns the query results as a *Rows.
    
    func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
    
    	s.closemu.RLock()
    	defer s.closemu.RUnlock()
    
    
    	strategy := cachedOrNewConn
    	for i := 0; i < maxBadConnRetries+1; i++ {
    		if i == maxBadConnRetries {
    			strategy = alwaysNewConn
    		}
    		dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
    
    		if err != nil {
    			if err == driver.ErrBadConn {
    				continue
    			}
    			return nil, err
    		}
    
    		rowsi, err = rowsiFromStatement(ctx, dc.ci, ds, args...)
    
    		if err == nil {
    			// Note: ownership of ci passes to the *Rows, to be freed
    			// with releaseConn.
    			rows := &Rows{
    				dc:    dc,
    				rowsi: rowsi,
    				// releaseConn set below
    			}
    
    			// addDep must be added before initContextClose or it could attempt
    			// to removeDep before it has been added.
    
    
    			// releaseConn must be set before initContextClose or it could
    			// release the connection before it is set.
    
    			rows.releaseConn = func(err error) {
    				releaseConn(err)
    				s.db.removeDep(s, rows)
    			}
    
    			var txctx context.Context
    
    			}
    			rows.initContextClose(ctx, txctx)
    
    		if err != driver.ErrBadConn {
    			return nil, err
    		}
    
    	return nil, driver.ErrBadConn
    
    // Query executes a prepared query statement with the given arguments
    // and returns the query results as a *Rows.
    func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
    	return s.QueryContext(context.Background(), args...)
    }
    
    
    func rowsiFromStatement(ctx context.Context, ci driver.Conn, ds *driverStmt, args ...interface{}) (driver.Rows, error) {
    
    	dargs, err := driverArgsConnLocked(ci, ds, args)
    	if err != nil {
    		return nil, err
    	}
    
    	rowsi, err := ctxDriverStmtQuery(ctx, ds.si, dargs)
    
    	if err != nil {
    		return nil, err
    	}
    
    // QueryRowContext executes a prepared query statement with the given arguments.
    
    // If an error occurs during the execution of the statement, that error will
    // be returned by a call to Scan on the returned *Row, which is always non-nil.
    // If the query selects no rows, the *Row's Scan will return ErrNoRows.
    // Otherwise, the *Row's Scan scans the first selected row and discards
    // the rest.
    
    func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row {
    	rows, err := s.QueryContext(ctx, args...)
    
    	if err != nil {
    		return &Row{err: err}
    	}
    	return &Row{rows: rows}
    }
    
    
    // QueryRow executes a prepared query statement with the given arguments.
    // If an error occurs during the execution of the statement, that error will
    // be returned by a call to Scan on the returned *Row, which is always non-nil.
    // If the query selects no rows, the *Row's Scan will return ErrNoRows.
    // Otherwise, the *Row's Scan scans the first selected row and discards
    // the rest.
    //
    // Example usage:
    //
    //  var name string
    //  err := nameByUseridStmt.QueryRow(id).Scan(&name)
    func (s *Stmt) QueryRow(args ...interface{}) *Row {
    	return s.QueryRowContext(context.Background(), args...)
    }
    
    
    // Close closes the statement.
    
    func (s *Stmt) Close() error {
    
    	s.closemu.Lock()
    	defer s.closemu.Unlock()
    
    
    	if s.stickyErr != nil {
    		return s.stickyErr
    	}
    
    	s.mu.Lock()
    	if s.closed {
    
    		s.mu.Unlock()
    
    		return nil
    	}
    	s.closed = true
    
    	if s.parentStmt != nil {
    		// If parentStmt is set, we must not close s.txds since it's stored
    		// in the css array of the parentStmt.
    		return s.db.removeDep(s.parentStmt, s)
    	}
    
    }
    
    func (s *Stmt) finalClose() error {
    
    	s.mu.Lock()
    	defer s.mu.Unlock()
    	if s.css != nil {
    		for _, v := range s.css {
    
    			s.db.noteUnusedDriverStatement(v.dc, v.ds)
    			v.dc.removeOpenStmt(v.ds)
    
    		}
    		s.css = nil
    
    	}
    	return nil
    }
    
    // Rows is the result of a query. Its cursor starts before the first row
    
    // of the result set. Use Next to advance from row to row.
    
    type Rows struct {
    
    	dc          *driverConn // owned; must call releaseConn when closed to release
    
    	cancel      func()      // called when Rows is closed, may be nil.
    	closeStmt   *driverStmt // if non-nil, statement to Close on close
    
    	// closemu prevents Rows from closing while there
    	// is an active streaming result. It is held for read during non-close operations
    	// and exclusively during close.
    	//
    	// closemu guards lasterr and closed.
    	closemu sync.RWMutex
    	closed  bool
    	lasterr error // non-nil only if closed is true
    
    	// lastcols is only used in Scan, Next, and NextResultSet which are expected
    
    Kevin Burke's avatar
    Kevin Burke committed
    	// not to be called concurrently.
    
    func (rs *Rows) initContextClose(ctx, txctx context.Context) {
    
    	if ctx.Done() == nil && (txctx == nil || txctx.Done() == nil) {
    		return
    	}
    
    	ctx, rs.cancel = context.WithCancel(ctx)
    
    	go rs.awaitDone(ctx, txctx)
    
    // awaitDone blocks until either ctx or txctx is canceled. The ctx is provided
    // from the query context and is canceled when the query Rows is closed.
    // If the query was issued in a transaction, the transaction's context
    // is also provided in txctx to ensure Rows is closed if the Tx is closed.
    func (rs *Rows) awaitDone(ctx, txctx context.Context) {
    	var txctxDone <-chan struct{}
    	if txctx != nil {
    		txctxDone = txctx.Done()
    	}
    	select {
    	case <-ctx.Done():
    	case <-txctxDone:
    	}
    
    // Next prepares the next result row for reading with the Scan method. It
    
    // returns true on success, or false if there is no next result row or an error
    
    // happened while preparing it. Err should be consulted to distinguish between
    
    // the two cases.
    //
    // Every call to Scan, even the first one, must be preceded by a call to Next.
    
    func (rs *Rows) Next() bool {
    
    	var doClose, ok bool
    	withLock(rs.closemu.RLocker(), func() {
    		doClose, ok = rs.nextLocked()
    	})
    	if doClose {
    		rs.Close()
    	}
    	return ok
    }
    
    func (rs *Rows) nextLocked() (doClose, ok bool) {
    	if rs.closed {
    		return false, false
    
    
    	// Lock the driver connection before calling the driver interface
    	// rowsi to prevent a Tx from rolling back the connection at the same time.
    	rs.dc.Lock()
    	defer rs.dc.Unlock()
    
    
    	if rs.lastcols == nil {
    
    		rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
    
    	rs.lasterr = rs.rowsi.Next(rs.lastcols)
    
    	if rs.lasterr != nil {
    		// Close the connection if there is a driver error.
    		if rs.lasterr != io.EOF {
    
    		}
    		nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
    		if !ok {
    
    		}
    		// The driver is at the end of the current result set.
    		// Test to see if there is another result set after the current one.
    
    shawnps's avatar
    shawnps committed
    		// Only close Rows if there is no further result sets to read.
    
    		if !nextResultSet.HasNextResultSet() {
    
    }
    
    // NextResultSet prepares the next result set for reading. It returns true if
    // there is further result sets, or false if there is no further result set
    // or if there is an error advancing to it. The Err method should be consulted
    // to distinguish between the two cases.
    //
    // After calling NextResultSet, the Next method should always be called before
    // scanning. If there are further result sets they may not have rows in the result
    // set.
    func (rs *Rows) NextResultSet() bool {
    
    	var doClose bool
    	defer func() {
    		if doClose {
    			rs.Close()
    		}
    	}()
    	rs.closemu.RLock()
    	defer rs.closemu.RUnlock()
    
    	if rs.closed {
    
    	rs.lastcols = nil
    	nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
    	if !ok {
    
    
    	// Lock the driver connection before calling the driver interface
    	// rowsi to prevent a Tx from rolling back the connection at the same time.
    	rs.dc.Lock()
    	defer rs.dc.Unlock()
    
    
    	rs.lasterr = nextResultSet.NextResultSet()
    
    // Err returns the error, if any, that was encountered during iteration.
    
    // Err may be called after an explicit or implicit Close.
    
    	rs.closemu.RLock()
    	defer rs.closemu.RUnlock()
    
    	if rs.lasterr == io.EOF {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    // Columns returns the column names.
    // Columns returns an error if the rows are closed, or if the rows
    // are from QueryRow and there was a deferred error.
    func (rs *Rows) Columns() ([]string, error) {
    
    	rs.closemu.RLock()
    	defer rs.closemu.RUnlock()
    	if rs.closed {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		return nil, errors.New("sql: Rows are closed")
    	}
    	if rs.rowsi == nil {
    		return nil, errors.New("sql: no Rows available")
    	}
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    	return rs.rowsi.Columns(), nil
    }
    
    
    // ColumnTypes returns column information such as column type, length,
    // and nullable. Some information may not be available from some drivers.
    func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
    
    	rs.closemu.RLock()
    	defer rs.closemu.RUnlock()
    	if rs.closed {
    
    		return nil, errors.New("sql: Rows are closed")
    	}
    	if rs.rowsi == nil {
    		return nil, errors.New("sql: no Rows available")
    	}
    
    	rs.dc.Lock()
    	defer rs.dc.Unlock()
    
    	return rowsColumnInfoSetupConnLocked(rs.rowsi), nil
    
    }
    
    // ColumnType contains the name and type of a column.
    type ColumnType struct {
    	name string
    
    	hasNullable       bool
    	hasLength         bool
    	hasPrecisionScale bool
    
    	nullable     bool
    	length       int64
    	databaseType string
    	precision    int64
    	scale        int64
    	scanType     reflect.Type
    }
    
    // Name returns the name or alias of the column.
    func (ci *ColumnType) Name() string {
    	return ci.name
    }
    
    // Length returns the column type length for variable length column types such
    // as text and binary field types. If the type length is unbounded the value will
    // be math.MaxInt64 (any database limits will still apply).
    // If the column type is not variable length, such as an int, or if not supported
    // by the driver ok is false.
    func (ci *ColumnType) Length() (length int64, ok bool) {
    	return ci.length, ci.hasLength
    }
    
    // DecimalSize returns the scale and precision of a decimal type.
    // If not applicable or if not supported ok is false.
    func (ci *ColumnType) DecimalSize() (precision, scale int64, ok bool) {
    	return ci.precision, ci.scale, ci.hasPrecisionScale
    }
    
    // ScanType returns a Go type suitable for scanning into using Rows.Scan.
    // If a driver does not support this property ScanType will return
    // the type of an empty interface.
    func (ci *ColumnType) ScanType() reflect.Type {
    	return ci.scanType
    }
    
    // Nullable returns whether the column may be null.
    // If a driver does not support this property ok will be false.
    func (ci *ColumnType) Nullable() (nullable, ok bool) {
    	return ci.nullable, ci.hasNullable
    }
    
    // DatabaseTypeName returns the database system name of the column type. If an empty
    // string is returned the driver type name is not supported.
    // Consult your driver documentation for a list of driver data types. Length specifiers
    // are not included.
    // Common type include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", "INT", "BIGINT".
    func (ci *ColumnType) DatabaseTypeName() string {
    	return ci.databaseType
    }
    
    
    func rowsColumnInfoSetupConnLocked(rowsi driver.Rows) []*ColumnType {
    
    	names := rowsi.Columns()
    
    	list := make([]*ColumnType, len(names))
    	for i := range list {
    		ci := &ColumnType{
    			name: names[i],
    		}
    		list[i] = ci
    
    		if prop, ok := rowsi.(driver.RowsColumnTypeScanType); ok {
    			ci.scanType = prop.ColumnTypeScanType(i)
    		} else {
    			ci.scanType = reflect.TypeOf(new(interface{})).Elem()
    		}
    		if prop, ok := rowsi.(driver.RowsColumnTypeDatabaseTypeName); ok {
    			ci.databaseType = prop.ColumnTypeDatabaseTypeName(i)
    		}
    		if prop, ok := rowsi.(driver.RowsColumnTypeLength); ok {
    			ci.length, ci.hasLength = prop.ColumnTypeLength(i)
    		}
    		if prop, ok := rowsi.(driver.RowsColumnTypeNullable); ok {
    			ci.nullable, ci.hasNullable = prop.ColumnTypeNullable(i)
    		}
    		if prop, ok := rowsi.(driver.RowsColumnTypePrecisionScale); ok {
    			ci.precision, ci.scale, ci.hasPrecisionScale = prop.ColumnTypePrecisionScale(i)
    		}
    	}
    	return list
    }
    
    
    // Scan copies the columns in the current row into the values pointed
    
    // at by dest. The number of values in dest must be the same as the
    // number of columns in Rows.
    
    // Scan converts columns read from the database into the following
    // common Go types and special types provided by the sql package:
    //
    //    *string
    //    *[]byte
    //    *int, *int8, *int16, *int32, *int64
    //    *uint, *uint8, *uint16, *uint32, *uint64
    //    *bool
    //    *float32, *float64
    //    *interface{}
    //    *RawBytes
    //    any type implementing Scanner (see Scanner docs)
    //
    // In the most simple case, if the type of the value from the source
    // column is an integer, bool or string type T and dest is of type *T,
    // Scan simply assigns the value through the pointer.
    //
    // Scan also converts between string and numeric types, as long as no
    // information would be lost. While Scan stringifies all numbers
    // scanned from numeric database columns into *string, scans into
    // numeric types are checked for overflow. For example, a float64 with
    // value 300 or a string with value "300" can scan into a uint16, but
    // not into a uint8, though float64(255) or "255" can scan into a
    // uint8. One exception is that scans of some float64 numbers to
    // strings may lose information when stringifying. In general, scan
    // floating point columns into *float64.
    //
    // If a dest argument has type *[]byte, Scan saves in that argument a
    // copy of the corresponding data. The copy is owned by the caller and
    // can be modified and held indefinitely. The copy can be avoided by
    // using an argument of type *RawBytes instead; see the documentation
    // for RawBytes for restrictions on its use.
    
    //
    // If an argument has type *interface{}, Scan copies the value
    
    // provided by the underlying driver without conversion. When scanning
    // from a source value of type []byte to *interface{}, a copy of the
    // slice is made and the caller owns the result.
    //
    // Source values of type time.Time may be scanned into values of type
    // *time.Time, *interface{}, *string, or *[]byte. When converting to
    
    // the latter two, time.RFC3339Nano is used.
    
    //
    // Source values of type bool may be scanned into types *bool,
    // *interface{}, *string, *[]byte, or *RawBytes.
    //
    // For scanning into *bool, the source may be true, false, 1, 0, or
    // string inputs parseable by strconv.ParseBool.
    
    func (rs *Rows) Scan(dest ...interface{}) error {
    
    	rs.closemu.RLock()
    	if rs.closed {
    		rs.closemu.RUnlock()
    
    		return errors.New("sql: Rows are closed")
    
    	if rs.lastcols == nil {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		return errors.New("sql: Scan called without calling Next")
    
    	}
    	if len(dest) != len(rs.lastcols) {
    
    Brad Fitzpatrick's avatar
    Brad Fitzpatrick committed
    		return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
    
    	}
    	for i, sv := range rs.lastcols {
    		err := convertAssign(dest[i], sv)
    		if err != nil {
    
    			return fmt.Errorf(`sql: Scan error on column index %d, name %q: %v`, i, rs.rowsi.Columns()[i], err)
    
    // rowsCloseHook returns a function so tests may install the
    
    // hook through a test only mutex.
    
    var rowsCloseHook = func() func(*Rows, *error) { return nil }
    
    // Close closes the Rows, preventing further enumeration. If Next is called
    // and returns false and there are no further result sets,
    // the Rows are closed automatically and it will suffice to check the
    
    // result of Err. Close is idempotent and does not affect the result of Err.
    
    func (rs *Rows) Close() error {
    
    	return rs.close(nil)
    }
    
    func (rs *Rows) close(err error) error {
    	rs.closemu.Lock()
    	defer rs.closemu.Unlock()
    
    	if rs.closed {
    
    	rs.closed = true
    
    	if rs.lasterr == nil {
    		rs.lasterr = err
    	}
    
    	withLock(rs.dc, func() {
    		err = rs.rowsi.Close()
    	})
    
    	if fn := rowsCloseHook(); fn != nil {
    
    	if rs.closeStmt != nil {
    		rs.closeStmt.Close()
    	}
    
    	return err
    }
    
    // Row is the result of calling QueryRow to select a single row.
    type Row struct {
    	// One of these two will be non-nil:
    
    	err  error // deferred error for easy chaining
    
    	rows *Rows
    }
    
    // Scan copies the columns from the matched row into the values
    
    // pointed at by dest. See the documentation on Rows.Scan for details.
    // If more than one row matches the query,
    // Scan uses the first row and discards the rest. If no row matches
    
    // the query, Scan returns ErrNoRows.
    
    func (r *Row) Scan(dest ...interface{}) error {
    
    	if r.err != nil {
    		return r.err
    	}
    
    
    	// TODO(bradfitz): for now we need to defensively clone all
    
    	// []byte that the driver returned (not permitting
    
    	// *RawBytes in Rows.Scan), since we're about to close
    
    	// the Rows in our defer, when we return from this function.
    	// the contract with the driver.Next(...) interface is that it
    	// can return slices into read-only temporary memory that's
    
    	// only valid until the next Scan/Close. But the TODO is that
    	// for a lot of drivers, this copy will be unnecessary. We
    
    	// should provide an optional interface for drivers to
    	// implement to say, "don't worry, the []bytes that I return
    	// from Next will not be modified again." (for instance, if
    	// they were obtained from the network anyway) But for now we
    	// don't care.
    
    		if _, ok := dp.(*RawBytes); ok {
    			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
    		}
    
    		if err := r.rows.Err(); err != nil {
    			return err
    		}
    
    		return ErrNoRows
    	}
    	err := r.rows.Scan(dest...)
    	if err != nil {
    		return err
    	}
    
    	// Make sure the query can be processed to completion with no errors.
    	if err := r.rows.Close(); err != nil {
    		return err
    	}
    
    }
    
    // A Result summarizes an executed SQL command.
    type Result interface {
    
    	// LastInsertId returns the integer generated by the database
    	// in response to a command. Typically this will be from an
    	// "auto increment" column when inserting a new row. Not all
    	// databases support this feature, and the syntax of such
    	// statements varies.
    
    	LastInsertId() (int64, error)
    
    
    	// RowsAffected returns the number of rows affected by an
    	// update, insert, or delete. Not every database or database
    	// driver may support this.