1use std::sync::Arc;
17
18use crate::protocol::{BackendMessage, FrontendMessage, TransactionStatus};
19use crate::types::{Format, ToSql};
20
21use crate::connection::{Connection, ConnectionState};
22use crate::error::{PgError, PgServerError, Result};
23use crate::query::prepared::PreparedStatement;
24use crate::query::result::{CommandTag, ExecuteResult, QueryResult};
25use crate::query::row::{FieldDescription, Row};
26use crate::query::{read_data_row, read_row_description};
27use crate::transport::AsyncTransport;
28
29pub(crate) fn encode_params_text(params: &[&dyn ToSql]) -> Result<Vec<Option<Vec<u8>>>> {
40 let mut values = Vec::with_capacity(params.len());
41 for p in params {
42 let mut buf = Vec::new();
43 let is_null = p.to_sql(&crate::types::Type::UNKNOWN, &mut buf, Format::Text)?;
45 match is_null {
46 crate::types::IsNull::Yes => values.push(None),
47 crate::types::IsNull::No => values.push(Some(buf)),
48 }
49 }
50 Ok(values)
51}
52
53pub(crate) fn encode_params_binary(
59 params: &[&dyn ToSql],
60 param_types: &[crate::types::Type],
61) -> Result<Vec<Option<Vec<u8>>>> {
62 if params.len() != param_types.len() {
63 return Err(PgError::Config(format!(
64 "parameter count mismatch: expected {}, got {}",
65 param_types.len(),
66 params.len()
67 )));
68 }
69
70 let mut values = Vec::with_capacity(params.len());
71 for (p, ty) in params.iter().zip(param_types.iter()) {
72 let mut buf = Vec::new();
73 let is_null = p.to_sql(ty, &mut buf, Format::Binary)?;
74 match is_null {
75 crate::types::IsNull::Yes => values.push(None),
76 crate::types::IsNull::No => values.push(Some(buf)),
77 }
78 }
79 Ok(values)
80}
81
82impl Connection {
87 #[must_use = "query results should be checked for errors"]
108 pub async fn query_params(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<QueryResult> {
109 self.transition(ConnectionState::ActiveExtendedQuery)?;
110
111 let param_values = encode_params_text(params)?;
112
113 self.codec
117 .encode_and_write(
118 &mut self.transport,
119 &FrontendMessage::Parse {
120 name: String::new(),
121 sql: sql.to_string(),
122 param_types: vec![],
123 },
124 )
125 .await?;
126
127 self.codec
129 .encode_and_write(
130 &mut self.transport,
131 &FrontendMessage::Bind {
132 portal: String::new(),
133 statement: String::new(),
134 param_formats: vec![crate::protocol::FormatCode::Text],
135 params: param_values,
136 result_formats: vec![crate::protocol::FormatCode::Binary],
137 },
138 )
139 .await?;
140
141 self.codec
144 .encode_and_write(
145 &mut self.transport,
146 &FrontendMessage::Describe {
147 variant: b'P',
148 name: String::new(),
149 },
150 )
151 .await?;
152
153 self.codec
155 .encode_and_write(
156 &mut self.transport,
157 &FrontendMessage::Execute {
158 portal: String::new(),
159 max_rows: 0,
160 },
161 )
162 .await?;
163
164 self.codec
166 .encode_and_write(&mut self.transport, &FrontendMessage::Sync)
167 .await?;
168
169 self.transport.flush().await.map_err(PgError::Transport)?;
171
172 let result = self.read_extended_query_result().await;
174 self.state = ConnectionState::Idle;
175 result
176 }
177
178 #[must_use = "execute results should be checked for errors"]
180 pub async fn execute_params(
181 &mut self,
182 sql: &str,
183 params: &[&dyn ToSql],
184 ) -> Result<ExecuteResult> {
185 let result = self.query_params(sql, params).await?;
186 Ok(ExecuteResult::new(result.command_tag().clone()))
187 }
188
189 #[must_use = "stream errors should be checked"]
211 pub async fn query_params_stream(
212 &mut self,
213 sql: &str,
214 params: &[&dyn ToSql],
215 ) -> Result<crate::query::stream::RowStream<'_>> {
216 use crate::query::stream::RowStream;
217
218 #[cfg(feature = "tracing")]
219 tracing::debug!(
220 target: crate::tracing_ext::TARGET_QUERY,
221 sql_len = sql.len(),
222 sql_truncated = %crate::tracing_ext::truncate_str(sql, 200),
223 param_count = params.len(),
224 protocol = "extended",
225 "Executing parameterized query"
226 );
227 #[cfg(feature = "tracing")]
228 tracing::trace!(target: crate::tracing_ext::TARGET_QUERY, sql = %sql, "Full SQL text");
229
230 if self.needs_recovery {
231 self.recover().await?;
232 }
233
234 self.transition(ConnectionState::Streaming)?;
235
236 let param_values = encode_params_text(params)?;
237
238 self.codec
242 .encode_and_write(
243 &mut self.transport,
244 &FrontendMessage::Parse {
245 name: String::new(),
246 sql: sql.to_string(),
247 param_types: vec![],
248 },
249 )
250 .await?;
251
252 self.codec
254 .encode_and_write(
255 &mut self.transport,
256 &FrontendMessage::Bind {
257 portal: String::new(),
258 statement: String::new(),
259 param_formats: vec![crate::protocol::FormatCode::Text],
260 params: param_values,
261 result_formats: vec![crate::protocol::FormatCode::Binary],
262 },
263 )
264 .await?;
265
266 self.codec
269 .encode_and_write(
270 &mut self.transport,
271 &FrontendMessage::Describe {
272 variant: b'P',
273 name: String::new(),
274 },
275 )
276 .await?;
277
278 self.codec
280 .encode_and_write(
281 &mut self.transport,
282 &FrontendMessage::Execute {
283 portal: String::new(),
284 max_rows: 0,
285 },
286 )
287 .await?;
288
289 self.codec
291 .encode_and_write(&mut self.transport, &FrontendMessage::Sync)
292 .await?;
293
294 self.transport.flush().await.map_err(PgError::Transport)?;
296
297 let mut columns: Option<Arc<Vec<FieldDescription>>> = None;
301 loop {
302 let msg = self.codec.read_message(&mut self.transport).await?;
303 if self.handle_async_message(&msg) {
304 continue;
305 }
306 match msg {
307 BackendMessage::ParseComplete => {}
308 BackendMessage::BindComplete => {}
309 BackendMessage::RowDescription(body) => {
310 columns = Some(Arc::new(read_row_description(body)?));
311 break;
312 }
313 BackendMessage::NoData => {
314 break;
315 }
316 BackendMessage::CommandComplete(_body) => {
317 break;
322 }
323 BackendMessage::ReadyForQuery(body) => {
324 self.transaction_status = TransactionStatus::from_u8(body.status())
328 .unwrap_or(TransactionStatus::Idle);
329 break;
330 }
331 BackendMessage::ErrorResponse(body) => {
332 let server_err = PgServerError::from_error_body(&body).map_err(PgError::Io)?;
333 self.read_until_ready().await?;
334 self.state = ConnectionState::Idle;
335 return Err(PgError::Server(Box::new(server_err)));
336 }
337 BackendMessage::EmptyQueryResponse => {
338 break;
339 }
340 _ => {}
341 }
342 }
343
344 Ok(RowStream::new_extended_receiving(self, columns))
345 }
346
347 #[must_use = "query results should be checked for errors"]
352 pub async fn query_prepared(
353 &mut self,
354 stmt: &PreparedStatement,
355 params: &[&dyn ToSql],
356 ) -> Result<QueryResult> {
357 self.transition(ConnectionState::ActiveExtendedQuery)?;
358
359 let param_values = encode_params_binary(params, &stmt.param_types)?;
360
361 self.codec
365 .encode_and_write(
366 &mut self.transport,
367 &FrontendMessage::Bind {
368 portal: String::new(),
369 statement: stmt.name.clone(),
370 param_formats: vec![crate::protocol::FormatCode::Binary],
371 params: param_values,
372 result_formats: vec![crate::protocol::FormatCode::Binary],
373 },
374 )
375 .await?;
376
377 self.codec
380 .encode_and_write(
381 &mut self.transport,
382 &FrontendMessage::Describe {
383 variant: b'P',
384 name: String::new(),
385 },
386 )
387 .await?;
388
389 self.codec
391 .encode_and_write(
392 &mut self.transport,
393 &FrontendMessage::Execute {
394 portal: String::new(),
395 max_rows: 0,
396 },
397 )
398 .await?;
399
400 self.codec
402 .encode_and_write(&mut self.transport, &FrontendMessage::Sync)
403 .await?;
404
405 self.transport.flush().await.map_err(PgError::Transport)?;
407
408 let result = self.read_extended_query_result().await;
410 self.state = ConnectionState::Idle;
411 result
412 }
413
414 #[must_use = "execute results should be checked for errors"]
416 pub async fn execute_prepared(
417 &mut self,
418 stmt: &PreparedStatement,
419 params: &[&dyn ToSql],
420 ) -> Result<ExecuteResult> {
421 let result = self.query_prepared(stmt, params).await?;
422 Ok(ExecuteResult::new(result.command_tag().clone()))
423 }
424}
425
426impl Connection {
431 async fn read_extended_query_result(&mut self) -> Result<QueryResult> {
437 let mut columns: Option<Arc<Vec<FieldDescription>>> = None;
438 let mut rows: Vec<Row> = Vec::new();
439 let mut tag = None;
440
441 loop {
442 let msg = self.codec.read_message(&mut self.transport).await?;
443 if self.handle_async_message(&msg) {
444 continue;
445 }
446 match msg {
447 BackendMessage::ParseComplete => {}
449 BackendMessage::BindComplete => {}
450 BackendMessage::NoData => {}
451
452 BackendMessage::RowDescription(body) => {
453 columns = Some(Arc::new(read_row_description(body)?));
454 }
455 BackendMessage::DataRow(body) => {
456 let values = read_data_row(body)?;
457 if columns.is_none() {
458 let synthetic: Vec<FieldDescription> = (0..values.len())
462 .map(|i| {
463 FieldDescription::new(
464 format!("col{}", i),
465 0,
466 0,
467 0, -1,
469 -1,
470 1, )
472 })
473 .collect();
474 columns = Some(Arc::new(synthetic));
475 }
476 rows.push(Row::new(columns.clone().unwrap(), values));
477 }
478 BackendMessage::CommandComplete(body) => {
479 tag = Some(CommandTag::new(body.tag().unwrap_or("").into()));
480 }
481 BackendMessage::EmptyQueryResponse => {
482 tag = Some(CommandTag::new("".into()));
483 }
484 BackendMessage::ErrorResponse(body) => {
485 let server_err = PgServerError::from_error_body(&body).map_err(PgError::Io)?;
486 self.read_until_ready().await?;
489 return Err(PgError::Server(Box::new(server_err)));
490 }
491 BackendMessage::ReadyForQuery(body) => {
492 self.transaction_status = TransactionStatus::from_u8(body.status())
493 .unwrap_or(TransactionStatus::Idle);
494 break;
495 }
496 _ => {}
497 }
498 }
499
500 Ok(QueryResult::new(
501 rows,
502 tag.unwrap_or_default(),
503 columns.unwrap_or_default(),
504 ))
505 }
506}
507
508#[cfg(test)]
513mod tests {
514 use super::*;
515 use crate::auth::{Codec, ServerParams};
516 use crate::config::Config;
517 use crate::connection::ConnectionState;
518 use crate::transport::{BufferedTransport, ClientTransport, MockTransport, PgTransport};
519 use std::collections::VecDeque;
520
521 fn make_connection(read_data: Vec<u8>) -> Connection {
522 let transport = PgTransport::Plain(BufferedTransport::new(ClientTransport::Mock(
523 MockTransport::new(read_data),
524 )));
525 Connection {
526 transport,
527 codec: Codec::new(),
528 server_params: ServerParams::default(),
529 state: ConnectionState::Idle,
530 config: Config::new(),
531 transaction_status: TransactionStatus::Idle,
532 notification_queue: VecDeque::new(),
533 notice_handler: None,
534 statement_counter: 0,
535 needs_recovery: false,
536 health: crate::reconnect::session::ConnectionHealth::new(),
537 session_state: crate::reconnect::session::SessionState::new(),
538 }
539 }
540
541 fn build_parse_complete() -> Vec<u8> {
542 vec![b'1', 0, 0, 0, 4]
543 }
544
545 fn build_bind_complete() -> Vec<u8> {
546 vec![b'2', 0, 0, 0, 4]
547 }
548
549 fn build_row_description_msg(fields: &[(&str, u32)]) -> Vec<u8> {
550 let mut buf = vec![b'T'];
551 let mut body = Vec::new();
552 body.extend_from_slice(&(fields.len() as i16).to_be_bytes());
553 for (name, type_oid) in fields {
554 body.extend_from_slice(name.as_bytes());
555 body.push(0);
556 body.extend_from_slice(&0u32.to_be_bytes()); body.extend_from_slice(&0i16.to_be_bytes()); body.extend_from_slice(&type_oid.to_be_bytes()); body.extend_from_slice(&(-1i16).to_be_bytes()); body.extend_from_slice(&(-1i32).to_be_bytes()); body.extend_from_slice(&0i16.to_be_bytes()); }
563 let len = (body.len() + 4) as i32;
564 buf.extend_from_slice(&len.to_be_bytes());
565 buf.extend_from_slice(&body);
566 buf
567 }
568
569 fn build_data_row_msg(values: &[Option<&str>]) -> Vec<u8> {
570 let mut buf = vec![b'D'];
571 let mut body = Vec::new();
572 body.extend_from_slice(&(values.len() as i16).to_be_bytes());
573 for val in values {
574 match val {
575 Some(v) => {
576 let bytes = v.as_bytes();
577 body.extend_from_slice(&(bytes.len() as i32).to_be_bytes());
578 body.extend_from_slice(bytes);
579 }
580 None => {
581 body.extend_from_slice(&(-1i32).to_be_bytes());
582 }
583 }
584 }
585 let len = (body.len() + 4) as i32;
586 buf.extend_from_slice(&len.to_be_bytes());
587 buf.extend_from_slice(&body);
588 buf
589 }
590
591 fn build_command_complete_msg(tag: &str) -> Vec<u8> {
592 let mut buf = vec![b'C'];
593 let mut body = Vec::new();
594 body.extend_from_slice(tag.as_bytes());
595 body.push(0);
596 let len = (body.len() + 4) as i32;
597 buf.extend_from_slice(&len.to_be_bytes());
598 buf.extend_from_slice(&body);
599 buf
600 }
601
602 fn build_ready_for_query(status: u8) -> Vec<u8> {
603 vec![b'Z', 0, 0, 0, 5, status]
604 }
605
606 #[tokio::test]
607 async fn test_query_params_select() {
608 let mut data = Vec::new();
609 data.extend_from_slice(&build_parse_complete());
610 data.extend_from_slice(&build_bind_complete());
611 data.extend_from_slice(&build_row_description_msg(&[(
612 "val",
613 crate::types::INT4_OID,
614 )]));
615 data.extend_from_slice(&build_data_row_msg(&[Some("42")]));
616 data.extend_from_slice(&build_command_complete_msg("SELECT 1"));
617 data.extend_from_slice(&build_ready_for_query(b'I'));
618
619 let mut conn = make_connection(data);
620 let result = conn.query_params("SELECT $1", &[&42i32]).await.unwrap();
621 assert_eq!(result.len(), 1);
622 let v: i32 = result.rows()[0].get(0).unwrap();
623 assert_eq!(v, 42);
624 }
625
626 #[tokio::test]
627 async fn test_query_params_insert() {
628 let mut data = Vec::new();
629 data.extend_from_slice(&build_parse_complete());
630 data.extend_from_slice(&build_bind_complete());
631 data.extend_from_slice(&build_command_complete_msg("INSERT 0 1"));
632 data.extend_from_slice(&build_ready_for_query(b'I'));
633
634 let mut conn = make_connection(data);
635 let result = conn
636 .execute_params("INSERT INTO t (id) VALUES ($1)", &[&1i32])
637 .await
638 .unwrap();
639 assert_eq!(result.rows_affected(), Some(1));
640 }
641
642 #[tokio::test]
643 async fn test_query_params_insert_two_params() {
644 let mut data = Vec::new();
645 data.extend_from_slice(&build_parse_complete());
646 data.extend_from_slice(&build_bind_complete());
647 data.extend_from_slice(&build_command_complete_msg("INSERT 0 1"));
648 data.extend_from_slice(&build_ready_for_query(b'I'));
649
650 let mut conn = make_connection(data);
651 let result = conn
652 .execute_params(
653 "INSERT INTO t (id, name) VALUES ($1, $2)",
654 &[&200i32, &"param_insert"],
655 )
656 .await
657 .unwrap();
658 assert_eq!(result.rows_affected(), Some(1));
659 }
660
661 #[tokio::test]
662 async fn test_query_prepared_select() {
663 let mut data = Vec::new();
664 data.extend_from_slice(&build_bind_complete());
665 data.extend_from_slice(&build_row_description_msg(&[(
666 "val",
667 crate::types::INT4_OID,
668 )]));
669 data.extend_from_slice(&build_data_row_msg(&[Some("99")]));
670 data.extend_from_slice(&build_command_complete_msg("SELECT 1"));
671 data.extend_from_slice(&build_ready_for_query(b'I'));
672
673 let mut conn = make_connection(data);
674 let stmt = PreparedStatement {
675 name: "__pg_stmt_1".into(),
676 sql: "SELECT $1".into(),
677 param_types: vec![crate::types::Type::INT4],
678 columns: Arc::new(vec![]),
679 };
680 let result = conn.query_prepared(&stmt, &[&99i32]).await.unwrap();
681 assert_eq!(result.len(), 1);
682 let v: i32 = result.rows()[0].get(0).unwrap();
683 assert_eq!(v, 99);
684 }
685
686 #[tokio::test]
687 async fn test_query_params_error() {
688 let mut data = Vec::new();
689 let mut err = vec![b'E', 0, 0, 0, 22];
690 err.extend_from_slice(b"S");
691 err.extend_from_slice(b"ERROR\0");
692 err.extend_from_slice(b"M");
693 err.extend_from_slice(b"syntax error\0");
694 err.push(0);
695 data.extend_from_slice(&err);
696 data.extend_from_slice(&build_ready_for_query(b'I'));
697
698 let mut conn = make_connection(data);
699 let result = conn.query_params("BAD $1", &[&1i32]).await;
700 assert!(result.is_err());
701 assert!(conn.is_idle());
702 }
703
704 fn build_error_response_msg(code: &str, message: &str) -> Vec<u8> {
705 let mut buf = vec![b'E'];
706 let mut body = Vec::new();
707 body.push(b'S');
709 body.extend_from_slice(b"ERROR");
710 body.push(0);
711 body.push(b'C');
713 body.extend_from_slice(code.as_bytes());
714 body.push(0);
715 body.push(b'M');
717 body.extend_from_slice(message.as_bytes());
718 body.push(0);
719 body.push(0);
721 let len = (body.len() + 4) as i32;
722 buf.extend_from_slice(&len.to_be_bytes());
723 buf.extend_from_slice(&body);
724 buf
725 }
726
727 #[tokio::test]
728 async fn test_query_params_stream() {
729 let mut data = Vec::new();
730 data.extend_from_slice(&build_parse_complete());
731 data.extend_from_slice(&build_bind_complete());
732 data.extend_from_slice(&build_row_description_msg(&[
733 ("id", crate::types::INT4_OID),
734 ("name", crate::types::TEXT_OID),
735 ]));
736 data.extend_from_slice(&build_data_row_msg(&[Some("1"), Some("Alice")]));
737 data.extend_from_slice(&build_data_row_msg(&[Some("2"), Some("Bob")]));
738 data.extend_from_slice(&build_command_complete_msg("SELECT 2"));
739 data.extend_from_slice(&build_ready_for_query(b'I'));
740
741 let mut conn = make_connection(data);
742 let mut stream = conn
743 .query_params_stream("SELECT * FROM users WHERE id > $1", &[&0i32])
744 .await
745 .unwrap();
746
747 let row1 = stream.next().await.unwrap().unwrap();
748 assert_eq!(row1.get::<i32>(0).unwrap(), 1);
749 assert_eq!(row1.get::<String>(1).unwrap(), "Alice");
750
751 let row2 = stream.next().await.unwrap().unwrap();
752 assert_eq!(row2.get::<i32>(0).unwrap(), 2);
753 assert_eq!(row2.get::<String>(1).unwrap(), "Bob");
754
755 assert!(stream.next().await.unwrap().is_none());
756 assert!(stream.is_done());
757 }
758
759 #[tokio::test]
760 async fn test_query_params_stream_error() {
761 let mut data = Vec::new();
762 data.extend_from_slice(&build_parse_complete());
763 data.extend_from_slice(&build_bind_complete());
764 data.extend_from_slice(&build_error_response_msg("23505", "duplicate key value"));
766 data.extend_from_slice(&build_ready_for_query(b'I'));
767
768 let mut conn = make_connection(data);
769 let result = conn
770 .query_params_stream("INSERT INTO t VALUES ($1)", &[&1i32])
771 .await;
772 assert!(result.is_err());
773 match result {
774 Err(PgError::Server(e)) => {
775 assert_eq!(e.code(), "23505");
776 }
777 _ => panic!("expected server error"),
778 }
779 }
780
781 #[tokio::test]
782 async fn test_query_params_stream_no_data() {
783 let mut data = Vec::new();
785 data.extend_from_slice(&build_parse_complete());
786 data.extend_from_slice(&build_bind_complete());
787 let nodata = vec![b'n', 0, 0, 0, 4];
789 data.extend_from_slice(&nodata);
790 data.extend_from_slice(&build_command_complete_msg("INSERT 0 1"));
791 data.extend_from_slice(&build_ready_for_query(b'I'));
792
793 let mut conn = make_connection(data);
794 let mut stream = conn
795 .query_params_stream("INSERT INTO t VALUES ($1)", &[&1i32])
796 .await
797 .unwrap();
798
799 assert!(stream.next().await.unwrap().is_none());
800 assert!(stream.is_done());
801 }
802}