sqlx_postgres/message/
parse.rs

1use crate::io::BufMutExt;
2use crate::io::{PgBufMutExt, StatementId};
3use crate::message::{FrontendMessage, FrontendMessageFormat};
4use crate::types::Oid;
5use sqlx_core::Error;
6use std::num::Saturating;
7
8#[derive(Debug)]
9pub struct Parse<'a> {
10    /// The ID of the destination prepared statement.
11    pub statement: StatementId,
12
13    /// The query string to be parsed.
14    pub query: &'a str,
15
16    /// The parameter data types specified (could be zero). Note that this is not an
17    /// indication of the number of parameters that might appear in the query string,
18    /// only the number that the frontend wants to pre-specify types for.
19    pub param_types: &'a [Oid],
20}
21
22impl FrontendMessage for Parse<'_> {
23    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Parse;
24
25    fn body_size_hint(&self) -> Saturating<usize> {
26        let mut size = Saturating(0);
27
28        size += self.statement.name_len();
29
30        size += self.query.len();
31        size += 1; // NUL terminator
32
33        size += 2; // param_types_len
34
35        // `param_types`
36        size += self.param_types.len().saturating_mul(4);
37
38        size
39    }
40
41    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {
42        buf.put_statement_name(self.statement);
43
44        buf.put_str_nul(self.query);
45
46        // Note: actually interpreted as unsigned
47        // https://github.com/launchbadge/sqlx/issues/3464
48        let param_types_len = u16::try_from(self.param_types.len()).map_err(|_| {
49            err_protocol!(
50                "param_types.len() too large for binary protocol: {}",
51                self.param_types.len()
52            )
53        })?;
54
55        buf.extend(param_types_len.to_be_bytes());
56
57        for &oid in self.param_types {
58            buf.extend(oid.0.to_be_bytes());
59        }
60
61        Ok(())
62    }
63}
64
65#[test]
66fn test_encode_parse() {
67    const EXPECTED: &[u8] = b"P\0\0\0\x26sqlx_s_1234567890\0SELECT $1\0\0\x01\0\0\0\x19";
68
69    let mut buf = Vec::new();
70    let m = Parse {
71        statement: StatementId::TEST_VAL,
72        query: "SELECT $1",
73        param_types: &[Oid(25)],
74    };
75
76    m.encode_msg(&mut buf).unwrap();
77
78    assert_eq!(buf, EXPECTED);
79}