package sqlximport ("database/sql""database/sql/driver""errors""fmt""io/ioutil""path/filepath""reflect""strings""sync""github.com/jmoiron/sqlx/reflectx")// Although the NameMapper is convenient, in practice it should not// be relied on except for application code. If you are writing a library// that uses sqlx, you should be aware that the name mappings you expect// can be overridden by your user's application.// NameMapper is used to map column names to struct field names. By default,// it uses strings.ToLower to lowercase struct field names. It can be set// to whatever you want, but it is encouraged to be set before sqlx is used// as name-to-field mappings are cached after first use on a type.var NameMapper = strings.ToLowervar origMapper = reflect.ValueOf(NameMapper)// Rather than creating on init, this is created when necessary so that// importers have time to customize the NameMapper.var mpr *reflectx.Mapper// mprMu protects mpr.var mprMu sync.Mutex// mapper returns a valid mapper using the configured NameMapper func.func mapper() *reflectx.Mapper {mprMu.Lock()defer mprMu.Unlock()if mpr == nil {mpr = reflectx.NewMapperFunc("db", NameMapper)} else if origMapper != reflect.ValueOf(NameMapper) {// if NameMapper has changed, create a new mappermpr = reflectx.NewMapperFunc("db", NameMapper)origMapper = reflect.ValueOf(NameMapper)}return mpr}// 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 fieldsfunc isScannable(t reflect.Type) bool {if reflect.PtrTo(t).Implements(_scannerInterface) {return true}if t.Kind() != reflect.Struct {return true}// it's not important that we use the right mapper for this particular object,// we're only concerned on how many exported fields this struct hasm := mapper()if len(m.TypeMap(t).Index) == 0 {return true}return false}// ColScanner is an interface used by MapScan and SliceScantype ColScanner interface {Columns() ([]string, error)Scan(dest ...interface{}) errorErr() error}// Queryer is an interface used by Get and Selecttype Queryer interface {Query(query string, args ...interface{}) (*sql.Rows, error)Queryx(query string, args ...interface{}) (*Rows, error)QueryRowx(query string, args ...interface{}) *Row}// Execer is an interface used by MustExec and LoadFiletype Execer interface {Exec(query string, args ...interface{}) (sql.Result, error)}// Binder is an interface for something which can bind queries (Tx, DB)type binder interface {DriverName() stringRebind(string) stringBindNamed(string, interface{}) (string, []interface{}, error)}// Ext is a union interface which can bind, query, and exec, used by// NamedQuery and NamedExec.type Ext interface {binderQueryerExecer}// Preparer is an interface used by Preparex.type Preparer interface {Prepare(query string) (*sql.Stmt, error)}// determine if any of our extensions are unsafefunc isUnsafe(i interface{}) bool {switch v := i.(type) {case Row:return v.unsafecase *Row:return v.unsafecase Rows:return v.unsafecase *Rows:return v.unsafecase NamedStmt:return v.Stmt.unsafecase *NamedStmt:return v.Stmt.unsafecase Stmt:return v.unsafecase *Stmt:return v.unsafecase qStmt:return v.unsafecase *qStmt:return v.unsafecase DB:return v.unsafecase *DB:return v.unsafecase Tx:return v.unsafecase *Tx:return v.unsafecase sql.Rows, *sql.Rows:return falsedefault:return false}}func mapperFor(i interface{}) *reflectx.Mapper {switch i.(type) {case DB:return i.(DB).Mappercase *DB:return i.(*DB).Mappercase Tx:return i.(Tx).Mappercase *Tx:return i.(*Tx).Mapperdefault:return mapper()}}var _scannerInterface = reflect.TypeOf((*sql.Scanner)(nil)).Elem()var _valuerInterface = reflect.TypeOf((*driver.Valuer)(nil)).Elem()// Row is a reimplementation of sql.Row in order to gain access to the underlying// sql.Rows.Columns() data, necessary for StructScan.type Row struct {err errorunsafe boolrows *sql.RowsMapper *reflectx.Mapper}// Scan is a fixed implementation of sql.Row.Scan, which does not discard the// underlying error from the internal rows object if it exists.func (r *Row) Scan(dest ...interface{}) error {if r.err != nil {return r.err}// TODO(bradfitz): for now we need to defensively clone all// []byte that the driver returned (not permitting// *RawBytes in Rows.Scan), 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.defer r.rows.Close()for _, dp := range dest {if _, ok := dp.(*sql.RawBytes); ok {return errors.New("sql: RawBytes isn't allowed on Row.Scan")}}if !r.rows.Next() {if err := r.rows.Err(); err != nil {return err}return sql.ErrNoRows}err := r.rows.Scan(dest...)if err != nil {return err}// Make sure the query can be processed to completion with no errors.if err := r.rows.Close(); err != nil {return err}return nil}// Columns returns the underlying sql.Rows.Columns(), or the deferred error usually// returned by Row.Scan()func (r *Row) Columns() ([]string, error) {if r.err != nil {return []string{}, r.err}return r.rows.Columns()}// ColumnTypes returns the underlying sql.Rows.ColumnTypes(), or the deferred errorfunc (r *Row) ColumnTypes() ([]*sql.ColumnType, error) {if r.err != nil {return []*sql.ColumnType{}, r.err}return r.rows.ColumnTypes()}// Err returns the error encountered while scanning.func (r *Row) Err() error {return r.err}// DB is a wrapper around sql.DB which keeps track of the driverName upon Open,// used mostly to automatically bind named queries using the right bindvars.type DB struct {*sql.DBdriverName stringunsafe boolMapper *reflectx.Mapper}// NewDb returns a new sqlx DB wrapper for a pre-existing *sql.DB. The// driverName of the original database is required for named query support.func NewDb(db *sql.DB, driverName string) *DB {return &DB{DB: db, driverName: driverName, Mapper: mapper()}}// DriverName returns the driverName passed to the Open function for this DB.func (db *DB) DriverName() string {return db.driverName}// Open is the same as sql.Open, but returns an *sqlx.DB instead.func Open(driverName, dataSourceName string) (*DB, error) {db, err := sql.Open(driverName, dataSourceName)if err != nil {return nil, err}return &DB{DB: db, driverName: driverName, Mapper: mapper()}, err}// MustOpen is the same as sql.Open, but returns an *sqlx.DB instead and panics on error.func MustOpen(driverName, dataSourceName string) *DB {db, err := Open(driverName, dataSourceName)if err != nil {panic(err)}return db}// MapperFunc sets a new mapper for this db using the default sqlx struct tag// and the provided mapper function.func (db *DB) MapperFunc(mf func(string) string) {db.Mapper = reflectx.NewMapperFunc("db", mf)}// Rebind transforms a query from QUESTION to the DB driver's bindvar type.func (db *DB) Rebind(query string) string {return Rebind(BindType(db.driverName), query)}// Unsafe returns a version of DB which will silently succeed to scan when// columns in the SQL result have no fields in the destination struct.// sqlx.Stmt and sqlx.Tx which are created from this DB will inherit its// safety behavior.func (db *DB) Unsafe() *DB {return &DB{DB: db.DB, driverName: db.driverName, unsafe: true, Mapper: db.Mapper}}// BindNamed binds a query using the DB driver's bindvar type.func (db *DB) BindNamed(query string, arg interface{}) (string, []interface{}, error) {return bindNamedMapper(BindType(db.driverName), query, arg, db.Mapper)}// NamedQuery using this DB.// Any named placeholder parameters are replaced with fields from arg.func (db *DB) NamedQuery(query string, arg interface{}) (*Rows, error) {return NamedQuery(db, query, arg)}// NamedExec using this DB.// Any named placeholder parameters are replaced with fields from arg.func (db *DB) NamedExec(query string, arg interface{}) (sql.Result, error) {return NamedExec(db, query, arg)}// Select using this DB.// Any placeholder parameters are replaced with supplied args.func (db *DB) Select(dest interface{}, query string, args ...interface{}) error {return Select(db, dest, query, args...)}// Get using this DB.// Any placeholder parameters are replaced with supplied args.// An error is returned if the result set is empty.func (db *DB) Get(dest interface{}, query string, args ...interface{}) error {return Get(db, dest, query, args...)}// MustBegin starts a transaction, and panics on error. Returns an *sqlx.Tx instead// of an *sql.Tx.func (db *DB) MustBegin() *Tx {tx, err := db.Beginx()if err != nil {panic(err)}return tx}// Beginx begins a transaction and returns an *sqlx.Tx instead of an *sql.Tx.func (db *DB) Beginx() (*Tx, error) {tx, err := db.DB.Begin()if err != nil {return nil, err}return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err}// Queryx queries the database and returns an *sqlx.Rows.// Any placeholder parameters are replaced with supplied args.func (db *DB) Queryx(query string, args ...interface{}) (*Rows, error) {r, err := db.DB.Query(query, args...)if err != nil {return nil, err}return &Rows{Rows: r, unsafe: db.unsafe, Mapper: db.Mapper}, err}// QueryRowx queries the database and returns an *sqlx.Row.// Any placeholder parameters are replaced with supplied args.func (db *DB) QueryRowx(query string, args ...interface{}) *Row {rows, err := db.DB.Query(query, args...)return &Row{rows: rows, err: err, unsafe: db.unsafe, Mapper: db.Mapper}}// MustExec (panic) runs MustExec using this database.// Any placeholder parameters are replaced with supplied args.func (db *DB) MustExec(query string, args ...interface{}) sql.Result {return MustExec(db, query, args...)}// Preparex returns an sqlx.Stmt instead of a sql.Stmtfunc (db *DB) Preparex(query string) (*Stmt, error) {return Preparex(db, query)}// PrepareNamed returns an sqlx.NamedStmtfunc (db *DB) PrepareNamed(query string) (*NamedStmt, error) {return prepareNamed(db, query)}// Tx is an sqlx wrapper around sql.Tx with extra functionalitytype Tx struct {*sql.TxdriverName stringunsafe boolMapper *reflectx.Mapper}// DriverName returns the driverName used by the DB which began this transaction.func (tx *Tx) DriverName() string {return tx.driverName}// Rebind a query within a transaction's bindvar type.func (tx *Tx) Rebind(query string) string {return Rebind(BindType(tx.driverName), query)}// Unsafe returns a version of Tx which will silently succeed to scan when// columns in the SQL result have no fields in the destination struct.func (tx *Tx) Unsafe() *Tx {return &Tx{Tx: tx.Tx, driverName: tx.driverName, unsafe: true, Mapper: tx.Mapper}}// BindNamed binds a query within a transaction's bindvar type.func (tx *Tx) BindNamed(query string, arg interface{}) (string, []interface{}, error) {return bindNamedMapper(BindType(tx.driverName), query, arg, tx.Mapper)}// NamedQuery within a transaction.// Any named placeholder parameters are replaced with fields from arg.func (tx *Tx) NamedQuery(query string, arg interface{}) (*Rows, error) {return NamedQuery(tx, query, arg)}// NamedExec a named query within a transaction.// Any named placeholder parameters are replaced with fields from arg.func (tx *Tx) NamedExec(query string, arg interface{}) (sql.Result, error) {return NamedExec(tx, query, arg)}// Select within a transaction.// Any placeholder parameters are replaced with supplied args.func (tx *Tx) Select(dest interface{}, query string, args ...interface{}) error {return Select(tx, dest, query, args...)}// Queryx within a transaction.// Any placeholder parameters are replaced with supplied args.func (tx *Tx) Queryx(query string, args ...interface{}) (*Rows, error) {r, err := tx.Tx.Query(query, args...)if err != nil {return nil, err}return &Rows{Rows: r, unsafe: tx.unsafe, Mapper: tx.Mapper}, err}// QueryRowx within a transaction.// Any placeholder parameters are replaced with supplied args.func (tx *Tx) QueryRowx(query string, args ...interface{}) *Row {rows, err := tx.Tx.Query(query, args...)return &Row{rows: rows, err: err, unsafe: tx.unsafe, Mapper: tx.Mapper}}// Get within a transaction.// Any placeholder parameters are replaced with supplied args.// An error is returned if the result set is empty.func (tx *Tx) Get(dest interface{}, query string, args ...interface{}) error {return Get(tx, dest, query, args...)}// MustExec runs MustExec within a transaction.// Any placeholder parameters are replaced with supplied args.func (tx *Tx) MustExec(query string, args ...interface{}) sql.Result {return MustExec(tx, query, args...)}// Preparex a statement within a transaction.func (tx *Tx) Preparex(query string) (*Stmt, error) {return Preparex(tx, query)}// Stmtx returns a version of the prepared statement which runs within a transaction. Provided// stmt can be either *sql.Stmt or *sqlx.Stmt.func (tx *Tx) Stmtx(stmt interface{}) *Stmt {var s *sql.Stmtswitch v := stmt.(type) {case Stmt:s = v.Stmtcase *Stmt:s = v.Stmtcase sql.Stmt:s = &vcase *sql.Stmt:s = vdefault:panic(fmt.Sprintf("non-statement type %v passed to Stmtx", reflect.ValueOf(stmt).Type()))}return &Stmt{Stmt: tx.Stmt(s), Mapper: tx.Mapper}}// NamedStmt returns a version of the prepared statement which runs within a transaction.func (tx *Tx) NamedStmt(stmt *NamedStmt) *NamedStmt {return &NamedStmt{QueryString: stmt.QueryString,Params: stmt.Params,Stmt: tx.Stmtx(stmt.Stmt),}}// PrepareNamed returns an sqlx.NamedStmtfunc (tx *Tx) PrepareNamed(query string) (*NamedStmt, error) {return prepareNamed(tx, query)}// Stmt is an sqlx wrapper around sql.Stmt with extra functionalitytype Stmt struct {*sql.Stmtunsafe boolMapper *reflectx.Mapper}// Unsafe returns a version of Stmt which will silently succeed to scan when// columns in the SQL result have no fields in the destination struct.func (s *Stmt) Unsafe() *Stmt {return &Stmt{Stmt: s.Stmt, unsafe: true, Mapper: s.Mapper}}// Select using the prepared statement.// Any placeholder parameters are replaced with supplied args.func (s *Stmt) Select(dest interface{}, args ...interface{}) error {return Select(&qStmt{s}, dest, "", args...)}// Get using the prepared statement.// Any placeholder parameters are replaced with supplied args.// An error is returned if the result set is empty.func (s *Stmt) Get(dest interface{}, args ...interface{}) error {return Get(&qStmt{s}, dest, "", args...)}// MustExec (panic) using this statement. Note that the query portion of the error// output will be blank, as Stmt does not expose its query.// Any placeholder parameters are replaced with supplied args.func (s *Stmt) MustExec(args ...interface{}) sql.Result {return MustExec(&qStmt{s}, "", args...)}// QueryRowx using this statement.// Any placeholder parameters are replaced with supplied args.func (s *Stmt) QueryRowx(args ...interface{}) *Row {qs := &qStmt{s}return qs.QueryRowx("", args...)}// Queryx using this statement.// Any placeholder parameters are replaced with supplied args.func (s *Stmt) Queryx(args ...interface{}) (*Rows, error) {qs := &qStmt{s}return qs.Queryx("", args...)}// qStmt is an unexposed wrapper which lets you use a Stmt as a Queryer & Execer by// implementing those interfaces and ignoring the `query` argument.type qStmt struct{ *Stmt }func (q *qStmt) Query(query string, args ...interface{}) (*sql.Rows, error) {return q.Stmt.Query(args...)}func (q *qStmt) Queryx(query string, args ...interface{}) (*Rows, error) {r, err := q.Stmt.Query(args...)if err != nil {return nil, err}return &Rows{Rows: r, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}, err}func (q *qStmt) QueryRowx(query string, args ...interface{}) *Row {rows, err := q.Stmt.Query(args...)return &Row{rows: rows, err: err, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}}func (q *qStmt) Exec(query string, args ...interface{}) (sql.Result, error) {return q.Stmt.Exec(args...)}// Rows is a wrapper around sql.Rows which caches costly reflect operations// during a looped StructScantype Rows struct {*sql.Rowsunsafe boolMapper *reflectx.Mapper// these fields cache memory use for a rows during iteration w/ structScanstarted boolfields [][]intvalues []interface{}}// SliceScan using this Rows.func (r *Rows) SliceScan() ([]interface{}, error) {return SliceScan(r)}// MapScan using this Rows.func (r *Rows) MapScan(dest map[string]interface{}) error {return MapScan(r, dest)}// StructScan is like sql.Rows.Scan, but scans a single Row into a single Struct.// Use this and iterate over Rows manually when the memory load of Select() might be// prohibitive. *Rows.StructScan caches the reflect work of matching up column// positions to fields to avoid that overhead per scan, which means it is not safe// to run StructScan on the same Rows instance with different struct types.func (r *Rows) StructScan(dest interface{}) error {v := reflect.ValueOf(dest)if v.Kind() != reflect.Ptr {return errors.New("must pass a pointer, not a value, to StructScan destination")}v = v.Elem()if !r.started {columns, err := r.Columns()if err != nil {return err}m := r.Mapperr.fields = m.TraversalsByName(v.Type(), columns)// if we are not unsafe and are missing fields, return an errorif f, err := missingFields(r.fields); err != nil && !r.unsafe {return fmt.Errorf("missing destination name %s in %T", columns[f], dest)}r.values = make([]interface{}, len(columns))r.started = true}err := fieldsByTraversal(v, r.fields, r.values, true)if err != nil {return err}// scan into the struct field pointers and append to our resultserr = r.Scan(r.values...)if err != nil {return err}return r.Err()}// Connect to a database and verify with a ping.func Connect(driverName, dataSourceName string) (*DB, error) {db, err := Open(driverName, dataSourceName)if err != nil {return nil, err}err = db.Ping()if err != nil {db.Close()return nil, err}return db, nil}// MustConnect connects to a database and panics on error.func MustConnect(driverName, dataSourceName string) *DB {db, err := Connect(driverName, dataSourceName)if err != nil {panic(err)}return db}// Preparex prepares a statement.func Preparex(p Preparer, query string) (*Stmt, error) {s, err := p.Prepare(query)if err != nil {return nil, err}return &Stmt{Stmt: s, unsafe: isUnsafe(p), Mapper: mapperFor(p)}, err}// Select executes a query using the provided Queryer, and StructScans each row// into dest, which must be a slice. If the slice elements are scannable, then// the result set must have only one column. Otherwise, StructScan is used.// The *sql.Rows are closed automatically.// Any placeholder parameters are replaced with supplied args.func Select(q Queryer, dest interface{}, query string, args ...interface{}) error {rows, err := q.Queryx(query, args...)if err != nil {return err}// if something happens here, we want to make sure the rows are Closeddefer rows.Close()return scanAll(rows, dest, false)}// Get does a QueryRow using the provided Queryer, and scans the resulting row// to dest. If dest is scannable, the result must only have one column. Otherwise,// StructScan is used. Get will return sql.ErrNoRows like row.Scan would.// Any placeholder parameters are replaced with supplied args.// An error is returned if the result set is empty.func Get(q Queryer, dest interface{}, query string, args ...interface{}) error {r := q.QueryRowx(query, args...)return r.scanAny(dest, false)}// LoadFile exec's every statement in a file (as a single call to Exec).// LoadFile may return a nil *sql.Result if errors are encountered locating or// reading the file at path. LoadFile reads the entire file into memory, so it// is not suitable for loading large data dumps, but can be useful for initializing// schemas or loading indexes.//// FIXME: this does not really work with multi-statement files for mattn/go-sqlite3// or the go-mysql-driver/mysql drivers; pq seems to be an exception here. Detecting// this by requiring something with DriverName() and then attempting to split the// queries will be difficult to get right, and its current driver-specific behavior// is deemed at least not complex in its incorrectness.func LoadFile(e Execer, path string) (*sql.Result, error) {realpath, err := filepath.Abs(path)if err != nil {return nil, err}contents, err := ioutil.ReadFile(realpath)if err != nil {return nil, err}res, err := e.Exec(string(contents))return &res, err}// MustExec execs the query using e and panics if there was an error.// Any placeholder parameters are replaced with supplied args.func MustExec(e Execer, query string, args ...interface{}) sql.Result {res, err := e.Exec(query, args...)if err != nil {panic(err)}return res}// SliceScan using this Rows.func (r *Row) SliceScan() ([]interface{}, error) {return SliceScan(r)}// MapScan using this Rows.func (r *Row) MapScan(dest map[string]interface{}) error {return MapScan(r, dest)}func (r *Row) scanAny(dest interface{}, structOnly bool) error {if r.err != nil {return r.err}if r.rows == nil {r.err = sql.ErrNoRowsreturn r.err}defer r.rows.Close()v := reflect.ValueOf(dest)if v.Kind() != reflect.Ptr {return errors.New("must pass a pointer, not a value, to StructScan destination")}if v.IsNil() {return errors.New("nil pointer passed to StructScan destination")}base := reflectx.Deref(v.Type())scannable := isScannable(base)if structOnly && scannable {return structOnlyError(base)}columns, err := r.Columns()if err != nil {return err}if scannable && len(columns) > 1 {return fmt.Errorf("scannable dest type %s with >1 columns (%d) in result", base.Kind(), len(columns))}if scannable {return r.Scan(dest)}m := r.Mapperfields := m.TraversalsByName(v.Type(), columns)// if we are not unsafe and are missing fields, return an errorif f, err := missingFields(fields); err != nil && !r.unsafe {return fmt.Errorf("missing destination name %s in %T", columns[f], dest)}values := make([]interface{}, len(columns))err = fieldsByTraversal(v, fields, values, true)if err != nil {return err}// scan into the struct field pointers and append to our resultsreturn r.Scan(values...)}// StructScan a single Row into dest.func (r *Row) StructScan(dest interface{}) error {return r.scanAny(dest, true)}// SliceScan a row, returning a []interface{} with values similar to MapScan.// This function is primarily intended for use where the number of columns// is not known. Because you can pass an []interface{} directly to Scan,// it's recommended that you do that as it will not have to allocate new// slices per row.func SliceScan(r ColScanner) ([]interface{}, error) {// ignore r.started, since we needn't use reflect for anything.columns, err := r.Columns()if err != nil {return []interface{}{}, err}values := make([]interface{}, len(columns))for i := range values {values[i] = new(interface{})}err = r.Scan(values...)if err != nil {return values, err}for i := range columns {values[i] = *(values[i].(*interface{}))}return values, r.Err()}// MapScan scans a single Row into the dest map[string]interface{}.// Use this to get results for SQL that might not be under your control// (for instance, if you're building an interface for an SQL server that// executes SQL from input). Please do not use this as a primary interface!// This will modify the map sent to it in place, so reuse the same map with// care. Columns which occur more than once in the result will overwrite// each other!func MapScan(r ColScanner, dest map[string]interface{}) error {// ignore r.started, since we needn't use reflect for anything.columns, err := r.Columns()if err != nil {return err}values := make([]interface{}, len(columns))for i := range values {values[i] = new(interface{})}err = r.Scan(values...)if err != nil {return err}for i, column := range columns {dest[column] = *(values[i].(*interface{}))}return r.Err()}type rowsi interface {Close() errorColumns() ([]string, error)Err() errorNext() boolScan(...interface{}) error}// structOnlyError returns an error appropriate for type when a non-scannable// struct is expected but something else is givenfunc structOnlyError(t reflect.Type) error {isStruct := t.Kind() == reflect.StructisScanner := reflect.PtrTo(t).Implements(_scannerInterface)if !isStruct {return fmt.Errorf("expected %s but got %s", reflect.Struct, t.Kind())}if isScanner {return fmt.Errorf("structscan expects a struct dest but the provided struct type %s implements scanner", t.Name())}return fmt.Errorf("expected a struct, but struct %s has no exported fields", t.Name())}// scanAll scans all rows into a destination, which must be a slice of any// type. If the destination slice type is a Struct, then StructScan will be// used on each row. If the destination is some other kind of base type, 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)//// 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// to `Get` and `Select`. The reason that this has been implemented like this is// this is the only way to not duplicate reflect work in the new API while// maintaining backwards compatibility.func scanAll(rows rowsi, dest interface{}, structOnly bool) error {var v, vp reflect.Valuevalue := reflect.ValueOf(dest)// json.Unmarshal returns errors for theseif value.Kind() != reflect.Ptr {return errors.New("must pass a pointer, not a value, to StructScan destination")}if value.IsNil() {return errors.New("nil pointer passed to StructScan destination")}direct := reflect.Indirect(value)slice, err := baseType(value.Type(), reflect.Slice)if err != nil {return err}isPtr := slice.Elem().Kind() == reflect.Ptrbase := reflectx.Deref(slice.Elem())scannable := isScannable(base)if structOnly && scannable {return structOnlyError(base)}columns, err := rows.Columns()if err != nil {return err}// if it's a base type make sure it only has 1 column; if not return an errorif scannable && len(columns) > 1 {return fmt.Errorf("non-struct dest type %s with >1 columns (%d)", base.Kind(), len(columns))}if !scannable {var values []interface{}var m *reflectx.Mapperswitch rows.(type) {case *Rows:m = rows.(*Rows).Mapperdefault:m = mapper()}fields := m.TraversalsByName(base, columns)// if we are not unsafe and are missing fields, return an errorif f, err := missingFields(fields); err != nil && !isUnsafe(rows) {return fmt.Errorf("missing destination name %s in %T", columns[f], dest)}values = make([]interface{}, len(columns))for rows.Next() {// create a new struct type (which returns PtrTo) and indirect itvp = reflect.New(base)v = reflect.Indirect(vp)err = fieldsByTraversal(v, fields, values, true)if err != nil {return err}// scan into the struct field pointers and append to our resultserr = rows.Scan(values...)if err != nil {return err}if isPtr {direct.Set(reflect.Append(direct, vp))} else {direct.Set(reflect.Append(direct, v))}}} else {for rows.Next() {vp = reflect.New(base)err = rows.Scan(vp.Interface())if err != nil {return err}// appendif isPtr {direct.Set(reflect.Append(direct, vp))} else {direct.Set(reflect.Append(direct, reflect.Indirect(vp)))}}}return rows.Err()}// FIXME: StructScan was the very first bit of API in sqlx, and now unfortunately// it doesn't really feel like it's named properly. There is an incongruency// between this and the way that StructScan (which might better be ScanStruct// anyway) works on a rows object.// StructScan all rows from an sql.Rows or an sqlx.Rows into the dest slice.// StructScan will scan in the entire rows result, so if you do not want to// allocate structs for the entire result, use Queryx and see sqlx.Rows.StructScan.// If rows is sqlx.Rows, it will use its mapper, otherwise it will use the default.func StructScan(rows rowsi, dest interface{}) error {return scanAll(rows, dest, true)}// reflect helpersfunc baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {t = reflectx.Deref(t)if t.Kind() != expected {return nil, fmt.Errorf("expected %s but got %s", expected, t.Kind())}return t, nil}// fieldsByName fills a values interface with fields from the passed value based// on the traversals in int. If ptrs is true, return addresses instead of values.// We write this instead of using FieldsByName to save allocations and map lookups// when iterating over many rows. Empty traversals will get an interface pointer.// Because of the necessity of requesting ptrs or values, it's considered a bit too// specialized for inclusion in reflectx itself.func fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{}, ptrs bool) error {v = reflect.Indirect(v)if v.Kind() != reflect.Struct {return errors.New("argument not a struct")}for i, traversal := range traversals {if len(traversal) == 0 {values[i] = new(interface{})continue}f := reflectx.FieldByIndexes(v, traversal)if ptrs {values[i] = f.Addr().Interface()} else {values[i] = f.Interface()}}return nil}func missingFields(transversals [][]int) (field int, err error) {for i, t := range transversals {if len(t) == 0 {return i, errors.New("missing field")}}return 0, nil}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。