@@ -103,6 +103,7 @@ use stmt::{Column, Statement};
103
103
use tls:: TlsHandshake ;
104
104
use transaction:: { IsolationLevel , Transaction } ;
105
105
use types:: { Field , FromSql , IsNull , Kind , Oid , ToSql , Type } ;
106
+ use text_rows:: TextRows ;
106
107
107
108
#[ doc( inline) ]
108
109
pub use error:: Error ;
@@ -118,6 +119,7 @@ pub mod notification;
118
119
pub mod params;
119
120
mod priv_io;
120
121
pub mod rows;
122
+ pub mod text_rows;
121
123
pub mod stmt;
122
124
pub mod tls;
123
125
pub mod transaction;
@@ -534,18 +536,7 @@ impl InnerConnection {
534
536
. and_then ( |oid| self . get_type ( oid) )
535
537
. collect ( ) ?;
536
538
537
- let columns = match raw_columns {
538
- Some ( body) => body. fields ( )
539
- . and_then ( |field| {
540
- Ok ( Column :: new (
541
- field. name ( ) . to_owned ( ) ,
542
- self . get_type ( field. type_oid ( ) ) ?,
543
- ) )
544
- } )
545
- . collect ( ) ?,
546
- None => vec ! [ ] ,
547
- } ;
548
-
539
+ let columns = self . parse_cols ( raw_columns) ?;
549
540
Ok ( ( param_types, columns) )
550
541
}
551
542
@@ -735,6 +726,22 @@ impl InnerConnection {
735
726
Ok ( ty)
736
727
}
737
728
729
+
730
+ fn parse_cols ( & mut self , raw : Option < backend:: RowDescriptionBody > ) -> Result < Vec < Column > > {
731
+ match raw {
732
+ Some ( body) => body. fields ( )
733
+ . and_then ( |field| {
734
+ Ok ( Column :: new (
735
+ field. name ( ) . to_owned ( ) ,
736
+ self . get_type ( field. type_oid ( ) ) ?,
737
+ ) )
738
+ } )
739
+ . collect ( )
740
+ . map_err ( From :: from) ,
741
+ None => Ok ( vec ! [ ] ) ,
742
+ }
743
+ }
744
+
738
745
fn setup_typeinfo_query ( & mut self ) -> Result < ( ) > {
739
746
if self . has_typeinfo_query {
740
747
return Ok ( ( ) ) ;
@@ -919,6 +926,49 @@ impl InnerConnection {
919
926
}
920
927
}
921
928
929
+ fn simple_query_ ( & mut self , query : & str ) -> Result < Vec < TextRows > > {
930
+ check_desync ! ( self ) ;
931
+ debug ! ( "executing query: {}" , query) ;
932
+ self . stream . write_message ( |buf| frontend:: query ( query, buf) ) ?;
933
+ self . stream . flush ( ) ?;
934
+
935
+ let mut result = vec ! [ ] ;
936
+ let mut rows = vec ! [ ] ;
937
+ let mut columns = None ;
938
+
939
+ loop {
940
+ match self . read_message ( ) ? {
941
+ backend:: Message :: ReadyForQuery ( _) => break ,
942
+ backend:: Message :: DataRow ( body) => {
943
+ rows. push ( RowData :: new ( body) ?) ;
944
+ }
945
+ backend:: Message :: CopyInResponse ( _) => {
946
+ self . stream . write_message ( |buf| {
947
+ frontend:: copy_fail ( "COPY queries cannot be directly executed" , buf)
948
+ } ) ?;
949
+ self . stream . write_message (
950
+ |buf| Ok :: < ( ) , io:: Error > ( frontend:: sync ( buf) ) ,
951
+ ) ?;
952
+ self . stream . flush ( ) ?;
953
+ }
954
+ backend:: Message :: ErrorResponse ( body) => {
955
+ self . wait_for_ready ( ) ?;
956
+ return Err ( err ( & mut body. fields ( ) ) ) ;
957
+ }
958
+ backend:: Message :: RowDescription ( body) => {
959
+ columns = Some ( self . parse_cols ( Some ( body) ) ?) ;
960
+ }
961
+ backend:: Message :: CommandComplete ( _) => {
962
+ if let Some ( cols) = columns. take ( ) {
963
+ result. push ( TextRows :: new ( cols, mem:: replace ( & mut rows, Vec :: new ( ) ) ) ) ;
964
+ }
965
+ }
966
+ _ => bad_response ! ( self ) ,
967
+ }
968
+ }
969
+ Ok ( result)
970
+ }
971
+
922
972
fn quick_query ( & mut self , query : & str ) -> Result < Vec < Vec < Option < String > > > > {
923
973
check_desync ! ( self ) ;
924
974
debug ! ( "executing query: {}" , query) ;
@@ -1254,7 +1304,8 @@ impl Connection {
1254
1304
pub fn set_transaction_config ( & self , config : & transaction:: Config ) -> Result < ( ) > {
1255
1305
let mut command = "SET SESSION CHARACTERISTICS AS TRANSACTION" . to_owned ( ) ;
1256
1306
config. build_command ( & mut command) ;
1257
- self . batch_execute ( & command)
1307
+ self . simple_query ( & command)
1308
+ . map ( |_| ( ) )
1258
1309
}
1259
1310
1260
1311
/// Execute a sequence of SQL statements.
@@ -1291,10 +1342,42 @@ impl Connection {
1291
1342
/// CREATE INDEX ON purchase (time);
1292
1343
/// ").unwrap();
1293
1344
/// ```
1345
+ #[ deprecated( since="0.15.3" , note="please use `simple_query` instead" ) ]
1294
1346
pub fn batch_execute ( & self , query : & str ) -> Result < ( ) > {
1295
1347
self . 0 . borrow_mut ( ) . quick_query ( query) . map ( |_| ( ) )
1296
1348
}
1297
1349
1350
+
1351
+ /// Send a simple, non-prepared query
1352
+ ///
1353
+ /// Executes a query without making a prepared statement. All result columns
1354
+ /// are returned in a UTF-8 text format rather than compact binary
1355
+ /// representations. This can be useful when communicating with services
1356
+ /// like _pgbouncer_ which speak "basic" postgres but don't support prepared
1357
+ /// statements.
1358
+ ///
1359
+ /// Because rust-postgres' query parameter substitution relies on prepared
1360
+ /// statements, it's not possible to pass a separate parameters list with
1361
+ /// this API.
1362
+ ///
1363
+ /// In general, the `query` API should be prefered whenever possible.
1364
+ ///
1365
+ /// # Example
1366
+ ///
1367
+ /// ```rust,no_run
1368
+ /// # use postgres::{Connection, TlsMode};
1369
+ /// # let conn = Connection::connect("", TlsMode::None).unwrap();
1370
+ /// for response in &conn.simple_query("SELECT foo FROM bar WHERE baz = 'quux'").unwrap() {
1371
+ /// for row in response {
1372
+ /// let foo: &str = row.get("foo");
1373
+ /// println!("foo: {}", foo);
1374
+ /// }
1375
+ /// }
1376
+ /// ```
1377
+ pub fn simple_query ( & self , query : & str ) -> Result < Vec < TextRows > > {
1378
+ self . 0 . borrow_mut ( ) . simple_query_ ( query)
1379
+ }
1380
+
1298
1381
/// Returns a structure providing access to asynchronous notifications.
1299
1382
///
1300
1383
/// Use the `LISTEN` command to register this connection for notifications.
@@ -1368,10 +1451,14 @@ pub trait GenericConnection {
1368
1451
fn transaction < ' a > ( & ' a self ) -> Result < Transaction < ' a > > ;
1369
1452
1370
1453
/// Like `Connection::batch_execute`.
1454
+ #[ deprecated( since="0.15.3" , note="please use `simple_query` instead" ) ]
1371
1455
fn batch_execute ( & self , query : & str ) -> Result < ( ) > ;
1372
1456
1373
1457
/// Like `Connection::is_active`.
1374
1458
fn is_active ( & self ) -> bool ;
1459
+
1460
+ /// Like `Connection::simple_query`.
1461
+ fn simple_query ( & self , query : & str ) -> Result < Vec < TextRows > > ;
1375
1462
}
1376
1463
1377
1464
impl GenericConnection for Connection {
@@ -1396,12 +1483,17 @@ impl GenericConnection for Connection {
1396
1483
}
1397
1484
1398
1485
fn batch_execute ( & self , query : & str ) -> Result < ( ) > {
1399
- self . batch_execute ( query)
1486
+ self . simple_query ( query)
1487
+ . map ( |_| ( ) )
1400
1488
}
1401
1489
1402
1490
fn is_active ( & self ) -> bool {
1403
1491
self . is_active ( )
1404
1492
}
1493
+
1494
+ fn simple_query ( & self , query : & str ) -> Result < Vec < TextRows > > {
1495
+ self . simple_query ( query)
1496
+ }
1405
1497
}
1406
1498
1407
1499
impl < ' a > GenericConnection for Transaction < ' a > {
@@ -1426,7 +1518,12 @@ impl<'a> GenericConnection for Transaction<'a> {
1426
1518
}
1427
1519
1428
1520
fn batch_execute ( & self , query : & str ) -> Result < ( ) > {
1429
- self . batch_execute ( query)
1521
+ self . simple_query ( query)
1522
+ . map ( |_| ( ) )
1523
+ }
1524
+
1525
+ fn simple_query ( & self , query : & str ) -> Result < Vec < TextRows > > {
1526
+ self . simple_query ( query)
1430
1527
}
1431
1528
1432
1529
fn is_active ( & self ) -> bool {
0 commit comments