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;
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}