Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion scylla-cql/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! This module contains various errors which can be returned by `scylla::Session`

use crate::frame::frame_errors::{FrameError, ParseError};
use crate::frame::frame_errors::{CqlResponseParseError, FrameError, ParseError};
use crate::frame::protocol_features::ProtocolFeatures;
use crate::frame::value::SerializeValuesError;
use crate::types::serialize::SerializationError;
Expand All @@ -21,6 +21,10 @@ pub enum QueryError {
#[error(transparent)]
BadQuery(#[from] BadQuery),

/// Failed to deserialize a CQL response from the server.
#[error(transparent)]
CqlResponseParseError(#[from] CqlResponseParseError),

/// Input/Output error has occurred, connection broken etc.
#[error("IO Error: {0}")]
IoError(Arc<std::io::Error>),
Expand Down Expand Up @@ -381,6 +385,10 @@ pub enum NewSessionError {
#[error(transparent)]
BadQuery(#[from] BadQuery),

/// Failed to deserialize a CQL response from the server.
#[error(transparent)]
CqlResponseParseError(#[from] CqlResponseParseError),

/// Input/Output error has occurred, connection broken etc.
#[error("IO Error: {0}")]
IoError(Arc<std::io::Error>),
Expand Down Expand Up @@ -482,6 +490,7 @@ impl From<QueryError> for NewSessionError {
match query_error {
QueryError::DbError(e, msg) => NewSessionError::DbError(e, msg),
QueryError::BadQuery(e) => NewSessionError::BadQuery(e),
QueryError::CqlResponseParseError(e) => NewSessionError::CqlResponseParseError(e),
QueryError::IoError(e) => NewSessionError::IoError(e),
QueryError::ProtocolError(m) => NewSessionError::ProtocolError(m),
QueryError::InvalidMessage(m) => NewSessionError::InvalidMessage(m),
Expand Down
276 changes: 270 additions & 6 deletions scylla-cql/src/frame/frame_errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use super::TryFromPrimitiveError;
use crate::cql_to_rust::CqlTypeError;
use crate::frame::value::SerializeValuesError;
Expand Down Expand Up @@ -45,8 +47,6 @@ pub enum ParseError {
DeserializationError(#[from] DeserializationError),
#[error(transparent)]
IoError(#[from] std::io::Error),
#[error("type not yet implemented, id: {0}")]
TypeNotImplemented(u16),
#[error(transparent)]
SerializeValuesError(#[from] SerializeValuesError),
#[error(transparent)]
Expand All @@ -55,6 +55,264 @@ pub enum ParseError {
CqlTypeError(#[from] CqlTypeError),
}

/// An error type returned when deserialization of CQL
/// server response fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlResponseParseError {
#[error("Failed to deserialize ERROR response: {0}")]
CqlErrorParseError(#[from] CqlErrorParseError),
#[error("Failed to deserialize AUTH_CHALLENGE response: {0}")]
CqlAuthChallengeParseError(#[from] CqlAuthChallengeParseError),
#[error("Failed to deserialize AUTH_SUCCESS response: {0}")]
CqlAuthSuccessParseError(#[from] CqlAuthSuccessParseError),
#[error("Failed to deserialize AUTHENTICATE response: {0}")]
CqlAuthenticateParseError(#[from] CqlAuthenticateParseError),
#[error("Failed to deserialize SUPPORTED response: {0}")]
CqlSupportedParseError(#[from] CqlSupportedParseError),
#[error("Failed to deserialize EVENT response: {0}")]
CqlEventParseError(#[from] CqlEventParseError),
#[error(transparent)]
CqlResultParseError(#[from] CqlResultParseError),
}

/// An error type returned when deserialization of ERROR response fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlErrorParseError {
#[error("Malformed error code: {0}")]
ErrorCodeParseError(LowLevelDeserializationError),
#[error("Malformed error reason: {0}")]
ReasonParseError(LowLevelDeserializationError),
#[error("Malformed error field {field} of DB error {db_error}: {err}")]
MalformedErrorField {
db_error: &'static str,
field: &'static str,
err: LowLevelDeserializationError,
},
}

/// An error type returned when deserialization of AUTH_CHALLENGE response fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlAuthChallengeParseError {
#[error("Malformed authenticate message: {0}")]
AuthMessageParseError(LowLevelDeserializationError),
}

/// An error type returned when deserialization of AUTH_SUCCESS response fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlAuthSuccessParseError {
#[error("Malformed success message: {0}")]
SuccessMessageParseError(LowLevelDeserializationError),
}

/// An error type returned when deserialization of AUTHENTICATE response fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlAuthenticateParseError {
#[error("Malformed authenticator name: {0}")]
AuthNameParseError(LowLevelDeserializationError),
}

/// An error type returned when deserialization of SUPPORTED response fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlSupportedParseError {
#[error("Malformed options map: {0}")]
OptionsMapDeserialization(LowLevelDeserializationError),
}

/// An error type returned when deserialization of RESULT response fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlResultParseError {
#[error("Malformed RESULT response id: {0}")]
ResultIdParseError(LowLevelDeserializationError),
#[error("Unknown RESULT response id: {0}")]
UnknownResultId(i32),
#[error("'Set_keyspace' response deserialization failed: {0}")]
SetKeyspaceParseError(#[from] SetKeyspaceParseError),
// This is an error returned during deserialization of
// `RESULT::Schema_change` response, and not `EVENT` response.
#[error("'Schema_change' response deserialization failed: {0}")]
SchemaChangeParseError(#[from] SchemaChangeEventParseError),
#[error("'Prepared' response deserialization failed: {0}")]
PreparedParseError(#[from] PreparedParseError),
#[error("'Rows' response deserialization failed: {0}")]
RowsParseError(#[from] RowsParseError),
}

#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum SetKeyspaceParseError {
#[error("Malformed keyspace name: {0}")]
MalformedKeyspaceName(#[from] LowLevelDeserializationError),
}

/// An error type returned when deserialization of
/// `EVENT` response fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlEventParseError {
#[error("Malformed event type string: {0}")]
EventTypeParseError(LowLevelDeserializationError),
#[error("Unknown event type: {0}")]
UnknownEventType(String),
#[error("Failed to deserialize schema change event: {0}")]
SchemaChangeEventParseError(#[from] SchemaChangeEventParseError),
#[error("Failed to deserialize topology change event: {0}")]
TopologyChangeEventParseError(ClusterChangeEventParseError),
#[error("Failed to deserialize status change event: {0}")]
StatusChangeEventParseError(ClusterChangeEventParseError),
}

/// An error type returned when deserialization of
/// SchemaChangeEvent fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum SchemaChangeEventParseError {
#[error("Malformed schema change type string: {0}")]
TypeOfChangeParseError(LowLevelDeserializationError),
#[error("Malformed schema change target string:: {0}")]
TargetTypeParseError(LowLevelDeserializationError),
#[error("Malformed name of keyspace affected by schema change: {0}")]
AffectedKeyspaceParseError(LowLevelDeserializationError),
#[error("Malformed name of the table affected by schema change: {0}")]
AffectedTableNameParseError(LowLevelDeserializationError),
#[error("Malformed name of the target affected by schema change: {0}")]
AffectedTargetNameParseError(LowLevelDeserializationError),
#[error(
"Malformed number of arguments of the function/aggregate affected by schema change: {0}"
)]
ArgumentCountParseError(LowLevelDeserializationError),
#[error("Malformed argument of the function/aggregate affected by schema change: {0}")]
FunctionArgumentParseError(LowLevelDeserializationError),
#[error("Unknown target of schema change: {0}")]
UnknownTargetOfSchemaChange(String),
}

/// An error type returned when deserialization of [Status/Topology]ChangeEvent fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum ClusterChangeEventParseError {
#[error("Malformed type of change: {0}")]
TypeOfChangeParseError(LowLevelDeserializationError),
#[error("Malformed node address: {0}")]
NodeAddressParseError(LowLevelDeserializationError),
#[error("Unknown type of change: {0}")]
UnknownTypeOfChange(String),
}

/// An error type returned when deserialization
/// of `RESULT::`Prepared` response fails.
#[non_exhaustive]
#[derive(Debug, Error, Clone)]
pub enum PreparedParseError {
#[error("Malformed prepared statement's id length: {0}")]
IdLengthParseError(LowLevelDeserializationError),
#[error("Invalid result metadata: {0}")]
ResultMetadataParseError(ResultMetadataParseError),
#[error("Invalid prepared metadata: {0}")]
PreparedMetadataParseError(ResultMetadataParseError),
}

/// An error type returned when deserialization
/// of `RESULT::Rows` response fails.
#[non_exhaustive]
#[derive(Debug, Error, Clone)]
pub enum RowsParseError {
#[error("Invalid result metadata: {0}")]
ResultMetadataParseError(#[from] ResultMetadataParseError),
#[error("Invalid result metadata, server claims {col_count} columns, received {col_specs_count} col specs.")]
ColumnCountMismatch {
col_count: usize,
col_specs_count: usize,
},
#[error("Malformed rows count: {0}")]
RowsCountParseError(LowLevelDeserializationError),
#[error("Data deserialization failed: {0}")]
DataDeserializationError(#[from] DeserializationError),
}

/// An error type returned when deserialization
/// of `[Result/Prepared]Metadata` failed.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum ResultMetadataParseError {
#[error("Malformed metadata flags: {0}")]
FlagsParseError(LowLevelDeserializationError),
#[error("Malformed column count: {0}")]
ColumnCountParseError(LowLevelDeserializationError),
#[error("Malformed partition key count: {0}")]
PkCountParseError(LowLevelDeserializationError),
#[error("Malformed partition key index: {0}")]
PkIndexParseError(LowLevelDeserializationError),
#[error("Malformed paging state: {0}")]
PagingStateParseError(LowLevelDeserializationError),
#[error("Invalid global table spec: {0}")]
GlobalTableSpecParseError(#[from] TableSpecParseError),
#[error("Invalid column spec: {0}")]
ColumnSpecParseError(#[from] ColumnSpecParseError),
}

/// An error type returned when deserialization
/// of table specification fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum TableSpecParseError {
#[error("Malformed keyspace name: {0}")]
MalformedKeyspaceName(LowLevelDeserializationError),
#[error("Malformed table name: {0}")]
MalformedTableName(LowLevelDeserializationError),
}

/// An error type returned when deserialization
/// of table column specifications fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
#[error("Column spec deserialization failed, column index: {column_index}, error: {kind}")]
pub struct ColumnSpecParseError {
pub column_index: usize,
pub kind: ColumnSpecParseErrorKind,
}

/// The type of error that appeared during deserialization
/// of a column specification.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum ColumnSpecParseErrorKind {
#[error("Invalid table spec: {0}")]
TableSpecParseError(#[from] TableSpecParseError),
#[error("Malformed column name: {0}")]
ColumnNameParseError(#[from] LowLevelDeserializationError),
#[error("Invalid column type: {0}")]
ColumnTypeParseError(#[from] CqlTypeParseError),
}

/// An error type returned when deserialization of CQL type name fails.
#[non_exhaustive]
#[derive(Error, Debug, Clone)]
pub enum CqlTypeParseError {
#[error("Malformed type id: {0}")]
TypeIdParseError(LowLevelDeserializationError),
#[error("Malformed custom type name: {0}")]
CustomTypeNameParseError(LowLevelDeserializationError),
#[error("Malformed name of UDT keyspace: {0}")]
UdtKeyspaceNameParseError(LowLevelDeserializationError),
#[error("Malformed UDT name: {0}")]
UdtNameParseError(LowLevelDeserializationError),
#[error("Malformed UDT fields count: {0}")]
UdtFieldsCountParseError(LowLevelDeserializationError),
#[error("Malformed UDT's field name: {0}")]
UdtFieldNameParseError(LowLevelDeserializationError),
#[error("Malformed tuple length: {0}")]
TupleLengthParseError(LowLevelDeserializationError),
#[error("CQL Type not yet implemented, id: {0}")]
TypeNotImplemented(u16),
}

/// A low level deserialization error.
///
/// This type of error is returned when deserialization
Expand All @@ -66,22 +324,28 @@ pub enum ParseError {
/// - conversion errors - e.g. slice-to-array or primitive-to-enum
/// - not enough bytes in the buffer to deserialize a value
#[non_exhaustive]
#[derive(Error, Debug)]
#[derive(Error, Debug, Clone)]
pub enum LowLevelDeserializationError {
#[error(transparent)]
IoError(#[from] std::io::Error),
IoError(Arc<std::io::Error>),
#[error(transparent)]
TryFromIntError(#[from] std::num::TryFromIntError),
#[error("Failed to convert slice into array: {0}")]
#[error(transparent)]
TryFromSliceError(#[from] std::array::TryFromSliceError),
#[error("Not enough bytes! expected: {expected}, received: {received}")]
TooFewBytesReceived { expected: usize, received: usize },
#[error("Invalid value length: {0}")]
InvalidValueLength(i32),
#[error("Unknown consistency: {0}")]
UnknownConsistency(#[from] TryFromPrimitiveError<u16>),
#[error("Invalid inet bytes length: {0}")]
#[error("Invalid inet bytes length: {0}. Accepted lengths are 4 and 16 bytes.")]
InvalidInetLength(u8),
#[error("UTF8 deserialization failed: {0}")]
UTF8DeserializationError(#[from] std::str::Utf8Error),
}

impl From<std::io::Error> for LowLevelDeserializationError {
fn from(value: std::io::Error) -> Self {
Self::IoError(Arc::new(value))
}
}
22 changes: 15 additions & 7 deletions scylla-cql/src/frame/response/authenticate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::frame::frame_errors::ParseError;
use crate::frame::frame_errors::{
CqlAuthChallengeParseError, CqlAuthSuccessParseError, CqlAuthenticateParseError,
};
use crate::frame::types;

// Implements Authenticate message.
Expand All @@ -8,8 +10,10 @@ pub struct Authenticate {
}

impl Authenticate {
pub fn deserialize(buf: &mut &[u8]) -> Result<Self, ParseError> {
let authenticator_name = types::read_string(buf)?.to_string();
pub fn deserialize(buf: &mut &[u8]) -> Result<Self, CqlAuthenticateParseError> {
let authenticator_name = types::read_string(buf)
.map_err(CqlAuthenticateParseError::AuthNameParseError)?
.to_string();

Ok(Authenticate { authenticator_name })
}
Expand All @@ -21,8 +25,10 @@ pub struct AuthSuccess {
}

impl AuthSuccess {
pub fn deserialize(buf: &mut &[u8]) -> Result<Self, ParseError> {
let success_message = types::read_bytes_opt(buf)?.map(|b| b.to_owned());
pub fn deserialize(buf: &mut &[u8]) -> Result<Self, CqlAuthSuccessParseError> {
let success_message = types::read_bytes_opt(buf)
.map_err(CqlAuthSuccessParseError::SuccessMessageParseError)?
.map(ToOwned::to_owned);

Ok(AuthSuccess { success_message })
}
Expand All @@ -34,8 +40,10 @@ pub struct AuthChallenge {
}

impl AuthChallenge {
pub fn deserialize(buf: &mut &[u8]) -> Result<Self, ParseError> {
let authenticate_message = types::read_bytes_opt(buf)?.map(|b| b.to_owned());
pub fn deserialize(buf: &mut &[u8]) -> Result<Self, CqlAuthChallengeParseError> {
let authenticate_message = types::read_bytes_opt(buf)
.map_err(CqlAuthChallengeParseError::AuthMessageParseError)?
.map(|b| b.to_owned());

Ok(AuthChallenge {
authenticate_message,
Expand Down
Loading