sql/
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;
16
17use common_error::ext::ErrorExt;
18use common_error::status_code::StatusCode;
19use common_macro::stack_trace_debug;
20use common_time::timestamp::TimeUnit;
21use common_time::Timestamp;
22use datafusion_common::DataFusionError;
23use datafusion_sql::sqlparser::ast::UnaryOperator;
24use datatypes::prelude::{ConcreteDataType, Value};
25use snafu::{Location, Snafu};
26use sqlparser::ast::Ident;
27use sqlparser::parser::ParserError;
28
29use crate::ast::{Expr, Value as SqlValue};
30use crate::parsers::error::TQLError;
31
32pub type Result<T> = std::result::Result<T, Error>;
33
34/// SQL parser errors.
35// Now the error in parser does not contain backtrace to avoid generating backtrace
36// every time the parser parses an invalid SQL.
37#[derive(Snafu)]
38#[snafu(visibility(pub))]
39#[stack_trace_debug]
40pub enum Error {
41    #[snafu(display("SQL statement is not supported, keyword: {}", keyword))]
42    Unsupported {
43        keyword: String,
44        #[snafu(implicit)]
45        location: Location,
46    },
47
48    #[snafu(display(
49        "Unexpected token while parsing SQL statement, expected: '{}', found: {}",
50        expected,
51        actual,
52    ))]
53    Unexpected {
54        expected: String,
55        actual: String,
56        #[snafu(source)]
57        error: ParserError,
58        #[snafu(implicit)]
59        location: Location,
60    },
61
62    #[snafu(display(
63        "Unsupported expr in default constraint: {:?} for column: {}",
64        expr,
65        column_name
66    ))]
67    UnsupportedDefaultValue {
68        column_name: String,
69        expr: Expr,
70        #[snafu(implicit)]
71        location: Location,
72    },
73
74    // Syntax error from sql parser.
75    #[snafu(display("Invalid SQL syntax"))]
76    Syntax {
77        #[snafu(source)]
78        error: ParserError,
79        #[snafu(implicit)]
80        location: Location,
81    },
82
83    // Syntax error from tql parser.
84    #[snafu(display("Invalid TQL syntax"))]
85    TQLSyntax {
86        #[snafu(source)]
87        error: TQLError,
88        #[snafu(implicit)]
89        location: Location,
90    },
91
92    #[snafu(display("Missing time index constraint"))]
93    MissingTimeIndex {},
94
95    #[snafu(display("Invalid time index: {}", msg))]
96    InvalidTimeIndex {
97        msg: String,
98        #[snafu(implicit)]
99        location: Location,
100    },
101
102    #[snafu(display("Invalid SQL, error: {}", msg))]
103    InvalidSql {
104        msg: String,
105        #[snafu(implicit)]
106        location: Location,
107    },
108
109    #[snafu(display(
110        "Unexpected token while parsing SQL statement, expected: '{}', found: {}",
111        expected,
112        actual,
113    ))]
114    UnexpectedToken {
115        expected: String,
116        actual: String,
117        #[snafu(implicit)]
118        location: Location,
119    },
120
121    #[snafu(display("Invalid column option, column name: {}, error: {}", name, msg))]
122    InvalidColumnOption {
123        name: String,
124        msg: String,
125        #[snafu(implicit)]
126        location: Location,
127    },
128
129    #[snafu(display("SQL data type not supported yet: {:?}", t))]
130    SqlTypeNotSupported {
131        t: crate::ast::DataType,
132        #[snafu(implicit)]
133        location: Location,
134    },
135    #[snafu(display("ConcreteDataType not supported yet: {:?}", t))]
136    ConcreteTypeNotSupported {
137        t: ConcreteDataType,
138        #[snafu(implicit)]
139        location: Location,
140    },
141
142    #[snafu(display("Failed to parse value: {}", msg))]
143    ParseSqlValue {
144        msg: String,
145        #[snafu(implicit)]
146        location: Location,
147    },
148
149    #[snafu(display(
150        "Column {} expect type: {:?}, actual: {:?}",
151        column_name,
152        expect,
153        actual,
154    ))]
155    ColumnTypeMismatch {
156        column_name: String,
157        expect: ConcreteDataType,
158        actual: ConcreteDataType,
159        #[snafu(implicit)]
160        location: Location,
161    },
162
163    #[snafu(display("Invalid database name: {}", name))]
164    InvalidDatabaseName {
165        name: String,
166        #[snafu(implicit)]
167        location: Location,
168    },
169
170    #[snafu(display("Invalid interval provided: {}", reason))]
171    InvalidInterval {
172        reason: String,
173        #[snafu(implicit)]
174        location: Location,
175    },
176
177    #[snafu(display("Unrecognized database option key: {}", key))]
178    InvalidDatabaseOption {
179        key: String,
180        #[snafu(implicit)]
181        location: Location,
182    },
183
184    #[snafu(display("Invalid table name: {}", name))]
185    InvalidTableName {
186        name: String,
187        #[snafu(implicit)]
188        location: Location,
189    },
190
191    #[snafu(display("Invalid flow name: {}", name))]
192    InvalidFlowName {
193        name: String,
194        #[snafu(implicit)]
195        location: Location,
196    },
197
198    #[cfg(feature = "enterprise")]
199    #[snafu(display("Invalid trigger name: {}", name))]
200    InvalidTriggerName {
201        name: String,
202        #[snafu(implicit)]
203        location: Location,
204    },
205
206    #[snafu(display("Invalid flow query: {}", reason))]
207    InvalidFlowQuery {
208        reason: String,
209        #[snafu(implicit)]
210        location: Location,
211    },
212
213    #[snafu(display("Invalid default constraint, column: {}", column))]
214    InvalidDefault {
215        column: String,
216        #[snafu(implicit)]
217        location: Location,
218        source: datatypes::error::Error,
219    },
220
221    #[snafu(display("Failed to cast SQL value {} to datatype {}", sql_value, datatype))]
222    InvalidCast {
223        sql_value: sqlparser::ast::Value,
224        datatype: ConcreteDataType,
225        #[snafu(implicit)]
226        location: Location,
227        source: datatypes::error::Error,
228    },
229
230    #[snafu(display("Invalid unary operator {} for value {}", unary_op, value))]
231    InvalidUnaryOp {
232        unary_op: UnaryOperator,
233        value: Value,
234        #[snafu(implicit)]
235        location: Location,
236    },
237
238    #[snafu(display("Unsupported unary operator {}", unary_op))]
239    UnsupportedUnaryOp {
240        unary_op: UnaryOperator,
241        #[snafu(implicit)]
242        location: Location,
243    },
244
245    #[snafu(display("Unrecognized table option key: {}", key))]
246    InvalidTableOption {
247        key: String,
248        #[snafu(implicit)]
249        location: Location,
250    },
251
252    #[snafu(display("Unrecognized table option key: {}, value: {}", key, value))]
253    InvalidTableOptionValue {
254        key: Ident,
255        value: Expr,
256        #[snafu(implicit)]
257        location: Location,
258    },
259
260    #[snafu(display("Failed to serialize column default constraint"))]
261    SerializeColumnDefaultConstraint {
262        #[snafu(implicit)]
263        location: Location,
264        source: datatypes::error::Error,
265    },
266
267    #[snafu(display("Failed to convert data type to gRPC data type defined in proto"))]
268    ConvertToGrpcDataType {
269        #[snafu(implicit)]
270        location: Location,
271        source: api::error::Error,
272    },
273
274    #[snafu(display("Invalid sql value: {}", value))]
275    InvalidSqlValue {
276        value: String,
277        #[snafu(implicit)]
278        location: Location,
279    },
280
281    #[snafu(display(
282        "Converting timestamp {:?} to unit {:?} overflow",
283        timestamp,
284        target_unit
285    ))]
286    TimestampOverflow {
287        timestamp: Timestamp,
288        target_unit: TimeUnit,
289        #[snafu(implicit)]
290        location: Location,
291    },
292
293    #[snafu(display("Unable to convert statement {} to DataFusion statement", statement))]
294    ConvertToDfStatement {
295        statement: String,
296        #[snafu(implicit)]
297        location: Location,
298    },
299
300    #[snafu(display("Unable to convert sql value {} to datatype {:?}", value, datatype))]
301    ConvertSqlValue {
302        value: SqlValue,
303        datatype: ConcreteDataType,
304        #[snafu(implicit)]
305        location: Location,
306    },
307
308    #[snafu(display("Unable to convert value {} to sql value", value))]
309    ConvertValue {
310        value: Value,
311        #[snafu(implicit)]
312        location: Location,
313    },
314
315    #[snafu(display("Failed to convert to logical TQL expression"))]
316    ConvertToLogicalExpression {
317        #[snafu(source)]
318        error: DataFusionError,
319        #[snafu(implicit)]
320        location: Location,
321    },
322
323    #[snafu(display("Failed to simplify TQL expression"))]
324    Simplification {
325        #[snafu(source)]
326        error: DataFusionError,
327        #[snafu(implicit)]
328        location: Location,
329    },
330
331    #[snafu(display(
332        "Permission denied while operating catalog {} from current catalog {}",
333        target,
334        current
335    ))]
336    PermissionDenied {
337        target: String,
338        current: String,
339        #[snafu(implicit)]
340        location: Location,
341    },
342
343    #[snafu(display("Failed to set fulltext option"))]
344    SetFulltextOption {
345        source: datatypes::error::Error,
346        #[snafu(implicit)]
347        location: Location,
348    },
349
350    #[snafu(display("Failed to set SKIPPING index option"))]
351    SetSkippingIndexOption {
352        source: datatypes::error::Error,
353        #[snafu(implicit)]
354        location: Location,
355    },
356
357    #[snafu(display("Datatype error: {}", source))]
358    Datatype {
359        source: datatypes::error::Error,
360        #[snafu(implicit)]
361        location: Location,
362    },
363
364    #[snafu(display(
365        "Invalid partition number: {}, should be in range [2, 65536]",
366        partition_num
367    ))]
368    InvalidPartitionNumber {
369        partition_num: u32,
370        #[snafu(implicit)]
371        location: Location,
372    },
373
374    #[snafu(display("Unable to convert {} to datatype {:?}", value, datatype))]
375    ConvertStr {
376        value: String,
377        datatype: ConcreteDataType,
378        #[snafu(implicit)]
379        location: Location,
380    },
381
382    #[cfg(feature = "enterprise")]
383    #[snafu(display("Missing `{}` clause", name))]
384    MissingClause {
385        name: String,
386        #[snafu(implicit)]
387        location: Location,
388    },
389
390    #[cfg(feature = "enterprise")]
391    #[snafu(display("Unrecognized trigger webhook option key: {}", key))]
392    InvalidTriggerWebhookOption {
393        key: String,
394        #[snafu(implicit)]
395        location: Location,
396    },
397
398    #[cfg(feature = "enterprise")]
399    #[snafu(display("The execution interval cannot be negative"))]
400    NegativeInterval {
401        #[snafu(source)]
402        error: std::num::TryFromIntError,
403        #[snafu(implicit)]
404        location: Location,
405    },
406
407    #[cfg(feature = "enterprise")]
408    #[snafu(display("Must specify at least one notify channel"))]
409    MissingNotifyChannel {
410        #[snafu(implicit)]
411        location: Location,
412    },
413}
414
415impl ErrorExt for Error {
416    fn status_code(&self) -> StatusCode {
417        use Error::*;
418
419        match self {
420            UnsupportedDefaultValue { .. } | Unsupported { .. } => StatusCode::Unsupported,
421            Unexpected { .. }
422            | Syntax { .. }
423            | TQLSyntax { .. }
424            | MissingTimeIndex { .. }
425            | InvalidTimeIndex { .. }
426            | InvalidSql { .. }
427            | ParseSqlValue { .. }
428            | SqlTypeNotSupported { .. }
429            | ConcreteTypeNotSupported { .. }
430            | UnexpectedToken { .. }
431            | InvalidDefault { .. } => StatusCode::InvalidSyntax,
432
433            #[cfg(feature = "enterprise")]
434            MissingClause { .. } | MissingNotifyChannel { .. } => StatusCode::InvalidSyntax,
435
436            InvalidColumnOption { .. }
437            | InvalidTableOptionValue { .. }
438            | InvalidDatabaseName { .. }
439            | InvalidDatabaseOption { .. }
440            | ColumnTypeMismatch { .. }
441            | InvalidTableName { .. }
442            | InvalidFlowName { .. }
443            | InvalidFlowQuery { .. }
444            | InvalidSqlValue { .. }
445            | TimestampOverflow { .. }
446            | InvalidTableOption { .. }
447            | InvalidCast { .. }
448            | ConvertToLogicalExpression { .. }
449            | Simplification { .. }
450            | InvalidInterval { .. }
451            | InvalidUnaryOp { .. }
452            | InvalidPartitionNumber { .. }
453            | UnsupportedUnaryOp { .. }
454            | ConvertStr { .. } => StatusCode::InvalidArguments,
455
456            #[cfg(feature = "enterprise")]
457            InvalidTriggerName { .. } => StatusCode::InvalidArguments,
458
459            #[cfg(feature = "enterprise")]
460            InvalidTriggerWebhookOption { .. } | NegativeInterval { .. } => {
461                StatusCode::InvalidArguments
462            }
463
464            SerializeColumnDefaultConstraint { source, .. } => source.status_code(),
465            ConvertToGrpcDataType { source, .. } => source.status_code(),
466            Datatype { source, .. } => source.status_code(),
467            ConvertToDfStatement { .. } => StatusCode::Internal,
468            ConvertSqlValue { .. } | ConvertValue { .. } => StatusCode::Unsupported,
469
470            PermissionDenied { .. } => StatusCode::PermissionDenied,
471            SetFulltextOption { .. } | SetSkippingIndexOption { .. } => StatusCode::Unexpected,
472        }
473    }
474
475    fn as_any(&self) -> &dyn Any {
476        self
477    }
478}