frontend/
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_datasource::file_format::Format;
18use common_error::define_into_tonic_status;
19use common_error::ext::{BoxedError, ErrorExt};
20use common_error::status_code::StatusCode;
21use common_macro::stack_trace_debug;
22use common_query::error::datafusion_status_code;
23use datafusion::error::DataFusionError;
24use session::ReadPreference;
25use snafu::{Location, Snafu};
26use store_api::storage::RegionId;
27
28#[derive(Snafu)]
29#[snafu(visibility(pub))]
30#[stack_trace_debug]
31pub enum Error {
32    #[snafu(display("Failed to invalidate table cache"))]
33    InvalidateTableCache {
34        #[snafu(implicit)]
35        location: Location,
36        source: common_meta::error::Error,
37    },
38
39    #[snafu(display("Failed to handle heartbeat response"))]
40    HandleHeartbeatResponse {
41        #[snafu(implicit)]
42        location: Location,
43        source: common_meta::error::Error,
44    },
45
46    #[snafu(display("External error"))]
47    External {
48        #[snafu(implicit)]
49        location: Location,
50        source: BoxedError,
51    },
52
53    #[snafu(display("Failed to query"))]
54    RequestQuery {
55        #[snafu(implicit)]
56        location: Location,
57        source: common_meta::error::Error,
58    },
59
60    #[snafu(display("Failed to start server"))]
61    StartServer {
62        #[snafu(implicit)]
63        location: Location,
64        source: servers::error::Error,
65    },
66
67    #[snafu(display("Failed to shutdown server"))]
68    ShutdownServer {
69        #[snafu(implicit)]
70        location: Location,
71        source: servers::error::Error,
72    },
73
74    #[snafu(display("Failed to parse address {}", addr))]
75    ParseAddr {
76        addr: String,
77        #[snafu(source)]
78        error: std::net::AddrParseError,
79    },
80
81    #[snafu(display("Failed to parse SQL"))]
82    ParseSql {
83        #[snafu(implicit)]
84        location: Location,
85        source: sql::error::Error,
86    },
87
88    #[snafu(display("Invalid SQL, error: {}", err_msg))]
89    InvalidSql {
90        err_msg: String,
91        #[snafu(implicit)]
92        location: Location,
93    },
94
95    #[snafu(display("Incomplete GRPC request: {}", err_msg))]
96    IncompleteGrpcRequest {
97        err_msg: String,
98        #[snafu(implicit)]
99        location: Location,
100    },
101
102    #[snafu(display("Invalid InsertRequest, reason: {}", reason))]
103    InvalidInsertRequest {
104        reason: String,
105        #[snafu(implicit)]
106        location: Location,
107    },
108
109    #[snafu(display("Invalid DeleteRequest, reason: {}", reason))]
110    InvalidDeleteRequest {
111        reason: String,
112        #[snafu(implicit)]
113        location: Location,
114    },
115
116    #[snafu(display("Table not found: {}", table_name))]
117    TableNotFound { table_name: String },
118
119    #[snafu(display("General catalog error"))]
120    Catalog {
121        #[snafu(implicit)]
122        location: Location,
123        source: catalog::error::Error,
124    },
125
126    #[snafu(display("Failed to create heartbeat stream to Metasrv"))]
127    CreateMetaHeartbeatStream {
128        source: meta_client::error::Error,
129        #[snafu(implicit)]
130        location: Location,
131    },
132
133    #[snafu(display(
134        "Failed to find region peer for region id {}, read preference: {}",
135        region_id,
136        read_preference
137    ))]
138    FindRegionPeer {
139        region_id: RegionId,
140        read_preference: ReadPreference,
141        #[snafu(implicit)]
142        location: Location,
143        source: partition::error::Error,
144    },
145
146    #[snafu(display("Schema {} already exists", name))]
147    SchemaExists {
148        name: String,
149        #[snafu(implicit)]
150        location: Location,
151    },
152
153    #[snafu(display("Table occurs error"))]
154    Table {
155        #[snafu(implicit)]
156        location: Location,
157        source: table::error::Error,
158    },
159
160    #[snafu(display("Cannot find column by name: {}", msg))]
161    ColumnNotFound {
162        msg: String,
163        #[snafu(implicit)]
164        location: Location,
165    },
166
167    #[snafu(display("Failed to collect recordbatch"))]
168    CollectRecordbatch {
169        #[snafu(implicit)]
170        location: Location,
171        source: common_recordbatch::error::Error,
172    },
173
174    #[snafu(display("Failed to plan statement"))]
175    PlanStatement {
176        #[snafu(implicit)]
177        location: Location,
178        source: query::error::Error,
179    },
180
181    #[snafu(display("Failed to read table: {table_name}"))]
182    ReadTable {
183        table_name: String,
184        #[snafu(implicit)]
185        location: Location,
186        source: query::error::Error,
187    },
188
189    #[snafu(display("Failed to execute logical plan"))]
190    ExecLogicalPlan {
191        #[snafu(implicit)]
192        location: Location,
193        source: query::error::Error,
194    },
195
196    #[snafu(display("Operation to region server failed"))]
197    InvokeRegionServer {
198        #[snafu(implicit)]
199        location: Location,
200        source: servers::error::Error,
201    },
202
203    #[snafu(display("Not supported: {}", feat))]
204    NotSupported { feat: String },
205
206    #[snafu(display("SQL execution intercepted"))]
207    SqlExecIntercepted {
208        #[snafu(implicit)]
209        location: Location,
210        source: BoxedError,
211    },
212
213    // TODO(ruihang): merge all query execution error kinds
214    #[snafu(display("Failed to execute PromQL query {}", query))]
215    ExecutePromql {
216        query: String,
217        #[snafu(implicit)]
218        location: Location,
219        source: servers::error::Error,
220    },
221
222    #[snafu(display("Failed to create logical plan for prometheus query"))]
223    PromStoreRemoteQueryPlan {
224        #[snafu(implicit)]
225        location: Location,
226        source: servers::error::Error,
227    },
228
229    #[snafu(display("Failed to create logical plan for prometheus metric names query"))]
230    PrometheusMetricNamesQueryPlan {
231        #[snafu(implicit)]
232        location: Location,
233        source: servers::error::Error,
234    },
235
236    #[snafu(display("Failed to create logical plan for prometheus label values query"))]
237    PrometheusLabelValuesQueryPlan {
238        #[snafu(implicit)]
239        location: Location,
240        source: query::promql::error::Error,
241    },
242
243    #[snafu(display("Failed to describe schema for given statement"))]
244    DescribeStatement {
245        #[snafu(implicit)]
246        location: Location,
247        source: query::error::Error,
248    },
249
250    #[snafu(display("Illegal primary keys definition: {}", msg))]
251    IllegalPrimaryKeysDef {
252        msg: String,
253        #[snafu(implicit)]
254        location: Location,
255    },
256
257    #[snafu(display("Failed to insert value into table: {}", table_name))]
258    Insert {
259        table_name: String,
260        #[snafu(implicit)]
261        location: Location,
262        source: table::error::Error,
263    },
264
265    #[snafu(display("Unsupported format: {:?}", format))]
266    UnsupportedFormat {
267        #[snafu(implicit)]
268        location: Location,
269        format: Format,
270    },
271
272    #[snafu(display("Failed to pass permission check"))]
273    Permission {
274        source: auth::error::Error,
275        #[snafu(implicit)]
276        location: Location,
277    },
278
279    #[snafu(display(
280        "No valid default value can be built automatically, column: {}",
281        column,
282    ))]
283    ColumnNoneDefaultValue {
284        column: String,
285        #[snafu(implicit)]
286        location: Location,
287    },
288
289    #[snafu(display("Invalid region request, reason: {}", reason))]
290    InvalidRegionRequest { reason: String },
291
292    #[snafu(display("Table operation error"))]
293    TableOperation {
294        source: operator::error::Error,
295        #[snafu(implicit)]
296        location: Location,
297    },
298
299    #[snafu(display("Invalid auth config"))]
300    IllegalAuthConfig { source: auth::error::Error },
301
302    #[snafu(display("Failed to serialize options to TOML"))]
303    TomlFormat {
304        #[snafu(implicit)]
305        location: Location,
306        #[snafu(source(from(common_config::error::Error, Box::new)))]
307        source: Box<common_config::error::Error>,
308    },
309
310    #[snafu(display("Failed to get cache from cache registry: {}", name))]
311    CacheRequired {
312        #[snafu(implicit)]
313        location: Location,
314        name: String,
315    },
316
317    #[snafu(display("Invalid tls config"))]
318    InvalidTlsConfig {
319        #[snafu(source)]
320        error: common_grpc::error::Error,
321        #[snafu(implicit)]
322        location: Location,
323    },
324
325    #[snafu(display("Failed to init plugin"))]
326    // this comment is to bypass the unused snafu check in "check-snafu.py"
327    InitPlugin {
328        #[snafu(implicit)]
329        location: Location,
330        source: BoxedError,
331    },
332
333    #[snafu(display("Failed to decode logical plan from substrait"))]
334    SubstraitDecodeLogicalPlan {
335        #[snafu(implicit)]
336        location: Location,
337        source: common_query::error::Error,
338    },
339
340    #[snafu(display("DataFusionError"))]
341    DataFusion {
342        #[snafu(source)]
343        error: DataFusionError,
344        #[snafu(implicit)]
345        location: Location,
346    },
347
348    #[snafu(display("Query has been cancelled"))]
349    Cancelled {
350        #[snafu(implicit)]
351        location: Location,
352    },
353
354    #[snafu(display("Canceling statement due to statement timeout"))]
355    StatementTimeout {
356        #[snafu(implicit)]
357        location: Location,
358    },
359
360    #[snafu(display("Failed to acquire more permits from limiter"))]
361    AcquireLimiter {
362        #[snafu(source)]
363        error: tokio::sync::AcquireError,
364        #[snafu(implicit)]
365        location: Location,
366    },
367}
368
369pub type Result<T> = std::result::Result<T, Error>;
370
371impl ErrorExt for Error {
372    fn status_code(&self) -> StatusCode {
373        match self {
374            Error::TomlFormat { .. }
375            | Error::ParseAddr { .. }
376            | Error::InvalidSql { .. }
377            | Error::InvalidInsertRequest { .. }
378            | Error::InvalidDeleteRequest { .. }
379            | Error::IllegalPrimaryKeysDef { .. }
380            | Error::SchemaExists { .. }
381            | Error::ColumnNotFound { .. }
382            | Error::UnsupportedFormat { .. }
383            | Error::IllegalAuthConfig { .. }
384            | Error::ColumnNoneDefaultValue { .. }
385            | Error::IncompleteGrpcRequest { .. }
386            | Error::InvalidTlsConfig { .. } => StatusCode::InvalidArguments,
387
388            Error::NotSupported { .. } => StatusCode::Unsupported,
389
390            Error::Permission { source, .. } => source.status_code(),
391
392            Error::DescribeStatement { source, .. } => source.status_code(),
393
394            Error::HandleHeartbeatResponse { source, .. } => source.status_code(),
395
396            Error::PromStoreRemoteQueryPlan { source, .. }
397            | Error::PrometheusMetricNamesQueryPlan { source, .. }
398            | Error::ExecutePromql { source, .. } => source.status_code(),
399
400            Error::SubstraitDecodeLogicalPlan { source, .. } => source.status_code(),
401
402            Error::PrometheusLabelValuesQueryPlan { source, .. } => source.status_code(),
403
404            Error::CollectRecordbatch { .. } => StatusCode::EngineExecuteQuery,
405
406            Error::SqlExecIntercepted { source, .. } => source.status_code(),
407            Error::StartServer { source, .. } => source.status_code(),
408            Error::ShutdownServer { source, .. } => source.status_code(),
409
410            Error::ParseSql { source, .. } => source.status_code(),
411
412            Error::InvalidateTableCache { source, .. } => source.status_code(),
413
414            Error::Table { source, .. } | Error::Insert { source, .. } => source.status_code(),
415
416            Error::RequestQuery { source, .. } => source.status_code(),
417
418            Error::CacheRequired { .. } => StatusCode::Internal,
419
420            Error::InvalidRegionRequest { .. } => StatusCode::IllegalState,
421
422            Error::TableNotFound { .. } => StatusCode::TableNotFound,
423
424            Error::Catalog { source, .. } => source.status_code(),
425
426            Error::CreateMetaHeartbeatStream { source, .. } => source.status_code(),
427
428            Error::PlanStatement { source, .. }
429            | Error::ReadTable { source, .. }
430            | Error::ExecLogicalPlan { source, .. } => source.status_code(),
431
432            Error::InvokeRegionServer { source, .. } => source.status_code(),
433            Error::External { source, .. } | Error::InitPlugin { source, .. } => {
434                source.status_code()
435            }
436            Error::FindRegionPeer { source, .. } => source.status_code(),
437
438            Error::TableOperation { source, .. } => source.status_code(),
439
440            Error::DataFusion { error, .. } => datafusion_status_code::<Self>(error, None),
441
442            Error::Cancelled { .. } => StatusCode::Cancelled,
443
444            Error::StatementTimeout { .. } => StatusCode::Cancelled,
445
446            Error::AcquireLimiter { .. } => StatusCode::Internal,
447        }
448    }
449
450    fn as_any(&self) -> &dyn Any {
451        self
452    }
453}
454
455define_into_tonic_status!(Error);
456
457impl From<operator::error::Error> for Error {
458    fn from(e: operator::error::Error) -> Error {
459        Error::TableOperation {
460            source: e,
461            location: Location::default(),
462        }
463    }
464}