1use std::any::Any;
16use std::time::{Duration, TryFromFloatSecsError};
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 datatypes::prelude::ConcreteDataType;
24use datatypes::value::Value;
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("Unsupported expr type: {}", name))]
33 UnsupportedExpr {
34 name: String,
35 #[snafu(implicit)]
36 location: Location,
37 },
38
39 #[snafu(display("Unsupported show variable: {}", name))]
40 UnsupportedVariable {
41 name: String,
42 #[snafu(implicit)]
43 location: Location,
44 },
45
46 #[snafu(display("Operation {} not implemented yet", operation))]
47 Unimplemented {
48 operation: String,
49 #[snafu(implicit)]
50 location: Location,
51 },
52
53 #[snafu(display("General catalog error"))]
54 Catalog {
55 source: catalog::error::Error,
56 #[snafu(implicit)]
57 location: Location,
58 },
59
60 #[snafu(display("Partition rule manager error"))]
61 PartitionRuleManager {
62 source: partition::error::Error,
63 #[snafu(implicit)]
64 location: Location,
65 },
66
67 #[snafu(display("Table not found: {}", table))]
68 TableNotFound {
69 table: String,
70 #[snafu(implicit)]
71 location: Location,
72 },
73
74 #[snafu(display("Failed to create RecordBatch"))]
75 CreateRecordBatch {
76 source: common_recordbatch::error::Error,
77 #[snafu(implicit)]
78 location: Location,
79 },
80
81 #[snafu(display("Failure during query execution"))]
82 QueryExecution {
83 source: BoxedError,
84 #[snafu(implicit)]
85 location: Location,
86 },
87
88 #[snafu(display("Failure during query planning"))]
89 QueryPlan {
90 source: BoxedError,
91 #[snafu(implicit)]
92 location: Location,
93 },
94
95 #[snafu(display("Failure during query parsing, query: {}", query))]
96 QueryParse {
97 query: String,
98 source: BoxedError,
99 #[snafu(implicit)]
100 location: Location,
101 },
102
103 #[snafu(display("Illegal access to catalog: {} and schema: {}", catalog, schema))]
104 QueryAccessDenied {
105 catalog: String,
106 schema: String,
107 #[snafu(implicit)]
108 location: Location,
109 },
110
111 #[snafu(display("The SQL string has multiple statements, query: {}", query))]
112 MultipleStatements {
113 query: String,
114 #[snafu(implicit)]
115 location: Location,
116 },
117
118 #[snafu(display("Failed to parse timestamp `{}`", raw))]
119 ParseTimestamp {
120 raw: String,
121 #[snafu(source)]
122 error: chrono::ParseError,
123 #[snafu(implicit)]
124 location: Location,
125 },
126
127 #[snafu(display("Failed to parse float number `{}`", raw))]
128 ParseFloat {
129 raw: String,
130 #[snafu(source)]
131 error: std::num::ParseFloatError,
132 #[snafu(implicit)]
133 location: Location,
134 },
135
136 #[snafu(transparent)]
137 DataFusion {
138 #[snafu(source)]
139 error: DataFusionError,
140 #[snafu(implicit)]
141 location: Location,
142 },
143
144 #[snafu(display("General SQL error"))]
145 Sql {
146 #[snafu(implicit)]
147 location: Location,
148 source: sql::error::Error,
149 },
150
151 #[snafu(display("Failed to plan SQL"))]
152 PlanSql {
153 #[snafu(source)]
154 error: DataFusionError,
155 #[snafu(implicit)]
156 location: Location,
157 },
158
159 #[snafu(display("Timestamp column for table '{table_name}' is missing!"))]
160 MissingTimestampColumn {
161 table_name: String,
162 #[snafu(implicit)]
163 location: Location,
164 },
165
166 #[snafu(display("Failed to convert value to sql value: {}", value))]
167 ConvertSqlValue {
168 value: Value,
169 source: sql::error::Error,
170 #[snafu(implicit)]
171 location: Location,
172 },
173
174 #[snafu(display("Failed to convert concrete type to sql type: {:?}", datatype))]
175 ConvertSqlType {
176 datatype: ConcreteDataType,
177 source: sql::error::Error,
178 #[snafu(implicit)]
179 location: Location,
180 },
181
182 #[snafu(display("Missing required field: {}", name))]
183 MissingRequiredField {
184 name: String,
185 #[snafu(implicit)]
186 location: Location,
187 },
188
189 #[snafu(display("Failed to regex"))]
190 BuildRegex {
191 #[snafu(implicit)]
192 location: Location,
193 #[snafu(source)]
194 error: regex::Error,
195 },
196
197 #[snafu(display("Failed to build data source backend"))]
198 BuildBackend {
199 source: common_datasource::error::Error,
200 #[snafu(implicit)]
201 location: Location,
202 },
203
204 #[snafu(display("Failed to list objects"))]
205 ListObjects {
206 source: common_datasource::error::Error,
207 #[snafu(implicit)]
208 location: Location,
209 },
210
211 #[snafu(display("Failed to parse file format"))]
212 ParseFileFormat {
213 source: common_datasource::error::Error,
214 #[snafu(implicit)]
215 location: Location,
216 },
217
218 #[snafu(display("Failed to infer schema"))]
219 InferSchema {
220 source: common_datasource::error::Error,
221 #[snafu(implicit)]
222 location: Location,
223 },
224
225 #[snafu(display("Failed to convert datafusion schema"))]
226 ConvertSchema {
227 source: datatypes::error::Error,
228 #[snafu(implicit)]
229 location: Location,
230 },
231
232 #[snafu(display("Unknown table type, downcast failed"))]
233 UnknownTable {
234 #[snafu(implicit)]
235 location: Location,
236 },
237
238 #[snafu(display("Cannot find time index column in table {}", table))]
239 TimeIndexNotFound {
240 table: String,
241 #[snafu(implicit)]
242 location: Location,
243 },
244
245 #[snafu(display("Failed to add duration '{:?}' to SystemTime, overflowed", duration))]
246 AddSystemTimeOverflow {
247 duration: Duration,
248 #[snafu(implicit)]
249 location: Location,
250 },
251
252 #[snafu(display(
253 "Column schema incompatible, column: {}, file_type: {}, table_type: {}",
254 column,
255 file_type,
256 table_type
257 ))]
258 ColumnSchemaIncompatible {
259 column: String,
260 file_type: ConcreteDataType,
261 table_type: ConcreteDataType,
262 #[snafu(implicit)]
263 location: Location,
264 },
265
266 #[snafu(display("Column schema has no default value, column: {}", column))]
267 ColumnSchemaNoDefault {
268 column: String,
269 #[snafu(implicit)]
270 location: Location,
271 },
272
273 #[snafu(display("Region query error"))]
274 RegionQuery {
275 source: BoxedError,
276 #[snafu(implicit)]
277 location: Location,
278 },
279
280 #[snafu(display("Table mutation error"))]
281 TableMutation {
282 source: common_query::error::Error,
283 #[snafu(implicit)]
284 location: Location,
285 },
286
287 #[snafu(display("Missing table mutation handler"))]
288 MissingTableMutationHandler {
289 #[snafu(implicit)]
290 location: Location,
291 },
292
293 #[snafu(display("Range Query: {}", msg))]
294 RangeQuery {
295 msg: String,
296 #[snafu(implicit)]
297 location: Location,
298 },
299
300 #[snafu(display(
301 "Failed to get metadata from engine {} for region_id {}",
302 engine,
303 region_id,
304 ))]
305 GetRegionMetadata {
306 engine: String,
307 region_id: RegionId,
308 #[snafu(implicit)]
309 location: Location,
310 source: BoxedError,
311 },
312
313 #[snafu(display("Cannot change read-only table: {}", table))]
314 TableReadOnly {
315 table: String,
316 #[snafu(implicit)]
317 location: Location,
318 },
319
320 #[snafu(display("Failed to get fulltext options"))]
321 GetFulltextOptions {
322 source: datatypes::error::Error,
323 #[snafu(implicit)]
324 location: Location,
325 },
326
327 #[snafu(display("Failed to get SKIPPING index options"))]
328 GetSkippingIndexOptions {
329 source: datatypes::error::Error,
330 #[snafu(implicit)]
331 location: Location,
332 },
333
334 #[snafu(display(
335 "Column schema mismatch in CTE {}, original: {:?}, expected: {:?}",
336 cte_name,
337 original,
338 expected,
339 ))]
340 CteColumnSchemaMismatch {
341 cte_name: String,
342 original: Vec<String>,
343 expected: Vec<String>,
344 #[snafu(implicit)]
345 location: Location,
346 },
347
348 #[snafu(display("Failed to convert value for region pruning"))]
349 ConvertValue {
350 source: datatypes::error::Error,
351 #[snafu(implicit)]
352 location: Location,
353 },
354
355 #[snafu(display("Failed to convert float seconds to duration, raw: {}", raw))]
356 TryIntoDuration {
357 raw: String,
358 #[snafu(source)]
359 error: TryFromFloatSecsError,
360 #[snafu(implicit)]
361 location: Location,
362 },
363
364 #[snafu(transparent)]
365 Datatypes {
366 source: datatypes::error::Error,
367 #[snafu(implicit)]
368 location: Location,
369 },
370}
371
372impl ErrorExt for Error {
373 fn status_code(&self) -> StatusCode {
374 use Error::*;
375
376 match self {
377 QueryParse { .. } | MultipleStatements { .. } | RangeQuery { .. } => {
378 StatusCode::InvalidSyntax
379 }
380 UnsupportedExpr { .. }
381 | Unimplemented { .. }
382 | UnknownTable { .. }
383 | TimeIndexNotFound { .. }
384 | ParseTimestamp { .. }
385 | ParseFloat { .. }
386 | MissingRequiredField { .. }
387 | BuildRegex { .. }
388 | ConvertSchema { .. }
389 | AddSystemTimeOverflow { .. }
390 | ColumnSchemaIncompatible { .. }
391 | UnsupportedVariable { .. }
392 | ColumnSchemaNoDefault { .. }
393 | CteColumnSchemaMismatch { .. }
394 | ConvertValue { .. }
395 | TryIntoDuration { .. } => StatusCode::InvalidArguments,
396
397 BuildBackend { .. } | ListObjects { .. } => StatusCode::StorageUnavailable,
398
399 TableNotFound { .. } => StatusCode::TableNotFound,
400
401 ParseFileFormat { source, .. } | InferSchema { source, .. } => source.status_code(),
402
403 QueryAccessDenied { .. } => StatusCode::AccessDenied,
404 Catalog { source, .. } => source.status_code(),
405 CreateRecordBatch { source, .. } => source.status_code(),
406 PartitionRuleManager { source, .. } => source.status_code(),
407 QueryExecution { source, .. } | QueryPlan { source, .. } => source.status_code(),
408 PlanSql { error, .. } => {
409 datafusion_status_code::<Self>(error, Some(StatusCode::PlanQuery))
410 }
411
412 DataFusion { error, .. } => datafusion_status_code::<Self>(error, None),
413
414 MissingTimestampColumn { .. } => StatusCode::EngineExecuteQuery,
415 Sql { source, .. } => source.status_code(),
416
417 ConvertSqlType { source, .. } | ConvertSqlValue { source, .. } => source.status_code(),
418
419 RegionQuery { source, .. } => source.status_code(),
420 TableMutation { source, .. } => source.status_code(),
421 MissingTableMutationHandler { .. } => StatusCode::Unexpected,
422 GetRegionMetadata { .. } => StatusCode::RegionNotReady,
423 TableReadOnly { .. } => StatusCode::Unsupported,
424
425 GetFulltextOptions { source, .. }
426 | GetSkippingIndexOptions { source, .. }
427 | Datatypes { source, .. } => source.status_code(),
428 }
429 }
430
431 fn as_any(&self) -> &dyn Any {
432 self
433 }
434}
435
436pub type Result<T> = std::result::Result<T, Error>;
437
438impl From<Error> for DataFusionError {
439 fn from(e: Error) -> DataFusionError {
440 DataFusionError::External(Box::new(e))
441 }
442}