diff options
| author | Daniel Theophanes <kardianos@gmail.com> | 2018-10-29 16:22:37 -0700 |
|---|---|---|
| committer | Daniel Theophanes <kardianos@gmail.com> | 2018-11-08 21:19:17 +0000 |
| commit | 968742a824de0a6459d2820d11b9e2e58803f472 (patch) | |
| tree | 946104b6aa08dd0e575944ee2b56f1ba16711d80 /src/database/sql/convert.go | |
| parent | ad4a58e31501bce5de2aad90a620eaecdc1eecb8 (diff) | |
| download | go-968742a824de0a6459d2820d11b9e2e58803f472.tar.xz | |
database/sql: add support for returning cursors to client
This CL add support for converting a returned cursor (presented
to this package as a driver.Rows) and scanning it into a *Rows.
Fixes #28515
Change-Id: Id8191c568dc135af9e5e8555efcd01987708edcb
Reviewed-on: https://go-review.googlesource.com/c/145738
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/database/sql/convert.go')
| -rw-r--r-- | src/database/sql/convert.go | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go index 92a2ebe0e9..c450d987a4 100644 --- a/src/database/sql/convert.go +++ b/src/database/sql/convert.go @@ -203,10 +203,18 @@ func driverArgsConnLocked(ci driver.Conn, ds *driverStmt, args []interface{}) ([ } -// convertAssign copies to dest the value in src, converting it if possible. -// An error is returned if the copy would result in loss of information. -// dest should be a pointer type. +// convertAssign is the same as convertAssignRows, but without the optional +// rows argument. func convertAssign(dest, src interface{}) error { + return convertAssignRows(dest, src, nil) +} + +// convertAssignRows copies to dest the value in src, converting it if possible. +// An error is returned if the copy would result in loss of information. +// dest should be a pointer type. If rows is passed in, the rows will +// be used as the parent for any cursor values converted from a +// driver.Rows to a *Rows. +func convertAssignRows(dest, src interface{}, rows *Rows) error { // Common cases, without reflect. switch s := src.(type) { case string: @@ -299,6 +307,35 @@ func convertAssign(dest, src interface{}) error { *d = nil return nil } + // The driver is returning a cursor the client may iterate over. + case driver.Rows: + switch d := dest.(type) { + case *Rows: + if d == nil { + return errNilPtr + } + if rows == nil { + return errors.New("invalid context to convert cursor rows, missing parent *Rows") + } + rows.closemu.Lock() + *d = Rows{ + dc: rows.dc, + releaseConn: func(error) {}, + rowsi: s, + } + // Chain the cancel function. + parentCancel := rows.cancel + rows.cancel = func() { + // When Rows.cancel is called, the closemu will be locked as well. + // So we can access rs.lasterr. + d.close(rows.lasterr) + if parentCancel != nil { + parentCancel() + } + } + rows.closemu.Unlock() + return nil + } } var sv reflect.Value @@ -381,7 +418,7 @@ func convertAssign(dest, src interface{}) error { return nil } dv.Set(reflect.New(dv.Type().Elem())) - return convertAssign(dv.Interface(), src) + return convertAssignRows(dv.Interface(), src, rows) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: s := asString(src) i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) |
