Skip to main content

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, RetryHint};
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(
168        "Ambiguous value column in table '{table_name}', candidates: {field_columns:?}"
169    ))]
170    AmbiguousValueColumn {
171        table_name: String,
172        field_columns: Vec<String>,
173        #[snafu(implicit)]
174        location: Location,
175    },
176
177    #[snafu(display("Unexpected type {data_type} for column '{column}' of table '{table_name}'"))]
178    UnexpectedColumnType {
179        table_name: String,
180        column: String,
181        data_type: String,
182        #[snafu(implicit)]
183        location: Location,
184    },
185
186    #[snafu(display("Failed to collect recordbatch"))]
187    CollectRecordbatch {
188        #[snafu(implicit)]
189        location: Location,
190        source: common_recordbatch::error::Error,
191    },
192
193    #[snafu(display("Failed to plan statement"))]
194    PlanStatement {
195        #[snafu(implicit)]
196        location: Location,
197        source: query::error::Error,
198    },
199
200    #[snafu(display("Failed to read table: {table_name}"))]
201    ReadTable {
202        table_name: String,
203        #[snafu(implicit)]
204        location: Location,
205        source: query::error::Error,
206    },
207
208    #[snafu(display("Failed to execute logical plan"))]
209    ExecLogicalPlan {
210        #[snafu(implicit)]
211        location: Location,
212        source: query::error::Error,
213    },
214
215    #[snafu(display("Not supported: {}", feat))]
216    NotSupported { feat: String },
217
218    #[snafu(display("SQL execution intercepted"))]
219    SqlExecIntercepted {
220        #[snafu(implicit)]
221        location: Location,
222        source: BoxedError,
223    },
224
225    // TODO(ruihang): merge all query execution error kinds
226    #[snafu(display("Failed to execute PromQL query {}", query))]
227    ExecutePromql {
228        query: String,
229        #[snafu(implicit)]
230        location: Location,
231        source: servers::error::Error,
232    },
233
234    #[snafu(display("Failed to create logical plan for prometheus query"))]
235    PromStoreRemoteQueryPlan {
236        #[snafu(implicit)]
237        location: Location,
238        source: servers::error::Error,
239    },
240
241    #[snafu(display("Failed to create logical plan for prometheus metric names query"))]
242    PrometheusMetricNamesQueryPlan {
243        #[snafu(implicit)]
244        location: Location,
245        source: servers::error::Error,
246    },
247
248    #[snafu(display("Failed to create logical plan for prometheus label values query"))]
249    PrometheusLabelValuesQueryPlan {
250        #[snafu(implicit)]
251        location: Location,
252        source: query::promql::error::Error,
253    },
254
255    #[snafu(display("Failed to describe schema for given statement"))]
256    DescribeStatement {
257        #[snafu(implicit)]
258        location: Location,
259        source: query::error::Error,
260    },
261
262    #[snafu(display("Illegal primary keys definition: {}", msg))]
263    IllegalPrimaryKeysDef {
264        msg: String,
265        #[snafu(implicit)]
266        location: Location,
267    },
268
269    #[snafu(display("Failed to insert value into table: {}", table_name))]
270    Insert {
271        table_name: String,
272        #[snafu(implicit)]
273        location: Location,
274        source: table::error::Error,
275    },
276
277    #[snafu(display("Unsupported format: {:?}", format))]
278    UnsupportedFormat {
279        #[snafu(implicit)]
280        location: Location,
281        format: Format,
282    },
283
284    #[snafu(display("Failed to pass permission check"))]
285    Permission {
286        source: auth::error::Error,
287        #[snafu(implicit)]
288        location: Location,
289    },
290
291    #[snafu(display(
292        "No valid default value can be built automatically, column: {}",
293        column,
294    ))]
295    ColumnNoneDefaultValue {
296        column: String,
297        #[snafu(implicit)]
298        location: Location,
299    },
300
301    #[snafu(display("Table operation error"))]
302    TableOperation {
303        source: operator::error::Error,
304        #[snafu(implicit)]
305        location: Location,
306    },
307
308    #[snafu(display("Invalid auth config"))]
309    IllegalAuthConfig { source: auth::error::Error },
310
311    #[snafu(display("Failed to serialize options to TOML"))]
312    TomlFormat {
313        #[snafu(implicit)]
314        location: Location,
315        #[snafu(source(from(common_config::error::Error, Box::new)))]
316        source: Box<common_config::error::Error>,
317    },
318
319    #[snafu(display("Failed to get cache from cache registry: {}", name))]
320    CacheRequired {
321        #[snafu(implicit)]
322        location: Location,
323        name: String,
324    },
325
326    #[snafu(display("Invalid tls config"))]
327    InvalidTlsConfig {
328        #[snafu(source)]
329        error: common_grpc::error::Error,
330        #[snafu(implicit)]
331        location: Location,
332    },
333
334    #[snafu(display("Failed to init plugin"))]
335    // this comment is to bypass the unused snafu check in "check-snafu.py"
336    InitPlugin {
337        #[snafu(implicit)]
338        location: Location,
339        source: BoxedError,
340    },
341
342    #[snafu(display("Failed to decode logical plan from substrait"))]
343    SubstraitDecodeLogicalPlan {
344        #[snafu(implicit)]
345        location: Location,
346        source: common_query::error::Error,
347    },
348
349    #[snafu(display("DataFusionError"))]
350    DataFusion {
351        #[snafu(source)]
352        error: DataFusionError,
353        #[snafu(implicit)]
354        location: Location,
355    },
356
357    #[snafu(display("Query has been cancelled"))]
358    Cancelled {
359        #[snafu(implicit)]
360        location: Location,
361    },
362
363    #[snafu(display("Canceling statement due to statement timeout"))]
364    StatementTimeout {
365        #[snafu(implicit)]
366        location: Location,
367    },
368
369    #[snafu(display("Service suspended"))]
370    Suspended {
371        #[snafu(implicit)]
372        location: Location,
373    },
374}
375
376pub type Result<T> = std::result::Result<T, Error>;
377
378impl ErrorExt for Error {
379    fn status_code(&self) -> StatusCode {
380        match self {
381            Error::TomlFormat { .. }
382            | Error::ParseAddr { .. }
383            | Error::InvalidSql { .. }
384            | Error::InvalidInsertRequest { .. }
385            | Error::InvalidDeleteRequest { .. }
386            | Error::IllegalPrimaryKeysDef { .. }
387            | Error::SchemaExists { .. }
388            | Error::ColumnNotFound { .. }
389            | Error::AmbiguousValueColumn { .. }
390            | Error::UnsupportedFormat { .. }
391            | Error::IllegalAuthConfig { .. }
392            | Error::ColumnNoneDefaultValue { .. }
393            | Error::IncompleteGrpcRequest { .. }
394            | Error::InvalidTlsConfig { .. } => StatusCode::InvalidArguments,
395
396            Error::NotSupported { .. } => StatusCode::Unsupported,
397
398            Error::Permission { source, .. } => source.status_code(),
399
400            Error::DescribeStatement { source, .. } => source.status_code(),
401
402            Error::HandleHeartbeatResponse { source, .. } => source.status_code(),
403
404            Error::PromStoreRemoteQueryPlan { source, .. }
405            | Error::PrometheusMetricNamesQueryPlan { source, .. }
406            | Error::ExecutePromql { source, .. } => source.status_code(),
407
408            Error::SubstraitDecodeLogicalPlan { source, .. } => source.status_code(),
409
410            Error::PrometheusLabelValuesQueryPlan { source, .. } => source.status_code(),
411
412            Error::CollectRecordbatch { source, .. } => source.status_code(),
413
414            Error::SqlExecIntercepted { source, .. } => source.status_code(),
415            Error::StartServer { source, .. } => source.status_code(),
416            Error::ShutdownServer { source, .. } => source.status_code(),
417
418            Error::ParseSql { source, .. } => source.status_code(),
419
420            Error::InvalidateTableCache { source, .. } => source.status_code(),
421
422            Error::Table { source, .. } | Error::Insert { source, .. } => source.status_code(),
423
424            Error::RequestQuery { source, .. } => source.status_code(),
425
426            Error::CacheRequired { .. } | Error::UnexpectedColumnType { .. } => {
427                StatusCode::Internal
428            }
429
430            Error::TableNotFound { .. } => StatusCode::TableNotFound,
431
432            Error::Catalog { source, .. } => source.status_code(),
433
434            Error::CreateMetaHeartbeatStream { source, .. } => source.status_code(),
435
436            Error::PlanStatement { source, .. }
437            | Error::ReadTable { source, .. }
438            | Error::ExecLogicalPlan { source, .. } => source.status_code(),
439
440            Error::External { source, .. } | Error::InitPlugin { source, .. } => {
441                source.status_code()
442            }
443            Error::FindRegionPeer { source, .. } => source.status_code(),
444
445            Error::TableOperation { source, .. } => source.status_code(),
446
447            Error::DataFusion { error, .. } => datafusion_status_code::<Self>(error, None),
448
449            Error::Cancelled { .. } => StatusCode::Cancelled,
450
451            Error::StatementTimeout { .. } => StatusCode::Cancelled,
452
453            Error::Suspended { .. } => StatusCode::Suspended,
454        }
455    }
456
457    fn as_any(&self) -> &dyn Any {
458        self
459    }
460
461    fn retry_hint(&self) -> RetryHint {
462        match self {
463            Error::InvalidateTableCache { source, .. }
464            | Error::HandleHeartbeatResponse { source, .. }
465            | Error::RequestQuery { source, .. } => source.retry_hint(),
466
467            Error::External { source, .. }
468            | Error::SqlExecIntercepted { source, .. }
469            | Error::InitPlugin { source, .. } => source.retry_hint(),
470
471            Error::StartServer { source, .. }
472            | Error::ShutdownServer { source, .. }
473            | Error::ExecutePromql { source, .. }
474            | Error::PromStoreRemoteQueryPlan { source, .. }
475            | Error::PrometheusMetricNamesQueryPlan { source, .. } => source.retry_hint(),
476
477            Error::ParseSql { source, .. } => source.retry_hint(),
478            Error::Catalog { source, .. } => source.retry_hint(),
479            Error::CreateMetaHeartbeatStream { source, .. } => source.retry_hint(),
480            Error::FindRegionPeer { source, .. } => source.retry_hint(),
481            Error::Table { source, .. } => source.retry_hint(),
482            Error::CollectRecordbatch { source, .. } => source.retry_hint(),
483            Error::PlanStatement { source, .. }
484            | Error::ReadTable { source, .. }
485            | Error::ExecLogicalPlan { source, .. }
486            | Error::DescribeStatement { source, .. } => source.retry_hint(),
487            Error::PrometheusLabelValuesQueryPlan { source, .. } => source.retry_hint(),
488            Error::Insert { source, .. } => source.retry_hint(),
489            Error::Permission { source, .. } => source.retry_hint(),
490            Error::TableOperation { source, .. } => source.retry_hint(),
491            Error::IllegalAuthConfig { source, .. } => source.retry_hint(),
492            Error::TomlFormat { source, .. } => source.retry_hint(),
493            Error::InvalidTlsConfig { error, .. } => error.retry_hint(),
494            Error::SubstraitDecodeLogicalPlan { source, .. } => source.retry_hint(),
495
496            _ => RetryHint::NonRetryable,
497        }
498    }
499}
500
501define_into_tonic_status!(Error);
502
503impl From<operator::error::Error> for Error {
504    fn from(e: operator::error::Error) -> Error {
505        Error::TableOperation {
506            source: e,
507            location: Location::default(),
508        }
509    }
510}