diff options
Diffstat (limited to 'src/pkg/exp/sql/sql.go')
| -rw-r--r-- | src/pkg/exp/sql/sql.go | 913 |
1 files changed, 0 insertions, 913 deletions
diff --git a/src/pkg/exp/sql/sql.go b/src/pkg/exp/sql/sql.go deleted file mode 100644 index 3201e76674..0000000000 --- a/src/pkg/exp/sql/sql.go +++ /dev/null @@ -1,913 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package sql provides a generic interface around SQL (or SQL-like) -// databases. -package sql - -import ( - "errors" - "fmt" - "io" - "sync" - - "exp/sql/driver" -) - -var drivers = make(map[string]driver.Driver) - -// Register makes a database driver available by the provided name. -// If Register is called twice with the same name or if driver is nil, -// it panics. -func Register(name string, driver driver.Driver) { - if driver == nil { - panic("sql: Register driver is nil") - } - if _, dup := drivers[name]; dup { - panic("sql: Register called twice for driver " + name) - } - drivers[name] = driver -} - -// RawBytes is a byte slice that holds a reference to memory owned by -// the database itself. After a Scan into a RawBytes, the slice is only -// valid until the next call to Next, Scan, or Close. -type RawBytes []byte - -// NullString represents a string that may be null. -// NullString implements the ScannerInto interface so -// it can be used as a scan destination: -// -// var s NullString -// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) -// ... -// if s.Valid { -// // use s.String -// } else { -// // NULL value -// } -// -// TODO(bradfitz): add other types. -type NullString struct { - String string - Valid bool // Valid is true if String is not NULL -} - -// ScanInto implements the ScannerInto interface. -func (ns *NullString) ScanInto(value interface{}) error { - if value == nil { - ns.String, ns.Valid = "", false - return nil - } - ns.Valid = true - return convertAssign(&ns.String, value) -} - -// SubsetValue implements the driver SubsetValuer interface. -func (ns NullString) SubsetValue() (interface{}, error) { - if !ns.Valid { - return nil, nil - } - return ns.String, nil -} - -// ScannerInto is an interface used by Scan. -type ScannerInto interface { - // ScanInto assigns a value from a database driver. - // - // The value will be of one of the following restricted - // set of types: - // - // int64 - // float64 - // bool - // []byte - // nil - for NULL values - // - // An error should be returned if the value can not be stored - // without loss of information. - ScanInto(value interface{}) error -} - -// ErrNoRows is returned by Scan when QueryRow doesn't return a -// row. In such a case, QueryRow returns a placeholder *Row value that -// defers this error until a Scan. -var ErrNoRows = errors.New("sql: no rows in result set") - -// DB is a database handle. It's safe for concurrent use by multiple -// goroutines. -type DB struct { - driver driver.Driver - dsn string - - mu sync.Mutex // protects freeConn and closed - freeConn []driver.Conn - closed bool -} - -// Open opens a database specified by its database driver name and a -// driver-specific data source name, usually consisting of at least a -// database name and connection information. -// -// Most users will open a database via a driver-specific connection -// helper function that returns a *DB. -func Open(driverName, dataSourceName string) (*DB, error) { - driver, ok := drivers[driverName] - if !ok { - return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName) - } - return &DB{driver: driver, dsn: dataSourceName}, nil -} - -// Close closes the database, releasing any open resources. -func (db *DB) Close() error { - db.mu.Lock() - defer db.mu.Unlock() - var err error - for _, c := range db.freeConn { - err1 := c.Close() - if err1 != nil { - err = err1 - } - } - db.freeConn = nil - db.closed = true - return err -} - -func (db *DB) maxIdleConns() int { - const defaultMaxIdleConns = 2 - // TODO(bradfitz): ask driver, if supported, for its default preference - // TODO(bradfitz): let users override? - return defaultMaxIdleConns -} - -// conn returns a newly-opened or cached driver.Conn -func (db *DB) conn() (driver.Conn, error) { - db.mu.Lock() - if db.closed { - db.mu.Unlock() - return nil, errors.New("sql: database is closed") - } - if n := len(db.freeConn); n > 0 { - conn := db.freeConn[n-1] - db.freeConn = db.freeConn[:n-1] - db.mu.Unlock() - return conn, nil - } - db.mu.Unlock() - return db.driver.Open(db.dsn) -} - -func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) { - db.mu.Lock() - defer db.mu.Unlock() - for n, conn := range db.freeConn { - if conn == wanted { - db.freeConn[n] = db.freeConn[len(db.freeConn)-1] - db.freeConn = db.freeConn[:len(db.freeConn)-1] - return wanted, true - } - } - return nil, false -} - -func (db *DB) putConn(c driver.Conn) { - db.mu.Lock() - defer db.mu.Unlock() - if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() { - db.freeConn = append(db.freeConn, c) - return - } - db.closeConn(c) // TODO(bradfitz): release lock before calling this? -} - -func (db *DB) closeConn(c driver.Conn) { - // TODO: check to see if we need this Conn for any prepared statements - // that are active. - c.Close() -} - -// Prepare creates a prepared statement for later execution. -func (db *DB) Prepare(query string) (*Stmt, error) { - // TODO: check if db.driver supports an optional - // driver.Preparer interface and call that instead, if so, - // otherwise we make a prepared statement that's bound - // to a connection, and to execute this prepared statement - // we either need to use this connection (if it's free), else - // get a new connection + re-prepare + execute on that one. - ci, err := db.conn() - if err != nil { - return nil, err - } - defer db.putConn(ci) - si, err := ci.Prepare(query) - if err != nil { - return nil, err - } - stmt := &Stmt{ - db: db, - query: query, - css: []connStmt{{ci, si}}, - } - return stmt, nil -} - -// Exec executes a query without returning any rows. -func (db *DB) Exec(query string, args ...interface{}) (Result, error) { - sargs, err := subsetTypeArgs(args) - if err != nil { - return nil, err - } - - ci, err := db.conn() - if err != nil { - return nil, err - } - defer db.putConn(ci) - - if execer, ok := ci.(driver.Execer); ok { - resi, err := execer.Exec(query, sargs) - if err != driver.ErrSkip { - if err != nil { - return nil, err - } - return result{resi}, nil - } - } - - sti, err := ci.Prepare(query) - if err != nil { - return nil, err - } - defer sti.Close() - - resi, err := sti.Exec(sargs) - if err != nil { - return nil, err - } - return result{resi}, nil -} - -// Query executes a query that returns rows, typically a SELECT. -func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { - stmt, err := db.Prepare(query) - if err != nil { - return nil, err - } - rows, err := stmt.Query(args...) - if err != nil { - stmt.Close() - return nil, err - } - rows.closeStmt = stmt - return rows, nil -} - -// QueryRow executes a query that is expected to return at most one row. -// QueryRow always return a non-nil value. Errors are deferred until -// Row's Scan method is called. -func (db *DB) QueryRow(query string, args ...interface{}) *Row { - rows, err := db.Query(query, args...) - return &Row{rows: rows, err: err} -} - -// Begin starts a transaction. The isolation level is dependent on -// the driver. -func (db *DB) Begin() (*Tx, error) { - ci, err := db.conn() - if err != nil { - return nil, err - } - txi, err := ci.Begin() - if err != nil { - db.putConn(ci) - return nil, fmt.Errorf("sql: failed to Begin transaction: %v", err) - } - return &Tx{ - db: db, - ci: ci, - txi: txi, - }, nil -} - -// DriverDatabase returns the database's underlying driver. -func (db *DB) Driver() driver.Driver { - return db.driver -} - -// Tx is an in-progress database transaction. -// -// A transaction must end with a call to Commit or Rollback. -// -// After a call to Commit or Rollback, all operations on the -// transaction fail with ErrTransactionFinished. -type Tx struct { - db *DB - - // ci is owned exclusively until Commit or Rollback, at which point - // it's returned with putConn. - ci driver.Conn - txi driver.Tx - - // cimu is held while somebody is using ci (between grabConn - // and releaseConn) - cimu sync.Mutex - - // done transitions from false to true exactly once, on Commit - // or Rollback. once done, all operations fail with - // ErrTransactionFinished. - done bool -} - -var ErrTransactionFinished = errors.New("sql: Transaction has already been committed or rolled back") - -func (tx *Tx) close() { - if tx.done { - panic("double close") // internal error - } - tx.done = true - tx.db.putConn(tx.ci) - tx.ci = nil - tx.txi = nil -} - -func (tx *Tx) grabConn() (driver.Conn, error) { - if tx.done { - return nil, ErrTransactionFinished - } - tx.cimu.Lock() - return tx.ci, nil -} - -func (tx *Tx) releaseConn() { - tx.cimu.Unlock() -} - -// Commit commits the transaction. -func (tx *Tx) Commit() error { - if tx.done { - return ErrTransactionFinished - } - defer tx.close() - return tx.txi.Commit() -} - -// Rollback aborts the transaction. -func (tx *Tx) Rollback() error { - if tx.done { - return ErrTransactionFinished - } - defer tx.close() - return tx.txi.Rollback() -} - -// 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) { - // TODO(bradfitz): We could be more efficient here and either - // provide a method to take an existing Stmt (created on - // perhaps a different Conn), and re-create it on this Conn if - // necessary. Or, better: keep a map in DB of query string to - // Stmts, and have Stmt.Execute do the right thing and - // re-prepare if the Conn in use doesn't have that prepared - // statement. But we'll want to avoid caching the statement - // in the case where we only call conn.Prepare implicitly - // (such as in db.Exec or tx.Exec), but the caller package - // can't be holding a reference to the returned statement. - // Perhaps just looking at the reference count (by noting - // Stmt.Close) would be enough. We might also want a finalizer - // on Stmt to drop the reference count. - ci, err := tx.grabConn() - if err != nil { - return nil, err - } - defer tx.releaseConn() - - si, err := ci.Prepare(query) - if err != nil { - return nil, err - } - - stmt := &Stmt{ - db: tx.db, - tx: tx, - txsi: si, - query: query, - } - return stmt, nil -} - -// 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) -func (tx *Tx) Stmt(stmt *Stmt) *Stmt { - // TODO(bradfitz): optimize this. Currently this re-prepares - // each time. This is fine for now to illustrate the API but - // we should really cache already-prepared statements - // per-Conn. See also the big comment in Tx.Prepare. - - if tx.db != stmt.db { - return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")} - } - ci, err := tx.grabConn() - if err != nil { - return &Stmt{stickyErr: err} - } - defer tx.releaseConn() - si, err := ci.Prepare(stmt.query) - return &Stmt{ - db: tx.db, - tx: tx, - txsi: si, - query: stmt.query, - stickyErr: err, - } -} - -// 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) { - ci, err := tx.grabConn() - if err != nil { - return nil, err - } - defer tx.releaseConn() - - if execer, ok := ci.(driver.Execer); ok { - resi, err := execer.Exec(query, args) - if err != nil { - return nil, err - } - return result{resi}, nil - } - - sti, err := ci.Prepare(query) - if err != nil { - return nil, err - } - defer sti.Close() - - sargs, err := subsetTypeArgs(args) - if err != nil { - return nil, err - } - - resi, err := sti.Exec(sargs) - if err != nil { - return nil, err - } - return result{resi}, nil -} - -// Query executes a query that returns rows, typically a SELECT. -func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) { - if tx.done { - return nil, ErrTransactionFinished - } - stmt, err := tx.Prepare(query) - if err != nil { - return nil, err - } - defer stmt.Close() - return stmt.Query(args...) -} - -// QueryRow executes a query that is expected to return at most one row. -// QueryRow always return a non-nil value. Errors are deferred until -// Row's Scan method is called. -func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { - rows, err := tx.Query(query, args...) - return &Row{rows: rows, err: err} -} - -// connStmt is a prepared statement on a particular connection. -type connStmt struct { - ci driver.Conn - si driver.Stmt -} - -// Stmt is a prepared statement. 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 - - // If in a transaction, else both nil: - tx *Tx - txsi driver.Stmt - - mu sync.Mutex // protects the rest of the fields - closed bool - - // css is a list of underlying driver statement interfaces - // that are valid on particular connections. This is only - // used if tx == nil and one is found that has idle - // connections. If tx != nil, txsi is always used. - css []connStmt -} - -// 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) { - _, releaseConn, si, err := s.connStmt() - if err != nil { - return nil, err - } - defer releaseConn() - - // -1 means the driver doesn't know how to count the number of - // placeholders, so we won't sanity check input here and instead let the - // driver deal with errors. - if want := si.NumInput(); want != -1 && len(args) != want { - return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args)) - } - - // Convert args to subset types. - if cc, ok := si.(driver.ColumnConverter); ok { - for n, arg := range args { - // First, see if the value itself knows how to convert - // itself to a driver type. For example, a NullString - // struct changing into a string or nil. - if svi, ok := arg.(driver.SubsetValuer); ok { - sv, err := svi.SubsetValue() - if err != nil { - return nil, fmt.Errorf("sql: argument index %d from SubsetValue: %v", n, err) - } - if !driver.IsParameterSubsetType(sv) { - return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from SubsetValue", n, sv) - } - arg = sv - } - - // Second, ask the column to sanity check itself. For - // example, drivers might use this to make sure that - // an int64 values being inserted into a 16-bit - // integer field is in range (before getting - // truncated), or that a nil can't go into a NOT NULL - // column before going across the network to get the - // same error. - args[n], err = cc.ColumnConverter(n).ConvertValue(arg) - if err != nil { - return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) - } - if !driver.IsParameterSubsetType(args[n]) { - return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T", - arg, args[n]) - } - } - } else { - for n, arg := range args { - args[n], err = driver.DefaultParameterConverter.ConvertValue(arg) - if err != nil { - return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) - } - } - } - - resi, err := si.Exec(args) - if err != nil { - return nil, err - } - return result{resi}, nil -} - -// 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() (ci driver.Conn, releaseConn func(), si driver.Stmt, err error) { - if err = s.stickyErr; err != nil { - return - } - s.mu.Lock() - if s.closed { - s.mu.Unlock() - err = errors.New("sql: statement is closed") - return - } - - // In a transaction, we always use the connection that the - // transaction was created on. - if s.tx != nil { - s.mu.Unlock() - ci, err = s.tx.grabConn() // blocks, waiting for the connection. - if err != nil { - return - } - releaseConn = func() { s.tx.releaseConn() } - return ci, releaseConn, s.txsi, nil - } - - var cs connStmt - match := false - for _, v := range s.css { - // TODO(bradfitz): lazily clean up entries in this - // list with dead conns while enumerating - if _, match = s.db.connIfFree(cs.ci); match { - cs = v - break - } - } - s.mu.Unlock() - - // Make a new conn if all are busy. - // TODO(bradfitz): or wait for one? make configurable later? - if !match { - ci, err := s.db.conn() - if err != nil { - return nil, nil, nil, err - } - si, err := ci.Prepare(s.query) - if err != nil { - return nil, nil, nil, err - } - s.mu.Lock() - cs = connStmt{ci, si} - s.css = append(s.css, cs) - s.mu.Unlock() - } - - conn := cs.ci - releaseConn = func() { s.db.putConn(conn) } - return conn, releaseConn, cs.si, nil -} - -// 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) { - ci, releaseConn, si, err := s.connStmt() - if err != nil { - return nil, err - } - - // -1 means the driver doesn't know how to count the number of - // placeholders, so we won't sanity check input here and instead let the - // driver deal with errors. - if want := si.NumInput(); want != -1 && len(args) != want { - return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args)) - } - sargs, err := subsetTypeArgs(args) - if err != nil { - return nil, err - } - rowsi, err := si.Query(sargs) - if err != nil { - s.db.putConn(ci) - return nil, err - } - // Note: ownership of ci passes to the *Rows, to be freed - // with releaseConn. - rows := &Rows{ - db: s.db, - ci: ci, - releaseConn: releaseConn, - rowsi: rowsi, - } - return rows, nil -} - -// 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(&s) -func (s *Stmt) QueryRow(args ...interface{}) *Row { - rows, err := s.Query(args...) - if err != nil { - return &Row{err: err} - } - return &Row{rows: rows} -} - -// Close closes the statement. -func (s *Stmt) Close() error { - if s.stickyErr != nil { - return s.stickyErr - } - s.mu.Lock() - defer s.mu.Unlock() - if s.closed { - return nil - } - s.closed = true - - if s.tx != nil { - s.txsi.Close() - } else { - for _, v := range s.css { - if ci, match := s.db.connIfFree(v.ci); match { - v.si.Close() - s.db.putConn(ci) - } else { - // TODO(bradfitz): care that we can't close - // this statement because the statement's - // connection is in use? - } - } - } - return nil -} - -// Rows is the result of a query. Its cursor starts before the first row -// of the result set. Use Next to advance through the rows: -// -// rows, err := db.Query("SELECT ...") -// ... -// for rows.Next() { -// var id int -// var name string -// err = rows.Scan(&id, &name) -// ... -// } -// err = rows.Err() // get any error encountered during iteration -// ... -type Rows struct { - db *DB - ci driver.Conn // owned; must call putconn when closed to release - releaseConn func() - rowsi driver.Rows - - closed bool - lastcols []interface{} - lasterr error - closeStmt *Stmt // if non-nil, statement to Close on close -} - -// Next prepares the next result row for reading with the Scan method. -// It returns true on success, false if there is no next result row. -// Every call to Scan, even the first one, must be preceded by a call -// to Next. -func (rs *Rows) Next() bool { - if rs.closed { - return false - } - if rs.lasterr != nil { - return false - } - if rs.lastcols == nil { - rs.lastcols = make([]interface{}, len(rs.rowsi.Columns())) - } - rs.lasterr = rs.rowsi.Next(rs.lastcols) - if rs.lasterr == io.EOF { - rs.Close() - } - return rs.lasterr == nil -} - -// Err returns the error, if any, that was encountered during iteration. -func (rs *Rows) Err() error { - if rs.lasterr == io.EOF { - return nil - } - return rs.lasterr -} - -// 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) { - if rs.closed { - return nil, errors.New("sql: Rows are closed") - } - if rs.rowsi == nil { - return nil, errors.New("sql: no Rows available") - } - return rs.rowsi.Columns(), nil -} - -// Scan copies the columns in the current row into the values pointed -// at by dest. -// -// If an 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. -func (rs *Rows) Scan(dest ...interface{}) error { - if rs.closed { - return errors.New("sql: Rows closed") - } - if rs.lasterr != nil { - return rs.lasterr - } - if rs.lastcols == nil { - return errors.New("sql: Scan called without calling Next") - } - if len(dest) != len(rs.lastcols) { - 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: %v", i, err) - } - } - for _, dp := range dest { - b, ok := dp.(*[]byte) - if !ok { - continue - } - if _, ok = dp.(*RawBytes); ok { - continue - } - clone := make([]byte, len(*b)) - copy(clone, *b) - *b = clone - } - return nil -} - -// Close closes the Rows, preventing further enumeration. If the -// end is encountered, the Rows are closed automatically. Close -// is idempotent. -func (rs *Rows) Close() error { - if rs.closed { - return nil - } - rs.closed = true - err := rs.rowsi.Close() - rs.releaseConn() - 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. 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 - } - defer r.rows.Close() - if !r.rows.Next() { - return ErrNoRows - } - err := r.rows.Scan(dest...) - if err != nil { - return err - } - - // TODO(bradfitz): for now we need to defensively clone all - // []byte that the driver returned, 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. - for _, dp := range dest { - if _, ok := dp.(*RawBytes); ok { - return errors.New("sql: RawBytes isn't allowed on Row.Scan") - } - b, ok := dp.(*[]byte) - if !ok { - continue - } - clone := make([]byte, len(*b)) - copy(clone, *b) - *b = clone - } - return nil -} - -// A Result summarizes an executed SQL command. -type Result interface { - LastInsertId() (int64, error) - RowsAffected() (int64, error) -} - -type result struct { - driver.Result -} |
