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