diff --git a/Cargo.lock b/Cargo.lock index c8be3e154ddd8..c08e776947cca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14299,9 +14299,9 @@ dependencies = [ [[package]] name = "thiserror-ext" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c19760dc47062bca5c1b3699b032111c93802d51ac47660db11b08afc6bad2" +checksum = "ef4323942237f7cc071061f2c5f0db919e6053c2cdf58c6bc974883073429737" dependencies = [ "thiserror 1.0.63", "thiserror-ext-derive", @@ -14309,9 +14309,9 @@ dependencies = [ [[package]] name = "thiserror-ext-derive" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "667c8c48f68021098038115926c64d9950b0582062ae63f7d30638b1168daf03" +checksum = "96541747c50e6c73e094737938f4f5dfaf50c48a31adff4197a3e2a481371674" dependencies = [ "either", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index c260bf8c52932..6f9b85aa5c1ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -163,7 +163,7 @@ parquet = { version = "53.2", features = ["async"] } mysql_async = { version = "0.34", default-features = false, features = [ "default", ] } -thiserror-ext = "0.1.2" +thiserror-ext = { version = "0.2.1", features = ["backtrace"] } tikv-jemalloc-ctl = { git = "https://github.com/risingwavelabs/jemallocator.git", rev = "64a2d9" } tikv-jemallocator = { git = "https://github.com/risingwavelabs/jemallocator.git", features = [ "profiling", diff --git a/src/frontend/src/expr/function_call.rs b/src/frontend/src/expr/function_call.rs index 101bdea17c004..a8a5598b7349e 100644 --- a/src/frontend/src/expr/function_call.rs +++ b/src/frontend/src/expr/function_call.rs @@ -14,10 +14,10 @@ use itertools::Itertools; use risingwave_common::catalog::Schema; -use risingwave_common::error::{bail, def_anyhow_newtype}; use risingwave_common::types::{DataType, ScalarImpl}; use risingwave_common::util::iter_util::ZipEqFast; -use thiserror_ext::AsReport; +use thiserror::Error; +use thiserror_ext::{AsReport, Box, Macro}; use super::type_inference::cast; use super::{infer_some_all, infer_type, CastContext, Expr, ExprImpl, Literal}; @@ -174,7 +174,7 @@ impl FunctionCall { ) -> Result<(), CastError> { // Can only cast to a struct type. let DataType::Struct(t) = &target_type else { - bail!( + bail_cast_error!( "cannot cast type \"{}\" to \"{}\"", func.return_type(), // typically "record" target_type, @@ -191,8 +191,8 @@ impl FunctionCall { func.return_type = target_type; Ok(()) } - std::cmp::Ordering::Less => bail!("input has too few columns"), - std::cmp::Ordering::Greater => bail!("input has too many columns"), + std::cmp::Ordering::Less => bail_cast_error!("input has too few columns"), + std::cmp::Ordering::Greater => bail_cast_error!("input has too many columns"), } } @@ -423,9 +423,14 @@ pub fn is_row_function(expr: &ExprImpl) -> bool { false } -def_anyhow_newtype! { - pub CastError, +#[derive(Error, Debug, Box, Macro)] +#[thiserror_ext(newtype(name = CastError), macro(path = "crate::expr::function_call"))] +#[error("{message}")] +pub struct CastErrorInner { + pub source: Option, + pub message: Box, } + pub type CastResult = Result; impl From for ErrorCode { diff --git a/src/frontend/src/expr/mod.rs b/src/frontend/src/expr/mod.rs index bc36679b3547f..cf1d0cc21879d 100644 --- a/src/frontend/src/expr/mod.rs +++ b/src/frontend/src/expr/mod.rs @@ -14,6 +14,7 @@ use enum_as_inner::EnumAsInner; use fixedbitset::FixedBitSet; +use function_call::bail_cast_error; use futures::FutureExt; use paste::paste; use risingwave_common::array::ListValue; @@ -300,7 +301,7 @@ impl ExprImpl { ))), DataType::Int32 => Ok(self), dt if dt.is_int() => Ok(self.cast_explicit(DataType::Int32)?), - _ => bail!("unsupported input type"), + _ => bail_cast_error!("unsupported input type"), } } diff --git a/src/frontend/src/expr/type_inference/cast.rs b/src/frontend/src/expr/type_inference/cast.rs index 66ad6969ae316..806d13f9fb301 100644 --- a/src/frontend/src/expr/type_inference/cast.rs +++ b/src/frontend/src/expr/type_inference/cast.rs @@ -15,15 +15,13 @@ use std::collections::BTreeMap; use std::sync::LazyLock; -use anyhow::Context; use itertools::Itertools as _; use parse_display::Display; -use risingwave_common::error::bail; use risingwave_common::types::{DataType, DataTypeName}; use risingwave_common::util::iter_util::ZipEqFast; use crate::error::ErrorCode; -use crate::expr::function_call::{CastError, CastResult}; +use crate::expr::function_call::{bail_cast_error, cast_error, CastError, CastResult}; use crate::expr::{Expr as _, ExprImpl, InputRef, Literal}; /// Find the least restrictive type. Used by `VALUES`, `CASE`, `UNION`, etc. @@ -121,7 +119,7 @@ fn canmeh(ok: bool) -> CastResult { if ok { Ok(()) } else { - bail!("") + bail_cast_error!() } } fn cannot() -> CastResult { @@ -144,13 +142,15 @@ pub fn cast(source: &DataType, target: &DataType, allows: CastContext) -> Result } else { canmeh(cast_ok_base(source, target, allows)) } - .with_context(|| { - format!( + .map_err(|inner| { + cast_error!( + source = inner, "cannot cast type \"{}\" to \"{}\" in {:?} context", - source, target, allows + source, + target, + allows ) }) - .map_err(Into::into) } /// Checks whether casting from `source` to `target` is ok in `allows` context. @@ -171,7 +171,7 @@ fn cast_ok_struct(source: &DataType, target: &DataType, allows: CastContext) -> unreachable!("record type should be already processed at this point"); } if lty.len() != rty.len() { - bail!("cannot cast structs of different lengths"); + bail_cast_error!("cannot cast structs of different lengths"); } // ... and all fields are castable lty.types()