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::parser::ParserError;
24
25use crate::parsers::error::TQLError;
26
27pub type Result<T> = std::result::Result<T, Error>;
28
29#[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 #[snafu(display("Invalid SQL syntax"))]
59 Syntax {
60 #[snafu(source)]
61 error: ParserError,
62 #[snafu(implicit)]
63 location: Location,
64 },
65
66 #[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}