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("Failed to get VECTOR index options"))]
335 GetVectorIndexOptions {
336 source: datatypes::error::Error,
337 #[snafu(implicit)]
338 location: Location,
339 },
340
341 #[snafu(display(
342 "Column schema mismatch in CTE {}, original: {:?}, expected: {:?}",
343 cte_name,
344 original,
345 expected,
346 ))]
347 CteColumnSchemaMismatch {
348 cte_name: String,
349 original: Vec<String>,
350 expected: Vec<String>,
351 #[snafu(implicit)]
352 location: Location,
353 },
354
355 #[snafu(display("Failed to convert value for region pruning"))]
356 ConvertValue {
357 source: datatypes::error::Error,
358 #[snafu(implicit)]
359 location: Location,
360 },
361
362 #[snafu(display("Failed to convert float seconds to duration, raw: {}", raw))]
363 TryIntoDuration {
364 raw: String,
365 #[snafu(source)]
366 error: TryFromFloatSecsError,
367 #[snafu(implicit)]
368 location: Location,
369 },
370
371 #[snafu(display("Invalid query context extension: {}", reason))]
372 InvalidQueryContextExtension {
373 reason: String,
374 #[snafu(implicit)]
375 location: Location,
376 },
377
378 #[snafu(display(
379 "Conflicting snapshot sequence observed for region {} in a single query (existing={}, new={})",
380 region_id,
381 existing,
382 new
383 ))]
384 ConflictingSnapshotSequence {
385 region_id: RegionId,
386 existing: u64,
387 new: u64,
388 #[snafu(implicit)]
389 location: Location,
390 },
391
392 #[snafu(transparent)]
393 Datatypes {
394 source: datatypes::error::Error,
395 #[snafu(implicit)]
396 location: Location,
397 },
398}
399
400impl ErrorExt for Error {
401 fn status_code(&self) -> StatusCode {
402 use Error::*;
403
404 match self {
405 QueryParse { .. } | MultipleStatements { .. } | RangeQuery { .. } => {
406 StatusCode::InvalidSyntax
407 }
408 UnsupportedExpr { .. }
409 | Unimplemented { .. }
410 | UnknownTable { .. }
411 | TimeIndexNotFound { .. }
412 | ParseTimestamp { .. }
413 | ParseFloat { .. }
414 | MissingRequiredField { .. }
415 | BuildRegex { .. }
416 | ConvertSchema { .. }
417 | AddSystemTimeOverflow { .. }
418 | ColumnSchemaIncompatible { .. }
419 | UnsupportedVariable { .. }
420 | ColumnSchemaNoDefault { .. }
421 | CteColumnSchemaMismatch { .. }
422 | ConvertValue { .. }
423 | TryIntoDuration { .. }
424 | InvalidQueryContextExtension { .. }
425 | ConflictingSnapshotSequence { .. } => StatusCode::InvalidArguments,
426
427 BuildBackend { .. } | ListObjects { .. } => StatusCode::StorageUnavailable,
428
429 TableNotFound { .. } => StatusCode::TableNotFound,
430
431 ParseFileFormat { source, .. } | InferSchema { source, .. } => source.status_code(),
432
433 QueryAccessDenied { .. } => StatusCode::AccessDenied,
434 Catalog { source, .. } => source.status_code(),
435 CreateRecordBatch { source, .. } => source.status_code(),
436 PartitionRuleManager { source, .. } => source.status_code(),
437 QueryExecution { source, .. } | QueryPlan { source, .. } => source.status_code(),
438 PlanSql { error, .. } => {
439 datafusion_status_code::<Self>(error, Some(StatusCode::PlanQuery))
440 }
441
442 DataFusion { error, .. } => datafusion_status_code::<Self>(error, None),
443
444 MissingTimestampColumn { .. } => StatusCode::EngineExecuteQuery,
445 Sql { source, .. } => source.status_code(),
446
447 ConvertSqlType { source, .. } | ConvertSqlValue { source, .. } => source.status_code(),
448
449 RegionQuery { source, .. } => source.status_code(),
450 TableMutation { source, .. } => source.status_code(),
451 MissingTableMutationHandler { .. } => StatusCode::Unexpected,
452 GetRegionMetadata { .. } => StatusCode::RegionNotReady,
453 TableReadOnly { .. } => StatusCode::Unsupported,
454
455 GetFulltextOptions { source, .. }
456 | GetSkippingIndexOptions { source, .. }
457 | GetVectorIndexOptions { source, .. }
458 | Datatypes { source, .. } => source.status_code(),
459 }
460 }
461
462 fn as_any(&self) -> &dyn Any {
463 self
464 }
465}
466
467pub type Result<T> = std::result::Result<T, Error>;
468
469impl From<Error> for DataFusionError {
470 fn from(e: Error) -> DataFusionError {
471 DataFusionError::External(Box::new(e))
472 }
473}