Skip to content

Commit

Permalink
Invalidate cache on Rows.NextResultSet call
Browse files Browse the repository at this point in the history
When reading multiple result sets from sqlx.Rows using StructScan,
some information obtained usCCCing costly reflect operations is
cached for performance optimisation.
However, different result sets in a single sqlx.Rows object might
have different structures, so cache should be invalidated and rebuild
after each NextResultSet call. Now this method is not overwritten,
so old cache interferes with new structures after first result set scan.

Relates #857
  • Loading branch information
kamilkoduo committed Apr 12, 2023
1 parent 28212d4 commit a817d1d
Showing 1 changed file with 17 additions and 7 deletions.
24 changes: 17 additions & 7 deletions sqlx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"database/sql/driver"
"errors"
"fmt"

"io/ioutil"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -51,9 +50,9 @@ func mapper() *reflectx.Mapper {

// isScannable takes the reflect.Type and the actual dest value and returns
// whether or not it's Scannable. Something is scannable if:
// * it is not a struct
// * it implements sql.Scanner
// * it has no exported fields
// - it is not a struct
// - it implements sql.Scanner
// - it has no exported fields
func isScannable(t reflect.Type) bool {
if reflect.PtrTo(t).Implements(_scannerInterface) {
return true
Expand Down Expand Up @@ -633,6 +632,17 @@ func (r *Rows) StructScan(dest interface{}) error {
return r.Err()
}

// NextResultSet behaves like sql.NextResultSet, but cleans cache of previous result set.
func (r *Rows) NextResultSet() bool {
if !r.Rows.NextResultSet() {
return false
}
r.started = false
r.fields = nil
r.values = nil
return true
}

// Connect to a database and verify with a ping.
func Connect(driverName, dataSourceName string) (*DB, error) {
db, err := Open(driverName, dataSourceName)
Expand Down Expand Up @@ -884,9 +894,9 @@ func structOnlyError(t reflect.Type) error {
// then each row must only have one column which can scan into that type. This
// allows you to do something like:
//
// rows, _ := db.Query("select id from people;")
// var ids []int
// scanAll(rows, &ids, false)
// rows, _ := db.Query("select id from people;")
// var ids []int
// scanAll(rows, &ids, false)
//
// and ids will be a list of the id results. I realize that this is a desirable
// interface to expose to users, but for now it will only be exposed via changes
Expand Down

0 comments on commit a817d1d

Please sign in to comment.