Skip to content

Commit

Permalink
Merge pull request #1026 from muzarski/remove_parse_error
Browse files Browse the repository at this point in the history
errors: Replace `ParseError` with `CqlResponseParseError` in `frame::response` module
  • Loading branch information
Lorak-mmk authored Aug 22, 2024
2 parents 45f0288 + 46d639b commit 9dcc2f1
Show file tree
Hide file tree
Showing 10 changed files with 585 additions and 154 deletions.
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

0 comments on commit 9dcc2f1

Please sign in to comment.