query/promql/
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
15use std::any::Any;
16
17use common_error::ext::ErrorExt;
18use common_error::status_code::StatusCode;
19use common_macro::stack_trace_debug;
20use common_time::timestamp::TimeUnit;
21use datafusion::error::DataFusionError;
22use promql::error::Error as PromqlError;
23use promql_parser::parser::token::TokenType;
24use promql_parser::parser::{Expr as PromExpr, VectorMatchCardinality};
25use snafu::{Location, Snafu};
26
27#[derive(Snafu)]
28#[snafu(visibility(pub))]
29#[stack_trace_debug]
30pub enum Error {
31    #[snafu(display("Unsupported expr type: {}", name))]
32    UnsupportedExpr {
33        name: String,
34        #[snafu(implicit)]
35        location: Location,
36    },
37
38    #[snafu(display("Unsupported vector matches: {:?}", name))]
39    UnsupportedVectorMatch {
40        name: VectorMatchCardinality,
41        #[snafu(implicit)]
42        location: Location,
43    },
44
45    #[snafu(display("Unexpected token: {:?}", token))]
46    UnexpectedToken {
47        token: TokenType,
48        #[snafu(implicit)]
49        location: Location,
50    },
51
52    #[snafu(display("Internal error during building DataFusion plan"))]
53    DataFusionPlanning {
54        #[snafu(source)]
55        error: datafusion::error::DataFusionError,
56        #[snafu(implicit)]
57        location: Location,
58    },
59
60    #[snafu(display("Unexpected plan or expression: {}", desc))]
61    UnexpectedPlanExpr {
62        desc: String,
63        #[snafu(implicit)]
64        location: Location,
65    },
66
67    #[snafu(display("Unknown table type, downcast failed"))]
68    UnknownTable {
69        #[snafu(implicit)]
70        location: Location,
71    },
72
73    #[snafu(display("Cannot find time index column in table {}", table))]
74    TimeIndexNotFound {
75        table: String,
76        #[snafu(implicit)]
77        location: Location,
78    },
79
80    #[snafu(display("Cannot find value columns in table {}", table))]
81    ValueNotFound {
82        table: String,
83        #[snafu(implicit)]
84        location: Location,
85    },
86
87    #[snafu(display("Failed to create PromQL plan node"))]
88    PromqlPlanNode {
89        #[snafu(source)]
90        source: PromqlError,
91        #[snafu(implicit)]
92        location: Location,
93    },
94
95    #[snafu(display(
96        "Cannot accept multiple vector as function input, PromQL expr: {:?}",
97        expr,
98    ))]
99    MultipleVector {
100        expr: PromExpr,
101        #[snafu(implicit)]
102        location: Location,
103    },
104
105    #[snafu(display(
106        "Table (metric) name not found, this indicates a procedure error in PromQL planner"
107    ))]
108    TableNameNotFound {
109        #[snafu(implicit)]
110        location: Location,
111    },
112
113    #[snafu(display("General catalog error: "))]
114    Catalog {
115        #[snafu(implicit)]
116        location: Location,
117        source: catalog::error::Error,
118    },
119
120    #[snafu(display("Expect a range selector, but not found"))]
121    ExpectRangeSelector {
122        #[snafu(implicit)]
123        location: Location,
124    },
125
126    #[snafu(display("Zero range in range selector"))]
127    ZeroRangeSelector {
128        #[snafu(implicit)]
129        location: Location,
130    },
131
132    #[snafu(display(
133        "The end time must be greater than start time, start: {:?}, end: {:?}",
134        start,
135        end
136    ))]
137    InvalidTimeRange {
138        start: i64,
139        end: i64,
140        #[snafu(implicit)]
141        location: Location,
142    },
143
144    #[snafu(display("Cannot find column {col}"))]
145    ColumnNotFound {
146        col: String,
147        #[snafu(implicit)]
148        location: Location,
149    },
150
151    #[snafu(display("Found multiple metric matchers in selector"))]
152    MultipleMetricMatchers {
153        #[snafu(implicit)]
154        location: Location,
155    },
156
157    #[snafu(display("Expect a metric matcher, but not found"))]
158    NoMetricMatcher {
159        #[snafu(implicit)]
160        location: Location,
161    },
162
163    #[snafu(display("Invalid function argument for {}", fn_name))]
164    FunctionInvalidArgument {
165        fn_name: String,
166        #[snafu(implicit)]
167        location: Location,
168    },
169
170    #[snafu(display(
171        "Attempt to combine two tables with different column sets, left: {:?}, right: {:?}",
172        left,
173        right
174    ))]
175    CombineTableColumnMismatch {
176        left: Vec<String>,
177        right: Vec<String>,
178        #[snafu(implicit)]
179        location: Location,
180    },
181
182    #[snafu(display("Multi fields calculation is not supported in {}", operator))]
183    MultiFieldsNotSupported {
184        operator: String,
185        #[snafu(implicit)]
186        location: Location,
187    },
188
189    #[snafu(display("Matcher operator {matcher_op} is not supported for {matcher}"))]
190    UnsupportedMatcherOp {
191        matcher_op: String,
192        matcher: String,
193        #[snafu(implicit)]
194        location: Location,
195    },
196
197    #[snafu(display("Timestamp out of range: {} of {:?}", timestamp, unit))]
198    TimestampOutOfRange {
199        timestamp: i64,
200        unit: TimeUnit,
201        #[snafu(implicit)]
202        location: Location,
203    },
204}
205
206impl ErrorExt for Error {
207    fn status_code(&self) -> StatusCode {
208        use Error::*;
209        match self {
210            TimeIndexNotFound { .. }
211            | ValueNotFound { .. }
212            | UnsupportedExpr { .. }
213            | UnexpectedToken { .. }
214            | MultipleVector { .. }
215            | ExpectRangeSelector { .. }
216            | ZeroRangeSelector { .. }
217            | InvalidTimeRange { .. }
218            | ColumnNotFound { .. }
219            | FunctionInvalidArgument { .. }
220            | UnsupportedVectorMatch { .. }
221            | CombineTableColumnMismatch { .. }
222            | UnexpectedPlanExpr { .. }
223            | UnsupportedMatcherOp { .. }
224            | TimestampOutOfRange { .. } => StatusCode::InvalidArguments,
225
226            UnknownTable { .. } => StatusCode::Internal,
227
228            PromqlPlanNode { source, .. } => source.status_code(),
229
230            DataFusionPlanning { .. } => StatusCode::PlanQuery,
231
232            TableNameNotFound { .. } => StatusCode::TableNotFound,
233
234            MultipleMetricMatchers { .. } | NoMetricMatcher { .. } => StatusCode::InvalidSyntax,
235
236            MultiFieldsNotSupported { .. } => StatusCode::Unsupported,
237            Catalog { source, .. } => source.status_code(),
238        }
239    }
240
241    fn as_any(&self) -> &dyn Any {
242        self
243    }
244}
245
246pub type Result<T> = std::result::Result<T, Error>;
247
248impl From<Error> for DataFusionError {
249    fn from(err: Error) -> Self {
250        DataFusionError::External(Box::new(err))
251    }
252}