1use crate::cassandra::consistency::Consistency;
2use crate::cassandra::util::{Protected, ProtectedInner};
3use crate::cassandra::value::ValueType;
4use crate::cassandra::write_type::WriteType;
5
6use crate::cassandra_sys::cass_error_desc;
7use crate::cassandra_sys::cass_error_result_code;
8use crate::cassandra_sys::cass_error_result_free;
9use crate::cassandra_sys::cass_future_error_code;
10use crate::cassandra_sys::cass_future_error_message;
11use crate::cassandra_sys::cass_future_get_error_result;
12use crate::cassandra_sys::CassErrorResult as CassErrorResult_;
13use crate::cassandra_sys::CassError_;
14use crate::cassandra_sys::CassFuture as _Future;
15use crate::cassandra_sys::CASS_OK;
16use crate::cassandra_sys::{
17 cass_error_num_arg_types, cass_error_result_arg_type, cass_error_result_consistency,
18 cass_error_result_data_present, cass_error_result_function, cass_error_result_keyspace,
19 cass_error_result_num_failures, cass_error_result_responses_received,
20 cass_error_result_responses_required, cass_error_result_table, cass_error_result_write_type,
21};
22use crate::cassandra_sys::{cass_false, cass_true};
23use crate::Session;
24
25use std::error::Error as IError;
26use std::ffi::{CStr, CString};
27use std::fmt::{Debug, Display, Formatter};
28use std::os::raw::c_char;
29use std::{fmt, mem, slice, str};
30
31error_chain! {
33 foreign_links {
34 StringContainsNul(::std::ffi::NulError)
35 #[doc = "Attempted to pass a string containing `\\0` to Cassandra"];
36
37 InvalidUtf8(::std::str::Utf8Error)
38 #[doc = "Attempted to decode an invalid UTF-8-encoded string"];
39 }
40
41 errors {
42 CassError(code: CassErrorCode, msg: String) {
44 description("Cassandra error")
45 display("Cassandra error {:?}: {}", &code, &msg)
46 }
47
48 BatchSessionMismatch {
50 description("Batch cannot add a statement belonging to another session.")
51 display("Batch session mismatch")
52 }
53
54 CassErrorResult(
56 code: CassErrorCode,
57 msg: String,
58 consistency: Consistency,
59 actual: i32,
60 required: i32,
61 num_failures: i32,
62 data_present: bool,
63 write_type: WriteType,
64 keyspace: Option<String>,
65 table: Option<String>,
66 function: Option<(String, Vec<String>)>
67 ) {
68 description("Cassandra detailed error")
69 display("Cassandra detailed error {:?}: {}", &code, &msg)
70 }
71
72 UnsupportedType(expected: &'static str, actual: ValueType) {
74 description("Unsupported type")
75 display("Unsupported type {}; expected {}", actual, expected)
76 }
77
78 }
79}
80
81pub(crate) trait CassErrorExt {
83 fn to_result<T>(&self, default: T) -> Result<T>;
85
86 fn to_error(&self) -> Error;
88}
89
90impl CassErrorExt for CassError_ {
91 fn to_result<T>(&self, default: T) -> Result<T> {
92 unsafe {
93 match *self {
94 CASS_OK => Ok(default),
95 _ => {
96 let message = CStr::from_ptr(cass_error_desc(*self))
97 .to_string_lossy()
98 .into_owned();
99 Err(ErrorKind::CassError(CassErrorCode::build(*self), message).into())
100 }
101 }
102 }
103 }
104
105 fn to_error(&self) -> Error {
106 unsafe {
107 let message = CStr::from_ptr(cass_error_desc(*self))
108 .to_string_lossy()
109 .into_owned();
110 ErrorKind::CassError(CassErrorCode::build(*self), message).into()
111 }
112 }
113}
114
115impl CassErrorExt for CassErrorCode {
116 fn to_result<T>(&self, default: T) -> Result<T> {
117 self.inner().to_result(default)
118 }
119 fn to_error(&self) -> Error {
120 self.inner().to_error()
121 }
122}
123
124pub(crate) unsafe fn build_error_result(
126 code: CassErrorCode,
127 message: String,
128 e: *const CassErrorResult_,
129) -> Error {
130 if e.is_null() {
131 ErrorKind::CassError(code, message).into()
133 } else {
134 let consistency = Consistency::build(cass_error_result_consistency(e));
136 let actual = cass_error_result_responses_received(e);
137 let required = cass_error_result_responses_required(e);
140 let num_failures = cass_error_result_num_failures(e);
141 let data_present = cass_error_result_data_present(e) != cass_false;
142 let write_type = WriteType::build(cass_error_result_write_type(e));
143 let keyspace = get_lossy_string(|s, s_len| cass_error_result_keyspace(e, s, s_len));
144 let table = get_lossy_string(|s, s_len| cass_error_result_table(e, s, s_len));
145 let function = get_lossy_string(|s, s_len| cass_error_result_function(e, s, s_len));
146 let function_call = function.map(|function| {
147 let i = cass_error_num_arg_types(e);
148 let mut args = vec![];
149 for i in 0..i {
150 let arg = get_lossy_string(|s, s_len| cass_error_result_arg_type(e, i, s, s_len))
151 .unwrap_or("<error>".to_string());
152 args.push(arg);
153 }
154 (function, args)
155 });
156 cass_error_result_free(e);
157 ErrorKind::CassErrorResult(
158 code,
159 message,
160 consistency,
161 actual,
162 required,
163 num_failures,
164 data_present,
165 write_type,
166 keyspace,
167 table,
168 function_call,
169 )
170 .into()
171 }
172}
173
174pub(crate) unsafe fn get_cass_future_error(rc: CassError_, inner: *mut _Future) -> Error {
176 let code = CassErrorCode::build(rc);
177 let message = get_lossy_string(|s, s_len| {
178 cass_future_error_message(inner, s, s_len);
179 CASS_OK
180 })
181 .unwrap(); build_error_result(code, message, cass_future_get_error_result(inner))
183}
184
185#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
187#[allow(missing_docs)] #[allow(non_camel_case_types)] pub enum CassErrorCode {
190 LIB_BAD_PARAMS,
192 LIB_NO_STREAMS,
193 LIB_UNABLE_TO_INIT,
194 LIB_MESSAGE_ENCODE,
195 LIB_HOST_RESOLUTION,
196 LIB_UNEXPECTED_RESPONSE,
197 LIB_REQUEST_QUEUE_FULL,
198 LIB_NO_AVAILABLE_IO_THREAD,
199 LIB_WRITE_ERROR,
200 LIB_NO_HOSTS_AVAILABLE,
201 LIB_INDEX_OUT_OF_BOUNDS,
202 LIB_INVALID_ITEM_COUNT,
203 LIB_INVALID_VALUE_TYPE,
204 LIB_REQUEST_TIMED_OUT,
205 LIB_UNABLE_TO_SET_KEYSPACE,
206 LIB_CALLBACK_ALREADY_SET,
207 LIB_INVALID_STATEMENT_TYPE,
208 LIB_NAME_DOES_NOT_EXIST,
209 LIB_UNABLE_TO_DETERMINE_PROTOCOL,
210 LIB_NULL_VALUE,
211 LIB_NOT_IMPLEMENTED,
212 LIB_UNABLE_TO_CONNECT,
213 LIB_UNABLE_TO_CLOSE,
214 LIB_NO_PAGING_STATE,
215 LIB_PARAMETER_UNSET,
216 LIB_INVALID_ERROR_RESULT_TYPE,
217 LIB_INVALID_FUTURE_TYPE,
218 LIB_INTERNAL_ERROR,
219 LIB_INVALID_CUSTOM_TYPE,
220 LIB_INVALID_DATA,
221 LIB_NOT_ENOUGH_DATA,
222 LIB_INVALID_STATE,
223 LIB_NO_CUSTOM_PAYLOAD,
224 LIB_EXECUTION_PROFILE_INVALID,
225 SERVER_SERVER_ERROR,
226 SERVER_PROTOCOL_ERROR,
227 SERVER_BAD_CREDENTIALS,
228 SERVER_UNAVAILABLE,
229 SERVER_OVERLOADED,
230 SERVER_IS_BOOTSTRAPPING,
231 SERVER_TRUNCATE_ERROR,
232 SERVER_WRITE_TIMEOUT,
233 SERVER_READ_TIMEOUT,
234 SERVER_READ_FAILURE,
235 SERVER_FUNCTION_FAILURE,
236 SERVER_WRITE_FAILURE,
237 SERVER_SYNTAX_ERROR,
238 SERVER_UNAUTHORIZED,
239 SERVER_INVALID_QUERY,
240 SERVER_CONFIG_ERROR,
241 SERVER_ALREADY_EXISTS,
242 SERVER_UNPREPARED,
243 SSL_INVALID_CERT,
244 SSL_INVALID_PRIVATE_KEY,
245 SSL_NO_PEER_CERT,
246 SSL_INVALID_PEER_CERT,
247 SSL_IDENTITY_MISMATCH,
248 SSL_PROTOCOL_ERROR,
249 }
251
252enhance_nullary_enum!(CassErrorCode, CassError_, {
253 (LIB_BAD_PARAMS, CASS_ERROR_LIB_BAD_PARAMS, "LIB_BAD_PARAMS"),
254 (LIB_NO_STREAMS, CASS_ERROR_LIB_NO_STREAMS, "LIB_NO_STREAMS"),
255 (LIB_UNABLE_TO_INIT, CASS_ERROR_LIB_UNABLE_TO_INIT, "LIB_UNABLE_TO_INIT"),
256 (LIB_MESSAGE_ENCODE, CASS_ERROR_LIB_MESSAGE_ENCODE, "LIB_MESSAGE_ENCODE"),
257 (LIB_HOST_RESOLUTION, CASS_ERROR_LIB_HOST_RESOLUTION, "LIB_HOST_RESOLUTION"),
258 (LIB_UNEXPECTED_RESPONSE, CASS_ERROR_LIB_UNEXPECTED_RESPONSE, "LIB_UNEXPECTED_RESPONSE"),
259 (LIB_REQUEST_QUEUE_FULL, CASS_ERROR_LIB_REQUEST_QUEUE_FULL, "LIB_REQUEST_QUEUE_FULL"),
260 (LIB_NO_AVAILABLE_IO_THREAD, CASS_ERROR_LIB_NO_AVAILABLE_IO_THREAD, "LIB_NO_AVAILABLE_IO_THREAD"),
261 (LIB_WRITE_ERROR, CASS_ERROR_LIB_WRITE_ERROR, "LIB_WRITE_ERROR"),
262 (LIB_NO_HOSTS_AVAILABLE, CASS_ERROR_LIB_NO_HOSTS_AVAILABLE, "LIB_NO_HOSTS_AVAILABLE"),
263 (LIB_INDEX_OUT_OF_BOUNDS, CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS, "LIB_INDEX_OUT_OF_BOUNDS"),
264 (LIB_INVALID_ITEM_COUNT, CASS_ERROR_LIB_INVALID_ITEM_COUNT, "LIB_INVALID_ITEM_COUNT"),
265 (LIB_INVALID_VALUE_TYPE, CASS_ERROR_LIB_INVALID_VALUE_TYPE, "LIB_INVALID_VALUE_TYPE"),
266 (LIB_REQUEST_TIMED_OUT, CASS_ERROR_LIB_REQUEST_TIMED_OUT, "LIB_REQUEST_TIMED_OUT"),
267 (LIB_UNABLE_TO_SET_KEYSPACE, CASS_ERROR_LIB_UNABLE_TO_SET_KEYSPACE, "LIB_UNABLE_TO_SET_KEYSPACE"),
268 (LIB_CALLBACK_ALREADY_SET, CASS_ERROR_LIB_CALLBACK_ALREADY_SET, "LIB_CALLBACK_ALREADY_SET"),
269 (LIB_INVALID_STATEMENT_TYPE, CASS_ERROR_LIB_INVALID_STATEMENT_TYPE, "LIB_INVALID_STATEMENT_TYPE"),
270 (LIB_NAME_DOES_NOT_EXIST, CASS_ERROR_LIB_NAME_DOES_NOT_EXIST, "LIB_NAME_DOES_NOT_EXIST"),
271 (LIB_UNABLE_TO_DETERMINE_PROTOCOL, CASS_ERROR_LIB_UNABLE_TO_DETERMINE_PROTOCOL, "LIB_UNABLE_TO_DETERMINE_PROTOCOL"),
272 (LIB_NULL_VALUE, CASS_ERROR_LIB_NULL_VALUE, "LIB_NULL_VALUE"),
273 (LIB_NOT_IMPLEMENTED, CASS_ERROR_LIB_NOT_IMPLEMENTED, "LIB_NOT_IMPLEMENTED"),
274 (LIB_UNABLE_TO_CONNECT, CASS_ERROR_LIB_UNABLE_TO_CONNECT, "LIB_UNABLE_TO_CONNECT"),
275 (LIB_UNABLE_TO_CLOSE, CASS_ERROR_LIB_UNABLE_TO_CLOSE, "LIB_UNABLE_TO_CLOSE"),
276 (LIB_NO_PAGING_STATE, CASS_ERROR_LIB_NO_PAGING_STATE, "LIB_NO_PAGING_STATE"),
277 (LIB_PARAMETER_UNSET, CASS_ERROR_LIB_PARAMETER_UNSET, "LIB_PARAMETER_UNSET"),
278 (LIB_INVALID_ERROR_RESULT_TYPE, CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE, "LIB_INVALID_ERROR_RESULT_TYPE"),
279 (LIB_INVALID_FUTURE_TYPE, CASS_ERROR_LIB_INVALID_FUTURE_TYPE, "LIB_INVALID_FUTURE_TYPE"),
280 (LIB_INTERNAL_ERROR, CASS_ERROR_LIB_INTERNAL_ERROR, "LIB_INTERNAL_ERROR"),
281 (LIB_INVALID_CUSTOM_TYPE, CASS_ERROR_LIB_INVALID_CUSTOM_TYPE, "LIB_INVALID_CUSTOM_TYPE"),
282 (LIB_INVALID_DATA, CASS_ERROR_LIB_INVALID_DATA, "LIB_INVALID_DATA"),
283 (LIB_NOT_ENOUGH_DATA, CASS_ERROR_LIB_NOT_ENOUGH_DATA, "LIB_NOT_ENOUGH_DATA"),
284 (LIB_INVALID_STATE, CASS_ERROR_LIB_INVALID_STATE, "LIB_INVALID_STATE"),
285 (LIB_NO_CUSTOM_PAYLOAD, CASS_ERROR_LIB_NO_CUSTOM_PAYLOAD, "LIB_NO_CUSTOM_PAYLOAD"),
286 (LIB_EXECUTION_PROFILE_INVALID, CASS_ERROR_LIB_EXECUTION_PROFILE_INVALID, "LIB_EXECUTION_PROFILE_INVALID"),
287 (SERVER_SERVER_ERROR, CASS_ERROR_SERVER_SERVER_ERROR, "SERVER_SERVER_ERROR"),
288 (SERVER_PROTOCOL_ERROR, CASS_ERROR_SERVER_PROTOCOL_ERROR, "SERVER_PROTOCOL_ERROR"),
289 (SERVER_BAD_CREDENTIALS, CASS_ERROR_SERVER_BAD_CREDENTIALS, "SERVER_BAD_CREDENTIALS"),
290 (SERVER_UNAVAILABLE, CASS_ERROR_SERVER_UNAVAILABLE, "SERVER_UNAVAILABLE"),
291 (SERVER_OVERLOADED, CASS_ERROR_SERVER_OVERLOADED, "SERVER_OVERLOADED"),
292 (SERVER_IS_BOOTSTRAPPING, CASS_ERROR_SERVER_IS_BOOTSTRAPPING, "SERVER_IS_BOOTSTRAPPING"),
293 (SERVER_TRUNCATE_ERROR, CASS_ERROR_SERVER_TRUNCATE_ERROR, "SERVER_TRUNCATE_ERROR"),
294 (SERVER_WRITE_TIMEOUT, CASS_ERROR_SERVER_WRITE_TIMEOUT, "SERVER_WRITE_TIMEOUT"),
295 (SERVER_READ_TIMEOUT, CASS_ERROR_SERVER_READ_TIMEOUT, "SERVER_READ_TIMEOUT"),
296 (SERVER_READ_FAILURE, CASS_ERROR_SERVER_READ_FAILURE, "SERVER_READ_FAILURE"),
297 (SERVER_FUNCTION_FAILURE, CASS_ERROR_SERVER_FUNCTION_FAILURE, "SERVER_FUNCTION_FAILURE"),
298 (SERVER_WRITE_FAILURE, CASS_ERROR_SERVER_WRITE_FAILURE, "SERVER_WRITE_FAILURE"),
299 (SERVER_SYNTAX_ERROR, CASS_ERROR_SERVER_SYNTAX_ERROR, "SERVER_SYNTAX_ERROR"),
300 (SERVER_UNAUTHORIZED, CASS_ERROR_SERVER_UNAUTHORIZED, "SERVER_UNAUTHORIZED"),
301 (SERVER_INVALID_QUERY, CASS_ERROR_SERVER_INVALID_QUERY, "SERVER_INVALID_QUERY"),
302 (SERVER_CONFIG_ERROR, CASS_ERROR_SERVER_CONFIG_ERROR, "SERVER_CONFIG_ERROR"),
303 (SERVER_ALREADY_EXISTS, CASS_ERROR_SERVER_ALREADY_EXISTS, "SERVER_ALREADY_EXISTS"),
304 (SERVER_UNPREPARED, CASS_ERROR_SERVER_UNPREPARED, "SERVER_UNPREPARED"),
305 (SSL_INVALID_CERT, CASS_ERROR_SSL_INVALID_CERT, "SSL_INVALID_CERT"),
306 (SSL_INVALID_PRIVATE_KEY, CASS_ERROR_SSL_INVALID_PRIVATE_KEY, "SSL_INVALID_PRIVATE_KEY"),
307 (SSL_NO_PEER_CERT, CASS_ERROR_SSL_NO_PEER_CERT, "SSL_NO_PEER_CERT"),
308 (SSL_INVALID_PEER_CERT, CASS_ERROR_SSL_INVALID_PEER_CERT, "SSL_INVALID_PEER_CERT"),
309 (SSL_IDENTITY_MISMATCH, CASS_ERROR_SSL_IDENTITY_MISMATCH, "SSL_IDENTITY_MISMATCH"),
310 (SSL_PROTOCOL_ERROR, CASS_ERROR_SSL_PROTOCOL_ERROR, "SSL_PROTOCOL_ERROR"),
311}, omit { CASS_OK, CASS_ERROR_LAST_ENTRY });
312
313pub(crate) unsafe fn get_lossy_string<F>(get: F) -> Option<String>
315where
316 F: Fn(*mut *const ::std::os::raw::c_char, *mut usize) -> CassError_,
317{
318 let mut msg = mem::zeroed();
319 let mut msg_len = mem::zeroed();
320 match (get)(&mut msg, &mut msg_len) {
321 CASS_OK => (),
322 _ => return None,
323 }
324 let slice = slice::from_raw_parts(msg as *const u8, msg_len as usize);
325 Some(String::from_utf8_lossy(slice).into_owned())
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331
332 #[test]
333 pub fn test_conversion() {
334 assert_eq!(
335 CassErrorCode::build(CassError_::CASS_ERROR_SERVER_PROTOCOL_ERROR),
336 CassErrorCode::SERVER_PROTOCOL_ERROR
337 );
338 match CassErrorCode::LIB_INVALID_DATA.inner() {
339 CassError_::CASS_ERROR_LIB_INVALID_DATA => (),
340 e => panic!("Unexpected return value {:?}", e),
341 }
342 }
343
344 #[test]
346 #[should_panic(expected = "Unexpected variant CassError_ :: CASS_OK")]
347 pub fn test_omitted_conversion_should_fail() {
348 CassErrorCode::build(CassError_::CASS_OK);
349 }
350}