cassandra_proto/frame/
frame_error.rs

1//! This modules contains [Cassandra's errors]
2//! (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011)
3//! which server could respond to client.
4
5use std::io;
6use std::result;
7
8use crate::error;
9use crate::consistency::Consistency;
10use crate::types::*;
11use crate::frame::traits::FromCursor;
12use crate::frame::Frame;
13
14/// CDRS specific `Result` which contains a [`Frame`] in case of `Ok` and `CDRSError` if `Err`.
15///
16/// [`Frame`]: ../frame/struct.Frame.html
17pub type Result = result::Result<Frame, CDRSError>;
18
19/// CDRS error which could be returned by Cassandra server as a response. As it goes
20/// from the specification it contains an error code and an error message. Apart of those
21/// depending of type of error it could contain an additional information about an error.
22/// This additional information is represented by `additional_info` property which is `ErrorKind`.
23#[derive(Debug)]
24pub struct CDRSError {
25    /// `i32` that points to a type of error.
26    pub error_code: CInt,
27    /// Error message string.
28    pub message: CString,
29    /// Additional information.
30    pub additional_info: AdditionalErrorInfo,
31}
32
33impl FromCursor for CDRSError {
34    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<CDRSError> {
35        let error_code = CInt::from_cursor(&mut cursor)?;
36        let message = CString::from_cursor(&mut cursor)?;
37        let additional_info = AdditionalErrorInfo::from_cursor_with_code(&mut cursor, error_code)?;
38
39        Ok(CDRSError { error_code: error_code,
40                       message: message,
41                       additional_info: additional_info, })
42    }
43}
44
45/// Additional error info in accordance to
46/// [Cassandra protocol v4]
47/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011).
48#[derive(Debug)]
49pub enum AdditionalErrorInfo {
50    Server(SimpleError),
51    Protocol(SimpleError),
52    Authentication(SimpleError),
53    Unavailable(UnavailableError),
54    Overloaded(SimpleError),
55    IsBootstrapping(SimpleError),
56    Truncate(SimpleError),
57    WriteTimeout(WriteTimeoutError),
58    ReadTimeout(ReadTimeoutError),
59    ReadFailure(ReadFailureError),
60    FunctionFailure(FunctionFailureError),
61    WriteFailure(WriteFailureError),
62    Syntax(SimpleError),
63    Unauthorized(SimpleError),
64    Invalid(SimpleError),
65    Config(SimpleError),
66    AlreadyExists(AlreadyExistsError),
67    Unprepared(UnpreparedError),
68}
69
70impl AdditionalErrorInfo {
71    pub fn from_cursor_with_code(mut cursor: &mut io::Cursor<&[u8]>,
72                                 error_code: CInt)
73                                 -> error::Result<AdditionalErrorInfo> {
74        match error_code {
75            0x0000 => Ok(AdditionalErrorInfo::Server(SimpleError::from_cursor(
76                &mut cursor,
77            )?)),
78            0x000A => Ok(AdditionalErrorInfo::Protocol(SimpleError::from_cursor(
79                &mut cursor,
80            )?)),
81            0x0100 => Ok(AdditionalErrorInfo::Authentication(
82                SimpleError::from_cursor(&mut cursor)?,
83            )),
84            0x1000 => Ok(AdditionalErrorInfo::Unavailable(
85                UnavailableError::from_cursor(&mut cursor)?,
86            )),
87            0x1001 => Ok(AdditionalErrorInfo::Overloaded(SimpleError::from_cursor(
88                &mut cursor,
89            )?)),
90            0x1002 => Ok(AdditionalErrorInfo::IsBootstrapping(
91                SimpleError::from_cursor(&mut cursor)?,
92            )),
93            0x1003 => Ok(AdditionalErrorInfo::Truncate(SimpleError::from_cursor(
94                &mut cursor,
95            )?)),
96            0x1100 => Ok(AdditionalErrorInfo::WriteTimeout(
97                WriteTimeoutError::from_cursor(&mut cursor)?,
98            )),
99            0x1200 => Ok(AdditionalErrorInfo::ReadTimeout(
100                ReadTimeoutError::from_cursor(&mut cursor)?,
101            )),
102            0x1300 => Ok(AdditionalErrorInfo::ReadFailure(
103                ReadFailureError::from_cursor(&mut cursor)?,
104            )),
105            0x1400 => Ok(AdditionalErrorInfo::FunctionFailure(
106                FunctionFailureError::from_cursor(&mut cursor)?,
107            )),
108            0x1500 => Ok(AdditionalErrorInfo::WriteFailure(
109                WriteFailureError::from_cursor(&mut cursor)?,
110            )),
111            0x2000 => Ok(AdditionalErrorInfo::Syntax(SimpleError::from_cursor(
112                &mut cursor,
113            )?)),
114            0x2100 => Ok(AdditionalErrorInfo::Unauthorized(
115                SimpleError::from_cursor(&mut cursor)?,
116            )),
117            0x2200 => Ok(AdditionalErrorInfo::Invalid(SimpleError::from_cursor(
118                &mut cursor,
119            )?)),
120            0x2300 => Ok(AdditionalErrorInfo::Config(SimpleError::from_cursor(
121                &mut cursor,
122            )?)),
123            0x2400 => Ok(AdditionalErrorInfo::AlreadyExists(
124                AlreadyExistsError::from_cursor(&mut cursor)?,
125            )),
126            0x2500 => Ok(AdditionalErrorInfo::Unprepared(
127                UnpreparedError::from_cursor(&mut cursor)?,
128            )),
129            code => Err(format!("Unexpected error code received: {}", code).into()),
130        }
131    }
132}
133
134/// Is used if error does not contain any additional info.
135#[derive(Debug)]
136pub struct SimpleError {}
137
138impl FromCursor for SimpleError {
139    fn from_cursor(mut _cursor: &mut io::Cursor<&[u8]>) -> error::Result<SimpleError> {
140        Ok(SimpleError {})
141    }
142}
143
144/// Additional info about
145/// [unavailable exception]
146/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1025)
147#[derive(Debug)]
148pub struct UnavailableError {
149    /// Consistency level of query.
150    pub cl: Consistency,
151    /// Number of nodes that should be available to respect `cl`.
152    pub required: CInt,
153    /// Number of replicas that we were know to be alive.
154    pub alive: CInt,
155}
156
157impl FromCursor for UnavailableError {
158    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnavailableError> {
159        let cl = Consistency::from_cursor(&mut cursor)?;
160        let required = CInt::from_cursor(&mut cursor)?;
161        let alive = CInt::from_cursor(&mut cursor)?;
162
163        Ok(UnavailableError { cl: cl,
164                              required: required,
165                              alive: alive, })
166    }
167}
168
169/// Timeout exception during a write request.
170#[derive(Debug)]
171pub struct WriteTimeoutError {
172    /// Consistency level of query.
173    pub cl: Consistency,
174    /// `i32` representing the number of nodes having acknowledged the request.
175    pub received: CInt,
176    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
177    pub blockfor: CInt,
178    /// Describes the type of the write that timed out
179    pub write_type: WriteType,
180}
181
182impl FromCursor for WriteTimeoutError {
183    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteTimeoutError> {
184        let cl = Consistency::from_cursor(&mut cursor)?;
185        let received = CInt::from_cursor(&mut cursor)?;
186        let blockfor = CInt::from_cursor(&mut cursor)?;
187        let write_type = WriteType::from_cursor(&mut cursor)?;
188
189        Ok(WriteTimeoutError { cl: cl,
190                               received: received,
191                               blockfor: blockfor,
192                               write_type: write_type, })
193    }
194}
195
196/// Timeout exception during a read request.
197#[derive(Debug)]
198pub struct ReadTimeoutError {
199    /// Consistency level of query.
200    pub cl: Consistency,
201    /// `i32` representing the number of nodes having acknowledged the request.
202    pub received: CInt,
203    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
204    pub blockfor: CInt,
205    data_present: u8,
206}
207
208impl ReadTimeoutError {
209    /// Shows if replica has resonded to a query.
210    pub fn replica_has_responded(&self) -> bool {
211        self.data_present != 0
212    }
213}
214
215impl FromCursor for ReadTimeoutError {
216    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadTimeoutError> {
217        let cl = Consistency::from_cursor(&mut cursor)?;
218        let received = CInt::from_cursor(&mut cursor)?;
219        let blockfor = CInt::from_cursor(&mut cursor)?;
220        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1)?.as_slice())? as u8;
221
222        Ok(ReadTimeoutError { cl: cl,
223                              received: received,
224                              blockfor: blockfor,
225                              data_present: data_present, })
226    }
227}
228
229/// A non-timeout exception during a read request.
230#[derive(Debug)]
231pub struct ReadFailureError {
232    /// Consistency level of query.
233    pub cl: Consistency,
234    /// `i32` representing the number of nodes having acknowledged the request.
235    pub received: CInt,
236    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
237    pub blockfor: CInt,
238    /// Represents the number of nodes that experience a failure while executing the request.
239    pub num_failures: CInt,
240    data_present: u8,
241}
242
243impl ReadFailureError {
244    /// Shows if replica has resonded to a query.
245    pub fn replica_has_responded(&self) -> bool {
246        self.data_present != 0
247    }
248}
249
250impl FromCursor for ReadFailureError {
251    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadFailureError> {
252        let cl = Consistency::from_cursor(&mut cursor)?;
253        let received = CInt::from_cursor(&mut cursor)?;
254        let blockfor = CInt::from_cursor(&mut cursor)?;
255        let num_failures = CInt::from_cursor(&mut cursor)?;
256        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1)?.as_slice())? as u8;
257
258        Ok(ReadFailureError { cl: cl,
259                              received: received,
260                              blockfor: blockfor,
261                              num_failures: num_failures,
262                              data_present: data_present, })
263    }
264}
265
266/// A (user defined) function failed during execution.
267#[derive(Debug)]
268pub struct FunctionFailureError {
269    /// The keyspace of the failed function.
270    pub keyspace: CString,
271    /// The name of the failed function
272    pub function: CString,
273    /// `Vec<CString>` one string for each argument type (as CQL type) of the failed function.
274    pub arg_types: CStringList,
275}
276
277impl FromCursor for FunctionFailureError {
278    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<FunctionFailureError> {
279        let keyspace = CString::from_cursor(&mut cursor)?;
280        let function = CString::from_cursor(&mut cursor)?;
281        let arg_types = CStringList::from_cursor(&mut cursor)?;
282
283        Ok(FunctionFailureError { keyspace: keyspace,
284                                  function: function,
285                                  arg_types: arg_types, })
286    }
287}
288
289/// A non-timeout exception during a write request.
290/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1106)
291#[derive(Debug)]
292pub struct WriteFailureError {
293    /// Consistency of the query having triggered the exception.
294    pub cl: Consistency,
295    /// Represents the number of nodes having answered the request.
296    pub received: CInt,
297    /// Represents the number of replicas whose acknowledgement is required to achieve `cl`.
298    pub blockfor: CInt,
299    /// Represents the number of nodes that experience a failure while executing the request.
300    pub num_failures: CInt,
301    /// describes the type of the write that failed.
302    pub write_type: WriteType,
303}
304
305impl FromCursor for WriteFailureError {
306    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteFailureError> {
307        let cl = Consistency::from_cursor(&mut cursor)?;
308        let received = CInt::from_cursor(&mut cursor)?;
309        let blockfor = CInt::from_cursor(&mut cursor)?;
310        let num_failures = CInt::from_cursor(&mut cursor)?;
311        let write_type = WriteType::from_cursor(&mut cursor)?;
312
313        Ok(WriteFailureError { cl: cl,
314                               received: received,
315                               blockfor: blockfor,
316                               num_failures: num_failures,
317                               write_type: write_type, })
318    }
319}
320
321/// Describes the type of the write that failed.
322/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1118)
323#[derive(Debug)]
324pub enum WriteType {
325    /// The write was a non-batched non-counter write
326    Simple,
327    /// The write was a (logged) batch write.
328    /// If this type is received, it means the batch log
329    /// has been successfully written
330    Batch,
331    /// The write was an unlogged batch. No batch log write has been attempted.
332    UnloggedBatch,
333    /// The write was a counter write (batched or not)
334    Counter,
335    /// The failure occured during the write to the batch log when a (logged) batch
336    /// write was requested.
337    BatchLog,
338}
339
340impl FromCursor for WriteType {
341    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteType> {
342        CString::from_cursor(&mut cursor).and_then(|wt| match wt.as_str() {
343                                                       "SIMPLE" => Ok(WriteType::Simple),
344                                                       "BATCH" => Ok(WriteType::Batch),
345                                                       "UNLOGGED_BATCH" => {
346                                                           Ok(WriteType::UnloggedBatch)
347                                                       }
348                                                       "COUNTER" => Ok(WriteType::Counter),
349                                                       "BATCH_LOG" => Ok(WriteType::BatchLog),
350                                                       _ => Err("Unexpected write type".into()),
351                                                   })
352    }
353}
354
355/// The query attempted to create a keyspace or a table that was already existing.
356/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1140)
357#[derive(Debug)]
358pub struct AlreadyExistsError {
359    /// Represents either the keyspace that already exists,
360    /// or the keyspace in which the table that already exists is.
361    pub ks: CString,
362    /// Represents the name of the table that already exists.
363    pub table: CString,
364}
365
366impl FromCursor for AlreadyExistsError {
367    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<AlreadyExistsError> {
368        let ks = CString::from_cursor(&mut cursor)?;
369        let table = CString::from_cursor(&mut cursor)?;
370
371        Ok(AlreadyExistsError { ks: ks,
372                                table: table, })
373    }
374}
375
376/// Can be thrown while a prepared statement tries to be
377/// executed if the provided prepared statement ID is not known by
378/// this host. [Read more...]
379/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1150)
380#[derive(Debug)]
381pub struct UnpreparedError {
382    /// Unknown ID.
383    pub id: CBytesShort,
384}
385
386impl FromCursor for UnpreparedError {
387    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnpreparedError> {
388        let id = CBytesShort::from_cursor(&mut cursor)?;
389
390        Ok(UnpreparedError { id: id })
391    }
392}