use crate::common::traits::*;
use crate::common::{return_codes::MIMER_SUCCESS, traits::GetHandle};
use mimerrust_sys as ffi;
#[doc(hidden)]
use core::cmp::Ordering;
#[doc(hidden)]
use std::{
ffi::{c_void, CString},
fmt,
};
#[derive(Debug)]
pub struct MimerError {
error_code: i32,
error_message: String,
}
impl MimerError {
pub(crate) fn new<T>(handle: &T, error_code: i32) -> MimerError
where
T: GetHandle,
{
if -26999 <= error_code && error_code <= -26000 {
return MimerError::mimer_error_from_code(error_code);
}
let mut ec = -1;
unsafe {
let handle = match handle.get_handle() {
Ok(MimerHandle::Session(session)) => *session as *const _ as *mut c_void,
Ok(MimerHandle::Statement(statement)) => *statement as *const _ as *mut c_void,
Err(ec) => return MimerError::mimer_error_from_code(ec),
};
let c_str_dummy = CString::new("").unwrap();
let dummy_ptr = c_str_dummy.into_raw();
let buffer_size: i32 = ffi::MimerGetError8(handle, &mut ec, dummy_ptr, 0);
let _ = CString::from_raw(dummy_ptr);
match buffer_size.cmp(MIMER_SUCCESS) {
Ordering::Greater => (),
Ordering::Equal => (),
Ordering::Less => return MimerError::mimer_error_from_code(buffer_size),
}
let c_buffer_size: usize = (buffer_size + 1) as usize;
let mut buffer = vec![255u8; c_buffer_size];
buffer[c_buffer_size - 1] = 0;
let c_str = CString::from_vec_unchecked(buffer);
let c_str_ptr = c_str.into_raw();
let rc = ffi::MimerGetError8(handle, &mut ec, c_str_ptr, c_buffer_size);
match rc.cmp(MIMER_SUCCESS) {
Ordering::Greater => (),
Ordering::Equal => (),
Ordering::Less => return MimerError::mimer_error_from_code(rc),
}
let maybe_string = CString::from_raw(c_str_ptr).into_string();
return match maybe_string {
Ok(s) => MimerError {
error_code: ec,
error_message: s,
},
Err(_) => MimerError::mimer_error_from_code(-26001),
};
};
}
pub(crate) fn mimer_error_from_code(ec: i32) -> MimerError {
let em = match ec {
-14006 => String::from("Login failure"),
-18500 => String::from("Database name not found in SQLHOSTS file"),
-24101 => String::from("An illegal sequence of API calls was detected"),
-21028 => {
String::from("Failed to do a LOCAL connection to the server for database <%>")
} -26001 => String::from("Error converting from utf-8 vector of bytes to String"),
-26002 => String::from("Invalid session pointer was returned from C API"),
-26003 => String::from("Connection is dropped"),
-26004 => String::from("Statement is dropped"),
-26005 => String::from("Handle is NULL"),
-26006 => String::from("Wrong number of parameters"),
-26007 => String::from("Could not convert UTF-8 string to CString"),
-26100 => String::from("Failed to get handle, handle is not a connection or statement"),
-26200 => {
String::from("Unsupported type conversion between MimerDatatype and Rust type")
}
-26201 => String::from("Unsupported type in Row::get_type()"),
-26203 => String::from("Invalid parameter type for MimerDatatype-variant"),
-26999 => String::from("Rust error"),
_ => String::from("Unknown error"),
};
MimerError {
error_code: ec,
error_message: em,
}
}
pub fn get_error_code(&self) -> i32 {
self.error_code
}
pub fn get_error_message(&self) -> &String {
&self.error_message
}
}
impl fmt::Display for MimerError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MimerError: {}, {}", self.error_code, self.error_message)
}
}
#[cfg(test)]
mod error_tests {
use super::*;
use crate::common::mimer_options::*;
use crate::statement::*;
use crate::testing::*;
#[test]
fn error_dropping_table() {
let conn = establish_connection();
let err = match conn.execute_statement(&format!("DROP TABLE {}", "non_existing_table")) {
Ok(_) => panic!("Execute statement succeded when it should have failed."),
Err(ec) => MimerError::new(&conn, ec),
};
let ec = err.get_error_code();
assert!(ec == -12501 || ec == -12517); println!("dropping non existing table: : {}", err);
}
#[test]
fn error_dropping_table_utf8() {
let conn = establish_connection();
let err = match conn.execute_statement(&format!("DROP TABLE ÄÄÄÄ")) {
Ok(_) => panic!("Execute statement succeded when it should have failed."),
Err(ec) => MimerError::new(&conn, ec),
};
let ec = err.get_error_code();
assert!(ec == -12501 || ec == -12517); println!("dropping non existing table: : {}", err);
}
#[test]
fn error_creating_table_utf8() {
let conn = establish_connection();
drop_create_table(&conn, "ÄÄÄÄÄÄÄÄ", EXAMPLE_TABLE_COLUMNS);
let err = match conn
.execute_statement(&format!("CREATE TABLE ÄÄÄÄÄÄÄÄ {}", EXAMPLE_TABLE_COLUMNS))
{
Ok(_) => panic!("Execute statement succeded when it should have failed."),
Err(ec) => MimerError::new(&conn, ec),
};
assert_eq!(err.get_error_code(), -12560); println!("error creating table test: {}", err);
}
#[test]
fn error_creating_table() {
let conn = establish_connection();
drop_create_table(&conn, EXAMPLE_TABLE, EXAMPLE_TABLE_COLUMNS);
let err = match conn.execute_statement(&format!(
"CREATE TABLE {} {}",
EXAMPLE_TABLE, EXAMPLE_TABLE_COLUMNS
)) {
Ok(_) => panic!("Execute statement succeded when it should have failed."),
Err(ec) => MimerError::new(&conn, ec),
};
assert_eq!(err.get_error_code(), -12560); println!("error creating table test: {}", err);
}
#[test]
fn error_prepare() {
let mut conn = establish_connection();
let stmnt: Result<Statement, i32>;
let option = CursorMode::Forward;
stmnt = conn.prepare("[an invalid query]", option);
let err = match stmnt {
Ok(_) => panic!("Prepare method succeeded when it should have failed."),
Err(ec) => MimerError::new(&conn, ec),
};
let ec = err.get_error_code();
assert!(ec == -12102 || ec == -12103); println!("error prepare test: {}", err);
}
}