1use 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#[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 #[snafu(display("Invalid SQL syntax"))]
61 Syntax {
62 #[snafu(source)]
63 error: ParserError,
64 #[snafu(implicit)]
65 location: Location,
66 },
67
68 #[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}