diff --git a/src/common/error/src/ext.rs b/src/common/error/src/ext.rs index 98bb9a083a..d69e4f1e94 100644 --- a/src/common/error/src/ext.rs +++ b/src/common/error/src/ext.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use crate::status_code::StatusCode; /// Extension to [`Error`](std::error::Error) in std. @@ -11,6 +13,10 @@ pub trait ErrorExt: std::error::Error { // Add `_opt` suffix to avoid confusing with similar method in `std::error::Error`, once backtrace // in std is stable, we can deprecate this method. fn backtrace_opt(&self) -> Option<&crate::snafu::Backtrace>; + + /// Returns the error as [Any](std::any::Any) so that it can be + /// downcast to a specific implementation. + fn as_any(&self) -> &dyn Any; } /// A helper macro to define a opaque boxed error based on errors that implement [ErrorExt] trait. @@ -61,6 +67,10 @@ macro_rules! define_opaque_error { fn backtrace_opt(&self) -> Option<&$crate::snafu::Backtrace> { self.inner.backtrace_opt() } + + fn as_any(&self) -> &dyn std::any::Any { + self.inner.as_any() + } } // Implement ErrorCompat for this opaque error so the backtrace is also available @@ -104,6 +114,10 @@ mod tests { fn backtrace_opt(&self) -> Option<&snafu::Backtrace> { ErrorCompat::backtrace(self) } + + fn as_any(&self) -> &dyn Any { + self + } } impl From for Error { @@ -150,6 +164,8 @@ mod tests { assert_eq!("This is a leaf error, val: 10", err.to_string()); assert_eq!(StatusCode::Internal, err.status_code()); + err.as_any().downcast_ref::().unwrap(); + // Test internal error. let err: Error = throw_internal().map_err(Into::into).err().unwrap(); let msg = format!("{:?}", err); @@ -163,5 +179,7 @@ mod tests { assert!(err.backtrace_opt().is_some()); assert_eq!("This is an internal error", err.to_string()); assert_eq!(StatusCode::Internal, err.status_code()); + + err.as_any().downcast_ref::().unwrap(); } } diff --git a/src/common/error/src/format.rs b/src/common/error/src/format.rs index b994e0aa8b..f4e592dc21 100644 --- a/src/common/error/src/format.rs +++ b/src/common/error/src/format.rs @@ -30,6 +30,8 @@ impl<'a, E: ErrorExt + ?Sized> fmt::Debug for DebugFormat<'a, E> { #[cfg(test)] mod tests { + use std::any::Any; + use snafu::{prelude::*, Backtrace, GenerateImplicitData}; use super::*; @@ -42,6 +44,10 @@ mod tests { fn backtrace_opt(&self) -> Option<&Backtrace> { None } + + fn as_any(&self) -> &dyn Any { + self + } } #[derive(Debug, Snafu)] @@ -54,6 +60,10 @@ mod tests { fn backtrace_opt(&self) -> Option<&Backtrace> { Some(&self.backtrace) } + + fn as_any(&self) -> &dyn Any { + self + } } #[derive(Debug, Snafu)] @@ -68,6 +78,10 @@ mod tests { fn backtrace_opt(&self) -> Option<&Backtrace> { Some(&self.backtrace) } + + fn as_any(&self) -> &dyn Any { + self + } } #[test] diff --git a/src/common/error/src/mock.rs b/src/common/error/src/mock.rs index 8568d87e31..f33dcb88ed 100644 --- a/src/common/error/src/mock.rs +++ b/src/common/error/src/mock.rs @@ -1,5 +1,6 @@ //! Utils for mock. +use std::any::Any; use std::fmt; use snafu::GenerateImplicitData; @@ -51,6 +52,10 @@ impl ErrorExt for MockError { fn backtrace_opt(&self) -> Option<&Backtrace> { self.backtrace.as_ref() } + + fn as_any(&self) -> &dyn Any { + self + } } impl ErrorCompat for MockError { diff --git a/src/datanode/src/error.rs b/src/datanode/src/error.rs index 195f4f0a94..537d5c75dc 100644 --- a/src/datanode/src/error.rs +++ b/src/datanode/src/error.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use common_error::prelude::*; /// Business error of datanode. @@ -36,6 +38,10 @@ impl ErrorExt for Error { fn backtrace_opt(&self) -> Option<&Backtrace> { ErrorCompat::backtrace(self) } + + fn as_any(&self) -> &dyn Any { + self + } } #[cfg(test)] diff --git a/src/query/src/catalog/memory.rs b/src/query/src/catalog/memory.rs index 1245b855b5..5d1eb5aa4a 100644 --- a/src/query/src/catalog/memory.rs +++ b/src/query/src/catalog/memory.rs @@ -31,6 +31,10 @@ impl ErrorExt for InnerError { fn backtrace_opt(&self) -> Option<&Backtrace> { ErrorCompat::backtrace(self) } + + fn as_any(&self) -> &dyn Any { + self + } } impl From for Error { diff --git a/src/query/src/datafusion/error.rs b/src/query/src/datafusion/error.rs index 69c6a01501..7ed2d319f1 100644 --- a/src/query/src/datafusion/error.rs +++ b/src/query/src/datafusion/error.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use common_error::prelude::*; use datafusion::error::DataFusionError; @@ -49,6 +51,10 @@ impl ErrorExt for InnerError { fn backtrace_opt(&self) -> Option<&Backtrace> { ErrorCompat::backtrace(self) } + + fn as_any(&self) -> &dyn Any { + self + } } impl From for Error { diff --git a/src/sql/src/error.rs b/src/sql/src/error.rs index df0219c8d6..5bf2768d90 100644 --- a/src/sql/src/error.rs +++ b/src/sql/src/error.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use common_error::prelude::*; use sqlparser::parser::ParserError; @@ -42,6 +44,10 @@ impl ErrorExt for Error { fn backtrace_opt(&self) -> Option<&Backtrace> { ErrorCompat::backtrace(self) } + + fn as_any(&self) -> &dyn Any { + self + } } #[cfg(test)] diff --git a/src/table/src/error.rs b/src/table/src/error.rs index 9e48a63248..1e9a0f4903 100644 --- a/src/table/src/error.rs +++ b/src/table/src/error.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use common_error::prelude::*; use datafusion::error::DataFusionError; @@ -29,6 +31,10 @@ impl ErrorExt for InnerError { fn backtrace_opt(&self) -> Option<&Backtrace> { ErrorCompat::backtrace(self) } + + fn as_any(&self) -> &dyn Any { + self + } } impl From for Error {