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 ) {
@@ -115,6 +118,9 @@ type conn struct {
115
118
// Whether to always send []byte parameters over as binary. Enables single
116
119
// round-trip mode for non-prepared Query calls.
117
120
binaryParameters bool
121
+
122
+ // Whether the connection is ready to execute a query.
123
+ readyForQuery bool
118
124
}
119
125
120
126
// Handle driver-side settings in parsed connection string.
@@ -587,6 +593,8 @@ func (cn *conn) gname() string {
587
593
}
588
594
589
595
func (cn * conn ) simpleExec (q string ) (res driver.Result , commandTag string , err error ) {
596
+ cn .waitReadyForQuery ()
597
+
590
598
b := cn .writeBuf ('Q' )
591
599
b .string (q )
592
600
cn .send (b )
@@ -614,51 +622,73 @@ func (cn *conn) simpleExec(q string) (res driver.Result, commandTag string, err
614
622
func (cn * conn ) simpleQuery (q string ) (res * rows , err error ) {
615
623
defer cn .errRecover (& err )
616
624
617
- b := cn .writeBuf ('Q' )
618
- b .string (q )
619
- cn .send (b )
625
+ querySent := false
626
+ nextResult := q == NextResults
620
627
621
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
+ }
641
+
622
642
t , r := cn .recv1 ()
623
643
switch t {
624
644
case 'C' , 'I' :
625
- // We allow queries which don't return any results through Query as
626
- // well as Exec. We still have to give database/sql a rows object
627
- // the user can close, though, to avoid connections from being
628
- // leaked. A "rows" with done=true works fine for that purpose.
629
- if err != nil {
630
- cn .bad = true
631
- errorf ("unexpected message %q in simple query execution" , t )
632
- }
633
- if res == nil {
634
- res = & rows {
635
- 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 )
653
+ }
654
+ if res == nil {
655
+ res = & rows {
656
+ cn : cn ,
657
+ }
636
658
}
659
+ res .done = true
637
660
}
638
- res .done = true
639
661
case 'Z' :
640
662
cn .processReadyForQuery (r )
641
- // done
642
- return
663
+ if querySent {
664
+ // done
665
+ return
666
+ }
643
667
case 'E' :
644
- res = nil
645
- err = parseError (r )
668
+ if nextResult || querySent {
669
+ res = nil
670
+ err = parseError (r )
671
+ }
646
672
case 'D' :
647
- if res == nil {
648
- cn .bad = true
649
- 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
650
681
}
651
- // the query didn't fail; kick off to Next
652
- cn .saveMessage (t , r )
653
- return
654
682
case 'T' :
655
- // res might be non-nil here if we received a previous
656
- // CommandComplete, but that's fine; just overwrite it
657
- res = & rows {cn : cn }
658
- res .colNames , res .colFmts , res .colTyps = parsePortalRowDescribe (r )
659
-
660
- // To work around a bug in QueryRow in Go 1.2 and earlier, wait
661
- // 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
+ }
662
692
default :
663
693
cn .bad = true
664
694
errorf ("unknown response for simple query: %q" , t )
@@ -742,6 +772,8 @@ func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) {
742
772
}
743
773
defer cn .errRecover (& err )
744
774
775
+ cn .waitReadyForQuery ()
776
+
745
777
if len (q ) >= 4 && strings .EqualFold (q [:4 ], "COPY" ) {
746
778
return cn .prepareCopyIn (q )
747
779
}
@@ -777,6 +809,8 @@ func (cn *conn) Query(query string, args []driver.Value) (_ driver.Rows, err err
777
809
return cn .simpleQuery (query )
778
810
}
779
811
812
+ cn .waitReadyForQuery ()
813
+
780
814
if cn .binaryParameters {
781
815
cn .sendBinaryModeQuery (query , args )
782
816
@@ -813,6 +847,8 @@ func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err
813
847
return r , err
814
848
}
815
849
850
+ cn .waitReadyForQuery ()
851
+
816
852
if cn .binaryParameters {
817
853
cn .sendBinaryModeQuery (query , args )
818
854
@@ -1301,6 +1337,10 @@ func (st *stmt) exec(v []driver.Value) {
1301
1337
}
1302
1338
1303
1339
cn := st .cn
1340
+ cn .waitReadyForQuery ()
1341
+ // Mark the connection has having sent a query.
1342
+ cn .readyForQuery = false
1343
+
1304
1344
w := cn .writeBuf ('B' )
1305
1345
w .byte (0 ) // unnamed portal
1306
1346
w .string (st .name )
@@ -1431,7 +1471,11 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
1431
1471
case 'E' :
1432
1472
err = parseError (& rs .rb )
1433
1473
case 'C' , 'I' :
1434
- continue
1474
+ rs .done = true
1475
+ if err != nil {
1476
+ return err
1477
+ }
1478
+ return io .EOF
1435
1479
case 'Z' :
1436
1480
conn .processReadyForQuery (& rs .rb )
1437
1481
rs .done = true
@@ -1527,6 +1571,9 @@ func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) {
1527
1571
errorf ("got %d parameters but PostgreSQL only supports 65535 parameters" , len (args ))
1528
1572
}
1529
1573
1574
+ // Mark the connection has having sent a query.
1575
+ cn .readyForQuery = false
1576
+
1530
1577
b := cn .writeBuf ('P' )
1531
1578
b .byte (0 ) // unnamed statement
1532
1579
b .string (query )
@@ -1576,6 +1623,7 @@ func (c *conn) processParameterStatus(r *readBuf) {
1576
1623
1577
1624
func (c * conn ) processReadyForQuery (r * readBuf ) {
1578
1625
c .txnStatus = transactionStatus (r .byte ())
1626
+ c .readyForQuery = true
1579
1627
}
1580
1628
1581
1629
func (cn * conn ) readReadyForQuery () {
@@ -1590,6 +1638,21 @@ func (cn *conn) readReadyForQuery() {
1590
1638
}
1591
1639
}
1592
1640
1641
+ func (cn * conn ) waitReadyForQuery () {
1642
+ // The postgres server sends a 'Z' command when it is ready to receive a
1643
+ // query. We use this as a sync marker to skip over commands we're not
1644
+ // handling in our current state. For example, we might be skipping over
1645
+ // subsequent results when a query contained multiple statements and only the
1646
+ // first result was retrieved.
1647
+ for ! cn .readyForQuery {
1648
+ t , r := cn .recv1 ()
1649
+ switch t {
1650
+ case 'Z' :
1651
+ cn .processReadyForQuery (r )
1652
+ }
1653
+ }
1654
+ }
1655
+
1593
1656
func (cn * conn ) readParseResponse () {
1594
1657
t , r := cn .recv1 ()
1595
1658
switch t {
0 commit comments