gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

rows.go (19506B)


      1 package pgx
      2 
      3 import (
      4 	"context"
      5 	"errors"
      6 	"fmt"
      7 	"reflect"
      8 	"strings"
      9 	"time"
     10 
     11 	"github.com/jackc/pgx/v5/internal/stmtcache"
     12 	"github.com/jackc/pgx/v5/pgconn"
     13 	"github.com/jackc/pgx/v5/pgtype"
     14 )
     15 
     16 // Rows is the result set returned from *Conn.Query. Rows must be closed before
     17 // the *Conn can be used again. Rows are closed by explicitly calling Close(),
     18 // calling Next() until it returns false, or when a fatal error occurs.
     19 //
     20 // Once a Rows is closed the only methods that may be called are Close(), Err(), and CommandTag().
     21 //
     22 // Rows is an interface instead of a struct to allow tests to mock Query. However,
     23 // adding a method to an interface is technically a breaking change. Because of this
     24 // the Rows interface is partially excluded from semantic version requirements.
     25 // Methods will not be removed or changed, but new methods may be added.
     26 type Rows interface {
     27 	// Close closes the rows, making the connection ready for use again. It is safe
     28 	// to call Close after rows is already closed.
     29 	Close()
     30 
     31 	// Err returns any error that occurred while reading. Err must only be called after the Rows is closed (either by
     32 	// calling Close or by Next returning false). If it is called early it may return nil even if there was an error
     33 	// executing the query.
     34 	Err() error
     35 
     36 	// CommandTag returns the command tag from this query. It is only available after Rows is closed.
     37 	CommandTag() pgconn.CommandTag
     38 
     39 	// FieldDescriptions returns the field descriptions of the columns. It may return nil. In particular this can occur
     40 	// when there was an error executing the query.
     41 	FieldDescriptions() []pgconn.FieldDescription
     42 
     43 	// Next prepares the next row for reading. It returns true if there is another
     44 	// row and false if no more rows are available. It automatically closes rows
     45 	// when all rows are read.
     46 	Next() bool
     47 
     48 	// Scan reads the values from the current row into dest values positionally.
     49 	// dest can include pointers to core types, values implementing the Scanner
     50 	// interface, and nil. nil will skip the value entirely. It is an error to
     51 	// call Scan without first calling Next() and checking that it returned true.
     52 	Scan(dest ...any) error
     53 
     54 	// Values returns the decoded row values. As with Scan(), it is an error to
     55 	// call Values without first calling Next() and checking that it returned
     56 	// true.
     57 	Values() ([]any, error)
     58 
     59 	// RawValues returns the unparsed bytes of the row values. The returned data is only valid until the next Next
     60 	// call or the Rows is closed.
     61 	RawValues() [][]byte
     62 
     63 	// Conn returns the underlying *Conn on which the query was executed. This may return nil if Rows did not come from a
     64 	// *Conn (e.g. if it was created by RowsFromResultReader)
     65 	Conn() *Conn
     66 }
     67 
     68 // Row is a convenience wrapper over Rows that is returned by QueryRow.
     69 //
     70 // Row is an interface instead of a struct to allow tests to mock QueryRow. However,
     71 // adding a method to an interface is technically a breaking change. Because of this
     72 // the Row interface is partially excluded from semantic version requirements.
     73 // Methods will not be removed or changed, but new methods may be added.
     74 type Row interface {
     75 	// Scan works the same as Rows. with the following exceptions. If no
     76 	// rows were found it returns ErrNoRows. If multiple rows are returned it
     77 	// ignores all but the first.
     78 	Scan(dest ...any) error
     79 }
     80 
     81 // RowScanner scans an entire row at a time into the RowScanner.
     82 type RowScanner interface {
     83 	// ScanRows scans the row.
     84 	ScanRow(rows Rows) error
     85 }
     86 
     87 // connRow implements the Row interface for Conn.QueryRow.
     88 type connRow baseRows
     89 
     90 func (r *connRow) Scan(dest ...any) (err error) {
     91 	rows := (*baseRows)(r)
     92 
     93 	if rows.Err() != nil {
     94 		return rows.Err()
     95 	}
     96 
     97 	for _, d := range dest {
     98 		if _, ok := d.(*pgtype.DriverBytes); ok {
     99 			rows.Close()
    100 			return fmt.Errorf("cannot scan into *pgtype.DriverBytes from QueryRow")
    101 		}
    102 	}
    103 
    104 	if !rows.Next() {
    105 		if rows.Err() == nil {
    106 			return ErrNoRows
    107 		}
    108 		return rows.Err()
    109 	}
    110 
    111 	rows.Scan(dest...)
    112 	rows.Close()
    113 	return rows.Err()
    114 }
    115 
    116 // baseRows implements the Rows interface for Conn.Query.
    117 type baseRows struct {
    118 	typeMap      *pgtype.Map
    119 	resultReader *pgconn.ResultReader
    120 
    121 	values [][]byte
    122 
    123 	commandTag pgconn.CommandTag
    124 	err        error
    125 	closed     bool
    126 
    127 	scanPlans []pgtype.ScanPlan
    128 	scanTypes []reflect.Type
    129 
    130 	conn              *Conn
    131 	multiResultReader *pgconn.MultiResultReader
    132 
    133 	queryTracer QueryTracer
    134 	batchTracer BatchTracer
    135 	ctx         context.Context
    136 	startTime   time.Time
    137 	sql         string
    138 	args        []any
    139 	rowCount    int
    140 }
    141 
    142 func (rows *baseRows) FieldDescriptions() []pgconn.FieldDescription {
    143 	return rows.resultReader.FieldDescriptions()
    144 }
    145 
    146 func (rows *baseRows) Close() {
    147 	if rows.closed {
    148 		return
    149 	}
    150 
    151 	rows.closed = true
    152 
    153 	if rows.resultReader != nil {
    154 		var closeErr error
    155 		rows.commandTag, closeErr = rows.resultReader.Close()
    156 		if rows.err == nil {
    157 			rows.err = closeErr
    158 		}
    159 	}
    160 
    161 	if rows.multiResultReader != nil {
    162 		closeErr := rows.multiResultReader.Close()
    163 		if rows.err == nil {
    164 			rows.err = closeErr
    165 		}
    166 	}
    167 
    168 	if rows.err != nil && rows.conn != nil && rows.sql != "" {
    169 		if stmtcache.IsStatementInvalid(rows.err) {
    170 			if sc := rows.conn.statementCache; sc != nil {
    171 				sc.Invalidate(rows.sql)
    172 			}
    173 
    174 			if sc := rows.conn.descriptionCache; sc != nil {
    175 				sc.Invalidate(rows.sql)
    176 			}
    177 		}
    178 	}
    179 
    180 	if rows.batchTracer != nil {
    181 		rows.batchTracer.TraceBatchQuery(rows.ctx, rows.conn, TraceBatchQueryData{SQL: rows.sql, Args: rows.args, CommandTag: rows.commandTag, Err: rows.err})
    182 	} else if rows.queryTracer != nil {
    183 		rows.queryTracer.TraceQueryEnd(rows.ctx, rows.conn, TraceQueryEndData{rows.commandTag, rows.err})
    184 	}
    185 }
    186 
    187 func (rows *baseRows) CommandTag() pgconn.CommandTag {
    188 	return rows.commandTag
    189 }
    190 
    191 func (rows *baseRows) Err() error {
    192 	return rows.err
    193 }
    194 
    195 // fatal signals an error occurred after the query was sent to the server. It
    196 // closes the rows automatically.
    197 func (rows *baseRows) fatal(err error) {
    198 	if rows.err != nil {
    199 		return
    200 	}
    201 
    202 	rows.err = err
    203 	rows.Close()
    204 }
    205 
    206 func (rows *baseRows) Next() bool {
    207 	if rows.closed {
    208 		return false
    209 	}
    210 
    211 	if rows.resultReader.NextRow() {
    212 		rows.rowCount++
    213 		rows.values = rows.resultReader.Values()
    214 		return true
    215 	} else {
    216 		rows.Close()
    217 		return false
    218 	}
    219 }
    220 
    221 func (rows *baseRows) Scan(dest ...any) error {
    222 	m := rows.typeMap
    223 	fieldDescriptions := rows.FieldDescriptions()
    224 	values := rows.values
    225 
    226 	if len(fieldDescriptions) != len(values) {
    227 		err := fmt.Errorf("number of field descriptions must equal number of values, got %d and %d", len(fieldDescriptions), len(values))
    228 		rows.fatal(err)
    229 		return err
    230 	}
    231 
    232 	if len(dest) == 1 {
    233 		if rc, ok := dest[0].(RowScanner); ok {
    234 			return rc.ScanRow(rows)
    235 		}
    236 	}
    237 
    238 	if len(fieldDescriptions) != len(dest) {
    239 		err := fmt.Errorf("number of field descriptions must equal number of destinations, got %d and %d", len(fieldDescriptions), len(dest))
    240 		rows.fatal(err)
    241 		return err
    242 	}
    243 
    244 	if rows.scanPlans == nil {
    245 		rows.scanPlans = make([]pgtype.ScanPlan, len(values))
    246 		rows.scanTypes = make([]reflect.Type, len(values))
    247 		for i := range dest {
    248 			rows.scanPlans[i] = m.PlanScan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, dest[i])
    249 			rows.scanTypes[i] = reflect.TypeOf(dest[i])
    250 		}
    251 	}
    252 
    253 	for i, dst := range dest {
    254 		if dst == nil {
    255 			continue
    256 		}
    257 
    258 		if rows.scanTypes[i] != reflect.TypeOf(dst) {
    259 			rows.scanPlans[i] = m.PlanScan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, dest[i])
    260 			rows.scanTypes[i] = reflect.TypeOf(dest[i])
    261 		}
    262 
    263 		err := rows.scanPlans[i].Scan(values[i], dst)
    264 		if err != nil {
    265 			err = ScanArgError{ColumnIndex: i, Err: err}
    266 			rows.fatal(err)
    267 			return err
    268 		}
    269 	}
    270 
    271 	return nil
    272 }
    273 
    274 func (rows *baseRows) Values() ([]any, error) {
    275 	if rows.closed {
    276 		return nil, errors.New("rows is closed")
    277 	}
    278 
    279 	values := make([]any, 0, len(rows.FieldDescriptions()))
    280 
    281 	for i := range rows.FieldDescriptions() {
    282 		buf := rows.values[i]
    283 		fd := &rows.FieldDescriptions()[i]
    284 
    285 		if buf == nil {
    286 			values = append(values, nil)
    287 			continue
    288 		}
    289 
    290 		if dt, ok := rows.typeMap.TypeForOID(fd.DataTypeOID); ok {
    291 			value, err := dt.Codec.DecodeValue(rows.typeMap, fd.DataTypeOID, fd.Format, buf)
    292 			if err != nil {
    293 				rows.fatal(err)
    294 			}
    295 			values = append(values, value)
    296 		} else {
    297 			switch fd.Format {
    298 			case TextFormatCode:
    299 				values = append(values, string(buf))
    300 			case BinaryFormatCode:
    301 				newBuf := make([]byte, len(buf))
    302 				copy(newBuf, buf)
    303 				values = append(values, newBuf)
    304 			default:
    305 				rows.fatal(errors.New("Unknown format code"))
    306 			}
    307 		}
    308 
    309 		if rows.Err() != nil {
    310 			return nil, rows.Err()
    311 		}
    312 	}
    313 
    314 	return values, rows.Err()
    315 }
    316 
    317 func (rows *baseRows) RawValues() [][]byte {
    318 	return rows.values
    319 }
    320 
    321 func (rows *baseRows) Conn() *Conn {
    322 	return rows.conn
    323 }
    324 
    325 type ScanArgError struct {
    326 	ColumnIndex int
    327 	Err         error
    328 }
    329 
    330 func (e ScanArgError) Error() string {
    331 	return fmt.Sprintf("can't scan into dest[%d]: %v", e.ColumnIndex, e.Err)
    332 }
    333 
    334 func (e ScanArgError) Unwrap() error {
    335 	return e.Err
    336 }
    337 
    338 // ScanRow decodes raw row data into dest. It can be used to scan rows read from the lower level pgconn interface.
    339 //
    340 // typeMap - OID to Go type mapping.
    341 // fieldDescriptions - OID and format of values
    342 // values - the raw data as returned from the PostgreSQL server
    343 // dest - the destination that values will be decoded into
    344 func ScanRow(typeMap *pgtype.Map, fieldDescriptions []pgconn.FieldDescription, values [][]byte, dest ...any) error {
    345 	if len(fieldDescriptions) != len(values) {
    346 		return fmt.Errorf("number of field descriptions must equal number of values, got %d and %d", len(fieldDescriptions), len(values))
    347 	}
    348 	if len(fieldDescriptions) != len(dest) {
    349 		return fmt.Errorf("number of field descriptions must equal number of destinations, got %d and %d", len(fieldDescriptions), len(dest))
    350 	}
    351 
    352 	for i, d := range dest {
    353 		if d == nil {
    354 			continue
    355 		}
    356 
    357 		err := typeMap.Scan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, values[i], d)
    358 		if err != nil {
    359 			return ScanArgError{ColumnIndex: i, Err: err}
    360 		}
    361 	}
    362 
    363 	return nil
    364 }
    365 
    366 // RowsFromResultReader returns a Rows that will read from values resultReader and decode with typeMap. It can be used
    367 // to read from the lower level pgconn interface.
    368 func RowsFromResultReader(typeMap *pgtype.Map, resultReader *pgconn.ResultReader) Rows {
    369 	return &baseRows{
    370 		typeMap:      typeMap,
    371 		resultReader: resultReader,
    372 	}
    373 }
    374 
    375 // ForEachRow iterates through rows. For each row it scans into the elements of scans and calls fn. If any row
    376 // fails to scan or fn returns an error the query will be aborted and the error will be returned. Rows will be closed
    377 // when ForEachRow returns.
    378 func ForEachRow(rows Rows, scans []any, fn func() error) (pgconn.CommandTag, error) {
    379 	defer rows.Close()
    380 
    381 	for rows.Next() {
    382 		err := rows.Scan(scans...)
    383 		if err != nil {
    384 			return pgconn.CommandTag{}, err
    385 		}
    386 
    387 		err = fn()
    388 		if err != nil {
    389 			return pgconn.CommandTag{}, err
    390 		}
    391 	}
    392 
    393 	if err := rows.Err(); err != nil {
    394 		return pgconn.CommandTag{}, err
    395 	}
    396 
    397 	return rows.CommandTag(), nil
    398 }
    399 
    400 // CollectableRow is the subset of Rows methods that a RowToFunc is allowed to call.
    401 type CollectableRow interface {
    402 	FieldDescriptions() []pgconn.FieldDescription
    403 	Scan(dest ...any) error
    404 	Values() ([]any, error)
    405 	RawValues() [][]byte
    406 }
    407 
    408 // RowToFunc is a function that scans or otherwise converts row to a T.
    409 type RowToFunc[T any] func(row CollectableRow) (T, error)
    410 
    411 // CollectRows iterates through rows, calling fn for each row, and collecting the results into a slice of T.
    412 func CollectRows[T any](rows Rows, fn RowToFunc[T]) ([]T, error) {
    413 	defer rows.Close()
    414 
    415 	slice := []T{}
    416 
    417 	for rows.Next() {
    418 		value, err := fn(rows)
    419 		if err != nil {
    420 			return nil, err
    421 		}
    422 		slice = append(slice, value)
    423 	}
    424 
    425 	if err := rows.Err(); err != nil {
    426 		return nil, err
    427 	}
    428 
    429 	return slice, nil
    430 }
    431 
    432 // CollectOneRow calls fn for the first row in rows and returns the result. If no rows are found returns an error where errors.Is(ErrNoRows) is true.
    433 // CollectOneRow is to CollectRows as QueryRow is to Query.
    434 func CollectOneRow[T any](rows Rows, fn RowToFunc[T]) (T, error) {
    435 	defer rows.Close()
    436 
    437 	var value T
    438 	var err error
    439 
    440 	if !rows.Next() {
    441 		if err = rows.Err(); err != nil {
    442 			return value, err
    443 		}
    444 		return value, ErrNoRows
    445 	}
    446 
    447 	value, err = fn(rows)
    448 	if err != nil {
    449 		return value, err
    450 	}
    451 
    452 	rows.Close()
    453 	return value, rows.Err()
    454 }
    455 
    456 // RowTo returns a T scanned from row.
    457 func RowTo[T any](row CollectableRow) (T, error) {
    458 	var value T
    459 	err := row.Scan(&value)
    460 	return value, err
    461 }
    462 
    463 // RowTo returns a the address of a T scanned from row.
    464 func RowToAddrOf[T any](row CollectableRow) (*T, error) {
    465 	var value T
    466 	err := row.Scan(&value)
    467 	return &value, err
    468 }
    469 
    470 // RowToMap returns a map scanned from row.
    471 func RowToMap(row CollectableRow) (map[string]any, error) {
    472 	var value map[string]any
    473 	err := row.Scan((*mapRowScanner)(&value))
    474 	return value, err
    475 }
    476 
    477 type mapRowScanner map[string]any
    478 
    479 func (rs *mapRowScanner) ScanRow(rows Rows) error {
    480 	values, err := rows.Values()
    481 	if err != nil {
    482 		return err
    483 	}
    484 
    485 	*rs = make(mapRowScanner, len(values))
    486 
    487 	for i := range values {
    488 		(*rs)[string(rows.FieldDescriptions()[i].Name)] = values[i]
    489 	}
    490 
    491 	return nil
    492 }
    493 
    494 // RowToStructByPos returns a T scanned from row. T must be a struct. T must have the same number a public fields as row
    495 // has fields. The row and T fields will by matched by position.
    496 func RowToStructByPos[T any](row CollectableRow) (T, error) {
    497 	var value T
    498 	err := row.Scan(&positionalStructRowScanner{ptrToStruct: &value})
    499 	return value, err
    500 }
    501 
    502 // RowToAddrOfStructByPos returns the address of a T scanned from row. T must be a struct. T must have the same number a
    503 // public fields as row has fields. The row and T fields will by matched by position.
    504 func RowToAddrOfStructByPos[T any](row CollectableRow) (*T, error) {
    505 	var value T
    506 	err := row.Scan(&positionalStructRowScanner{ptrToStruct: &value})
    507 	return &value, err
    508 }
    509 
    510 type positionalStructRowScanner struct {
    511 	ptrToStruct any
    512 }
    513 
    514 func (rs *positionalStructRowScanner) ScanRow(rows Rows) error {
    515 	dst := rs.ptrToStruct
    516 	dstValue := reflect.ValueOf(dst)
    517 	if dstValue.Kind() != reflect.Ptr {
    518 		return fmt.Errorf("dst not a pointer")
    519 	}
    520 
    521 	dstElemValue := dstValue.Elem()
    522 	scanTargets := rs.appendScanTargets(dstElemValue, nil)
    523 
    524 	if len(rows.RawValues()) > len(scanTargets) {
    525 		return fmt.Errorf("got %d values, but dst struct has only %d fields", len(rows.RawValues()), len(scanTargets))
    526 	}
    527 
    528 	return rows.Scan(scanTargets...)
    529 }
    530 
    531 func (rs *positionalStructRowScanner) appendScanTargets(dstElemValue reflect.Value, scanTargets []any) []any {
    532 	dstElemType := dstElemValue.Type()
    533 
    534 	if scanTargets == nil {
    535 		scanTargets = make([]any, 0, dstElemType.NumField())
    536 	}
    537 
    538 	for i := 0; i < dstElemType.NumField(); i++ {
    539 		sf := dstElemType.Field(i)
    540 		// Handle anonymous struct embedding, but do not try to handle embedded pointers.
    541 		if sf.Anonymous && sf.Type.Kind() == reflect.Struct {
    542 			scanTargets = rs.appendScanTargets(dstElemValue.Field(i), scanTargets)
    543 		} else if sf.PkgPath == "" {
    544 			scanTargets = append(scanTargets, dstElemValue.Field(i).Addr().Interface())
    545 		}
    546 	}
    547 
    548 	return scanTargets
    549 }
    550 
    551 // RowToStructByName returns a T scanned from row. T must be a struct. T must have the same number of named public
    552 // fields as row has fields. The row and T fields will by matched by name. The match is case-insensitive. The database
    553 // column name can be overridden with a "db" struct tag. If the "db" struct tag is "-" then the field will be ignored.
    554 func RowToStructByName[T any](row CollectableRow) (T, error) {
    555 	var value T
    556 	err := row.Scan(&namedStructRowScanner{ptrToStruct: &value})
    557 	return value, err
    558 }
    559 
    560 // RowToAddrOfStructByName returns the address of a T scanned from row. T must be a struct. T must have the same number
    561 // of named public fields as row has fields. The row and T fields will by matched by name. The match is
    562 // case-insensitive. The database column name can be overridden with a "db" struct tag. If the "db" struct tag is "-"
    563 // then the field will be ignored.
    564 func RowToAddrOfStructByName[T any](row CollectableRow) (*T, error) {
    565 	var value T
    566 	err := row.Scan(&namedStructRowScanner{ptrToStruct: &value})
    567 	return &value, err
    568 }
    569 
    570 // RowToStructByNameLax returns a T scanned from row. T must be a struct. T must have greater than or equal number of named public
    571 // fields as row has fields. The row and T fields will by matched by name. The match is case-insensitive. The database
    572 // column name can be overridden with a "db" struct tag. If the "db" struct tag is "-" then the field will be ignored.
    573 func RowToStructByNameLax[T any](row CollectableRow) (T, error) {
    574 	var value T
    575 	err := row.Scan(&namedStructRowScanner{ptrToStruct: &value, lax: true})
    576 	return value, err
    577 }
    578 
    579 // RowToAddrOfStructByNameLax returns the address of a T scanned from row. T must be a struct. T must have greater than or
    580 // equal number of named public fields as row has fields. The row and T fields will by matched by name. The match is
    581 // case-insensitive. The database column name can be overridden with a "db" struct tag. If the "db" struct tag is "-"
    582 // then the field will be ignored.
    583 func RowToAddrOfStructByNameLax[T any](row CollectableRow) (*T, error) {
    584 	var value T
    585 	err := row.Scan(&namedStructRowScanner{ptrToStruct: &value, lax: true})
    586 	return &value, err
    587 }
    588 
    589 type namedStructRowScanner struct {
    590 	ptrToStruct any
    591 	lax         bool
    592 }
    593 
    594 func (rs *namedStructRowScanner) ScanRow(rows Rows) error {
    595 	dst := rs.ptrToStruct
    596 	dstValue := reflect.ValueOf(dst)
    597 	if dstValue.Kind() != reflect.Ptr {
    598 		return fmt.Errorf("dst not a pointer")
    599 	}
    600 
    601 	dstElemValue := dstValue.Elem()
    602 	scanTargets, err := rs.appendScanTargets(dstElemValue, nil, rows.FieldDescriptions())
    603 	if err != nil {
    604 		return err
    605 	}
    606 
    607 	for i, t := range scanTargets {
    608 		if t == nil {
    609 			return fmt.Errorf("struct doesn't have corresponding row field %s", rows.FieldDescriptions()[i].Name)
    610 		}
    611 	}
    612 
    613 	return rows.Scan(scanTargets...)
    614 }
    615 
    616 const structTagKey = "db"
    617 
    618 func fieldPosByName(fldDescs []pgconn.FieldDescription, field string) (i int) {
    619 	i = -1
    620 	for i, desc := range fldDescs {
    621 		if strings.EqualFold(desc.Name, field) {
    622 			return i
    623 		}
    624 	}
    625 	return
    626 }
    627 
    628 func (rs *namedStructRowScanner) appendScanTargets(dstElemValue reflect.Value, scanTargets []any, fldDescs []pgconn.FieldDescription) ([]any, error) {
    629 	var err error
    630 	dstElemType := dstElemValue.Type()
    631 
    632 	if scanTargets == nil {
    633 		scanTargets = make([]any, len(fldDescs))
    634 	}
    635 
    636 	for i := 0; i < dstElemType.NumField(); i++ {
    637 		sf := dstElemType.Field(i)
    638 		if sf.PkgPath != "" && !sf.Anonymous {
    639 			// Field is unexported, skip it.
    640 			continue
    641 		}
    642 		// Handle anoymous struct embedding, but do not try to handle embedded pointers.
    643 		if sf.Anonymous && sf.Type.Kind() == reflect.Struct {
    644 			scanTargets, err = rs.appendScanTargets(dstElemValue.Field(i), scanTargets, fldDescs)
    645 			if err != nil {
    646 				return nil, err
    647 			}
    648 		} else {
    649 			dbTag, dbTagPresent := sf.Tag.Lookup(structTagKey)
    650 			if dbTagPresent {
    651 				dbTag = strings.Split(dbTag, ",")[0]
    652 			}
    653 			if dbTag == "-" {
    654 				// Field is ignored, skip it.
    655 				continue
    656 			}
    657 			colName := dbTag
    658 			if !dbTagPresent {
    659 				colName = sf.Name
    660 			}
    661 			fpos := fieldPosByName(fldDescs, colName)
    662 			if fpos == -1 {
    663 				if rs.lax {
    664 					continue
    665 				}
    666 				return nil, fmt.Errorf("cannot find field %s in returned row", colName)
    667 			}
    668 			if fpos >= len(scanTargets) && !rs.lax {
    669 				return nil, fmt.Errorf("cannot find field %s in returned row", colName)
    670 			}
    671 			scanTargets[fpos] = dstElemValue.Field(i).Addr().Interface()
    672 		}
    673 	}
    674 
    675 	return scanTargets, err
    676 }