1use 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 #[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 write retry config: {}", reason))]
327 InvalidWriteRetryConfig {
328 reason: &'static str,
329 #[snafu(implicit)]
330 location: Location,
331 },
332
333 #[snafu(display("Invalid tls config"))]
334 InvalidTlsConfig {
335 #[snafu(source)]
336 error: common_grpc::error::Error,
337 #[snafu(implicit)]
338 location: Location,
339 },
340
341 #[snafu(display("Failed to init plugin"))]
342 InitPlugin {
344 #[snafu(implicit)]
345 location: Location,
346 source: BoxedError,
347 },
348
349 #[snafu(display("Failed to decode logical plan from substrait"))]
350 SubstraitDecodeLogicalPlan {
351 #[snafu(implicit)]
352 location: Location,
353 source: common_query::error::Error,
354 },
355
356 #[snafu(display("DataFusionError"))]
357 DataFusion {
358 #[snafu(source)]
359 error: DataFusionError,
360 #[snafu(implicit)]
361 location: Location,
362 },
363
364 #[snafu(display("Query has been cancelled"))]
365 Cancelled {
366 #[snafu(implicit)]
367 location: Location,
368 },
369
370 #[snafu(display("Canceling statement due to statement timeout"))]
371 StatementTimeout {
372 #[snafu(implicit)]
373 location: Location,
374 },
375
376 #[snafu(display("Service suspended"))]
377 Suspended {
378 #[snafu(implicit)]
379 location: Location,
380 },
381}
382
383pub type Result<T> = std::result::Result<T, Error>;
384
385impl ErrorExt for Error {
386 fn status_code(&self) -> StatusCode {
387 match self {
388 Error::TomlFormat { .. }
389 | Error::ParseAddr { .. }
390 | Error::InvalidSql { .. }
391 | Error::InvalidInsertRequest { .. }
392 | Error::InvalidDeleteRequest { .. }
393 | Error::IllegalPrimaryKeysDef { .. }
394 | Error::SchemaExists { .. }
395 | Error::ColumnNotFound { .. }
396 | Error::AmbiguousValueColumn { .. }
397 | Error::UnsupportedFormat { .. }
398 | Error::IllegalAuthConfig { .. }
399 | Error::ColumnNoneDefaultValue { .. }
400 | Error::IncompleteGrpcRequest { .. }
401 | Error::InvalidTlsConfig { .. }
402 | Error::InvalidWriteRetryConfig { .. } => StatusCode::InvalidArguments,
403
404 Error::NotSupported { .. } => StatusCode::Unsupported,
405
406 Error::Permission { source, .. } => source.status_code(),
407
408 Error::DescribeStatement { source, .. } => source.status_code(),
409
410 Error::HandleHeartbeatResponse { source, .. } => source.status_code(),
411
412 Error::PromStoreRemoteQueryPlan { source, .. }
413 | Error::PrometheusMetricNamesQueryPlan { source, .. }
414 | Error::ExecutePromql { source, .. } => source.status_code(),
415
416 Error::SubstraitDecodeLogicalPlan { source, .. } => source.status_code(),
417
418 Error::PrometheusLabelValuesQueryPlan { source, .. } => source.status_code(),
419
420 Error::CollectRecordbatch { source, .. } => source.status_code(),
421
422 Error::SqlExecIntercepted { source, .. } => source.status_code(),
423 Error::StartServer { source, .. } => source.status_code(),
424 Error::ShutdownServer { source, .. } => source.status_code(),
425
426 Error::ParseSql { source, .. } => source.status_code(),
427
428 Error::InvalidateTableCache { source, .. } => source.status_code(),
429
430 Error::Table { source, .. } | Error::Insert { source, .. } => source.status_code(),
431
432 Error::RequestQuery { source, .. } => source.status_code(),
433
434 Error::CacheRequired { .. } | Error::UnexpectedColumnType { .. } => {
435 StatusCode::Internal
436 }
437
438 Error::TableNotFound { .. } => StatusCode::TableNotFound,
439
440 Error::Catalog { source, .. } => source.status_code(),
441
442 Error::CreateMetaHeartbeatStream { source, .. } => source.status_code(),
443
444 Error::PlanStatement { source, .. }
445 | Error::ReadTable { source, .. }
446 | Error::ExecLogicalPlan { source, .. } => source.status_code(),
447
448 Error::External { source, .. } | Error::InitPlugin { source, .. } => {
449 source.status_code()
450 }
451 Error::FindRegionPeer { source, .. } => source.status_code(),
452
453 Error::TableOperation { source, .. } => source.status_code(),
454
455 Error::DataFusion { error, .. } => datafusion_status_code::<Self>(error, None),
456
457 Error::Cancelled { .. } => StatusCode::Cancelled,
458
459 Error::StatementTimeout { .. } => StatusCode::Cancelled,
460
461 Error::Suspended { .. } => StatusCode::Suspended,
462 }
463 }
464
465 fn as_any(&self) -> &dyn Any {
466 self
467 }
468
469 fn retry_hint(&self) -> RetryHint {
470 match self {
471 Error::InvalidateTableCache { source, .. }
472 | Error::HandleHeartbeatResponse { source, .. }
473 | Error::RequestQuery { source, .. } => source.retry_hint(),
474
475 Error::External { source, .. }
476 | Error::SqlExecIntercepted { source, .. }
477 | Error::InitPlugin { source, .. } => source.retry_hint(),
478
479 Error::StartServer { source, .. }
480 | Error::ShutdownServer { source, .. }
481 | Error::ExecutePromql { source, .. }
482 | Error::PromStoreRemoteQueryPlan { source, .. }
483 | Error::PrometheusMetricNamesQueryPlan { source, .. } => source.retry_hint(),
484
485 Error::ParseSql { source, .. } => source.retry_hint(),
486 Error::Catalog { source, .. } => source.retry_hint(),
487 Error::CreateMetaHeartbeatStream { source, .. } => source.retry_hint(),
488 Error::FindRegionPeer { source, .. } => source.retry_hint(),
489 Error::Table { source, .. } => source.retry_hint(),
490 Error::CollectRecordbatch { source, .. } => source.retry_hint(),
491 Error::PlanStatement { source, .. }
492 | Error::ReadTable { source, .. }
493 | Error::ExecLogicalPlan { source, .. }
494 | Error::DescribeStatement { source, .. } => source.retry_hint(),
495 Error::PrometheusLabelValuesQueryPlan { source, .. } => source.retry_hint(),
496 Error::Insert { source, .. } => source.retry_hint(),
497 Error::Permission { source, .. } => source.retry_hint(),
498 Error::TableOperation { source, .. } => source.retry_hint(),
499 Error::IllegalAuthConfig { source, .. } => source.retry_hint(),
500 Error::TomlFormat { source, .. } => source.retry_hint(),
501 Error::InvalidTlsConfig { error, .. } => error.retry_hint(),
502 Error::SubstraitDecodeLogicalPlan { source, .. } => source.retry_hint(),
503
504 _ => RetryHint::NonRetryable,
505 }
506 }
507}
508
509define_into_tonic_status!(Error);
510
511impl From<operator::error::Error> for Error {
512 fn from(e: operator::error::Error) -> Error {
513 Error::TableOperation {
514 source: e,
515 location: Location::default(),
516 }
517 }
518}