odbc_api/
shared_connection.rs

1use std::sync::{Arc, Mutex};
2
3use crate::{
4    Connection, CursorImpl, Error, ParameterCollectionRef, Preallocated, Prepared,
5    connection::{ConnectionTransitions, FailedStateTransition},
6    handles::{StatementConnection, StatementParent},
7};
8
9/// A convinient type alias in case you want to use a connection from multiple threads which share
10/// ownership of it.
11pub type SharedConnection<'env> = Arc<Mutex<Connection<'env>>>;
12
13/// # Safety:
14///
15/// Connection is guaranteed to be alive and in connected state for the lifetime of
16/// [`SharedConnection`].
17unsafe impl StatementParent for SharedConnection<'_> {}
18
19impl<'env> ConnectionTransitions for SharedConnection<'env> {
20    type StatementParent = Self;
21
22    fn into_cursor(
23        self,
24        query: &str,
25        params: impl ParameterCollectionRef,
26        query_timeout_sec: Option<usize>,
27    ) -> Result<Option<CursorImpl<StatementConnection<Self>>>, FailedStateTransition<Self>> {
28        let guard = self
29            .lock()
30            .expect("Shared connection lock must not be poisned");
31        // Result borrows the connection. We convert the cursor into a raw pointer, to not confuse
32        // the borrow checker.
33        let result = guard.execute(query, params, query_timeout_sec);
34        let result = result.map(|opt| opt.map(|cursor| cursor.into_stmt().into_sys()));
35        drop(guard);
36        if let Err(error) = result {
37            return Err(FailedStateTransition {
38                error,
39                previous: self,
40            });
41        }
42        let Some(stmt_ptr) = result.unwrap() else {
43            return Ok(None);
44        };
45        // Safe: The connection is the parent of the statement referenced by `stmt_ptr`.
46        let stmt = unsafe { StatementConnection::new(stmt_ptr, self) };
47        // Safe: `stmt` is valid and in cursor state.
48        let cursor = unsafe { CursorImpl::new(stmt) };
49        Ok(Some(cursor))
50    }
51
52    fn into_prepared(self, query: &str) -> Result<Prepared<StatementConnection<Self>>, Error> {
53        let guard = self
54            .lock()
55            .expect("Shared connection lock must not be poisoned");
56        let stmt = guard.prepare(query)?;
57        let stmt_ptr = stmt.into_handle().into_sys();
58        drop(guard);
59        // Safe: The connection is the parent of the statement referenced by `stmt_ptr`.
60        let stmt = unsafe { StatementConnection::new(stmt_ptr, self) };
61        // `stmt` is valid and in prepared state.
62        let prepared = Prepared::new(stmt);
63        Ok(prepared)
64    }
65
66    fn into_preallocated(self) -> Result<Preallocated<StatementConnection<Self>>, Error> {
67        let guard = self
68            .lock()
69            .expect("Shared connection lock must not be poisoned");
70        let stmt = guard.preallocate()?;
71        let stmt_ptr = stmt.into_handle().into_sys();
72        drop(guard);
73        // Safe: The connection is the parent of the statement referenced by `stmt_ptr`.
74        let stmt = unsafe { StatementConnection::new(stmt_ptr, self) };
75        // `stmt` is valid and in freshly allocated state.
76        let preallocated = unsafe { Preallocated::new(stmt) };
77        Ok(preallocated)
78    }
79}