sqlx_core/postgres/message/
startup.rs

1use crate::io::{BufMutExt, Encode};
2use crate::postgres::io::PgBufMutExt;
3
4// To begin a session, a frontend opens a connection to the server and sends a startup message.
5// This message includes the names of the user and of the database the user wants to connect to;
6// it also identifies the particular protocol version to be used.
7
8// Optionally, the startup message can include additional settings for run-time parameters.
9
10pub struct Startup<'a> {
11    /// The database user name to connect as. Required; there is no default.
12    pub username: Option<&'a str>,
13
14    /// The database to connect to. Defaults to the user name.
15    pub database: Option<&'a str>,
16
17    /// Additional start-up params.
18    /// <https://www.postgresql.org/docs/devel/runtime-config-client.html>
19    pub params: &'a [(&'a str, &'a str)],
20}
21
22impl Encode<'_> for Startup<'_> {
23    fn encode_with(&self, buf: &mut Vec<u8>, _: ()) {
24        buf.reserve(120);
25
26        buf.put_length_prefixed(|buf| {
27            // The protocol version number. The most significant 16 bits are the
28            // major version number (3 for the protocol described here). The least
29            // significant 16 bits are the minor version number (0
30            // for the protocol described here)
31            buf.extend(&196_608_i32.to_be_bytes());
32
33            if let Some(username) = self.username {
34                // The database user name to connect as.
35                encode_startup_param(buf, "user", username);
36            }
37
38            if let Some(database) = self.database {
39                // The database to connect to. Defaults to the user name.
40                encode_startup_param(buf, "database", database);
41            }
42
43            for (name, value) in self.params {
44                encode_startup_param(buf, name, value);
45            }
46
47            // A zero byte is required as a terminator
48            // after the last name/value pair.
49            buf.push(0);
50        });
51    }
52}
53
54#[inline]
55fn encode_startup_param(buf: &mut Vec<u8>, name: &str, value: &str) {
56    buf.put_str_nul(name);
57    buf.put_str_nul(value);
58}
59
60#[test]
61fn test_encode_startup() {
62    const EXPECTED: &[u8] = b"\0\0\0)\0\x03\0\0user\0postgres\0database\0postgres\0\0";
63
64    let mut buf = Vec::new();
65    let m = Startup {
66        username: Some("postgres"),
67        database: Some("postgres"),
68        params: &[],
69    };
70
71    m.encode(&mut buf);
72
73    assert_eq!(buf, EXPECTED);
74}
75
76#[cfg(all(test, not(debug_assertions)))]
77#[bench]
78fn bench_encode_startup(b: &mut test::Bencher) {
79    use test::black_box;
80
81    let mut buf = Vec::with_capacity(128);
82
83    b.iter(|| {
84        buf.clear();
85
86        black_box(Startup {
87            username: Some("postgres"),
88            database: Some("postgres"),
89            params: &[],
90        })
91        .encode(&mut buf);
92    });
93}