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("Division by zero"))]
35    DivisionByZero {
36        #[snafu(implicit)]
37        location: Location,
38    },
39
40    #[snafu(display("Type mismatch: expected {expected}, actual {actual}"))]
41    TypeMismatch {
42        expected: ConcreteDataType,
43        actual: ConcreteDataType,
44        #[snafu(implicit)]
45        location: Location,
46    },
47
48    /// can't nest datatypes error because EvalError need to be store in map and serialization
49    #[snafu(display("Fail to unpack from value to given type: {msg}"))]
50    TryFromValue {
51        msg: String,
52        #[snafu(implicit)]
53        location: Location,
54    },
55
56    #[snafu(display("Fail to cast value of type {from} to given type {to}"))]
57    CastValue {
58        from: ConcreteDataType,
59        to: ConcreteDataType,
60        source: datatypes::Error,
61        #[snafu(implicit)]
62        location: Location,
63    },
64
65    #[snafu(display("{msg}"))]
66    DataType {
67        msg: String,
68        source: datatypes::Error,
69        #[snafu(implicit)]
70        location: Location,
71    },
72
73    #[snafu(display("Invalid argument: {reason}"))]
74    InvalidArgument {
75        reason: String,
76        #[snafu(implicit)]
77        location: Location,
78    },
79
80    #[snafu(display("Internal error: {reason}"))]
81    Internal {
82        reason: String,
83        #[snafu(implicit)]
84        location: Location,
85    },
86
87    #[snafu(display("Optimize error: {reason}"))]
88    Optimize {
89        reason: String,
90        #[snafu(implicit)]
91        location: Location,
92    },
93
94    #[snafu(display("Overflowed during evaluation"))]
95    Overflow {
96        #[snafu(implicit)]
97        location: Location,
98    },
99
100    #[snafu(display("Incoming data already expired by {} ms", expired_by))]
101    DataAlreadyExpired {
102        expired_by: i64,
103        #[snafu(implicit)]
104        location: Location,
105    },
106
107    #[snafu(display("Arrow error: {error:?}, context: {context}"))]
108    Arrow {
109        #[snafu(source)]
110        error: ArrowError,
111        context: String,
112        #[snafu(implicit)]
113        location: Location,
114    },
115
116    #[snafu(display("DataFusion error: {error:?}, context: {context}"))]
117    Datafusion {
118        #[snafu(source)]
119        error: DataFusionError,
120        context: String,
121        #[snafu(implicit)]
122        location: Location,
123    },
124
125    #[snafu(display("External error"))]
126    External {
127        #[snafu(implicit)]
128        location: Location,
129        source: BoxedError,
130    },
131}
132
133impl ErrorExt for EvalError {
134    fn status_code(&self) -> StatusCode {
135        use EvalError::*;
136        match self {
137            DivisionByZero { .. }
138            | TypeMismatch { .. }
139            | TryFromValue { .. }
140            | DataAlreadyExpired { .. }
141            | InvalidArgument { .. }
142            | Overflow { .. } => StatusCode::InvalidArguments,
143
144            CastValue { source, .. } | DataType { source, .. } => source.status_code(),
145
146            Internal { .. }
147            | Optimize { .. }
148            | Arrow { .. }
149            | Datafusion { .. }
150            | External { .. } => StatusCode::Internal,
151        }
152    }
153
154    fn as_any(&self) -> &dyn Any {
155        self
156    }
157}