use std::time::Duration;
use std::time::Instant;
use crate::bind_params::BindParameters;
use crate::client::{Client, ClientRef};
use crate::config::Config;
use crate::cursor::Cursor;
use crate::db_info::DbInfo;
use crate::db_value::ToDbValue;
use crate::end_user_security_context::EndUserSecurityContext;
use crate::error::Error;
use crate::exec_result::ExecResult;
use crate::messages::CommitMessage;
use crate::messages::PingMessage;
use crate::messages::RollbackMessage;
use crate::ora_version::OracleVersion;
use crate::row::Row;
use crate::statement::Statement;
pub(crate) struct ConnImpl {
client_ref: ClientRef,
db_info: DbInfo,
returned_to_pool: Instant,
}
pub(crate) enum ConnImplStatus {
Healthy,
RequiresPing,
RequiresClose,
}
impl ConnImpl {
pub(crate) fn change_password(
&self,
old_password: &str,
new_password: &str,
) -> Result<(), Error> {
let mut client = self.client_ref.lock().unwrap();
client.change_password(old_password, new_password)
}
pub(crate) fn clear_end_user_security_context(&self) -> Result<(), Error> {
self.client_ref
.lock()
.unwrap()
.clear_end_user_security_context();
Ok(())
}
pub(crate) fn close(&mut self) -> Result<(), Error> {
self.clear_end_user_security_context()?;
self.rollback()?;
self.client_ref.lock().unwrap().close()
}
pub(crate) fn connect(config: Config) -> Result<ConnImpl, Error> {
config.validate()?;
let mut client = Client::new(config);
let db_info = client.connect()?;
let client_ref = std::sync::Arc::new(std::sync::Mutex::new(client));
Ok(ConnImpl {
client_ref,
db_info,
returned_to_pool: Instant::now(),
})
}
pub(crate) fn get_status(
&self,
ping_interval_opt: Option<Duration>,
) -> ConnImplStatus {
if self.client_ref.lock().unwrap().requires_close() {
ConnImplStatus::RequiresClose
} else if let Some(ping_interval) = ping_interval_opt
&& self.returned_to_pool.elapsed() >= ping_interval
{
ConnImplStatus::RequiresPing
} else {
ConnImplStatus::Healthy
}
}
pub(crate) fn set_end_user_security_context(
&self,
context: EndUserSecurityContext,
) -> Result<(), Error> {
self.client_ref
.lock()
.unwrap()
.set_end_user_security_context(context)
}
pub(crate) fn set_returned_to_pool(&mut self) {
self.returned_to_pool = Instant::now();
}
pub fn commit(&self) -> Result<(), Error> {
let mut message = CommitMessage::new();
let mut client = self.client_ref.lock().unwrap();
client.process_message(&mut message)?;
Ok(())
}
pub fn execute(
&self,
sql: &str,
params: &[&dyn ToDbValue],
) -> Result<ExecResult, Error> {
self.statement(sql).execute(params)
}
pub fn execute_batch(
&self,
sql: &str,
params: BindParameters,
) -> Result<ExecResult, Error> {
self.statement(sql).execute_batch(params)
}
pub fn execute_named(
&self,
sql: &str,
params: &[(&str, &dyn ToDbValue)],
) -> Result<ExecResult, Error> {
self.statement(sql).execute_named(params)
}
pub fn get_call_timeout(&self) -> Result<Option<Duration>, Error> {
self.client_ref.lock().unwrap().get_call_timeout()
}
pub fn get_db_domain(&self) -> &str {
self.db_info.get_db_domain()
}
pub fn get_db_name(&self) -> &str {
self.db_info.get_db_name()
}
pub fn get_instance_name(&self) -> &str {
self.db_info.get_instance_name()
}
pub fn get_last_warning(&self) -> Option<String> {
self.client_ref.lock().unwrap().get_last_warning()
}
pub fn get_max_identifier_length(&self) -> usize {
self.db_info.get_max_identifier_length()
}
pub fn get_max_open_cursors(&self) -> usize {
self.db_info.get_max_open_cursors()
}
pub fn get_serial_num(&self) -> usize {
self.db_info.get_serial_num()
}
pub fn get_server_version(&self) -> OracleVersion {
self.db_info.get_server_version()
}
pub fn get_service_name(&self) -> &str {
self.db_info.get_service_name()
}
pub fn get_session_id(&self) -> usize {
self.db_info.get_session_id()
}
pub fn ping(&self) -> Result<(), Error> {
let mut message = PingMessage::new();
let mut client = self.client_ref.lock().unwrap();
client.process_message(&mut message)?;
Ok(())
}
pub fn query(
&self,
sql: &str,
params: &[&dyn ToDbValue],
) -> Result<Cursor, Error> {
self.statement(sql).query(params)
}
#[cfg(feature = "arrow")]
pub fn query_arrow(
&self,
sql: &str,
params: BindParameters,
) -> Result<arrow_array::RecordBatch, Error> {
self.statement(sql).query_arrow(params)
}
pub fn query_named(
&self,
sql: &str,
params: &[(&str, &dyn ToDbValue)],
) -> Result<Cursor, Error> {
self.statement(sql).query_named(params)
}
pub fn query_row(
&self,
sql: &str,
params: &[&dyn ToDbValue],
) -> Result<Row, Error> {
self.statement(sql)
.prefetch_rows(1)
.fetch_array_size(1)
.query_row(params)
}
pub fn query_row_named(
&self,
sql: &str,
params: &[(&str, &dyn ToDbValue)],
) -> Result<Row, Error> {
self.statement(sql)
.prefetch_rows(1)
.fetch_array_size(1)
.query_row_named(params)
}
pub fn rollback(&self) -> Result<(), Error> {
let mut message = RollbackMessage::new();
let mut client = self.client_ref.lock().unwrap();
client.process_message(&mut message)?;
Ok(())
}
pub fn set_call_timeout(
&self,
duration: Option<Duration>,
) -> Result<(), Error> {
self.client_ref.lock().unwrap().set_call_timeout(duration)
}
pub fn set_pending_action(&self, action: &str) {
let mut client = self.client_ref.lock().unwrap();
client.set_pending_action(action);
}
pub fn set_pending_client_identifier(&self, client_identifier: &str) {
let mut client = self.client_ref.lock().unwrap();
client.set_pending_client_identifier(client_identifier);
}
pub fn set_pending_client_info(&self, client_info: &str) {
let mut client = self.client_ref.lock().unwrap();
client.set_pending_client_info(client_info);
}
pub fn set_pending_db_op(&self, db_op: &str) {
let mut client = self.client_ref.lock().unwrap();
client.set_pending_db_op(db_op);
}
pub fn set_pending_module(&self, db_op: &str) {
let mut client = self.client_ref.lock().unwrap();
client.set_pending_module(db_op);
}
pub fn statement<'sql>(&self, sql: &'sql str) -> Statement<'sql> {
Statement::new(&self.client_ref, sql)
}
}
impl Drop for ConnImpl {
fn drop(&mut self) {
let _ = self.close();
}
}