1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! Oracle support for the r2d2 connection pool.
//!
//! If you want to use chrono data types, enable the ```chrono``` feature:
//!```toml
//![dependencies]
//!r2d2-oracle = { version = "0.2.0", features = ["chrono"] }
//!```

#![forbid(unsafe_code)]
// use deny instead of forbid due to bogus warnings, see also https://github.com/rust-lang/rust/issues/81670
#![deny(warnings)]
#![deny(missing_docs)]
#![forbid(missing_debug_implementations)]
#![forbid(unused)]

pub use oracle;
pub use r2d2;

/// An `r2d2::ManageConnection` for `oracle::Connection`s.
///
/// # Example
/// ```no_run
/// use std::thread;
/// use r2d2_oracle::OracleConnectionManager;
///
/// let manager = OracleConnectionManager::new("user", "password", "localhost");
/// let pool = r2d2::Pool::builder()
///      .max_size(15)
///      .build(manager)
///      .unwrap();
///
/// for _ in 0..20 {
///     let pool = pool.clone();
///     thread::spawn(move || {
///         let conn = pool.get().unwrap();
///         // use the connection
///         // it will be returned to the pool when it falls out of scope.
///     });
/// }
/// ```
#[derive(Debug)]
pub struct OracleConnectionManager {
    connector: oracle::Connector,
}

impl OracleConnectionManager {
    /// Initialise the connection manager with the data needed to create new connections.
    /// Refer to the documentation of `oracle::Connection` for further details on the parameters.
    ///
    /// # Example
    /// ```
    /// # use r2d2_oracle::OracleConnectionManager;
    /// let manager = OracleConnectionManager::new("user", "password", "localhost");
    /// ```
    pub fn new(username: &str, password: &str, connect_string: &str) -> OracleConnectionManager {
        OracleConnectionManager {
            connector: oracle::Connector::new(username, password, connect_string),
        }
    }

    /// Initialise the connection manager with the data needed to create new connections using `oracle::Connector`.
    /// This allows setting additional connection data.
    ///
    /// If a connection can be established only with a username, password and connect string, use `new` instead.
    ///
    /// # Example
    /// ```
    /// # use r2d2_oracle::OracleConnectionManager;
    /// // connect system/manager as sysdba
    /// let mut connector = oracle::Connector::new("system", "manager", "");
    /// connector.privilege(oracle::Privilege::Sysdba);
    /// let manager = OracleConnectionManager::from_connector(connector);
    /// ```
    pub fn from_connector(connector: oracle::Connector) -> OracleConnectionManager {
        OracleConnectionManager { connector }
    }
}

impl r2d2::ManageConnection for OracleConnectionManager {
    type Connection = oracle::Connection;
    type Error = oracle::Error;

    fn connect(&self) -> Result<oracle::Connection, oracle::Error> {
        self.connector.connect()
    }

    fn is_valid(&self, conn: &mut oracle::Connection) -> Result<(), oracle::Error> {
        conn.ping()
    }

    fn has_broken(&self, conn: &mut oracle::Connection) -> bool {
        !matches!(conn.status(), Ok(oracle::ConnStatus::Normal))
    }
}