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