]> Cypherpunks repositories - gostls13.git/commitdiff
sql: add Rows.Columns
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 15 Dec 2011 18:14:57 +0000 (10:14 -0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 15 Dec 2011 18:14:57 +0000 (10:14 -0800)
Also, fix package name in error messages.

Fixes #2453

R=rsc
CC=golang-dev
https://golang.org/cl/5483088

src/pkg/exp/sql/sql.go
src/pkg/exp/sql/sql_test.go

index 948b911f2e0a0ef554eff75a823afcc8cabececf..937982cdbe6f9b3661ea963047f0efe9d92fd828 100644 (file)
@@ -22,10 +22,10 @@ var drivers = make(map[string]driver.Driver)
 // it panics.
 func Register(name string, driver driver.Driver) {
        if driver == nil {
-               panic("db: Register driver is nil")
+               panic("sql: Register driver is nil")
        }
        if _, dup := drivers[name]; dup {
-               panic("db: Register called twice for driver " + name)
+               panic("sql: Register called twice for driver " + name)
        }
        drivers[name] = driver
 }
@@ -80,7 +80,7 @@ type ScannerInto interface {
 // 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("db: no rows in result set")
+var ErrNoRows = errors.New("sql: no rows in result set")
 
 // DB is a database handle. It's safe for concurrent use by multiple
 // goroutines.
@@ -102,7 +102,7 @@ type DB struct {
 func Open(driverName, dataSourceName string) (*DB, error) {
        driver, ok := drivers[driverName]
        if !ok {
-               return nil, fmt.Errorf("db: unknown driver %q (forgotten import?)", driverName)
+               return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
        }
        return &DB{driver: driver, dsn: dataSourceName}, nil
 }
@@ -514,7 +514,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
        // 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("db: expected %d arguments, got %d", want, len(args))
+               return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
        }
 
        // Convert args to subset types.
@@ -522,10 +522,10 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
                for n, arg := range args {
                        args[n], err = cc.ColumnConverter(n).ConvertValue(arg)
                        if err != nil {
-                               return nil, fmt.Errorf("db: converting Exec argument #%d's type: %v", n, err)
+                               return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
                        }
                        if !driver.IsParameterSubsetType(args[n]) {
-                               return nil, fmt.Errorf("db: driver ColumnConverter error converted %T to unsupported type %T",
+                               return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
                                        arg, args[n])
                        }
                }
@@ -533,7 +533,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
                for n, arg := range args {
                        args[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
                        if err != nil {
-                               return nil, fmt.Errorf("db: converting Exec argument #%d's type: %v", n, err)
+                               return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
                        }
                }
        }
@@ -555,7 +555,7 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
        s.mu.Lock()
        if s.closed {
                s.mu.Unlock()
-               err = errors.New("db: statement is closed")
+               err = errors.New("sql: statement is closed")
                return
        }
 
@@ -617,7 +617,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
        // 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("db: statement expects %d inputs; got %d", si.NumInput(), len(args))
+               return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args))
        }
        sargs, err := subsetTypeArgs(args)
        if err != nil {
@@ -737,27 +737,40 @@ func (rs *Rows) Err() error {
        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 dest contains pointers to []byte, the slices should
 // not be modified and should only be considered valid until the next
 // call to Next or Scan.
 func (rs *Rows) Scan(dest ...interface{}) error {
        if rs.closed {
-               return errors.New("db: Rows closed")
+               return errors.New("sql: Rows closed")
        }
        if rs.lasterr != nil {
                return rs.lasterr
        }
        if rs.lastcols == nil {
-               return errors.New("db: Scan called without calling Next")
+               return errors.New("sql: Scan called without calling Next")
        }
        if len(dest) != len(rs.lastcols) {
-               return fmt.Errorf("db: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
+               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("db: Scan error on column index %d: %v", i, err)
+                       return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
                }
        }
        return nil
index f8ccf764e73ada4f56fe86acab7866e693788974..5307a235ddf13fc0eb84b09eb7da9e3358ed0f3a 100644 (file)
@@ -75,6 +75,23 @@ func TestQuery(t *testing.T) {
        }
 }
 
+func TestRowsColumns(t *testing.T) {
+       db := newTestDB(t, "people")
+       defer closeDB(t, db)
+       rows, err := db.Query("SELECT|people|age,name|")
+       if err != nil {
+               t.Fatalf("Query: %v", err)
+       }
+       cols, err := rows.Columns()
+       if err != nil {
+               t.Fatalf("Columns: %v", err)
+       }
+       want := []string{"age", "name"}
+       if !reflect.DeepEqual(cols, want) {
+               t.Errorf("got %#v; want %#v", cols, want)
+       }
+}
+
 func TestQueryRow(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -187,12 +204,12 @@ func TestExec(t *testing.T) {
                {[]interface{}{7, 9}, ""},
 
                // Invalid conversions:
-               {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "db: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
-               {[]interface{}{"Brad", "strconv fail"}, "db: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
+               {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
+               {[]interface{}{"Brad", "strconv fail"}, "sql: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
 
                // Wrong number of args:
-               {[]interface{}{}, "db: expected 2 arguments, got 0"},
-               {[]interface{}{1, 2, 3}, "db: expected 2 arguments, got 3"},
+               {[]interface{}{}, "sql: expected 2 arguments, got 0"},
+               {[]interface{}{1, 2, 3}, "sql: expected 2 arguments, got 3"},
        }
        for n, et := range execTests {
                _, err := stmt.Exec(et.args...)