use super::{
as_handle::AsHandle, drop_handle, error::IntoResult, logging::log_diagnostics, Connection,
Error,
};
use log::debug;
use odbc_sys::{
AttrOdbcVersion, EnvironmentAttribute, FetchOrientation, HDbc, HEnv, Handle, HandleType,
SQLAllocHandle, SQLDataSourcesW, SQLDriversW, SQLSetEnvAttr, SqlReturn,
};
use std::{convert::TryInto, ptr::null_mut};
#[derive(Debug)]
pub struct Environment {
handle: HEnv,
}
unsafe impl Send for Environment {}
unsafe impl Sync for Environment {}
unsafe impl AsHandle for Environment {
fn as_handle(&self) -> Handle {
self.handle as Handle
}
fn handle_type(&self) -> HandleType {
HandleType::Env
}
}
impl Drop for Environment {
fn drop(&mut self) {
unsafe {
drop_handle(self.handle as Handle, HandleType::Env);
}
}
}
impl Environment {
pub unsafe fn new() -> Result<Self, Error> {
let mut handle = null_mut();
let (handle, info) = match SQLAllocHandle(HandleType::Env, null_mut(), &mut handle) {
SqlReturn::ERROR => return Err(Error::NoDiagnostics),
SqlReturn::SUCCESS => (handle, false),
SqlReturn::SUCCESS_WITH_INFO => (handle, true),
other => panic!(
"Unexpected Return value for allocating ODBC Environment: {:?}",
other
),
};
debug!("ODBC Environment created.");
let env = Environment {
handle: handle as HEnv,
};
if info {
log_diagnostics(&env);
}
Ok(env)
}
pub fn declare_version(&self, version: AttrOdbcVersion) -> Result<(), Error> {
unsafe {
SQLSetEnvAttr(
self.handle,
EnvironmentAttribute::OdbcVersion,
version.into(),
0,
)
.into_result(self)
}
}
pub fn allocate_connection(&self) -> Result<Connection, Error> {
let mut handle = null_mut();
unsafe {
SQLAllocHandle(HandleType::Dbc, self.as_handle(), &mut handle).into_result(self)?;
Ok(Connection::new(handle as HDbc))
}
}
pub fn as_raw(&self) -> HEnv {
self.handle
}
pub fn drivers_buffer_fill(
&mut self,
direction: FetchOrientation,
buffer_description: &mut Vec<u16>,
buffer_attributes: &mut Vec<u16>,
) -> Result<bool, Error> {
buffer_description.resize(buffer_description.capacity(), 0);
buffer_attributes.resize(buffer_attributes.capacity(), 0);
unsafe {
match SQLDriversW(
self.handle,
direction,
buffer_description.as_mut_ptr(),
buffer_description.len().try_into().unwrap(),
null_mut(),
buffer_attributes.as_mut_ptr(),
buffer_attributes.len().try_into().unwrap(),
null_mut(),
) {
SqlReturn::NO_DATA => Ok(false),
other => {
other.into_result(self)?;
Ok(true)
}
}
}
}
pub fn drivers_buffer_len(
&mut self,
direction: FetchOrientation,
) -> Result<Option<(i16, i16)>, Error> {
let mut length_description: i16 = 0;
let mut length_attributes: i16 = 0;
unsafe {
match SQLDriversW(
self.handle,
direction,
null_mut(),
0,
&mut length_description,
null_mut(),
0,
&mut length_attributes,
) {
SqlReturn::NO_DATA => return Ok(None),
other => other.into_result(self)?,
}
Ok(Some((length_description, length_attributes)))
}
}
pub fn data_source_buffer_len(
&mut self,
direction: FetchOrientation,
) -> Result<Option<(i16, i16)>, Error> {
let mut length_name: i16 = 0;
let mut length_description: i16 = 0;
unsafe {
match odbc_sys::SQLDataSourcesW(
self.handle,
direction,
null_mut(),
0,
&mut length_name,
null_mut(),
0,
&mut length_description,
) {
SqlReturn::NO_DATA => return Ok(None),
other => other.into_result(self)?,
}
Ok(Some((length_name, length_description)))
}
}
pub fn data_source_buffer_fill(
&mut self,
direction: FetchOrientation,
buffer_name: &mut Vec<u16>,
buffer_description: &mut Vec<u16>,
) -> Result<bool, Error> {
buffer_name.resize(buffer_name.capacity(), 0);
buffer_description.resize(buffer_description.capacity(), 0);
unsafe {
match SQLDataSourcesW(
self.handle,
direction,
buffer_name.as_mut_ptr(),
buffer_name.len().try_into().unwrap(),
null_mut(),
buffer_description.as_mut_ptr(),
buffer_description.len().try_into().unwrap(),
null_mut(),
) {
SqlReturn::NO_DATA => Ok(false),
other => {
other.into_result(self)?;
Ok(true)
}
}
}
}
}