1
1
use crate :: client:: { InnerClient , Responses } ;
2
2
use crate :: codec:: FrontendMessage ;
3
3
use crate :: connection:: RequestMessages ;
4
- use crate :: prepare:: get_type;
5
4
use crate :: types:: { BorrowToSql , IsNull } ;
6
- use crate :: { Column , Error , Portal , Row , Statement } ;
5
+ use crate :: { Error , Portal , Row , Statement } ;
7
6
use bytes:: { BufMut , Bytes , BytesMut } ;
8
- use fallible_iterator:: FallibleIterator ;
9
7
use futures_util:: { ready, Stream } ;
10
8
use log:: { debug, log_enabled, Level } ;
11
9
use pin_project_lite:: pin_project;
12
10
use postgres_protocol:: message:: backend:: { CommandCompleteBody , Message } ;
13
11
use postgres_protocol:: message:: frontend;
14
- use postgres_types:: Type ;
12
+ use postgres_types:: Format ;
15
13
use std:: fmt;
16
14
use std:: marker:: PhantomPinned ;
17
15
use std:: pin:: Pin ;
@@ -58,30 +56,29 @@ where
58
56
responses,
59
57
rows_affected : None ,
60
58
command_tag : None ,
59
+ status : None ,
60
+ output_format : Format :: Binary ,
61
61
_p : PhantomPinned ,
62
62
} )
63
63
}
64
64
65
65
pub async fn query_txt < S , I > (
66
66
client : & Arc < InnerClient > ,
67
- query : S ,
67
+ statement : Statement ,
68
68
params : I ,
69
69
) -> Result < RowStream , Error >
70
70
where
71
- S : AsRef < str > + Sync + Send ,
71
+ S : AsRef < str > ,
72
72
I : IntoIterator < Item = Option < S > > ,
73
73
I :: IntoIter : ExactSizeIterator ,
74
74
{
75
75
let params = params. into_iter ( ) ;
76
- let params_len = params. len ( ) ;
77
76
78
77
let buf = client. with_buf ( |buf| {
79
- // Parse, anonymous portal
80
- frontend:: parse ( "" , query. as_ref ( ) , std:: iter:: empty ( ) , buf) . map_err ( Error :: encode) ?;
81
78
// Bind, pass params as text, retrieve as binary
82
79
match frontend:: bind (
83
80
"" , // empty string selects the unnamed portal
84
- "" , // empty string selects the unnamed prepared statement
81
+ statement . name ( ) , // named prepared statement
85
82
std:: iter:: empty ( ) , // all parameters use the default format (text)
86
83
params,
87
84
|param, buf| match param {
99
96
Err ( frontend:: BindError :: Serialization ( e) ) => Err ( Error :: encode ( e) ) ,
100
97
} ?;
101
98
102
- // Describe portal to typecast results
103
- frontend:: describe ( b'P' , "" , buf) . map_err ( Error :: encode) ?;
104
99
// Execute
105
100
frontend:: execute ( "" , 0 , buf) . map_err ( Error :: encode) ?;
106
101
// Sync
@@ -109,43 +104,16 @@ where
109
104
Ok ( buf. split ( ) . freeze ( ) )
110
105
} ) ?;
111
106
112
- let mut responses = client. send ( RequestMessages :: Single ( FrontendMessage :: Raw ( buf) ) ) ?;
113
-
114
107
// now read the responses
115
-
116
- match responses. next ( ) . await ? {
117
- Message :: ParseComplete => { }
118
- _ => return Err ( Error :: unexpected_message ( ) ) ,
119
- }
120
- match responses. next ( ) . await ? {
121
- Message :: BindComplete => { }
122
- _ => return Err ( Error :: unexpected_message ( ) ) ,
123
- }
124
- let row_description = match responses. next ( ) . await ? {
125
- Message :: RowDescription ( body) => Some ( body) ,
126
- Message :: NoData => None ,
127
- _ => return Err ( Error :: unexpected_message ( ) ) ,
128
- } ;
129
-
130
- // construct statement object
131
-
132
- let parameters = vec ! [ Type :: UNKNOWN ; params_len] ;
133
-
134
- let mut columns = vec ! [ ] ;
135
- if let Some ( row_description) = row_description {
136
- let mut it = row_description. fields ( ) ;
137
- while let Some ( field) = it. next ( ) . map_err ( Error :: parse) ? {
138
- // NB: for some types that function may send a query to the server. At least in
139
- // raw text mode we don't need that info and can skip this.
140
- let type_ = get_type ( client, field. type_oid ( ) ) . await ?;
141
- let column = Column :: new ( field. name ( ) . to_string ( ) , type_, field) ;
142
- columns. push ( column) ;
143
- }
144
- }
145
-
146
- let statement = Statement :: new_text ( client, "" . to_owned ( ) , parameters, columns) ;
147
-
148
- Ok ( RowStream :: new ( statement, responses) )
108
+ let responses = start ( client, buf) . await ?;
109
+ Ok ( RowStream {
110
+ statement,
111
+ responses,
112
+ command_tag : None ,
113
+ status : None ,
114
+ output_format : Format :: Text ,
115
+ _p : PhantomPinned ,
116
+ } )
149
117
}
150
118
151
119
pub async fn query_portal (
@@ -166,6 +134,8 @@ pub async fn query_portal(
166
134
responses,
167
135
rows_affected : None ,
168
136
command_tag : None ,
137
+ status : None ,
138
+ output_format : Format :: Binary ,
169
139
_p : PhantomPinned ,
170
140
} )
171
141
}
@@ -301,23 +271,13 @@ pin_project! {
301
271
responses: Responses ,
302
272
rows_affected: Option <u64 >,
303
273
command_tag: Option <String >,
274
+ output_format: Format ,
275
+ status: Option <u8 >,
304
276
#[ pin]
305
277
_p: PhantomPinned ,
306
278
}
307
279
}
308
280
309
- impl RowStream {
310
- /// Creates a new `RowStream`.
311
- pub fn new ( statement : Statement , responses : Responses ) -> Self {
312
- RowStream {
313
- statement,
314
- responses,
315
- command_tag : None ,
316
- _p : PhantomPinned ,
317
- }
318
- }
319
- }
320
-
321
281
impl Stream for RowStream {
322
282
type Item = Result < Row , Error > ;
323
283
@@ -326,7 +286,11 @@ impl Stream for RowStream {
326
286
loop {
327
287
match ready ! ( this. responses. poll_next( cx) ?) {
328
288
Message :: DataRow ( body) => {
329
- return Poll :: Ready ( Some ( Ok ( Row :: new ( this. statement . clone ( ) , body) ?) ) )
289
+ return Poll :: Ready ( Some ( Ok ( Row :: new (
290
+ this. statement . clone ( ) ,
291
+ body,
292
+ * this. output_format ,
293
+ ) ?) ) )
330
294
}
331
295
Message :: CommandComplete ( body) => {
332
296
* this. rows_affected = Some ( extract_row_affected ( & body) ?) ;
@@ -336,7 +300,10 @@ impl Stream for RowStream {
336
300
}
337
301
}
338
302
Message :: EmptyQueryResponse | Message :: PortalSuspended => { }
339
- Message :: ReadyForQuery ( _) => return Poll :: Ready ( None ) ,
303
+ Message :: ReadyForQuery ( status) => {
304
+ * this. status = Some ( status. status ( ) ) ;
305
+ return Poll :: Ready ( None ) ;
306
+ }
340
307
_ => return Poll :: Ready ( Some ( Err ( Error :: unexpected_message ( ) ) ) ) ,
341
308
}
342
309
}
@@ -357,4 +324,11 @@ impl RowStream {
357
324
pub fn command_tag ( & self ) -> Option < String > {
358
325
self . command_tag . clone ( )
359
326
}
327
+
328
+ /// Returns if the connection is ready for querying, with the status of the connection.
329
+ ///
330
+ /// This might be available only after the stream has been exhausted.
331
+ pub fn ready_status ( & self ) -> Option < u8 > {
332
+ self . status
333
+ }
360
334
}
0 commit comments