use std::fmt::{Debug, Display};
use risingwave_common::array::{ArrayError, ArrayRef};
use risingwave_common::types::{DataType, DatumRef, ToText};
use risingwave_pb::PbFieldNotFound;
use thiserror::Error;
use thiserror_ext::AsReport;
pub type Result<T, E = ExprError> = std::result::Result<T, E>;
pub struct ContextUnavailable(&'static str);
impl ContextUnavailable {
pub fn new(field: &'static str) -> Self {
Self(field)
}
}
impl From<ContextUnavailable> for ExprError {
fn from(e: ContextUnavailable) -> Self {
ExprError::Context(e.0)
}
}
#[derive(Error, Debug)]
pub enum ExprError {
#[error("multiple errors:\n{1}")]
Multiple(ArrayRef, MultiExprError),
#[error("Unsupported function: {0}")]
UnsupportedFunction(String),
#[error("Unsupported cast: {0} to {1}")]
UnsupportedCast(DataType, DataType),
#[error("Casting to {0} out of range")]
CastOutOfRange(&'static str),
#[error("Numeric out of range")]
NumericOutOfRange,
#[error("Numeric out of range: underflow")]
NumericUnderflow,
#[error("Numeric out of range: overflow")]
NumericOverflow,
#[error("Division by zero")]
DivisionByZero,
#[error("Parse error: {0}")]
Parse(Box<str>),
#[error("Invalid parameter {name}: {reason}")]
InvalidParam {
name: &'static str,
reason: Box<str>,
},
#[error("Array error: {0}")]
Array(
#[from]
#[backtrace]
ArrayError,
),
#[error("More than one row returned by {0} used as an expression")]
MaxOneRow(&'static str),
#[error(transparent)]
Internal(
#[from]
#[backtrace]
anyhow::Error,
),
#[error("not a constant")]
NotConstant,
#[error("Context {0} not found")]
Context(&'static str),
#[error("field name must not be null")]
FieldNameNull,
#[error("too few arguments for format()")]
TooFewArguments,
#[error("invalid state: {0}")]
InvalidState(String),
#[error("{0}")]
Custom(String),
#[error("error while evaluating expression `{display}`")]
Function {
display: Box<str>,
#[backtrace]
source: Box<dyn std::error::Error + Send + Sync>,
},
}
static_assertions::const_assert_eq!(std::mem::size_of::<ExprError>(), 40);
impl ExprError {
pub fn function<'a>(
fn_name: &str,
args: impl IntoIterator<Item = DatumRef<'a>>,
source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
) -> Self {
use std::fmt::Write;
let display = {
let mut s = String::new();
write!(s, "{}(", fn_name).unwrap();
for (i, arg) in args.into_iter().enumerate() {
if i > 0 {
write!(s, ", ").unwrap();
}
if let Some(arg) = arg {
let arg = arg.to_text();
if arg.contains('\\') {
write!(s, "E").unwrap();
}
write!(s, "'").unwrap();
for c in arg.chars() {
match c {
'\'' => write!(s, "''").unwrap(),
'\\' => write!(s, "\\\\").unwrap(),
_ => write!(s, "{}", c).unwrap(),
}
}
write!(s, "'").unwrap();
} else {
write!(s, "NULL").unwrap();
}
}
write!(s, ")").unwrap();
s
};
Self::Function {
display: display.into(),
source: source.into(),
}
}
}
impl From<chrono::ParseError> for ExprError {
fn from(e: chrono::ParseError) -> Self {
Self::Parse(e.to_report_string().into())
}
}
impl From<PbFieldNotFound> for ExprError {
fn from(err: PbFieldNotFound) -> Self {
Self::Internal(anyhow::anyhow!(
"Failed to decode prost: field not found `{}`",
err.0
))
}
}
#[derive(Error, Debug)]
pub struct MultiExprError(Box<[ExprError]>);
impl MultiExprError {
pub fn into_first(self) -> ExprError {
self.0.into_vec().into_iter().next().expect("first error")
}
}
impl Display for MultiExprError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (i, e) in self.0.iter().enumerate() {
writeln!(f, "{i}: {}", e.as_report())?;
}
Ok(())
}
}
impl From<Vec<ExprError>> for MultiExprError {
fn from(v: Vec<ExprError>) -> Self {
Self(v.into_boxed_slice())
}
}
impl FromIterator<ExprError> for MultiExprError {
fn from_iter<T: IntoIterator<Item = ExprError>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}
impl IntoIterator for MultiExprError {
type IntoIter = std::vec::IntoIter<ExprError>;
type Item = ExprError;
fn into_iter(self) -> Self::IntoIter {
self.0.into_vec().into_iter()
}
}