@@ -2,12 +2,15 @@ use crate::client::{InnerClient, Responses};
2
2
use crate :: codec:: FrontendMessage ;
3
3
use crate :: connection:: RequestMessages ;
4
4
use crate :: types:: { BorrowToSql , IsNull } ;
5
- use crate :: { Error , Portal , Row , Statement } ;
5
+ use crate :: { Column , Error , Portal , Row , Statement } ;
6
6
use bytes:: { BufMut , Bytes , BytesMut } ;
7
+ use fallible_iterator:: FallibleIterator ;
7
8
use futures_util:: { ready, Stream } ;
8
9
use log:: { debug, log_enabled, Level } ;
9
10
use pin_project_lite:: pin_project;
10
- use postgres_protocol:: message:: backend:: { CommandCompleteBody , Message } ;
11
+ use postgres_protocol:: message:: backend:: {
12
+ CommandCompleteBody , Message , ParameterDescriptionBody , RowDescriptionBody ,
13
+ } ;
11
14
use postgres_protocol:: message:: frontend;
12
15
use postgres_types:: Format ;
13
16
use std:: fmt;
@@ -50,21 +53,22 @@ where
50
53
} else {
51
54
encode ( client, & statement, params) ?
52
55
} ;
53
- let responses = start ( client, buf) . await ?;
56
+ let ( statement , responses) = start ( client, buf) . await ?;
54
57
Ok ( RowStream {
55
58
statement,
56
59
responses,
57
60
rows_affected : None ,
58
61
command_tag : None ,
59
62
status : None ,
60
63
output_format : Format :: Binary ,
64
+ parameter_description : None ,
61
65
_p : PhantomPinned ,
62
66
} )
63
67
}
64
68
65
69
pub async fn query_txt < S , I > (
66
70
client : & Arc < InnerClient > ,
67
- statement : Statement ,
71
+ query : & str ,
68
72
params : I ,
69
73
) -> Result < RowStream , Error >
70
74
where
@@ -75,10 +79,15 @@ where
75
79
let params = params. into_iter ( ) ;
76
80
77
81
let buf = client. with_buf ( |buf| {
82
+ // prepare
83
+ frontend:: parse ( "" , query, std:: iter:: empty ( ) , buf) . map_err ( Error :: encode) ?;
84
+ frontend:: describe ( b'S' , "" , buf) . map_err ( Error :: encode) ?;
85
+ frontend:: flush ( buf) ;
86
+
78
87
// Bind, pass params as text, retrieve as binary
79
88
match frontend:: bind (
80
89
"" , // empty string selects the unnamed portal
81
- statement . name ( ) , // named prepared statement
90
+ "" , // unnamed prepared statement
82
91
std:: iter:: empty ( ) , // all parameters use the default format (text)
83
92
params,
84
93
|param, buf| match param {
@@ -105,9 +114,10 @@ where
105
114
} ) ?;
106
115
107
116
// now read the responses
108
- let responses = start ( client, buf) . await ?;
117
+ let ( statement , responses) = start ( client, buf) . await ?;
109
118
110
119
Ok ( RowStream {
120
+ parameter_description : None ,
111
121
statement,
112
122
responses,
113
123
command_tag : None ,
@@ -132,7 +142,8 @@ pub async fn query_portal(
132
142
let responses = client. send ( RequestMessages :: Single ( FrontendMessage :: Raw ( buf) ) ) ?;
133
143
134
144
Ok ( RowStream {
135
- statement : portal. statement ( ) . clone ( ) ,
145
+ parameter_description : None ,
146
+ statement : Some ( portal. statement ( ) . clone ( ) ) ,
136
147
responses,
137
148
rows_affected : None ,
138
149
command_tag : None ,
@@ -176,7 +187,7 @@ where
176
187
} else {
177
188
encode ( client, & statement, params) ?
178
189
} ;
179
- let mut responses = start ( client, buf) . await ?;
190
+ let ( _statement , mut responses) = start ( client, buf) . await ?;
180
191
181
192
let mut rows = 0 ;
182
193
loop {
@@ -192,19 +203,57 @@ where
192
203
}
193
204
}
194
205
195
- async fn start ( client : & InnerClient , buf : Bytes ) -> Result < Responses , Error > {
206
+ async fn start ( client : & InnerClient , buf : Bytes ) -> Result < ( Option < Statement > , Responses ) , Error > {
207
+ let mut parameter_description: Option < ParameterDescriptionBody > = None ;
208
+ let mut statement = None ;
196
209
let mut responses = client. send ( RequestMessages :: Single ( FrontendMessage :: Raw ( buf) ) ) ?;
197
210
198
- match responses. next ( ) . await ? {
199
- Message :: ParseComplete => match responses. next ( ) . await ? {
200
- Message :: BindComplete => { }
211
+ loop {
212
+ match responses. next ( ) . await ? {
213
+ Message :: ParseComplete => { }
214
+ Message :: BindComplete => return Ok ( ( statement, responses) ) ,
215
+ Message :: ParameterDescription ( body) => {
216
+ parameter_description = Some ( body) ; // tooo-o-ooo-o loooove
217
+ }
218
+ Message :: NoData => {
219
+ statement = Some ( make_statement ( parameter_description. take ( ) . unwrap ( ) , None ) ?) ;
220
+ }
221
+ Message :: RowDescription ( body) => {
222
+ statement = Some ( make_statement (
223
+ parameter_description. take ( ) . unwrap ( ) ,
224
+ Some ( body) ,
225
+ ) ?) ;
226
+ }
201
227
m => return Err ( Error :: unexpected_message ( m) ) ,
202
- } ,
203
- Message :: BindComplete => { }
204
- m => return Err ( Error :: unexpected_message ( m) ) ,
228
+ }
229
+ }
230
+ }
231
+
232
+ fn make_statement (
233
+ parameter_description : ParameterDescriptionBody ,
234
+ row_description : Option < RowDescriptionBody > ,
235
+ ) -> Result < Statement , Error > {
236
+ let mut parameters = vec ! [ ] ;
237
+ let mut it = parameter_description. parameters ( ) ;
238
+
239
+ while let Some ( oid) = it. next ( ) . map_err ( Error :: parse) . unwrap ( ) {
240
+ let type_ = crate :: prepare:: get_type ( oid) ;
241
+ parameters. push ( type_) ;
205
242
}
206
243
207
- Ok ( responses)
244
+ let mut columns = Vec :: new ( ) ;
245
+
246
+ if let Some ( row_description) = row_description {
247
+ let mut it = row_description. fields ( ) ;
248
+
249
+ while let Some ( field) = it. next ( ) . map_err ( Error :: parse) ? {
250
+ let type_ = crate :: prepare:: get_type ( field. type_oid ( ) ) ;
251
+ let column = Column :: new ( field. name ( ) . to_string ( ) , type_, field) ;
252
+ columns. push ( column) ;
253
+ }
254
+ }
255
+
256
+ Ok ( Statement :: unnamed ( parameters, columns) )
208
257
}
209
258
210
259
pub fn encode < P , I > ( client : & InnerClient , statement : & Statement , params : I ) -> Result < Bytes , Error >
@@ -214,12 +263,10 @@ where
214
263
I :: IntoIter : ExactSizeIterator ,
215
264
{
216
265
client. with_buf ( |buf| {
217
- if let Some ( query) = statement. query ( ) {
218
- frontend:: parse ( "" , query, [ ] , buf) . unwrap ( ) ;
219
- }
220
266
encode_bind ( statement, params, "" , buf) ?;
221
267
frontend:: execute ( "" , 0 , buf) . map_err ( Error :: encode) ?;
222
268
frontend:: sync ( buf) ;
269
+
223
270
Ok ( buf. split ( ) . freeze ( ) )
224
271
} )
225
272
}
@@ -276,12 +323,14 @@ where
276
323
pin_project ! {
277
324
/// A stream of table rows.
278
325
pub struct RowStream {
279
- statement: Statement ,
326
+ statement: Option < Statement > ,
280
327
responses: Responses ,
281
328
rows_affected: Option <u64 >,
282
329
command_tag: Option <String >,
283
330
output_format: Format ,
284
331
status: Option <u8 >,
332
+ parameter_description: Option <ParameterDescriptionBody >,
333
+
285
334
#[ pin]
286
335
_p: PhantomPinned ,
287
336
}
@@ -292,11 +341,12 @@ impl Stream for RowStream {
292
341
293
342
fn poll_next ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
294
343
let this = self . project ( ) ;
344
+
295
345
loop {
296
346
match ready ! ( this. responses. poll_next( cx) ?) {
297
347
Message :: DataRow ( body) => {
298
348
return Poll :: Ready ( Some ( Ok ( Row :: new (
299
- this. statement . clone ( ) ,
349
+ this. statement . as_ref ( ) . unwrap ( ) . clone ( ) ,
300
350
body,
301
351
* this. output_format ,
302
352
) ?) ) )
0 commit comments