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("Failed to collect recordbatch"))]
178 CollectRecordbatch {
179 #[snafu(implicit)]
180 location: Location,
181 source: common_recordbatch::error::Error,
182 },
183
184 #[snafu(display("Failed to plan statement"))]
185 PlanStatement {
186 #[snafu(implicit)]
187 location: Location,
188 source: query::error::Error,
189 },
190
191 #[snafu(display("Failed to read table: {table_name}"))]
192 ReadTable {
193 table_name: String,
194 #[snafu(implicit)]
195 location: Location,
196 source: query::error::Error,
197 },
198
199 #[snafu(display("Failed to execute logical plan"))]
200 ExecLogicalPlan {
201 #[snafu(implicit)]
202 location: Location,
203 source: query::error::Error,
204 },
205
206 #[snafu(display("Not supported: {}", feat))]
207 NotSupported { feat: String },
208
209 #[snafu(display("SQL execution intercepted"))]
210 SqlExecIntercepted {
211 #[snafu(implicit)]
212 location: Location,
213 source: BoxedError,
214 },
215
216 #[snafu(display("Failed to execute PromQL query {}", query))]
218 ExecutePromql {
219 query: String,
220 #[snafu(implicit)]
221 location: Location,
222 source: servers::error::Error,
223 },
224
225 #[snafu(display("Failed to create logical plan for prometheus query"))]
226 PromStoreRemoteQueryPlan {
227 #[snafu(implicit)]
228 location: Location,
229 source: servers::error::Error,
230 },
231
232 #[snafu(display("Failed to create logical plan for prometheus metric names query"))]
233 PrometheusMetricNamesQueryPlan {
234 #[snafu(implicit)]
235 location: Location,
236 source: servers::error::Error,
237 },
238
239 #[snafu(display("Failed to create logical plan for prometheus label values query"))]
240 PrometheusLabelValuesQueryPlan {
241 #[snafu(implicit)]
242 location: Location,
243 source: query::promql::error::Error,
244 },
245
246 #[snafu(display("Failed to describe schema for given statement"))]
247 DescribeStatement {
248 #[snafu(implicit)]
249 location: Location,
250 source: query::error::Error,
251 },
252
253 #[snafu(display("Illegal primary keys definition: {}", msg))]
254 IllegalPrimaryKeysDef {
255 msg: String,
256 #[snafu(implicit)]
257 location: Location,
258 },
259
260 #[snafu(display("Failed to insert value into table: {}", table_name))]
261 Insert {
262 table_name: String,
263 #[snafu(implicit)]
264 location: Location,
265 source: table::error::Error,
266 },
267
268 #[snafu(display("Unsupported format: {:?}", format))]
269 UnsupportedFormat {
270 #[snafu(implicit)]
271 location: Location,
272 format: Format,
273 },
274
275 #[snafu(display("Failed to pass permission check"))]
276 Permission {
277 source: auth::error::Error,
278 #[snafu(implicit)]
279 location: Location,
280 },
281
282 #[snafu(display(
283 "No valid default value can be built automatically, column: {}",
284 column,
285 ))]
286 ColumnNoneDefaultValue {
287 column: String,
288 #[snafu(implicit)]
289 location: Location,
290 },
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 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("Service suspended"))]
361 Suspended {
362 #[snafu(implicit)]
363 location: Location,
364 },
365}
366
367pub type Result<T> = std::result::Result<T, Error>;
368
369impl ErrorExt for Error {
370 fn status_code(&self) -> StatusCode {
371 match self {
372 Error::TomlFormat { .. }
373 | Error::ParseAddr { .. }
374 | Error::InvalidSql { .. }
375 | Error::InvalidInsertRequest { .. }
376 | Error::InvalidDeleteRequest { .. }
377 | Error::IllegalPrimaryKeysDef { .. }
378 | Error::SchemaExists { .. }
379 | Error::ColumnNotFound { .. }
380 | Error::AmbiguousValueColumn { .. }
381 | Error::UnsupportedFormat { .. }
382 | Error::IllegalAuthConfig { .. }
383 | Error::ColumnNoneDefaultValue { .. }
384 | Error::IncompleteGrpcRequest { .. }
385 | Error::InvalidTlsConfig { .. } => StatusCode::InvalidArguments,
386
387 Error::NotSupported { .. } => StatusCode::Unsupported,
388
389 Error::Permission { source, .. } => source.status_code(),
390
391 Error::DescribeStatement { source, .. } => source.status_code(),
392
393 Error::HandleHeartbeatResponse { source, .. } => source.status_code(),
394
395 Error::PromStoreRemoteQueryPlan { source, .. }
396 | Error::PrometheusMetricNamesQueryPlan { source, .. }
397 | Error::ExecutePromql { source, .. } => source.status_code(),
398
399 Error::SubstraitDecodeLogicalPlan { source, .. } => source.status_code(),
400
401 Error::PrometheusLabelValuesQueryPlan { source, .. } => source.status_code(),
402
403 Error::CollectRecordbatch { source, .. } => source.status_code(),
404
405 Error::SqlExecIntercepted { source, .. } => source.status_code(),
406 Error::StartServer { source, .. } => source.status_code(),
407 Error::ShutdownServer { source, .. } => source.status_code(),
408
409 Error::ParseSql { source, .. } => source.status_code(),
410
411 Error::InvalidateTableCache { source, .. } => source.status_code(),
412
413 Error::Table { source, .. } | Error::Insert { source, .. } => source.status_code(),
414
415 Error::RequestQuery { source, .. } => source.status_code(),
416
417 Error::CacheRequired { .. } => StatusCode::Internal,
418
419 Error::TableNotFound { .. } => StatusCode::TableNotFound,
420
421 Error::Catalog { source, .. } => source.status_code(),
422
423 Error::CreateMetaHeartbeatStream { source, .. } => source.status_code(),
424
425 Error::PlanStatement { source, .. }
426 | Error::ReadTable { source, .. }
427 | Error::ExecLogicalPlan { source, .. } => source.status_code(),
428
429 Error::External { source, .. } | Error::InitPlugin { source, .. } => {
430 source.status_code()
431 }
432 Error::FindRegionPeer { source, .. } => source.status_code(),
433
434 Error::TableOperation { source, .. } => source.status_code(),
435
436 Error::DataFusion { error, .. } => datafusion_status_code::<Self>(error, None),
437
438 Error::Cancelled { .. } => StatusCode::Cancelled,
439
440 Error::StatementTimeout { .. } => StatusCode::Cancelled,
441
442 Error::Suspended { .. } => StatusCode::Suspended,
443 }
444 }
445
446 fn as_any(&self) -> &dyn Any {
447 self
448 }
449
450 fn retry_hint(&self) -> RetryHint {
451 match self {
452 Error::InvalidateTableCache { source, .. }
453 | Error::HandleHeartbeatResponse { source, .. }
454 | Error::RequestQuery { source, .. } => source.retry_hint(),
455
456 Error::External { source, .. }
457 | Error::SqlExecIntercepted { source, .. }
458 | Error::InitPlugin { source, .. } => source.retry_hint(),
459
460 Error::StartServer { source, .. }
461 | Error::ShutdownServer { source, .. }
462 | Error::ExecutePromql { source, .. }
463 | Error::PromStoreRemoteQueryPlan { source, .. }
464 | Error::PrometheusMetricNamesQueryPlan { source, .. } => source.retry_hint(),
465
466 Error::ParseSql { source, .. } => source.retry_hint(),
467 Error::Catalog { source, .. } => source.retry_hint(),
468 Error::CreateMetaHeartbeatStream { source, .. } => source.retry_hint(),
469 Error::FindRegionPeer { source, .. } => source.retry_hint(),
470 Error::Table { source, .. } => source.retry_hint(),
471 Error::CollectRecordbatch { source, .. } => source.retry_hint(),
472 Error::PlanStatement { source, .. }
473 | Error::ReadTable { source, .. }
474 | Error::ExecLogicalPlan { source, .. }
475 | Error::DescribeStatement { source, .. } => source.retry_hint(),
476 Error::PrometheusLabelValuesQueryPlan { source, .. } => source.retry_hint(),
477 Error::Insert { source, .. } => source.retry_hint(),
478 Error::Permission { source, .. } => source.retry_hint(),
479 Error::TableOperation { source, .. } => source.retry_hint(),
480 Error::IllegalAuthConfig { source, .. } => source.retry_hint(),
481 Error::TomlFormat { source, .. } => source.retry_hint(),
482 Error::InvalidTlsConfig { error, .. } => error.retry_hint(),
483 Error::SubstraitDecodeLogicalPlan { source, .. } => source.retry_hint(),
484
485 _ => RetryHint::NonRetryable,
486 }
487 }
488}
489
490define_into_tonic_status!(Error);
491
492impl From<operator::error::Error> for Error {
493 fn from(e: operator::error::Error) -> Error {
494 Error::TableOperation {
495 source: e,
496 location: Location::default(),
497 }
498 }
499}