bb8_oracle/
lib.rs

1#![deny(missing_docs)]
2#![forbid(unsafe_code)]
3
4//! Oracle support for the bb8 connection pool.
5//!
6//! If you want to use chrono data types, enable the ```chrono``` feature:
7//!```toml
8//![dependencies]
9//!bb8-oracle = { version = "0.2.0", features = ["chrono"] }
10//!```
11
12use std::fmt;
13use std::sync::Arc;
14
15pub use bb8;
16pub use oracle;
17
18/// A `bb8::ManageConnection` for `oracle::Connection`s.
19///
20/// # Example
21/// ```no_run
22/// use std::thread;
23/// use bb8_oracle::OracleConnectionManager;
24///
25/// let manager = OracleConnectionManager::new("user", "password", "localhost");
26/// let pool = bb8::Pool::builder()
27///      .max_size(15)
28///      .build(manager).await
29///      .unwrap();
30///
31/// for _ in 0..20 {
32///     let pool = pool.clone();
33///     thread::spawn(move || {
34///         let conn = pool.get().unwrap();
35///         // use the connection
36///         // it will be returned to the pool when it falls out of scope.
37///     });
38/// }
39/// ```
40#[derive(Debug)]
41pub struct OracleConnectionManager {
42    connector: oracle::Connector,
43}
44
45impl OracleConnectionManager {
46    /// Initialise the connection manager with the data needed to create new connections.
47    /// Refer to the documentation of `oracle::Connection` for further details on the parameters.
48    ///
49    /// # Example
50    /// ```
51    /// # use bb8_oracle::OracleConnectionManager;
52    /// let manager = OracleConnectionManager::new("user", "password", "localhost");
53    /// ```
54    pub fn new<U: Into<String>, P: Into<String>, C: Into<String>>(username: U, password: P, connect_string: C) -> OracleConnectionManager {
55        let connector = oracle::Connector::new(username, password, connect_string);
56        OracleConnectionManager {
57            connector,
58        }
59    }
60
61    /// Initialise the connection manager with the data needed to create new connections using `oracle::Connector`.
62    /// This allows setting additional connection data.
63    ///
64    /// If a connection can be established only with a username, password and connect string, use `new` instead.
65    ///
66    /// # Example
67    /// ```
68    /// # use bb8_oracle::OracleConnectionManager;
69    /// // connect system/manager as sysdba
70    /// let mut connector = oracle::Connector::new("system", "manager", "");
71    /// connector.privilege(oracle::Privilege::Sysdba);
72    /// let manager = OracleConnectionManager::from_connector(connector);
73    /// ```
74    pub fn from_connector(connector: oracle::Connector) -> OracleConnectionManager {
75        OracleConnectionManager { connector }
76    }
77}
78
79/// An error that can occur during Oracle database connection pool operations.
80#[derive(Debug)]
81pub enum Error {
82    /// An error that occurred during database communication.
83    Database(oracle::Error),
84
85    /// An error that occurred because a pool operation panicked.
86    Panic(tokio::task::JoinError),
87}
88impl fmt::Display for Error {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        match self {
91            Self::Database(e) => write!(f, "database error: {}", e),
92            Self::Panic(e) => write!(f, "operation panicked: {}", e),
93        }
94    }
95}
96impl std::error::Error for Error {
97    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
98        match self {
99            Self::Database(e) => Some(e),
100            Self::Panic(e) => Some(e),
101        }
102    }
103}
104
105impl bb8::ManageConnection for OracleConnectionManager {
106    type Connection = Arc<oracle::Connection>;
107    type Error = Error;
108
109    async fn connect(&self) -> Result<Self::Connection, Self::Error> {
110        let connector_clone = self.connector.clone();
111        let result = tokio::task::spawn_blocking(move || {
112            connector_clone.connect()
113        }).await;
114        match result {
115            Ok(Ok(c)) => Ok(Arc::new(c)),
116            Ok(Err(e)) => Err(Error::Database(e)),
117            Err(e) => Err(Error::Panic(e)),
118        }
119    }
120
121    async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> {
122        let conn_clone = Arc::clone(&conn);
123        let result = tokio::task::spawn_blocking(move || {
124            conn_clone.ping()
125        }).await;
126        match result {
127            Ok(Ok(())) => Ok(()),
128            Ok(Err(e)) => Err(Error::Database(e)),
129            Err(e) => Err(Error::Panic(e)),
130        }
131    }
132
133    fn has_broken(&self, conn: &mut Self::Connection) -> bool {
134        !matches!(conn.status(), Ok(oracle::ConnStatus::Normal))
135    }
136}