Skip to main content

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