#[cfg(doc)]
use crate::pool::PoolBuilder;
use crate::util::{os_string_into_ansi_c_string, string_into_c_string};
#[cfg(doc)]
use crate::Connector;
use crate::DbError;
use crate::Error;
use crate::Result;
use odpic_sys::*;
use once_cell::sync::OnceCell;
use std::ffi::{CString, OsString};
use std::mem::{self, MaybeUninit};
use std::os::raw::c_char;
use std::ptr;
use std::sync::{Arc, Mutex};
#[derive(Clone, Debug)]
pub struct InitParams {
default_driver_name: Option<CString>,
load_error_url: Option<CString>,
oracle_client_lib_dir: Option<CString>,
oracle_client_config_dir: Option<CString>,
soda_use_json_desc: bool,
use_json_id: bool,
}
impl InitParams {
pub fn new() -> InitParams {
InitParams {
default_driver_name: None,
load_error_url: None,
oracle_client_lib_dir: None,
oracle_client_config_dir: None,
soda_use_json_desc: false,
use_json_id: false,
}
}
pub fn default_driver_name<T>(&mut self, name: T) -> Result<&mut InitParams>
where
T: Into<String>,
{
self.default_driver_name = Some(string_into_c_string(name.into(), "default_driver_name")?);
Ok(self)
}
pub fn load_error_url<T>(&mut self, url: T) -> Result<&mut InitParams>
where
T: Into<String>,
{
self.load_error_url = Some(string_into_c_string(url.into(), "load_error_url")?);
Ok(self)
}
pub fn oracle_client_lib_dir<T>(&mut self, dir: T) -> Result<&mut InitParams>
where
T: Into<OsString>,
{
self.oracle_client_lib_dir = Some(os_string_into_ansi_c_string(
dir.into(),
"oracle_client_lib_dir",
)?);
Ok(self)
}
pub fn oracle_client_config_dir<T>(&mut self, dir: T) -> Result<&mut InitParams>
where
T: Into<OsString>,
{
self.oracle_client_config_dir = Some(os_string_into_ansi_c_string(
dir.into(),
"oracle_client_config_dir",
)?);
Ok(self)
}
#[doc(hidden)]
pub fn soda_use_json_desc(&mut self, value: bool) -> &mut InitParams {
self.soda_use_json_desc = value;
self
}
#[doc(hidden)]
pub fn use_json_id(&mut self, value: bool) -> &mut InitParams {
self.use_json_id = value;
self
}
pub fn init(&self) -> Result<bool> {
let mut initialized_here = false;
GLOBAL_CONTEXT.get_or_try_init(|| {
let mut params = unsafe { mem::zeroed::<dpiContextCreateParams>() };
if let Some(ref name) = self.default_driver_name {
params.defaultDriverName = name.as_ptr();
}
if let Some(ref url) = self.load_error_url {
params.loadErrorUrl = url.as_ptr();
}
if let Some(ref dir) = self.oracle_client_lib_dir {
params.oracleClientLibDir = dir.as_ptr()
}
if let Some(ref dir) = self.oracle_client_config_dir {
params.oracleClientConfigDir = dir.as_ptr()
}
params.sodaUseJsonDesc = self.soda_use_json_desc.into();
params.useJsonId = self.use_json_id.into();
let result = Context::from_params(&mut params);
initialized_here = true;
result
})?;
Ok(initialized_here)
}
pub fn is_initialized() -> bool {
GLOBAL_CONTEXT.get().is_some()
}
}
impl Default for InitParams {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone)]
pub(crate) struct Context {
pub context: *mut dpiContext,
last_warning: Option<Arc<Mutex<Option<DbError>>>>,
}
unsafe impl Sync for Context {}
unsafe impl Send for Context {}
static GLOBAL_CONTEXT: OnceCell<Context> = OnceCell::new();
impl Context {
fn from_params(params: &mut dpiContextCreateParams) -> Result<Context> {
if params.defaultDriverName.is_null() {
let driver_name: &'static str =
concat!("rust-oracle : ", env!("CARGO_PKG_VERSION"), "\0");
params.defaultDriverName = driver_name.as_ptr() as *const c_char;
}
let mut ctxt = ptr::null_mut();
let mut err = MaybeUninit::uninit();
if unsafe {
dpiContext_createWithParams(
DPI_MAJOR_VERSION,
DPI_MINOR_VERSION,
params,
&mut ctxt,
err.as_mut_ptr(),
)
} == DPI_SUCCESS as i32
{
Ok(Context {
context: ctxt,
last_warning: None,
})
} else {
Err(Error::from_dpi_error(&unsafe { err.assume_init() }))
}
}
pub fn new0() -> Result<Context> {
Ok(GLOBAL_CONTEXT
.get_or_try_init(|| {
let mut params = unsafe { mem::zeroed() };
Context::from_params(&mut params)
})?
.clone())
}
pub fn new() -> Result<Context> {
let ctxt = Context::new0()?;
Ok(Context {
last_warning: Some(Arc::new(Mutex::new(None))),
..ctxt
})
}
pub fn last_warning(&self) -> Option<DbError> {
self.last_warning
.as_ref()
.and_then(|mutex| mutex.lock().unwrap().as_ref().cloned())
}
pub fn set_warning(&self) {
if let Some(ref mutex) = self.last_warning {
*mutex.lock().unwrap() = DbError::to_warning(self);
}
}
pub fn common_create_params(&self) -> dpiCommonCreateParams {
let mut params = MaybeUninit::uninit();
unsafe {
dpiContext_initCommonCreateParams(self.context, params.as_mut_ptr());
let mut params = params.assume_init();
params.createMode |= DPI_MODE_CREATE_THREADED;
params
}
}
pub fn conn_create_params(&self) -> dpiConnCreateParams {
let mut params = MaybeUninit::uninit();
unsafe {
dpiContext_initConnCreateParams(self.context, params.as_mut_ptr());
params.assume_init()
}
}
pub fn pool_create_params(&self) -> dpiPoolCreateParams {
let mut params = MaybeUninit::uninit();
unsafe {
dpiContext_initPoolCreateParams(self.context, params.as_mut_ptr());
params.assume_init()
}
}
}