Skip to main content

sentinel_driver/connection/
prepare.rs

1use super::{frontend, BackendMessage, CacheMetrics, Connection, Error, Oid, Result, Statement};
2
3impl Connection {
4    /// Prepare a statement on the server using extended query protocol.
5    ///
6    /// Returns a `Statement` with parameter types and column descriptions.
7    pub async fn prepare(&mut self, sql: &str) -> Result<Statement> {
8        let stmt_name = format!("_sentinel_p{}", self.process_id);
9
10        frontend::parse(self.conn.write_buf(), &stmt_name, sql, &[]);
11        frontend::describe_statement(self.conn.write_buf(), &stmt_name);
12        frontend::sync(self.conn.write_buf());
13        self.conn.send().await?;
14
15        // ParseComplete
16        match self.conn.recv().await? {
17            BackendMessage::ParseComplete => {}
18            BackendMessage::ErrorResponse { fields } => {
19                self.drain_until_ready().await.ok();
20                return Err(Error::server(
21                    fields.severity,
22                    fields.code,
23                    fields.message,
24                    fields.detail,
25                    fields.hint,
26                    fields.position,
27                ));
28            }
29            other => {
30                return Err(Error::protocol(format!(
31                    "expected ParseComplete, got {other:?}"
32                )))
33            }
34        }
35
36        // ParameterDescription
37        let param_oids = match self.conn.recv().await? {
38            BackendMessage::ParameterDescription { oids } => {
39                oids.into_iter().map(Oid::from).collect()
40            }
41            other => {
42                return Err(Error::protocol(format!(
43                    "expected ParameterDescription, got {other:?}"
44                )))
45            }
46        };
47
48        // RowDescription or NoData
49        let columns = match self.conn.recv().await? {
50            BackendMessage::RowDescription { fields } => Some(fields),
51            BackendMessage::NoData => None,
52            other => {
53                return Err(Error::protocol(format!(
54                    "expected RowDescription/NoData, got {other:?}"
55                )))
56            }
57        };
58
59        // ReadyForQuery
60        self.drain_until_ready().await?;
61
62        Ok(Statement::new(
63            stmt_name,
64            sql.to_string(),
65            param_oids,
66            columns,
67        ))
68    }
69
70    /// Register a prepared statement in the Tier 1 cache.
71    pub fn register_statement(&mut self, name: &str, statement: Statement) {
72        self.stmt_cache.register(name, statement);
73    }
74
75    /// Get statement cache metrics.
76    pub fn cache_metrics(&self) -> &CacheMetrics {
77        self.stmt_cache.metrics()
78    }
79}