use std::{ptr, sync::Arc, marker::PhantomData};
use crate::{Error, Result, oci::{self, *}, Environment, Session};
#[cfg_attr(docsrs, doc(cfg(feature="blocking")))]
pub struct ConnectionPool<'a> {
pool: Handle<OCICPool>,
err: Handle<OCIError>,
env: Arc<Handle<OCIEnv>>,
name: &'a [u8],
phantom_env: PhantomData<&'a Environment>,
}
impl Drop for ConnectionPool<'_> {
fn drop(&mut self) {
oci_connection_pool_destroy(&self.pool, &self.err);
}
}
impl<'a> ConnectionPool<'a> {
pub(crate) fn new(env: &'a Environment, dbname: &str, username: &str, password: &str, min: usize, inc: usize, max: usize) -> Result<Self> {
let err = Handle::<OCIError>::new(env)?;
let pool = Handle::<OCICPool>::new(env)?;
let mut pool_name_ptr = ptr::null::<u8>();
let mut pool_name_len = 0u32;
oci::connection_pool_create(
env.as_ref(), env.as_ref(), pool.as_ref(),
&mut pool_name_ptr, &mut pool_name_len,
dbname.as_ptr(), dbname.len() as u32,
min as u32, max as u32, inc as u32,
username.as_ptr(), username.len() as u32,
password.as_ptr(), password.len() as u32,
OCI_DEFAULT
)?;
let name = unsafe {
std::slice::from_raw_parts(pool_name_ptr, pool_name_len as usize)
};
Ok(Self {env: env.get_env(), err, pool, name, phantom_env: PhantomData})
}
pub(crate) fn get_svc_ctx(&self, auth_info: &OCIAuthInfo) -> Result<Ptr<OCISvcCtx>> {
let mut svc = Ptr::<OCISvcCtx>::null();
oci::session_get(
self.env.as_ref(), &self.err, svc.as_mut_ptr(), &auth_info,
self.name.as_ptr(), self.name.len() as u32,
OCI_SESSGET_CPOOL | OCI_SESSGET_STMTCACHE
)?;
Ok(svc)
}
pub(crate) fn get_env(&self) -> Arc<Handle<OCIEnv>> {
self.env.clone()
}
pub fn get_session(&self, user: &str, pass: &str) -> Result<Session<'_>> {
Session::from_connection_pool(self, user, pass)
}
pub fn idle_timeout(&self) -> Result<u32> {
self.pool.get_attr(OCI_ATTR_CONN_TIMEOUT, &self.err)
}
pub fn set_idle_timeout(&self, idle_time: u32) -> Result<()> {
let num_open = self.open_count()?;
if num_open > 0 {
self.pool.set_attr(OCI_ATTR_CONN_TIMEOUT, idle_time, &self.err)
} else {
Err(Error::new("pool is empty"))
}
}
pub fn is_nowait(&self) -> Result<bool> {
let flag : u8 = self.pool.get_attr(OCI_ATTR_CONN_NOWAIT, &self.err)?;
Ok(flag != 0)
}
pub fn set_nowait(&self) -> Result<()> {
oci::attr_set(self.pool.get_ptr().as_ref(), OCI_HTYPE_CPOOL, std::ptr::null(), 0, OCI_ATTR_CONN_NOWAIT, self.err.as_ref())
}
pub fn busy_count(&self) -> Result<usize> {
let count : u32 = self.pool.get_attr(OCI_ATTR_CONN_BUSY_COUNT, &self.err)?;
Ok(count as usize)
}
pub fn open_count(&self) -> Result<usize> {
let count : u32 = self.pool.get_attr(OCI_ATTR_CONN_OPEN_COUNT, &self.err)?;
Ok(count as usize)
}
}