use common::error;
use data::Data;
use error::{ErrorKind, Result};
use odpi::flags::ODPIExecMode;
use odpi::opaque::ODPIStmt;
use odpi::structs::{ODPIQueryInfo, ODPIStmtInfo};
use odpi::{enums, externs};
use query;
use std::convert::TryFrom;
use std::{ptr, slice};
use util::ODPIStr;
use variable::Var;
pub struct Statement {
inner: *mut ODPIStmt,
}
impl Statement {
#[doc(hidden)]
pub fn new(inner: *mut ODPIStmt) -> Self {
Self { inner }
}
#[doc(hidden)]
pub fn inner(&self) -> *mut ODPIStmt {
self.inner
}
pub fn bind_by_name(&self, name: &str, var: &Var) -> Result<()> {
let name_s: ODPIStr = TryFrom::try_from(name)?;
try_dpi!(
externs::dpiStmt_bindByName(self.inner, name_s.ptr(), name_s.len(), var.inner()),
Ok(()),
ErrorKind::Statement("dpiStmt_bindByName".to_string())
)
}
pub fn bind_by_pos(&self, pos: u32, var: &Var) -> Result<()> {
try_dpi!(
externs::dpiStmt_bindByPos(self.inner, pos, var.inner()),
Ok(()),
ErrorKind::Statement("dpiStmt_bindByPos".to_string())
)
}
pub fn bind_value_by_name(
&self,
name: &str,
native_type: enums::ODPINativeTypeNum,
data: &Data,
) -> Result<()> {
let name_s: ODPIStr = TryFrom::try_from(name)?;
try_dpi!(
externs::dpiStmt_bindValueByName(
self.inner,
name_s.ptr(),
name_s.len(),
native_type,
data.inner()
),
Ok(()),
ErrorKind::Statement("dpiStmt_bindValueByName".to_string())
)
}
pub fn bind_value_by_pos(
&self,
pos: u32,
native_type: enums::ODPINativeTypeNum,
data: &Data,
) -> Result<()> {
try_dpi!(
externs::dpiStmt_bindValueByPos(self.inner, pos, native_type, data.inner()),
Ok(()),
ErrorKind::Statement("dpiStmt_bindValueByPos".to_string())
)
}
pub fn close(&self, tag: Option<&str>) -> Result<()> {
let tag_s: ODPIStr = TryFrom::try_from(tag)?;
try_dpi!(
externs::dpiStmt_close(self.inner, tag_s.ptr(), tag_s.len()),
Ok(()),
ErrorKind::Statement("dpiStmt_close".to_string())
)
}
pub fn define_value(
&self,
pos: u32,
oracle_type: enums::ODPIOracleTypeNum,
native_type: enums::ODPINativeTypeNum,
size: Option<u32>,
size_is_bytes: Option<bool>,
) -> Result<()> {
let inner_size = if let Some(sz) = size { sz } else { 0 };
let inner_size_is_bytes = if let Some(szib) = size_is_bytes {
if szib {
1
} else {
0
}
} else {
0
};
try_dpi!(
externs::dpiStmt_defineValue(
self.inner,
pos,
oracle_type,
native_type,
inner_size,
inner_size_is_bytes,
ptr::null_mut()
),
Ok(()),
ErrorKind::Statement("dpiStmt_execute".to_string())
)
}
pub fn execute(&self, mode: ODPIExecMode) -> Result<u32> {
let mut cols_queried = 0;
try_dpi!(
externs::dpiStmt_execute(self.inner, mode, &mut cols_queried),
Ok(cols_queried),
ErrorKind::Statement("dpiStmt_execute".to_string())
)
}
pub fn execute_many(&self, mode: ODPIExecMode, num_iters: u32) -> Result<()> {
try_dpi!(
externs::dpiStmt_executeMany(self.inner, mode, num_iters),
Ok(()),
ErrorKind::Statement("dpiStmt_executeMany".to_string())
)
}
pub fn fetch(&self) -> Result<(bool, u32)> {
let mut found = 0;
let mut buffer_row_index = 0;
try_dpi!(
externs::dpiStmt_fetch(self.inner, &mut found, &mut buffer_row_index),
Ok((found == 1, buffer_row_index)),
ErrorKind::Statement("dpiStmt_fetch".to_string())
)
}
pub fn fetch_rows(&self, max_rows: u32) -> Result<(u32, u32, bool)> {
let mut buffer_row_index = 0;
let mut num_rows_fetched = 0;
let mut more_rows = 0;
try_dpi!(
externs::dpiStmt_fetchRows(
self.inner,
max_rows,
&mut buffer_row_index,
&mut num_rows_fetched,
&mut more_rows
),
Ok((buffer_row_index, num_rows_fetched, more_rows == 1)),
ErrorKind::Statement("dpiStmt_fetchRows".to_string())
)
}
pub fn get_batch_error_count(&self) -> Result<u32> {
let mut count = 0;
try_dpi!(
externs::dpiStmt_getBatchErrorCount(self.inner, &mut count),
Ok(count),
ErrorKind::Statement("dpiStmt_getBatchErrorCount".to_string())
)
}
pub fn get_batch_errors(&self, num_errors: u32) -> Result<Vec<error::Info>> {
let err_ptr = ptr::null_mut();
try_dpi!(
externs::dpiStmt_getBatchErrors(self.inner, num_errors, err_ptr),
{
let err_slice = unsafe { slice::from_raw_parts(err_ptr, num_errors as usize) };
let odpi_vec = Vec::from(err_slice);
let res_vec = odpi_vec.iter().map(|x| (*x).into()).collect();
Ok(res_vec)
},
ErrorKind::Statement("dpiStmt_getBatchErrors".to_string())
)
}
pub fn get_bind_count(&self) -> Result<u32> {
let mut count = 0;
try_dpi!(
externs::dpiStmt_getBindCount(self.inner, &mut count),
Ok(count),
ErrorKind::Statement("dpiStmt_getBindCount".to_string())
)
}
pub fn get_bind_names(&self, num_bind_names: u32) -> Result<Vec<String>> {
let mut actual_num_bind_names = num_bind_names;
let mut names_vec: Vec<*const ::std::os::raw::c_char> =
Vec::with_capacity(num_bind_names as usize);
let mut names_len_vec: Vec<u32> = Vec::with_capacity(num_bind_names as usize);
for _ in 0..num_bind_names {
names_vec.push(ptr::null());
names_len_vec.push(0);
}
try_dpi!(
externs::dpiStmt_getBindNames(
self.inner,
&mut actual_num_bind_names,
names_vec.as_mut_ptr(),
names_len_vec.as_mut_ptr()
),
{
let mut res = Vec::new();
for (idx, (name, name_len)) in
names_vec.iter().zip(names_len_vec.iter()).enumerate()
{
if idx <= actual_num_bind_names as usize {
let name_s = ODPIStr::new(*name, *name_len);
res.push(name_s.into());
}
}
Ok(res)
},
ErrorKind::Statement("dpiStmt_getBindNames".to_string())
)
}
pub fn get_fetch_array_size(&self) -> Result<u32> {
let mut size = 0;
try_dpi!(
externs::dpiStmt_getFetchArraySize(self.inner, &mut size),
Ok(size),
ErrorKind::Statement("dpiStmt_getFetchArraySize".to_string())
)
}
pub fn get_implicit_result(&self) -> Result<()> {
Err(ErrorKind::Statement("Not Implemented!".to_string()).into())
}
pub fn get_info(&self) -> Result<self::Info> {
let mut info: ODPIStmtInfo = Default::default();
try_dpi!(
externs::dpiStmt_getInfo(self.inner, &mut info),
Ok(Info::new(info)),
ErrorKind::Statement("dpiStmt_getInfo".to_string())
)
}
pub fn get_num_query_columns(&self) -> Result<u32> {
let mut cols = 0;
try_dpi!(
externs::dpiStmt_getNumQueryColumns(self.inner, &mut cols),
Ok(cols),
ErrorKind::Statement("dpiStmt_getNumQueryColumns".to_string())
)
}
pub fn get_query_info(&self, pos: u32) -> Result<query::Info> {
let mut qi: ODPIQueryInfo = Default::default();
try_dpi!(
externs::dpiStmt_getQueryInfo(self.inner, pos, &mut qi),
Ok(query::Info::new(qi)),
ErrorKind::Statement("dpiStmt_getQueryInfo".to_string())
)
}
pub fn get_query_value(&self, pos: u32) -> Result<(enums::ODPINativeTypeNum, Data)> {
let mut data = ptr::null_mut();
let mut native_type = 0;
try_dpi!(
externs::dpiStmt_getQueryValue(self.inner, pos, &mut native_type, &mut data),
Ok((native_type.into(), TryFrom::try_from(data)?)),
ErrorKind::Statement("dpiStmt_getQueryValue".to_string())
)
}
pub fn get_row_count(&self) -> Result<u64> {
let mut count = 0;
try_dpi!(
externs::dpiStmt_getRowCount(self.inner, &mut count),
Ok(count),
ErrorKind::Statement("dpiStmt_getRowCount".to_string())
)
}
pub fn get_row_counts(&self) -> Result<Vec<u64>> {
Err(ErrorKind::Statement("Not Implemented!".to_string()).into())
}
pub fn get_subscr_query_id(&self) -> Result<u64> {
Err(ErrorKind::Statement("Not Implemented!".to_string()).into())
}
pub fn scroll(
&self,
mode: enums::ODPIFetchMode,
offset: i32,
row_count_offset: i32,
) -> Result<()> {
try_dpi!(
externs::dpiStmt_scroll(self.inner, mode, offset, row_count_offset),
Ok(()),
ErrorKind::Statement("dpiStmt_scroll".to_string())
)
}
pub fn set_fetch_array_size(&self, _array_size: u32) -> Result<()> {
Err(ErrorKind::Statement("Not Implemented!".to_string()).into())
}
}
impl From<*mut ODPIStmt> for Statement {
fn from(inner: *mut ODPIStmt) -> Self {
Self { inner }
}
}
impl Drop for Statement {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe {
externs::dpiStmt_release(self.inner);
}
}
}
}
pub struct Info {
inner: ODPIStmtInfo,
}
impl Info {
#[doc(hidden)]
pub fn new(inner: ODPIStmtInfo) -> Self {
Self { inner }
}
pub fn is_query(&self) -> bool {
self.inner.is_query == 1
}
pub fn is_plsql(&self) -> bool {
self.inner.is_plsql == 1
}
pub fn is_ddl(&self) -> bool {
self.inner.is_ddl == 1
}
pub fn is_dml(&self) -> bool {
self.inner.is_dml == 1
}
pub fn statement_type(&self) -> enums::ODPIStatementType {
self.inner.statement_type
}
pub fn is_returning(&self) -> bool {
self.inner.is_returning == 1
}
}