diff --git a/scylla/src/client/caching_session.rs b/scylla/src/client/caching_session.rs index 9283638960..fb2348fa9f 100644 --- a/scylla/src/client/caching_session.rs +++ b/scylla/src/client/caching_session.rs @@ -1,7 +1,7 @@ use crate::batch::{Batch, BatchStatement}; #[allow(deprecated)] use crate::client::pager::LegacyRowIterator; -use crate::errors::ExecutionError; +use crate::errors::{ExecutionError, PrepareError}; use crate::prepared_statement::PreparedStatement; use crate::query::Query; #[allow(deprecated)] @@ -276,7 +276,7 @@ where pub async fn add_prepared_statement( &self, query: impl Into<&Query>, - ) -> Result { + ) -> Result { self.add_prepared_statement_owned(query.into().clone()) .await } @@ -284,7 +284,7 @@ where async fn add_prepared_statement_owned( &self, query: impl Into, - ) -> Result { + ) -> Result { let query = query.into(); if let Some(raw) = self.cache.get(&query.contents) { diff --git a/scylla/src/client/session.rs b/scylla/src/client/session.rs index dd2efbcaf1..3fc1f66c71 100644 --- a/scylla/src/client/session.rs +++ b/scylla/src/client/session.rs @@ -15,8 +15,8 @@ use crate::cluster::node::CloudEndpoint; use crate::cluster::node::{InternalKnownNode, KnownNode, NodeRef}; use crate::cluster::{Cluster, ClusterNeatDebug, ClusterState}; use crate::errors::{ - BadQuery, ExecutionError, MetadataError, NewSessionError, ProtocolError, RequestAttemptError, - RequestError, TracingProtocolError, UseKeyspaceError, + BadQuery, ExecutionError, MetadataError, NewSessionError, PrepareError, ProtocolError, + RequestAttemptError, RequestError, TracingProtocolError, UseKeyspaceError, }; use crate::frame::response::result; #[cfg(feature = "ssl")] @@ -1300,7 +1300,7 @@ where pub async fn prepare( &self, query: impl Into, - ) -> Result { + ) -> Result { let query = query.into(); let query_ref = &query; @@ -1319,12 +1319,12 @@ where let first_ok: Result = results.by_ref().find_or_first(Result::is_ok).unwrap(); let mut prepared: PreparedStatement = - first_ok.map_err(RequestAttemptError::into_execution_error)?; + first_ok.map_err(|first_attempt| PrepareError::AllAttemptsFailed { first_attempt })?; // Validate prepared ids equality for statement in results.flatten() { if prepared.get_id() != statement.get_id() { - return Err(ProtocolError::PreparedStatementIdsMismatch.into()); + return Err(PrepareError::PreparedStatementIdsMismatch); } // Collect all tracing ids from prepare() queries in the final result diff --git a/scylla/src/cluster/state.rs b/scylla/src/cluster/state.rs index e205332236..494ee0afb2 100644 --- a/scylla/src/cluster/state.rs +++ b/scylla/src/cluster/state.rs @@ -1,4 +1,4 @@ -use crate::errors::{BadQuery, ExecutionError}; +use crate::errors::{BadQuery, ConnectionPoolError}; use crate::network::{Connection, PoolConfig, VerifiedKeyspaceName}; use crate::policies::host_filter::HostFilter; use crate::prepared_statement::TokenCalculationError; @@ -268,7 +268,7 @@ impl ClusterState { /// Returns nonempty iterator of working connections to all shards. pub(crate) fn iter_working_connections( &self, - ) -> Result> + '_, ExecutionError> { + ) -> Result> + '_, ConnectionPoolError> { // The returned iterator is nonempty by nonemptiness invariant of `self.known_peers`. assert!(!self.known_peers.is_empty()); let mut peers_iter = self.known_peers.values(); diff --git a/scylla/src/errors.rs b/scylla/src/errors.rs index 8488c6d774..8dfd3333c2 100644 --- a/scylla/src/errors.rs +++ b/scylla/src/errors.rs @@ -44,6 +44,11 @@ use crate::response::query_result::{IntoRowsResultError, SingleRowError}; #[non_exhaustive] #[allow(deprecated)] pub enum ExecutionError { + /// Failed to prepare the statement. + /// Applies to unprepared statements with non-empty value parameters. + #[error("Failed to prepare the statement: {0}")] + PrepareError(#[from] PrepareError), + /// Database sent a response containing some error with a message #[error("Database returned an error: {0}, Error message: {1}")] DbError(DbError, String), @@ -150,6 +155,25 @@ impl From for ExecutionError { } } +/// An error returned by [`Session::prepare()`][crate::client::session::Session::prepare]. +#[derive(Error, Debug, Clone)] +#[non_exhaustive] +pub enum PrepareError { + /// Failed to find a node with working connection pool. + #[error("Failed to find a node with working connection pool: {0}")] + ConnectionPoolError(#[from] ConnectionPoolError), + + /// Failed to prepare statement on every connection from the pool. + #[error("Preparation failed on every connection from the selected pool. First attempt error: {first_attempt}")] + AllAttemptsFailed { first_attempt: RequestAttemptError }, + + /// Prepared statement id mismatch. + #[error( + "Prepared statement id mismatch between multiple connections - all result ids should be equal." + )] + PreparedStatementIdsMismatch, +} + /// Error that occurred during session creation #[derive(Error, Debug, Clone)] #[non_exhaustive] @@ -188,12 +212,6 @@ pub enum ProtocolError { )] UnexpectedResponse(CqlResponseKind), - /// Prepared statement id mismatch. - #[error( - "Prepared statement id mismatch between multiple connections - all result ids should be equal." - )] - PreparedStatementIdsMismatch, - /// Prepared statement id changed after repreparation. #[error( "Prepared statement id changed after repreparation; md5 sum (computed from the query string) should stay the same;\