|
32 | 32 | ErrSSLNotSupported = errors.New("pq: SSL is not enabled on the server")
|
33 | 33 | ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key file has group or world access. Permissions should be u=rw (0600) or less.")
|
34 | 34 | ErrCouldNotDetectUsername = errors.New("pq: Could not detect default username. Please provide one explicitly.")
|
| 35 | + ErrNoMoreResults = errors.New("pq: no more results") |
35 | 36 | )
|
36 | 37 |
|
| 38 | +const NextResults = "NEXT" |
| 39 | + |
37 | 40 | type drv struct{}
|
38 | 41 |
|
39 | 42 | func (d *drv) Open(name string) (driver.Conn, error) {
|
@@ -619,56 +622,73 @@ func (cn *conn) simpleExec(q string) (res driver.Result, commandTag string, err
|
619 | 622 | func (cn *conn) simpleQuery(q string) (res *rows, err error) {
|
620 | 623 | defer cn.errRecover(&err)
|
621 | 624 |
|
622 |
| - cn.waitReadyForQuery() |
623 |
| - |
624 |
| - // Mark the connection has having sent a query. |
625 |
| - cn.readyForQuery = false |
626 |
| - b := cn.writeBuf('Q') |
627 |
| - b.string(q) |
628 |
| - cn.send(b) |
| 625 | + querySent := false |
| 626 | + nextResult := q == NextResults |
629 | 627 |
|
630 | 628 | for {
|
| 629 | + if cn.readyForQuery && !querySent { |
| 630 | + if nextResult { |
| 631 | + return nil, ErrNoMoreResults |
| 632 | + } |
| 633 | + |
| 634 | + // Mark the connection has having sent a query. |
| 635 | + cn.readyForQuery = false |
| 636 | + b := cn.writeBuf('Q') |
| 637 | + b.string(q) |
| 638 | + cn.send(b) |
| 639 | + querySent = true |
| 640 | + } |
631 | 641 |
|
632 | 642 | t, r := cn.recv1()
|
633 | 643 | switch t {
|
634 | 644 | case 'C', 'I':
|
635 |
| - // We allow queries which don't return any results through Query as |
636 |
| - // well as Exec. We still have to give database/sql a rows object |
637 |
| - // the user can close, though, to avoid connections from being |
638 |
| - // leaked. A "rows" with done=true works fine for that purpose. |
639 |
| - if err != nil { |
640 |
| - cn.bad = true |
641 |
| - errorf("unexpected message %q in simple query execution", t) |
642 |
| - } |
643 |
| - if res == nil { |
644 |
| - res = &rows{ |
645 |
| - cn: cn, |
| 645 | + if nextResult || querySent { |
| 646 | + // We allow queries which don't return any results through Query as |
| 647 | + // well as Exec. We still have to give database/sql a rows object |
| 648 | + // the user can close, though, to avoid connections from being |
| 649 | + // leaked. A "rows" with done=true works fine for that purpose. |
| 650 | + if err != nil { |
| 651 | + cn.bad = true |
| 652 | + errorf("unexpected message %q in simple query execution", t) |
646 | 653 | }
|
| 654 | + if res == nil { |
| 655 | + res = &rows{ |
| 656 | + cn: cn, |
| 657 | + } |
| 658 | + } |
| 659 | + res.done = true |
647 | 660 | }
|
648 |
| - res.done = true |
649 | 661 | case 'Z':
|
650 | 662 | cn.processReadyForQuery(r)
|
651 |
| - // done |
652 |
| - return |
| 663 | + if querySent { |
| 664 | + // done |
| 665 | + return |
| 666 | + } |
653 | 667 | case 'E':
|
654 |
| - res = nil |
655 |
| - err = parseError(r) |
| 668 | + if nextResult || querySent { |
| 669 | + res = nil |
| 670 | + err = parseError(r) |
| 671 | + } |
656 | 672 | case 'D':
|
657 |
| - if res == nil { |
658 |
| - cn.bad = true |
659 |
| - errorf("unexpected DataRow in simple query execution") |
| 673 | + if nextResult || querySent { |
| 674 | + if res == nil { |
| 675 | + cn.bad = true |
| 676 | + errorf("unexpected DataRow in simple query execution") |
| 677 | + } |
| 678 | + // the query didn't fail; kick off to Next |
| 679 | + cn.saveMessage(t, r) |
| 680 | + return |
660 | 681 | }
|
661 |
| - // the query didn't fail; kick off to Next |
662 |
| - cn.saveMessage(t, r) |
663 |
| - return |
664 | 682 | case 'T':
|
665 |
| - // res might be non-nil here if we received a previous |
666 |
| - // CommandComplete, but that's fine; just overwrite it |
667 |
| - res = &rows{cn: cn} |
668 |
| - res.colNames, res.colFmts, res.colTyps = parsePortalRowDescribe(r) |
669 |
| - |
670 |
| - // To work around a bug in QueryRow in Go 1.2 and earlier, wait |
671 |
| - // until the first DataRow has been received. |
| 683 | + if nextResult || querySent { |
| 684 | + // res might be non-nil here if we received a previous |
| 685 | + // CommandComplete, but that's fine; just overwrite it |
| 686 | + res = &rows{cn: cn} |
| 687 | + res.colNames, res.colFmts, res.colTyps = parsePortalRowDescribe(r) |
| 688 | + |
| 689 | + // To work around a bug in QueryRow in Go 1.2 and earlier, wait |
| 690 | + // until the first DataRow has been received. |
| 691 | + } |
672 | 692 | default:
|
673 | 693 | cn.bad = true
|
674 | 694 | errorf("unknown response for simple query: %q", t)
|
|
0 commit comments