@@ -633,7 +633,7 @@ func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, c
633
633
}
634
634
}
635
635
636
- func (cn * conn ) prepareTo (q , stmtName string ) ( _ * stmt , err error ) {
636
+ func (cn * conn ) prepareTo (q , stmtName string ) * stmt {
637
637
st := & stmt {cn : cn , name : stmtName }
638
638
639
639
b := cn .writeBuf ('P' )
@@ -648,33 +648,11 @@ func (cn *conn) prepareTo(q, stmtName string) (_ *stmt, err error) {
648
648
b .next ('S' )
649
649
cn .send (b )
650
650
651
- for {
652
- t , r := cn .recv1 ()
653
- switch t {
654
- case '1' :
655
- case 't' :
656
- nparams := r .int16 ()
657
- st .paramTyps = make ([]oid.Oid , nparams )
658
-
659
- for i := range st .paramTyps {
660
- st .paramTyps [i ] = r .oid ()
661
- }
662
- case 'T' :
663
- st .colNames , st .colTyps = parseStatementRowDescribe (r )
664
- st .colFmts , st .colFmtData = decideColumnFormats (st .colTyps , cn .disablePreparedBinaryResult )
665
- case 'n' :
666
- // no data
667
- st .colFmtData = colFmtDataAllText
668
- case 'Z' :
669
- cn .processReadyForQuery (r )
670
- return st , err
671
- case 'E' :
672
- err = parseError (r )
673
- default :
674
- cn .bad = true
675
- errorf ("unexpected describe rows response: %q" , t )
676
- }
677
- }
651
+ cn .readParseResponse ()
652
+ st .paramTyps , st .colNames , st .colTyps = cn .readStatementDescribeResponse ()
653
+ st .colFmts , st .colFmtData = decideColumnFormats (st .colTyps , cn .disablePreparedBinaryResult )
654
+ cn .readReadyForQuery ()
655
+ return st
678
656
}
679
657
680
658
func (cn * conn ) Prepare (q string ) (_ driver.Stmt , err error ) {
@@ -686,7 +664,7 @@ func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) {
686
664
if len (q ) >= 4 && strings .EqualFold (q [:4 ], "COPY" ) {
687
665
return cn .prepareCopyIn (q )
688
666
}
689
- return cn .prepareTo (q , cn .gname ())
667
+ return cn .prepareTo (q , cn .gname ()), nil
690
668
}
691
669
692
670
func (cn * conn ) Close () (err error ) {
@@ -718,11 +696,7 @@ func (cn *conn) Query(query string, args []driver.Value) (_ driver.Rows, err err
718
696
return cn .simpleQuery (query )
719
697
}
720
698
721
- st , err := cn .prepareTo (query , "" )
722
- if err != nil {
723
- panic (err )
724
- }
725
-
699
+ st := cn .prepareTo (query , "" )
726
700
st .exec (args )
727
701
return & rows {
728
702
cn : cn ,
@@ -750,10 +724,7 @@ func (cn *conn) Exec(query string, args []driver.Value) (_ driver.Result, err er
750
724
// Use the unnamed statement to defer planning until bind
751
725
// time, or else value-based selectivity estimates cannot be
752
726
// used.
753
- st , err := cn .prepareTo (query , "" )
754
- if err != nil {
755
- panic (err )
756
- }
727
+ st := cn .prepareTo (query , "" )
757
728
758
729
r , err := st .Exec (args )
759
730
if err != nil {
@@ -1214,25 +1185,8 @@ func (st *stmt) Exec(v []driver.Value) (res driver.Result, err error) {
1214
1185
defer st .cn .errRecover (& err )
1215
1186
1216
1187
st .exec (v )
1217
-
1218
- for {
1219
- t , r := st .cn .recv1 ()
1220
- switch t {
1221
- case 'E' :
1222
- err = parseError (r )
1223
- case 'C' :
1224
- res , _ = st .cn .parseComplete (r .string ())
1225
- case 'Z' :
1226
- st .cn .processReadyForQuery (r )
1227
- // done
1228
- return
1229
- case 'T' , 'D' , 'I' :
1230
- // ignore any results
1231
- default :
1232
- st .cn .bad = true
1233
- errorf ("unknown exec response: %q" , t )
1234
- }
1235
- }
1188
+ res , _ , err = st .cn .readExecuteResponse ("simple query" )
1189
+ return res , err
1236
1190
}
1237
1191
1238
1192
func (st * stmt ) exec (v []driver.Value ) {
@@ -1243,16 +1197,17 @@ func (st *stmt) exec(v []driver.Value) {
1243
1197
errorf ("got %d parameters but the statement requires %d" , len (v ), len (st .paramTyps ))
1244
1198
}
1245
1199
1246
- w := st .cn .writeBuf ('B' )
1247
- w .byte (0 )
1200
+ cn := st .cn
1201
+ w := cn .writeBuf ('B' )
1202
+ w .byte (0 ) // unnamed portal
1248
1203
w .string (st .name )
1249
1204
w .int16 (0 )
1250
1205
w .int16 (len (v ))
1251
1206
for i , x := range v {
1252
1207
if x == nil {
1253
1208
w .int32 (- 1 )
1254
1209
} else {
1255
- b := encode (& st . cn .parameterStatus , x , st .paramTyps [i ])
1210
+ b := encode (& cn .parameterStatus , x , st .paramTyps [i ])
1256
1211
w .int32 (len (b ))
1257
1212
w .bytes (b )
1258
1213
}
@@ -1264,62 +1219,11 @@ func (st *stmt) exec(v []driver.Value) {
1264
1219
w .int32 (0 )
1265
1220
1266
1221
w .next ('S' )
1267
- st . cn .send (w )
1222
+ cn .send (w )
1268
1223
1269
- var err error
1270
- for {
1271
- t , r := st .cn .recv1 ()
1272
- switch t {
1273
- case 'E' :
1274
- err = parseError (r )
1275
- case '2' :
1276
- if err != nil {
1277
- panic (err )
1278
- }
1279
- goto workaround
1280
- case 'Z' :
1281
- st .cn .processReadyForQuery (r )
1282
- if err != nil {
1283
- panic (err )
1284
- }
1285
- return
1286
- default :
1287
- st .cn .bad = true
1288
- errorf ("unexpected bind response: %q" , t )
1289
- }
1290
- }
1224
+ cn .readBindResponse ()
1225
+ cn .postExecuteWorkaround ()
1291
1226
1292
- // Work around a bug in sql.DB.QueryRow: in Go 1.2 and earlier it ignores
1293
- // any errors from rows.Next, which masks errors that happened during the
1294
- // execution of the query. To avoid the problem in common cases, we wait
1295
- // here for one more message from the database. If it's not an error the
1296
- // query will likely succeed (or perhaps has already, if it's a
1297
- // CommandComplete), so we push the message into the conn struct; recv1
1298
- // will return it as the next message for rows.Next or rows.Close.
1299
- // However, if it's an error, we wait until ReadyForQuery and then return
1300
- // the error to our caller.
1301
- workaround:
1302
- for {
1303
- t , r := st .cn .recv1 ()
1304
- switch t {
1305
- case 'E' :
1306
- err = parseError (r )
1307
- case 'C' , 'D' , 'I' :
1308
- // the query didn't fail, but we can't process this message
1309
- st .cn .saveMessage (t , r )
1310
- return
1311
- case 'Z' :
1312
- if err == nil {
1313
- st .cn .bad = true
1314
- errorf ("unexpected ReadyForQuery during extended query execution" )
1315
- }
1316
- st .cn .processReadyForQuery (r )
1317
- panic (err )
1318
- default :
1319
- st .cn .bad = true
1320
- errorf ("unexpected message during query execution: %q" , t )
1321
- }
1322
- }
1323
1227
}
1324
1228
1325
1229
func (st * stmt ) NumInput () int {
@@ -1500,6 +1404,123 @@ func (c *conn) processReadyForQuery(r *readBuf) {
1500
1404
c .txnStatus = transactionStatus (r .byte ())
1501
1405
}
1502
1406
1407
+ func (cn * conn ) readReadyForQuery () {
1408
+ t , r := cn .recv1 ()
1409
+ switch t {
1410
+ case 'Z' :
1411
+ cn .processReadyForQuery (r )
1412
+ return
1413
+ default :
1414
+ cn .bad = true
1415
+ errorf ("unexpected message %q; expected ReadyForQuery" , t )
1416
+ }
1417
+ }
1418
+
1419
+ func (cn * conn ) readParseResponse () {
1420
+ t , r := cn .recv1 ()
1421
+ switch t {
1422
+ case '1' :
1423
+ return
1424
+ case 'E' :
1425
+ err := parseError (r )
1426
+ cn .readReadyForQuery ()
1427
+ panic (err )
1428
+ default :
1429
+ cn .bad = true
1430
+ errorf ("unexpected Parse response %q" , t )
1431
+ }
1432
+ }
1433
+
1434
+ func (cn * conn ) readStatementDescribeResponse () (paramTyps []oid.Oid , colNames []string , colTyps []oid.Oid ) {
1435
+ for {
1436
+ t , r := cn .recv1 ()
1437
+ switch t {
1438
+ case 't' :
1439
+ nparams := r .int16 ()
1440
+ paramTyps = make ([]oid.Oid , nparams )
1441
+ for i := range paramTyps {
1442
+ paramTyps [i ] = r .oid ()
1443
+ }
1444
+ case 'n' :
1445
+ return paramTyps , nil , nil
1446
+ case 'T' :
1447
+ colNames , colTyps = parseStatementRowDescribe (r )
1448
+ return paramTyps , colNames , colTyps
1449
+ case 'E' :
1450
+ err := parseError (r )
1451
+ cn .readReadyForQuery ()
1452
+ panic (err )
1453
+ default :
1454
+ cn .bad = true
1455
+ errorf ("unexpected Describe statement response %q" , t )
1456
+ }
1457
+ }
1458
+ }
1459
+
1460
+ func (cn * conn ) readBindResponse () {
1461
+ t , r := cn .recv1 ()
1462
+ switch t {
1463
+ case '2' :
1464
+ return
1465
+ case 'E' :
1466
+ err := parseError (r )
1467
+ cn .readReadyForQuery ()
1468
+ panic (err )
1469
+ default :
1470
+ cn .bad = true
1471
+ errorf ("unexpected Bind response %q" , t )
1472
+ }
1473
+ }
1474
+
1475
+ func (cn * conn ) postExecuteWorkaround () {
1476
+ // Work around a bug in sql.DB.QueryRow: in Go 1.2 and earlier it ignores
1477
+ // any errors from rows.Next, which masks errors that happened during the
1478
+ // execution of the query. To avoid the problem in common cases, we wait
1479
+ // here for one more message from the database. If it's not an error the
1480
+ // query will likely succeed (or perhaps has already, if it's a
1481
+ // CommandComplete), so we push the message into the conn struct; recv1
1482
+ // will return it as the next message for rows.Next or rows.Close.
1483
+ // However, if it's an error, we wait until ReadyForQuery and then return
1484
+ // the error to our caller.
1485
+ for {
1486
+ t , r := cn .recv1 ()
1487
+ switch t {
1488
+ case 'E' :
1489
+ err := parseError (r )
1490
+ cn .readReadyForQuery ()
1491
+ panic (err )
1492
+ case 'C' , 'D' , 'I' :
1493
+ // the query didn't fail, but we can't process this message
1494
+ cn .saveMessage (t , r )
1495
+ return
1496
+ default :
1497
+ cn .bad = true
1498
+ errorf ("unexpected message during extended query execution: %q" , t )
1499
+ }
1500
+ }
1501
+ }
1502
+
1503
+ // Only for Exec(), since we ignore the returned data
1504
+ func (cn * conn ) readExecuteResponse (protocolState string ) (res driver.Result , commandTag string , err error ) {
1505
+ for {
1506
+ t , r := cn .recv1 ()
1507
+ switch t {
1508
+ case 'C' :
1509
+ res , commandTag = cn .parseComplete (r .string ())
1510
+ case 'Z' :
1511
+ cn .processReadyForQuery (r )
1512
+ return res , commandTag , err
1513
+ case 'E' :
1514
+ err = parseError (r )
1515
+ case 'T' , 'D' , 'I' :
1516
+ // ignore any results
1517
+ default :
1518
+ cn .bad = true
1519
+ errorf ("unknown %s response: %q" , protocolState , t )
1520
+ }
1521
+ }
1522
+ }
1523
+
1503
1524
func parseStatementRowDescribe (r * readBuf ) (colNames []string , colTyps []oid.Oid ) {
1504
1525
n := r .int16 ()
1505
1526
colNames = make ([]string , n )
0 commit comments