use crate::binding::dpiContext_getError;
use crate::binding::dpiErrorInfo;
use crate::to_rust_str;
use crate::AssertSend;
use crate::AssertSync;
use crate::Context;
use std::error;
use std::ffi::CStr;
use std::fmt;
use std::num;
use std::str;
use std::sync;
use try_from;
pub enum Error {
OciError(DbError),
DpiError(DbError),
NullValue,
ParseError(Box<dyn error::Error + Send + Sync>),
OutOfRange(String),
InvalidTypeConversion(String, String),
InvalidBindIndex(usize),
InvalidBindName(String),
InvalidColumnIndex(usize),
InvalidColumnName(String),
InvalidAttributeName(String),
InvalidOperation(String),
UninitializedBindValue,
NoDataFound,
InternalError(String),
}
impl AssertSend for Error {}
impl AssertSync for Error {}
#[derive(Eq, PartialEq, Clone)]
pub struct ParseOracleTypeError {
typename: &'static str,
}
impl ParseOracleTypeError {
pub fn new(typename: &'static str) -> ParseOracleTypeError {
ParseOracleTypeError { typename: typename }
}
}
impl fmt::Display for ParseOracleTypeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} parse error", self.typename)
}
}
impl fmt::Debug for ParseOracleTypeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ParseOracleTypeError")
}
}
impl error::Error for ParseOracleTypeError {
fn description(&self) -> &str {
"Oracle type parse error"
}
fn cause(&self) -> Option<&dyn error::Error> {
None
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct DbError {
code: i32,
offset: u16,
message: String,
fn_name: String,
action: String,
}
impl DbError {
pub fn new(
code: i32,
offset: u16,
message: String,
fn_name: String,
action: String,
) -> DbError {
DbError {
code: code,
offset: offset,
message: message,
fn_name: fn_name,
action: action,
}
}
pub fn code(&self) -> i32 {
self.code
}
pub fn offset(&self) -> u16 {
self.offset
}
pub fn message(&self) -> &str {
&self.message
}
pub fn fn_name(&self) -> &str {
&self.fn_name
}
pub fn action(&self) -> &str {
&self.action
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::OciError(ref err) => write!(f, "OCI Error: {}", err.message),
Error::DpiError(ref err) => write!(f, "DPI Error: {}", err.message),
Error::NullValue => write!(f, "NULL value found"),
Error::ParseError(ref err) => write!(f, "{}", err),
Error::OutOfRange(ref msg) => write!(f, "out of range: {}", msg),
Error::InvalidTypeConversion(ref from, ref to) => {
write!(f, "invalid type conversion from {} to {}", from, to)
}
Error::InvalidBindIndex(ref idx) => {
write!(f, "invalid bind index (one-based): {}", idx)
}
Error::InvalidBindName(ref name) => write!(f, "invalid bind name: {}", name),
Error::InvalidColumnIndex(ref idx) => {
write!(f, "invalid column index (zero-based): {}", idx)
}
Error::InvalidColumnName(ref name) => write!(f, "invalid column name: {}", name),
Error::InvalidAttributeName(ref name) => write!(f, "invalid attribute name: {}", name),
Error::InvalidOperation(ref msg) => write!(f, "invalid operation: {}", msg),
Error::UninitializedBindValue => write!(f, "Try to access uninitialized bind value"),
Error::NoDataFound => write!(f, "No data found"),
Error::InternalError(ref msg) => write!(f, "Internal Error: {}", msg),
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::OciError(ref err) => write!(f, "OciError({:?})", err),
Error::DpiError(ref err) => write!(f, "DpiError({:?})", err),
Error::NullValue => write!(f, "NullValue"),
Error::ParseError(ref err) => write!(f, "ParseError({:?})", err),
Error::OutOfRange(ref msg) => write!(f, "OutOfRange({:?})", msg),
Error::InvalidTypeConversion(ref from, ref to) => {
write!(f, "InvalidTypeConversion(from: {:?}, to: {:?})", from, to)
}
Error::InvalidBindIndex(ref idx) => write!(f, "InvalidBindIndex({:?})", idx),
Error::InvalidBindName(ref name) => write!(f, "InvalidBindName({:?})", name),
Error::InvalidColumnIndex(ref idx) => write!(f, "InvalidColumnIndex({:?})", idx),
Error::InvalidColumnName(ref name) => write!(f, "InvalidColumnName({:?})", name),
Error::InvalidAttributeName(ref name) => write!(f, "InvalidAttributeName({:?})", name),
Error::InvalidOperation(ref msg) => write!(f, "InvalidOperation({:?})", msg),
Error::UninitializedBindValue => write!(f, "UninitializedBindValue"),
Error::NoDataFound => write!(f, "NoDataFound"),
Error::InternalError(ref msg) => write!(f, "InternalError({:?})", msg),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::OciError(_) => "Oracle OCI error",
Error::DpiError(_) => "ODPI-C error",
Error::NullValue => "NULL value",
Error::ParseError(_) => "parse error",
Error::OutOfRange(_) => "out of range",
Error::InvalidTypeConversion(_, _) => "invalid type conversion",
Error::InvalidBindIndex(_) => "invalid bind index",
Error::InvalidBindName(_) => "invalid bind name",
Error::InvalidColumnIndex(_) => "invalid column index",
Error::InvalidColumnName(_) => "invalid column name",
Error::InvalidAttributeName(_) => "invalid attribute name",
Error::InvalidOperation(_) => "invalid operation",
Error::UninitializedBindValue => "uninitialided bind value error",
Error::NoDataFound => "no data found",
Error::InternalError(_) => "internal error",
}
}
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
Error::ParseError(ref err) => Some(err.as_ref()),
_ => None,
}
}
}
impl From<ParseOracleTypeError> for Error {
fn from(err: ParseOracleTypeError) -> Self {
Error::ParseError(Box::new(err))
}
}
impl From<num::ParseIntError> for Error {
fn from(err: num::ParseIntError) -> Self {
Error::ParseError(Box::new(err))
}
}
impl From<num::ParseFloatError> for Error {
fn from(err: num::ParseFloatError) -> Self {
Error::ParseError(Box::new(err))
}
}
impl From<try_from::TryFromIntError> for Error {
fn from(err: try_from::TryFromIntError) -> Self {
Error::ParseError(Box::new(err))
}
}
impl From<str::Utf8Error> for Error {
fn from(err: str::Utf8Error) -> Self {
Error::ParseError(Box::new(err))
}
}
impl<T> From<sync::PoisonError<T>> for Error {
fn from(err: sync::PoisonError<T>) -> Self {
Error::InternalError(err.to_string())
}
}
pub fn error_from_dpi_error(err: &dpiErrorInfo) -> Error {
let err = DbError::new(
err.code,
err.offset,
to_rust_str(err.message, err.messageLength),
unsafe { CStr::from_ptr(err.fnName) }
.to_string_lossy()
.into_owned(),
unsafe { CStr::from_ptr(err.action) }
.to_string_lossy()
.into_owned(),
);
if err.message().starts_with("DPI") {
Error::DpiError(err)
} else {
Error::OciError(err)
}
}
pub(crate) fn error_from_context(ctxt: &Context) -> Error {
let mut err: dpiErrorInfo = Default::default();
unsafe {
dpiContext_getError(ctxt.context, &mut err);
};
crate::error::error_from_dpi_error(&err)
}
#[macro_export]
#[doc(hidden)]
macro_rules! chkerr {
($ctxt:expr, $code:expr) => {{
if unsafe { $code } == DPI_SUCCESS as i32 {
()
} else {
return Err($crate::error::error_from_context($ctxt));
}
}};
($ctxt:expr, $code:expr, $cleanup:stmt) => {{
if unsafe { $code } == DPI_SUCCESS as i32 {
()
} else {
let err = $crate::error::error_from_context($ctxt);
$cleanup
return Err(err);
}
}};
}