|
7 | 7 | "errors" |
8 | 8 | "fmt" |
9 | 9 | "io" |
| 10 | + "reflect" |
10 | 11 | "strconv" |
11 | 12 | "sync" |
12 | 13 |
|
@@ -249,7 +250,7 @@ func (c ocConn) Query(query string, args []driver.Value) (rows driver.Rows, err |
249 | 250 | return nil, err |
250 | 251 | } |
251 | 252 |
|
252 | | - return ocRows{parent: rows, ctx: ctx, options: c.options}, nil |
| 253 | + return wrapRows(rows, ctx, c.options), nil |
253 | 254 | } |
254 | 255 |
|
255 | 256 | return nil, driver.ErrSkip |
@@ -287,7 +288,7 @@ func (c ocConn) QueryContext(ctx context.Context, query string, args []driver.Na |
287 | 288 | return nil, err |
288 | 289 | } |
289 | 290 |
|
290 | | - return ocRows{parent: rows, ctx: ctx, options: c.options}, nil |
| 291 | + return wrapRows(rows, ctx, c.options), nil |
291 | 292 | } |
292 | 293 |
|
293 | 294 | return nil, driver.ErrSkip |
@@ -529,7 +530,7 @@ func (s ocStmt) Query(args []driver.Value) (rows driver.Rows, err error) { |
529 | 530 | if err != nil { |
530 | 531 | return nil, err |
531 | 532 | } |
532 | | - rows, err = ocRows{parent: rows, ctx: ctx, options: s.options}, nil |
| 533 | + rows, err = wrapRows(rows, ctx, s.options), nil |
533 | 534 | return |
534 | 535 | } |
535 | 536 |
|
@@ -603,17 +604,92 @@ func (s ocStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (row |
603 | 604 | if err != nil { |
604 | 605 | return nil, err |
605 | 606 | } |
606 | | - rows, err = ocRows{parent: rows, ctx: ctx, options: s.options}, nil |
| 607 | + rows, err = wrapRows(rows, ctx, s.options), nil |
607 | 608 | return |
608 | 609 | } |
609 | 610 |
|
| 611 | + |
| 612 | +// RowsColumnTypeScanType is a duplicate interface for driver.RowsColumnTypeScanType but |
| 613 | +// with the driver.Rows composition removed. |
| 614 | +// |
| 615 | +// This is used to embed a anonymous struct without running into ambiguous method errors. |
| 616 | +type RowsColumnTypeScanType interface { |
| 617 | + ColumnTypeScanType(index int) reflect.Type |
| 618 | +} |
| 619 | + |
610 | 620 | // ocRows implements driver.Rows. |
611 | 621 | type ocRows struct { |
612 | 622 | parent driver.Rows |
613 | 623 | ctx context.Context |
614 | 624 | options TraceOptions |
615 | 625 | } |
616 | 626 |
|
| 627 | +// HasNextResultSet calls the implements the driver.RowsNextResultSet for ocRows. |
| 628 | +// It returns the the underlying result of HasNextResultSet from the ocRows.parent |
| 629 | +// if the parent implements driver.RowsNextResultSet. |
| 630 | +func (r ocRows) HasNextResultSet() bool { |
| 631 | + if v, ok := r.parent.(driver.RowsNextResultSet); ok { |
| 632 | + return v.HasNextResultSet() |
| 633 | + } |
| 634 | + |
| 635 | + return false |
| 636 | +} |
| 637 | + |
| 638 | +// NextResultsSet calls the implements the driver.RowsNextResultSet for ocRows. |
| 639 | +// It returns the the underlying result of NextResultSet from the ocRows.parent |
| 640 | +// if the parent implements driver.RowsNextResultSet. |
| 641 | +func (r ocRows) NextResultSet() error { |
| 642 | + if v, ok := r.parent.(driver.RowsNextResultSet); ok { |
| 643 | + return v.NextResultSet() |
| 644 | + } |
| 645 | + |
| 646 | + return io.EOF |
| 647 | +} |
| 648 | + |
| 649 | +// ColumnTypeDatabaseTypeName calls the implements the driver.RowsColumnTypeDatabaseTypeName for ocRows. |
| 650 | +// It returns the the underlying result of ColumnTypeDatabaseTypeName from the ocRows.parent |
| 651 | +// if the parent implements driver.RowsColumnTypeDatabaseTypeName. |
| 652 | +func (r ocRows) ColumnTypeDatabaseTypeName(index int) string { |
| 653 | + if v, ok := r.parent.(driver.RowsColumnTypeDatabaseTypeName); ok { |
| 654 | + return v.ColumnTypeDatabaseTypeName(index) |
| 655 | + } |
| 656 | + |
| 657 | + return "" |
| 658 | +} |
| 659 | + |
| 660 | +// ColumnTypeLength calls the implements the driver.RowsColumnTypeLength for ocRows. |
| 661 | +// It returns the the underlying result of ColumnTypeLength from the ocRows.parent |
| 662 | +// if the parent implements driver.RowsColumnTypeLength. |
| 663 | +func (r ocRows) ColumnTypeLength(index int) (length int64, ok bool) { |
| 664 | + if v, ok := r.parent.(driver.RowsColumnTypeLength); ok { |
| 665 | + return v.ColumnTypeLength(index) |
| 666 | + } |
| 667 | + |
| 668 | + return 0, false |
| 669 | +} |
| 670 | + |
| 671 | +// ColumnTypeNullable calls the implements the driver.RowsColumnTypeNullable for ocRows. |
| 672 | +// It returns the the underlying result of ColumnTypeNullable from the ocRows.parent |
| 673 | +// if the parent implements driver.RowsColumnTypeNullable. |
| 674 | +func (r ocRows) ColumnTypeNullable(index int) (nullable, ok bool) { |
| 675 | + if v, ok := r.parent.(driver.RowsColumnTypeNullable); ok { |
| 676 | + return v.ColumnTypeNullable(index) |
| 677 | + } |
| 678 | + |
| 679 | + return false, false |
| 680 | +} |
| 681 | + |
| 682 | +// ColumnTypePrecisionScale calls the implements the driver.RowsColumnTypePrecisionScale for ocRows. |
| 683 | +// It returns the the underlying result of ColumnTypePrecisionScale from the ocRows.parent |
| 684 | +// if the parent implements driver.RowsColumnTypePrecisionScale. |
| 685 | +func (r ocRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { |
| 686 | + if v, ok := r.parent.(driver.RowsColumnTypePrecisionScale); ok { |
| 687 | + return v.ColumnTypePrecisionScale(index) |
| 688 | + } |
| 689 | + |
| 690 | + return 0, 0, false |
| 691 | +} |
| 692 | + |
617 | 693 | func (r ocRows) Columns() []string { |
618 | 694 | return r.parent.Columns() |
619 | 695 | } |
@@ -655,6 +731,30 @@ func (r ocRows) Next(dest []driver.Value) (err error) { |
655 | 731 | return |
656 | 732 | } |
657 | 733 |
|
| 734 | +// wrapRows returns a struct which conforms to the driver.Rows interface. |
| 735 | +// It checks if the parent adheres to any additional driver interfaces and returns a matching |
| 736 | +// implementation accordingly. |
| 737 | +func wrapRows(parent driver.Rows, ctx context.Context, options TraceOptions) driver.Rows { |
| 738 | + var ( |
| 739 | + ts, hasColumnTypeScan = parent.(driver.RowsColumnTypeScanType) |
| 740 | + ) |
| 741 | + |
| 742 | + r := ocRows{ |
| 743 | + parent: parent, |
| 744 | + ctx: ctx, |
| 745 | + options: options, |
| 746 | + } |
| 747 | + |
| 748 | + if hasColumnTypeScan { |
| 749 | + return struct { |
| 750 | + driver.Rows |
| 751 | + RowsColumnTypeScanType |
| 752 | + }{r, ts} |
| 753 | + } |
| 754 | + |
| 755 | + return r |
| 756 | +} |
| 757 | + |
658 | 758 | // ocTx implemens driver.Tx |
659 | 759 | type ocTx struct { |
660 | 760 | parent driver.Tx |
|
0 commit comments