1use std::any::Any;
16use std::fmt::Debug;
17
18use common_error::ext::{BoxedError, ErrorExt};
19use common_error::status_code::StatusCode;
20use common_macro::stack_trace_debug;
21use common_query::error::datafusion_status_code;
22use datafusion::error::DataFusionError;
23use snafu::{Location, Snafu};
24
25#[derive(Snafu)]
26#[snafu(visibility(pub))]
27#[stack_trace_debug]
28pub enum Error {
29 #[snafu(display("Failed to list catalogs"))]
30 ListCatalogs {
31 #[snafu(implicit)]
32 location: Location,
33 source: BoxedError,
34 },
35
36 #[snafu(display("Failed to list {}'s schemas", catalog))]
37 ListSchemas {
38 #[snafu(implicit)]
39 location: Location,
40 catalog: String,
41 source: BoxedError,
42 },
43
44 #[snafu(display("Failed to list {}.{}'s tables", catalog, schema))]
45 ListTables {
46 #[snafu(implicit)]
47 location: Location,
48 catalog: String,
49 schema: String,
50 source: BoxedError,
51 },
52
53 #[snafu(display("Failed to list nodes in cluster"))]
54 ListNodes {
55 #[snafu(implicit)]
56 location: Location,
57 source: BoxedError,
58 },
59
60 #[snafu(display("Failed to region stats in cluster"))]
61 ListRegionStats {
62 #[snafu(implicit)]
63 location: Location,
64 source: BoxedError,
65 },
66
67 #[snafu(display("Failed to list flow stats"))]
68 ListFlowStats {
69 #[snafu(implicit)]
70 location: Location,
71 source: BoxedError,
72 },
73
74 #[snafu(display("Failed to list flows in catalog {catalog}"))]
75 ListFlows {
76 #[snafu(implicit)]
77 location: Location,
78 catalog: String,
79 source: BoxedError,
80 },
81
82 #[snafu(display("Flow info not found: {flow_name} in catalog {catalog_name}"))]
83 FlowInfoNotFound {
84 flow_name: String,
85 catalog_name: String,
86 #[snafu(implicit)]
87 location: Location,
88 },
89
90 #[snafu(display("Can't convert value to json, input={input}"))]
91 Json {
92 input: String,
93 #[snafu(source)]
94 error: serde_json::error::Error,
95 #[snafu(implicit)]
96 location: Location,
97 },
98
99 #[snafu(display("Failed to get information extension client"))]
100 GetInformationExtension {
101 #[snafu(implicit)]
102 location: Location,
103 },
104
105 #[snafu(display("Failed to list procedures"))]
106 ListProcedures {
107 #[snafu(implicit)]
108 location: Location,
109 source: BoxedError,
110 },
111
112 #[snafu(display("Procedure id not found"))]
113 ProcedureIdNotFound {
114 #[snafu(implicit)]
115 location: Location,
116 },
117
118 #[snafu(display("convert proto data error"))]
119 ConvertProtoData {
120 #[snafu(implicit)]
121 location: Location,
122 source: BoxedError,
123 },
124
125 #[snafu(display("Failed to create table, table info: {}", table_info))]
126 CreateTable {
127 table_info: String,
128 #[snafu(implicit)]
129 location: Location,
130 source: table::error::Error,
131 },
132
133 #[snafu(display("Cannot find catalog by name: {}", catalog_name))]
134 CatalogNotFound {
135 catalog_name: String,
136 #[snafu(implicit)]
137 location: Location,
138 },
139
140 #[snafu(display("Cannot find schema {} in catalog {}", schema, catalog))]
141 SchemaNotFound {
142 catalog: String,
143 schema: String,
144 #[snafu(implicit)]
145 location: Location,
146 },
147
148 #[snafu(display("Table `{}` already exists", table))]
149 TableExists {
150 table: String,
151 #[snafu(implicit)]
152 location: Location,
153 },
154
155 #[snafu(display("Table not found: {}", table))]
156 TableNotExist {
157 table: String,
158 #[snafu(implicit)]
159 location: Location,
160 },
161
162 #[snafu(display("View info not found: {}", name))]
163 ViewInfoNotFound {
164 name: String,
165 #[snafu(implicit)]
166 location: Location,
167 },
168
169 #[snafu(display(
170 "View plan columns changed from: {} to: {}",
171 origin_names,
172 actual_names
173 ))]
174 ViewPlanColumnsChanged {
175 origin_names: String,
176 actual_names: String,
177 #[snafu(implicit)]
178 location: Location,
179 },
180
181 #[snafu(display("Partition manager not found, it's not expected."))]
182 PartitionManagerNotFound {
183 #[snafu(implicit)]
184 location: Location,
185 },
186
187 #[snafu(display("Failed to find table partitions"))]
188 FindPartitions { source: partition::error::Error },
189
190 #[snafu(display("Failed to find region routes"))]
191 FindRegionRoutes { source: partition::error::Error },
192
193 #[snafu(display("Failed to create recordbatch"))]
194 CreateRecordBatch {
195 #[snafu(implicit)]
196 location: Location,
197 source: common_recordbatch::error::Error,
198 },
199
200 #[snafu(display("Internal error"))]
201 Internal {
202 #[snafu(implicit)]
203 location: Location,
204 source: BoxedError,
205 },
206
207 #[snafu(display("Failed to upgrade weak catalog manager reference"))]
208 UpgradeWeakCatalogManagerRef {
209 #[snafu(implicit)]
210 location: Location,
211 },
212
213 #[snafu(display("Failed to decode logical plan for view: {}", name))]
214 DecodePlan {
215 name: String,
216 #[snafu(implicit)]
217 location: Location,
218 source: common_query::error::Error,
219 },
220
221 #[snafu(display("Illegal access to catalog: {} and schema: {}", catalog, schema))]
222 QueryAccessDenied { catalog: String, schema: String },
223
224 #[snafu(display("DataFusion error"))]
225 Datafusion {
226 #[snafu(source)]
227 error: DataFusionError,
228 #[snafu(implicit)]
229 location: Location,
230 },
231
232 #[snafu(display("Failed to project view columns"))]
233 ProjectViewColumns {
234 #[snafu(source)]
235 error: DataFusionError,
236 #[snafu(implicit)]
237 location: Location,
238 },
239
240 #[snafu(display("Table metadata manager error"))]
241 TableMetadataManager {
242 source: common_meta::error::Error,
243 #[snafu(implicit)]
244 location: Location,
245 },
246
247 #[snafu(display("Failed to get table cache"))]
248 GetTableCache {
249 source: common_meta::error::Error,
250 #[snafu(implicit)]
251 location: Location,
252 },
253
254 #[snafu(display("Failed to get view info from cache"))]
255 GetViewCache {
256 source: common_meta::error::Error,
257 #[snafu(implicit)]
258 location: Location,
259 },
260
261 #[snafu(display("Cache not found: {name}"))]
262 CacheNotFound {
263 name: String,
264 #[snafu(implicit)]
265 location: Location,
266 },
267
268 #[snafu(display("Failed to cast the catalog manager"))]
269 CastManager {
270 #[snafu(implicit)]
271 location: Location,
272 },
273
274 #[snafu(display("Failed to invoke frontend services"))]
275 InvokeFrontend {
276 source: common_frontend::error::Error,
277 #[snafu(implicit)]
278 location: Location,
279 },
280
281 #[snafu(display("Meta client is not provided"))]
282 MetaClientMissing {
283 #[snafu(implicit)]
284 location: Location,
285 },
286
287 #[snafu(display("Failed to find frontend node: {}", addr))]
288 FrontendNotFound {
289 addr: String,
290 #[snafu(implicit)]
291 location: Location,
292 },
293
294 #[snafu(display("Failed to handle query"))]
295 HandleQuery {
296 source: common_meta::error::Error,
297 #[snafu(implicit)]
298 location: Location,
299 },
300
301 #[snafu(display("Failed to project schema"))]
302 ProjectSchema {
303 source: datatypes::error::Error,
304 #[snafu(implicit)]
305 location: Location,
306 },
307}
308
309impl Error {
310 pub fn should_fail(&self) -> bool {
311 use Error::*;
312
313 matches!(
314 self,
315 GetViewCache { .. }
316 | ViewInfoNotFound { .. }
317 | DecodePlan { .. }
318 | ViewPlanColumnsChanged { .. }
319 | ProjectViewColumns { .. }
320 )
321 }
322}
323
324pub type Result<T> = std::result::Result<T, Error>;
325
326impl ErrorExt for Error {
327 fn status_code(&self) -> StatusCode {
328 match self {
329 Error::SchemaNotFound { .. }
330 | Error::CatalogNotFound { .. }
331 | Error::FindPartitions { .. }
332 | Error::FindRegionRoutes { .. }
333 | Error::CacheNotFound { .. }
334 | Error::CastManager { .. }
335 | Error::Json { .. }
336 | Error::GetInformationExtension { .. }
337 | Error::PartitionManagerNotFound { .. }
338 | Error::ProcedureIdNotFound { .. } => StatusCode::Unexpected,
339
340 Error::ViewPlanColumnsChanged { .. } => StatusCode::InvalidArguments,
341
342 Error::ViewInfoNotFound { .. } => StatusCode::TableNotFound,
343
344 Error::FlowInfoNotFound { .. } => StatusCode::FlowNotFound,
345
346 Error::UpgradeWeakCatalogManagerRef { .. } => StatusCode::Internal,
347
348 Error::CreateRecordBatch { source, .. } => source.status_code(),
349 Error::TableExists { .. } => StatusCode::TableAlreadyExists,
350 Error::TableNotExist { .. } => StatusCode::TableNotFound,
351 Error::ListCatalogs { source, .. }
352 | Error::ListNodes { source, .. }
353 | Error::ListSchemas { source, .. }
354 | Error::ListTables { source, .. }
355 | Error::ListFlows { source, .. }
356 | Error::ListFlowStats { source, .. }
357 | Error::ListProcedures { source, .. }
358 | Error::ListRegionStats { source, .. }
359 | Error::ConvertProtoData { source, .. } => source.status_code(),
360
361 Error::CreateTable { source, .. } => source.status_code(),
362
363 Error::DecodePlan { source, .. } => source.status_code(),
364
365 Error::Internal { source, .. } => source.status_code(),
366
367 Error::QueryAccessDenied { .. } => StatusCode::AccessDenied,
368 Error::Datafusion { error, .. } => datafusion_status_code::<Self>(error, None),
369 Error::ProjectViewColumns { .. } => StatusCode::EngineExecuteQuery,
370 Error::TableMetadataManager { source, .. } => source.status_code(),
371 Error::GetViewCache { source, .. } | Error::GetTableCache { source, .. } => {
372 source.status_code()
373 }
374 Error::InvokeFrontend { source, .. } => source.status_code(),
375 Error::FrontendNotFound { .. } | Error::MetaClientMissing { .. } => {
376 StatusCode::Unexpected
377 }
378 Error::HandleQuery { source, .. } => source.status_code(),
379 Error::ProjectSchema { source, .. } => source.status_code(),
380 }
381 }
382
383 fn as_any(&self) -> &dyn Any {
384 self
385 }
386}
387
388impl From<Error> for DataFusionError {
389 fn from(e: Error) -> Self {
390 DataFusionError::External(Box::new(e))
391 }
392}
393
394#[cfg(test)]
395mod tests {
396 use snafu::GenerateImplicitData;
397
398 use super::*;
399
400 #[test]
401 pub fn test_errors_to_datafusion_error() {
402 let e: DataFusionError = Error::TableExists {
403 table: "test_table".to_string(),
404 location: Location::generate(),
405 }
406 .into();
407 match e {
408 DataFusionError::External(_) => {}
409 _ => {
410 panic!("catalog error should be converted to DataFusionError::Internal")
411 }
412 }
413 }
414}