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 table name: {}", name))]
168    InvalidTableName {
169        name: String,
170        #[snafu(implicit)]
171        location: Location,
172    },
173
174    #[snafu(display("Invalid flow name: {}", name))]
175    InvalidFlowName {
176        name: String,
177        #[snafu(implicit)]
178        location: Location,
179    },
180
181    #[cfg(feature = "enterprise")]
182    #[snafu(display("Invalid trigger name: {}", name))]
183    InvalidTriggerName {
184        name: String,
185        #[snafu(implicit)]
186        location: Location,
187    },
188
189    #[snafu(display("Invalid flow query: {}", reason))]
190    InvalidFlowQuery {
191        reason: String,
192        #[snafu(implicit)]
193        location: Location,
194    },
195
196    #[snafu(display("Invalid default constraint, column: {}", column))]
197    InvalidDefault {
198        column: String,
199        #[snafu(implicit)]
200        location: Location,
201        source: datatypes::error::Error,
202    },
203
204    #[snafu(display("Unrecognized table option key: {}", key))]
205    InvalidTableOption {
206        key: String,
207        #[snafu(implicit)]
208        location: Location,
209    },
210
211    #[snafu(display("Invalid expr as option value, error: {error}"))]
212    InvalidExprAsOptionValue {
213        error: String,
214        #[snafu(implicit)]
215        location: Location,
216    },
217
218    #[snafu(display("Failed to serialize column default constraint"))]
219    SerializeColumnDefaultConstraint {
220        #[snafu(implicit)]
221        location: Location,
222        source: datatypes::error::Error,
223    },
224
225    #[snafu(display("Failed to convert data type to gRPC data type defined in proto"))]
226    ConvertToGrpcDataType {
227        #[snafu(implicit)]
228        location: Location,
229        source: api::error::Error,
230    },
231
232    #[snafu(display("Unable to convert statement {} to DataFusion statement", statement))]
233    ConvertToDfStatement {
234        statement: String,
235        #[snafu(implicit)]
236        location: Location,
237    },
238
239    #[snafu(display("Unable to convert value {} to sql value", value))]
240    ConvertValue {
241        value: Value,
242        #[snafu(implicit)]
243        location: Location,
244    },
245
246    #[snafu(display("Failed to convert to logical TQL expression"))]
247    ConvertToLogicalExpression {
248        #[snafu(source)]
249        error: DataFusionError,
250        #[snafu(implicit)]
251        location: Location,
252    },
253
254    #[snafu(display("Failed to simplify TQL expression"))]
255    Simplification {
256        #[snafu(source)]
257        error: DataFusionError,
258        #[snafu(implicit)]
259        location: Location,
260    },
261
262    #[snafu(display(
263        "Permission denied while operating catalog {} from current catalog {}",
264        target,
265        current
266    ))]
267    PermissionDenied {
268        target: String,
269        current: String,
270        #[snafu(implicit)]
271        location: Location,
272    },
273
274    #[snafu(display("Failed to set fulltext option"))]
275    SetFulltextOption {
276        source: datatypes::error::Error,
277        #[snafu(implicit)]
278        location: Location,
279    },
280
281    #[snafu(display("Failed to set SKIPPING index option"))]
282    SetSkippingIndexOption {
283        source: datatypes::error::Error,
284        #[snafu(implicit)]
285        location: Location,
286    },
287
288    #[snafu(display(
289        "Invalid partition number: {}, should be in range [2, 65536]",
290        partition_num
291    ))]
292    InvalidPartitionNumber {
293        partition_num: u32,
294        #[snafu(implicit)]
295        location: Location,
296    },
297
298    #[cfg(feature = "enterprise")]
299    #[snafu(display("Missing `{}` clause", name))]
300    MissingClause {
301        name: String,
302        #[snafu(implicit)]
303        location: Location,
304    },
305
306    #[cfg(feature = "enterprise")]
307    #[snafu(display("Unrecognized trigger webhook option key: {}", key))]
308    InvalidTriggerWebhookOption {
309        key: String,
310        #[snafu(implicit)]
311        location: Location,
312    },
313
314    #[cfg(feature = "enterprise")]
315    #[snafu(display("Must specify at least one notify channel"))]
316    MissingNotifyChannel {
317        #[snafu(implicit)]
318        location: Location,
319    },
320
321    #[snafu(display("Sql common error"))]
322    SqlCommon {
323        source: common_sql::error::Error,
324        #[snafu(implicit)]
325        location: Location,
326    },
327
328    #[cfg(feature = "enterprise")]
329    #[snafu(display("Duplicate clauses `{}` in a statement", clause))]
330    DuplicateClause {
331        clause: String,
332        #[snafu(implicit)]
333        location: Location,
334    },
335
336    #[snafu(display("Failed to set JSON structure settings: {value}"))]
337    SetJsonStructureSettings {
338        value: String,
339        source: datatypes::error::Error,
340        #[snafu(implicit)]
341        location: Location,
342    },
343}
344
345impl ErrorExt for Error {
346    fn status_code(&self) -> StatusCode {
347        use Error::*;
348
349        match self {
350            Unsupported { .. } => StatusCode::Unsupported,
351            Unexpected { .. }
352            | Syntax { .. }
353            | TQLSyntax { .. }
354            | MissingTimeIndex { .. }
355            | InvalidTimeIndex { .. }
356            | InvalidSql { .. }
357            | ParseSqlValue { .. }
358            | SqlTypeNotSupported { .. }
359            | ConcreteTypeNotSupported { .. }
360            | UnexpectedToken { .. }
361            | InvalidDefault { .. } => StatusCode::InvalidSyntax,
362
363            #[cfg(feature = "enterprise")]
364            MissingClause { .. } | MissingNotifyChannel { .. } | DuplicateClause { .. } => {
365                StatusCode::InvalidSyntax
366            }
367
368            InvalidColumnOption { .. }
369            | InvalidExprAsOptionValue { .. }
370            | InvalidDatabaseName { .. }
371            | InvalidDatabaseOption { .. }
372            | ColumnTypeMismatch { .. }
373            | InvalidTableName { .. }
374            | InvalidFlowName { .. }
375            | InvalidFlowQuery { .. }
376            | InvalidTableOption { .. }
377            | ConvertToLogicalExpression { .. }
378            | Simplification { .. }
379            | InvalidInterval { .. }
380            | InvalidPartitionNumber { .. } => StatusCode::InvalidArguments,
381
382            #[cfg(feature = "enterprise")]
383            InvalidTriggerName { .. } => StatusCode::InvalidArguments,
384
385            #[cfg(feature = "enterprise")]
386            InvalidTriggerWebhookOption { .. } => StatusCode::InvalidArguments,
387
388            SerializeColumnDefaultConstraint { source, .. }
389            | SetJsonStructureSettings { source, .. } => source.status_code(),
390
391            ConvertToGrpcDataType { source, .. } => source.status_code(),
392            SqlCommon { source, .. } => source.status_code(),
393            ConvertToDfStatement { .. } => StatusCode::Internal,
394            ConvertValue { .. } => StatusCode::Unsupported,
395
396            PermissionDenied { .. } => StatusCode::PermissionDenied,
397            SetFulltextOption { .. } | SetSkippingIndexOption { .. } => StatusCode::Unexpected,
398        }
399    }
400
401    fn as_any(&self) -> &dyn Any {
402        self
403    }
404}