Skip to main content

flow/expr/
error.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Error handling for expression evaluation.
16
17use std::any::Any;
18
19use arrow_schema::ArrowError;
20use common_error::ext::{BoxedError, ErrorExt};
21use common_error::status_code::StatusCode;
22use common_macro::stack_trace_debug;
23use datafusion_common::DataFusionError;
24use datatypes::data_type::ConcreteDataType;
25use snafu::{Location, Snafu};
26
27/// EvalError is about errors happen on columnar evaluation
28///
29/// TODO(discord9): add detailed location of column/operator(instead of code) to errors tp help identify related column
30#[derive(Snafu)]
31#[snafu(visibility(pub))]
32#[stack_trace_debug]
33pub enum EvalError {
34    #[snafu(display("Type mismatch: expected {expected}, actual {actual}"))]
35    TypeMismatch {
36        expected: ConcreteDataType,
37        actual: ConcreteDataType,
38        #[snafu(implicit)]
39        location: Location,
40    },
41
42    /// can't nest datatypes error because EvalError need to be store in map and serialization
43    #[snafu(display("Fail to unpack from value to given type: {msg}"))]
44    TryFromValue {
45        msg: String,
46        #[snafu(implicit)]
47        location: Location,
48    },
49
50    #[snafu(display("Fail to cast value of type {from} to given type {to}"))]
51    CastValue {
52        from: ConcreteDataType,
53        to: ConcreteDataType,
54        source: datatypes::Error,
55        #[snafu(implicit)]
56        location: Location,
57    },
58
59    #[snafu(display("{msg}"))]
60    DataType {
61        msg: String,
62        source: datatypes::Error,
63        #[snafu(implicit)]
64        location: Location,
65    },
66
67    #[snafu(display("Invalid argument: {reason}"))]
68    InvalidArgument {
69        reason: String,
70        #[snafu(implicit)]
71        location: Location,
72    },
73
74    #[snafu(display("Internal error: {reason}"))]
75    Internal {
76        reason: String,
77        #[snafu(implicit)]
78        location: Location,
79    },
80
81    #[snafu(display("Overflowed during evaluation"))]
82    Overflow {
83        #[snafu(implicit)]
84        location: Location,
85    },
86
87    #[snafu(display("Arrow error: {error:?}, context: {context}"))]
88    Arrow {
89        #[snafu(source)]
90        error: ArrowError,
91        context: String,
92        #[snafu(implicit)]
93        location: Location,
94    },
95
96    #[snafu(display("DataFusion error: {error:?}, context: {context}"))]
97    Datafusion {
98        #[snafu(source)]
99        error: DataFusionError,
100        context: String,
101        #[snafu(implicit)]
102        location: Location,
103    },
104
105    #[snafu(display("External error"))]
106    External {
107        #[snafu(implicit)]
108        location: Location,
109        source: BoxedError,
110    },
111}
112
113impl ErrorExt for EvalError {
114    fn status_code(&self) -> StatusCode {
115        use EvalError::*;
116        match self {
117            TypeMismatch { .. }
118            | TryFromValue { .. }
119            | InvalidArgument { .. }
120            | Overflow { .. } => StatusCode::InvalidArguments,
121
122            CastValue { source, .. } | DataType { source, .. } => source.status_code(),
123
124            Internal { .. } | Arrow { .. } | Datafusion { .. } | External { .. } => {
125                StatusCode::Internal
126            }
127        }
128    }
129
130    fn as_any(&self) -> &dyn Any {
131        self
132    }
133}