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