query/
error.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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}