1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use crate::*;
use libc::c_void;
use std::{ ptr, cmp, fmt, error, io, ffi::CStr };
const OCI_ERROR_MAXMSG_SIZE : usize = 3072;
const OCI_HTYPE_ENV : u32 = 1;
const OCI_HTYPE_ERROR : u32 = 2;
extern "C" {
fn OCIErrorGet(
hndlp: *const c_void,
recordno: u32,
sqlstate: *const c_void,
errcodep: *mut i32,
bufp: *mut u8,
bufsiz: u32,
hnd_type: u32,
) -> i32;
}
fn get_oracle_error(rc: i32, errhp: *mut c_void, htype: u32) -> (i32, String) {
let mut errcode = rc;
let mut errmsg : Vec<u8> = Vec::with_capacity(OCI_ERROR_MAXMSG_SIZE);
let errmsg_ptr = errmsg.as_mut_ptr();
let res = unsafe {
*errmsg_ptr = 0;
OCIErrorGet(errhp, 1, ptr::null(), &mut errcode, errmsg_ptr, OCI_ERROR_MAXMSG_SIZE as u32, htype)
};
let msg = if res == OCI_SUCCESS {
let msg = unsafe { CStr::from_ptr(errmsg_ptr as *const i8) };
msg.to_string_lossy().trim_end().to_owned()
} else {
match errcode {
OCI_NO_DATA => String::from("No Data"),
OCI_NEED_DATA => String::from("Need Data"),
_ => format!("Error {}", errcode),
}
};
(errcode, msg)
}
macro_rules! catch {
( $err:expr => $( $stmt:stmt );+ ) => {{
let res = unsafe { $($stmt);+ };
match res {
OCI_ERROR | OCI_INVALID_HANDLE => {
return Err( crate::Error::oci($err, res) );
}
_ => {}
}
}};
}
#[derive(Debug)]
pub enum Error {
Interface(String),
Oracle((i32,String))
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Oracle((errcode, errmsg)) => write!(f, "ORA-{:05}: {}", errcode, errmsg),
Error::Interface(errmsg) => write!(f, "{}", errmsg),
}
}
}
impl error::Error for Error {}
impl cmp::PartialEq for Error {
fn eq(&self, other: &Error) -> bool {
match (self, other) {
(Error::Oracle((this_code, _)), Error::Oracle((other_code, _))) =>
this_code == other_code,
(Error::Interface(this_msg), Error::Interface(other_msg)) =>
this_msg == other_msg,
_ =>
false,
}
}
}
impl From<Error> for io::Error {
fn from(err: Error) -> Self {
io::Error::new(io::ErrorKind::Other, err)
}
}
impl Error {
pub(crate) fn new(msg: &str) -> Self {
Error::Interface( msg.to_owned() )
}
pub(crate) fn env(env: *mut OCIEnv, rc: i32) -> Self {
Error::Oracle( get_oracle_error(rc, env as *mut c_void, OCI_HTYPE_ENV) )
}
pub(crate) fn oci(err: *mut OCIError, rc: i32) -> Self {
Error::Oracle( get_oracle_error(rc, err as *mut c_void, OCI_HTYPE_ERROR) )
}
}