1use std::any::Any;
16use std::time::Duration;
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
328impl ErrorExt for Error {
329 fn status_code(&self) -> StatusCode {
330 use Error::*;
331
332 match self {
333 QueryParse { .. } | MultipleStatements { .. } | RangeQuery { .. } => {
334 StatusCode::InvalidSyntax
335 }
336 UnsupportedExpr { .. }
337 | Unimplemented { .. }
338 | UnknownTable { .. }
339 | TimeIndexNotFound { .. }
340 | ParseTimestamp { .. }
341 | ParseFloat { .. }
342 | MissingRequiredField { .. }
343 | BuildRegex { .. }
344 | ConvertSchema { .. }
345 | AddSystemTimeOverflow { .. }
346 | ColumnSchemaIncompatible { .. }
347 | UnsupportedVariable { .. }
348 | ColumnSchemaNoDefault { .. } => StatusCode::InvalidArguments,
349
350 BuildBackend { .. } | ListObjects { .. } => StatusCode::StorageUnavailable,
351
352 TableNotFound { .. } => StatusCode::TableNotFound,
353
354 ParseFileFormat { source, .. } | InferSchema { source, .. } => source.status_code(),
355
356 QueryAccessDenied { .. } => StatusCode::AccessDenied,
357 Catalog { source, .. } => source.status_code(),
358 CreateRecordBatch { source, .. } => source.status_code(),
359 QueryExecution { source, .. } | QueryPlan { source, .. } => source.status_code(),
360 PlanSql { error, .. } => {
361 datafusion_status_code::<Self>(error, Some(StatusCode::PlanQuery))
362 }
363
364 DataFusion { error, .. } => datafusion_status_code::<Self>(error, None),
365
366 MissingTimestampColumn { .. } => StatusCode::EngineExecuteQuery,
367 Sql { source, .. } => source.status_code(),
368
369 ConvertSqlType { source, .. } | ConvertSqlValue { source, .. } => source.status_code(),
370
371 RegionQuery { source, .. } => source.status_code(),
372 TableMutation { source, .. } => source.status_code(),
373 MissingTableMutationHandler { .. } => StatusCode::Unexpected,
374 GetRegionMetadata { .. } => StatusCode::RegionNotReady,
375 TableReadOnly { .. } => StatusCode::Unsupported,
376 GetFulltextOptions { source, .. } | GetSkippingIndexOptions { source, .. } => {
377 source.status_code()
378 }
379 }
380 }
381
382 fn as_any(&self) -> &dyn Any {
383 self
384 }
385}
386
387pub type Result<T> = std::result::Result<T, Error>;
388
389impl From<Error> for DataFusionError {
390 fn from(e: Error) -> DataFusionError {
391 DataFusionError::External(Box::new(e))
392 }
393}