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("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(transparent)]
372    Datatypes {
373        source: datatypes::error::Error,
374        #[snafu(implicit)]
375        location: Location,
376    },
377}
378
379impl ErrorExt for Error {
380    fn status_code(&self) -> StatusCode {
381        use Error::*;
382
383        match self {
384            QueryParse { .. } | MultipleStatements { .. } | RangeQuery { .. } => {
385                StatusCode::InvalidSyntax
386            }
387            UnsupportedExpr { .. }
388            | Unimplemented { .. }
389            | UnknownTable { .. }
390            | TimeIndexNotFound { .. }
391            | ParseTimestamp { .. }
392            | ParseFloat { .. }
393            | MissingRequiredField { .. }
394            | BuildRegex { .. }
395            | ConvertSchema { .. }
396            | AddSystemTimeOverflow { .. }
397            | ColumnSchemaIncompatible { .. }
398            | UnsupportedVariable { .. }
399            | ColumnSchemaNoDefault { .. }
400            | CteColumnSchemaMismatch { .. }
401            | ConvertValue { .. }
402            | TryIntoDuration { .. } => StatusCode::InvalidArguments,
403
404            BuildBackend { .. } | ListObjects { .. } => StatusCode::StorageUnavailable,
405
406            TableNotFound { .. } => StatusCode::TableNotFound,
407
408            ParseFileFormat { source, .. } | InferSchema { source, .. } => source.status_code(),
409
410            QueryAccessDenied { .. } => StatusCode::AccessDenied,
411            Catalog { source, .. } => source.status_code(),
412            CreateRecordBatch { source, .. } => source.status_code(),
413            PartitionRuleManager { source, .. } => source.status_code(),
414            QueryExecution { source, .. } | QueryPlan { source, .. } => source.status_code(),
415            PlanSql { error, .. } => {
416                datafusion_status_code::<Self>(error, Some(StatusCode::PlanQuery))
417            }
418
419            DataFusion { error, .. } => datafusion_status_code::<Self>(error, None),
420
421            MissingTimestampColumn { .. } => StatusCode::EngineExecuteQuery,
422            Sql { source, .. } => source.status_code(),
423
424            ConvertSqlType { source, .. } | ConvertSqlValue { source, .. } => source.status_code(),
425
426            RegionQuery { source, .. } => source.status_code(),
427            TableMutation { source, .. } => source.status_code(),
428            MissingTableMutationHandler { .. } => StatusCode::Unexpected,
429            GetRegionMetadata { .. } => StatusCode::RegionNotReady,
430            TableReadOnly { .. } => StatusCode::Unsupported,
431
432            GetFulltextOptions { source, .. }
433            | GetSkippingIndexOptions { source, .. }
434            | GetVectorIndexOptions { source, .. }
435            | Datatypes { source, .. } => source.status_code(),
436        }
437    }
438
439    fn as_any(&self) -> &dyn Any {
440        self
441    }
442}
443
444pub type Result<T> = std::result::Result<T, Error>;
445
446impl From<Error> for DataFusionError {
447    fn from(e: Error) -> DataFusionError {
448        DataFusionError::External(Box::new(e))
449    }
450}