aboutsummaryrefslogtreecommitdiff
path: root/src/database/sql/convert.go
diff options
context:
space:
mode:
authorDaniel Theophanes <kardianos@gmail.com>2018-10-29 16:22:37 -0700
committerDaniel Theophanes <kardianos@gmail.com>2018-11-08 21:19:17 +0000
commit968742a824de0a6459d2820d11b9e2e58803f472 (patch)
tree946104b6aa08dd0e575944ee2b56f1ba16711d80 /src/database/sql/convert.go
parentad4a58e31501bce5de2aad90a620eaecdc1eecb8 (diff)
downloadgo-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.go45
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())