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