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