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 }