1use std::{
5 fmt::{Display, Formatter},
6 ops::{Deref, DerefMut},
7};
8
9use serde::{Deserialize, Serialize, de, ser};
10
11mod diagnostic;
12pub mod r#macro;
13pub mod render;
14pub mod util;
15
16use std::{array::TryFromSliceError, error, fmt, mem, num, string};
17
18use render::DefaultRenderer;
19
20use crate::{fragment::Fragment, value::r#type::Type};
21
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24pub struct OperatorChainEntry {
25 pub node_id: u64,
26 pub operator_name: String,
27 pub operator_version: String,
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
31pub struct Diagnostic {
32 pub code: String,
33 pub statement: Option<String>,
34 pub message: String,
35 pub column: Option<DiagnosticColumn>,
36 pub fragment: Fragment,
37 pub label: Option<String>,
38 pub help: Option<String>,
39 pub notes: Vec<String>,
40 pub cause: Option<Box<Diagnostic>>,
41 pub operator_chain: Option<Vec<OperatorChainEntry>>,
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46pub struct DiagnosticColumn {
47 pub name: String,
48 pub r#type: Type,
49}
50
51impl Default for Diagnostic {
52 fn default() -> Self {
53 Self {
54 code: String::new(),
55 statement: None,
56 message: String::new(),
57 column: None,
58 fragment: Fragment::None,
59 label: None,
60 help: None,
61 notes: Vec::new(),
62 cause: None,
63 operator_chain: None,
64 }
65 }
66}
67
68impl Display for Diagnostic {
69 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
70 f.write_fmt(format_args!("{}", self.code))
71 }
72}
73
74impl Diagnostic {
75 pub fn with_statement(&mut self, statement: String) {
78 self.statement = Some(statement.clone());
79
80 if let Some(ref mut cause) = self.cause {
82 let mut updated_cause = mem::replace(cause.as_mut(), Diagnostic::default());
83 updated_cause.with_statement(statement);
84 *cause = Box::new(updated_cause);
85 }
86 }
87
88 pub fn with_fragment(&mut self, new_fragment: Fragment) {
91 self.fragment = new_fragment;
95
96 if let Some(ref mut cause) = self.cause {
97 cause.with_fragment(self.fragment.clone());
98 }
99 }
100
101 pub fn fragment(&self) -> Option<Fragment> {
104 match &self.fragment {
105 Fragment::Statement {
106 ..
107 } => Some(self.fragment.clone()),
108 _ => None,
109 }
110 }
111}
112
113pub trait IntoDiagnostic {
119 fn into_diagnostic(self) -> Diagnostic;
121}
122
123#[derive(Debug, Clone, PartialEq)]
124pub enum UnaryOp {
125 Not,
126}
127
128impl Display for UnaryOp {
129 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
130 match self {
131 UnaryOp::Not => f.write_str("NOT"),
132 }
133 }
134}
135
136#[derive(Debug, Clone, PartialEq)]
137pub enum BinaryOp {
138 Add,
139 Sub,
140 Mul,
141 Div,
142 Rem,
143 Equal,
144 NotEqual,
145 LessThan,
146 LessThanEqual,
147 GreaterThan,
148 GreaterThanEqual,
149 Between,
150}
151
152impl BinaryOp {
153 pub fn symbol(&self) -> &'static str {
154 match self {
155 BinaryOp::Add => "+",
156 BinaryOp::Sub => "-",
157 BinaryOp::Mul => "*",
158 BinaryOp::Div => "/",
159 BinaryOp::Rem => "%",
160 BinaryOp::Equal => "==",
161 BinaryOp::NotEqual => "!=",
162 BinaryOp::LessThan => "<",
163 BinaryOp::LessThanEqual => "<=",
164 BinaryOp::GreaterThan => ">",
165 BinaryOp::GreaterThanEqual => ">=",
166 BinaryOp::Between => "BETWEEN",
167 }
168 }
169}
170
171impl Display for BinaryOp {
172 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
173 f.write_str(self.symbol())
174 }
175}
176
177#[derive(Debug, Clone, PartialEq)]
178pub enum LogicalOp {
179 Not,
180 And,
181 Or,
182 Xor,
183}
184
185impl Display for LogicalOp {
186 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
187 match self {
188 LogicalOp::Not => f.write_str("NOT"),
189 LogicalOp::And => f.write_str("AND"),
190 LogicalOp::Or => f.write_str("OR"),
191 LogicalOp::Xor => f.write_str("XOR"),
192 }
193 }
194}
195
196#[derive(Debug, Clone, PartialEq)]
197pub enum OperandCategory {
198 Number,
199 Text,
200 Temporal,
201 Uuid,
202}
203
204impl Display for OperandCategory {
205 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
206 match self {
207 OperandCategory::Number => f.write_str("number"),
208 OperandCategory::Text => f.write_str("text"),
209 OperandCategory::Temporal => f.write_str("temporal value"),
210 OperandCategory::Uuid => f.write_str("UUID"),
211 }
212 }
213}
214
215#[derive(Debug, Clone, PartialEq)]
216pub enum ConstraintKind {
217 Utf8MaxBytes {
218 actual: usize,
219 max: usize,
220 },
221 BlobMaxBytes {
222 actual: usize,
223 max: usize,
224 },
225 IntMaxBytes {
226 actual: usize,
227 max: usize,
228 },
229 UintMaxBytes {
230 actual: usize,
231 max: usize,
232 },
233 DecimalPrecision {
234 actual: u8,
235 max: u8,
236 },
237 DecimalScale {
238 actual: u8,
239 max: u8,
240 },
241 NoneNotAllowed {
242 column_type: Type,
243 },
244}
245
246#[derive(Debug, Clone, PartialEq)]
247pub enum TemporalKind {
248 InvalidDateFormat,
249 InvalidDateTimeFormat,
250 InvalidTimeFormat,
251 InvalidDurationFormat,
252 InvalidYear,
253 InvalidTimeComponentFormat {
254 component: String,
255 },
256 InvalidMonth,
257 InvalidDay,
258 InvalidHour,
259 InvalidMinute,
260 InvalidSecond,
261 InvalidFractionalSeconds,
262 InvalidDateValues,
263 InvalidTimeValues,
264 InvalidDurationCharacter,
265 IncompleteDurationSpecification,
266 InvalidUnitInContext {
267 unit: char,
268 in_time_part: bool,
269 },
270 InvalidDurationComponentValue {
271 unit: char,
272 },
273 UnrecognizedTemporalPattern,
274 EmptyDateComponent,
275 EmptyTimeComponent,
276 DuplicateDurationComponent {
277 component: char,
278 },
279 OutOfOrderDurationComponent {
280 component: char,
281 },
282 DateTimeOutOfRange,
283 DateTimeOverflow {
284 message: String,
285 },
286 DurationOverflow {
287 message: String,
288 },
289 DurationMixedSign {
290 days: i32,
291 nanos: i64,
292 },
293 TimeOverflow {
294 message: String,
295 },
296 DateOverflow {
297 message: String,
298 },
299}
300
301#[derive(Debug, Clone, PartialEq)]
302pub enum BlobEncodingKind {
303 InvalidHex,
304 InvalidBase64,
305 InvalidBase64Url,
306 InvalidBase58,
307 InvalidUtf8Sequence {
308 error: String,
309 },
310}
311
312#[derive(Debug, Clone, PartialEq)]
313pub enum AstErrorKind {
314 TokenizeError {
315 message: String,
316 },
317 UnexpectedEof,
318 ExpectedIdentifier,
319 InvalidColumnProperty,
320 InvalidPolicy,
321 UnexpectedToken {
322 expected: String,
323 },
324 UnsupportedToken,
325 MultipleExpressionsWithoutBraces,
326 UnrecognizedType,
327 UnsupportedAstNode {
328 node_type: String,
329 },
330 EmptyPipeline,
331}
332
333#[derive(Debug, Clone, PartialEq)]
334pub enum ProcedureErrorKind {
335 UndefinedProcedure {
336 name: String,
337 },
338}
339
340#[derive(Debug, Clone, PartialEq)]
341pub enum RuntimeErrorKind {
342 VariableNotFound {
343 name: String,
344 },
345 VariableIsDataframe {
346 name: String,
347 },
348 VariableIsImmutable {
349 name: String,
350 },
351 BreakOutsideLoop,
352 ContinueOutsideLoop,
353 MaxIterationsExceeded {
354 limit: usize,
355 },
356 UndefinedFunction {
357 name: String,
358 },
359 FieldNotFound {
360 variable: String,
361 field: String,
362 available: Vec<String>,
363 },
364 AppendTargetNotFrame {
365 name: String,
366 },
367}
368
369#[derive(Debug, Clone, PartialEq)]
370pub enum NetworkErrorKind {
371 Connection {
372 message: String,
373 },
374 Engine {
375 message: String,
376 },
377 Transport {
378 message: String,
379 },
380 Status {
381 message: String,
382 },
383}
384
385#[derive(Debug, Clone, PartialEq)]
386pub enum AuthErrorKind {
387 AuthenticationFailed {
388 reason: String,
389 },
390 AuthorizationDenied {
391 resource: String,
392 },
393 TokenExpired,
394 InvalidToken,
395}
396
397#[derive(Debug, Clone, PartialEq)]
398pub enum FunctionErrorKind {
399 UnknownFunction,
400 ArityMismatch {
401 expected: usize,
402 actual: usize,
403 },
404 TooManyArguments {
405 max_args: usize,
406 actual: usize,
407 },
408 InvalidArgumentType {
409 index: usize,
410 expected: Vec<Type>,
411 actual: Type,
412 },
413 UndefinedArgument {
414 index: usize,
415 },
416 MissingInput,
417 ExecutionFailed {
418 reason: String,
419 },
420 InternalError {
421 details: String,
422 },
423 GeneratorNotFound,
424}
425
426#[derive(Debug, thiserror::Error)]
427pub enum TypeError {
428 #[error("Cannot apply {operator} operator to {operand_category}")]
429 LogicalOperatorNotApplicable {
430 operator: LogicalOp,
431 operand_category: OperandCategory,
432 fragment: Fragment,
433 },
434
435 #[error("Cannot apply '{operator}' operator to {left} and {right}")]
436 BinaryOperatorNotApplicable {
437 operator: BinaryOp,
438 left: Type,
439 right: Type,
440 fragment: Fragment,
441 },
442
443 #[error("unsupported cast from {from} to {to}")]
444 UnsupportedCast {
445 from: Type,
446 to: Type,
447 fragment: Fragment,
448 },
449
450 #[error("failed to cast to {target}")]
451 CastToNumberFailed {
452 target: Type,
453 fragment: Fragment,
454 cause: Box<TypeError>,
455 },
456
457 #[error("failed to cast to {target}")]
458 CastToTemporalFailed {
459 target: Type,
460 fragment: Fragment,
461 cause: Box<TypeError>,
462 },
463
464 #[error("failed to cast to bool")]
465 CastToBooleanFailed {
466 fragment: Fragment,
467 cause: Box<TypeError>,
468 },
469
470 #[error("failed to cast to {target}")]
471 CastToUuidFailed {
472 target: Type,
473 fragment: Fragment,
474 cause: Box<TypeError>,
475 },
476
477 #[error("failed to cast BLOB to UTF8")]
478 CastBlobToUtf8Failed {
479 fragment: Fragment,
480 cause: Box<TypeError>,
481 },
482
483 #[error("{message}")]
484 ConstraintViolation {
485 kind: ConstraintKind,
486 message: String,
487 fragment: Fragment,
488 },
489
490 #[error("invalid number format")]
491 InvalidNumberFormat {
492 target: Type,
493 fragment: Fragment,
494 },
495
496 #[error("number out of range")]
497 NumberOutOfRange {
498 target: Type,
499 fragment: Fragment,
500 descriptor: Option<NumberOutOfRangeDescriptor>,
501 },
502
503 #[error("NaN not allowed")]
504 NanNotAllowed,
505
506 #[error("too large for precise float conversion")]
507 IntegerPrecisionLoss {
508 source_type: Type,
509 target: Type,
510 fragment: Fragment,
511 },
512
513 #[error("decimal scale exceeds precision")]
514 DecimalScaleExceedsPrecision {
515 scale: u8,
516 precision: u8,
517 fragment: Fragment,
518 },
519
520 #[error("invalid decimal precision")]
521 DecimalPrecisionInvalid {
522 precision: u8,
523 },
524
525 #[error("invalid boolean format")]
526 InvalidBooleanFormat {
527 fragment: Fragment,
528 },
529
530 #[error("empty boolean value")]
531 EmptyBooleanValue {
532 fragment: Fragment,
533 },
534
535 #[error("invalid boolean")]
536 InvalidNumberBoolean {
537 fragment: Fragment,
538 },
539
540 #[error("{message}")]
541 Temporal {
542 kind: TemporalKind,
543 message: String,
544 fragment: Fragment,
545 },
546
547 #[error("invalid UUID v4 format")]
548 InvalidUuid4Format {
549 fragment: Fragment,
550 },
551
552 #[error("invalid UUID v7 format")]
553 InvalidUuid7Format {
554 fragment: Fragment,
555 },
556
557 #[error("{message}")]
558 BlobEncoding {
559 kind: BlobEncodingKind,
560 message: String,
561 fragment: Fragment,
562 },
563
564 #[error("Serde deserialization error: {message}")]
565 SerdeDeserialize {
566 message: String,
567 },
568
569 #[error("Serde serialization error: {message}")]
570 SerdeSerialize {
571 message: String,
572 },
573
574 #[error("Keycode serialization error: {message}")]
575 SerdeKeycode {
576 message: String,
577 },
578
579 #[error("Array conversion error: {message}")]
580 ArrayConversion {
581 message: String,
582 },
583
584 #[error("UTF-8 conversion error: {message}")]
585 Utf8Conversion {
586 message: String,
587 },
588
589 #[error("Integer conversion error: {message}")]
590 IntegerConversion {
591 message: String,
592 },
593
594 #[error("{message}")]
595 Network {
596 kind: NetworkErrorKind,
597 message: String,
598 },
599
600 #[error("{message}")]
601 Auth {
602 kind: AuthErrorKind,
603 message: String,
604 },
605
606 #[error("dictionary entry ID {value} exceeds maximum {max_value} for type {id_type}")]
607 DictionaryCapacityExceeded {
608 id_type: Type,
609 value: u128,
610 max_value: u128,
611 },
612
613 #[error("{message}")]
614 AssertionFailed {
615 fragment: Fragment,
616 message: String,
617 expression: Option<String>,
618 },
619
620 #[error("{message}")]
621 Function {
622 kind: FunctionErrorKind,
623 message: String,
624 fragment: Fragment,
625 },
626
627 #[error("{message}")]
628 Ast {
629 kind: AstErrorKind,
630 message: String,
631 fragment: Fragment,
632 },
633
634 #[error("{message}")]
635 Runtime {
636 kind: RuntimeErrorKind,
637 message: String,
638 },
639
640 #[error("{message}")]
641 Procedure {
642 kind: ProcedureErrorKind,
643 message: String,
644 fragment: Fragment,
645 },
646}
647
648#[derive(Debug, Clone, PartialEq)]
649pub struct NumberOutOfRangeDescriptor {
650 pub namespace: Option<String>,
651 pub table: Option<String>,
652 pub column: Option<String>,
653 pub column_type: Option<Type>,
654}
655
656impl NumberOutOfRangeDescriptor {
657 pub fn location_string(&self) -> String {
658 match (self.namespace.as_deref(), self.table.as_deref(), self.column.as_deref()) {
659 (Some(s), Some(t), Some(c)) => format!("{}::{}.{}", s, t, c),
660 (Some(s), Some(t), None) => format!("{}::{}", s, t),
661 (None, Some(t), Some(c)) => format!("{}.{}", t, c),
662 (Some(s), None, Some(c)) => format!("{}::{}", s, c),
663 (Some(s), None, None) => s.to_string(),
664 (None, Some(t), None) => t.to_string(),
665 (None, None, Some(c)) => c.to_string(),
666 (None, None, None) => "unknown location".to_string(),
667 }
668 }
669}
670
671#[derive(Debug, PartialEq)]
672pub struct Error(pub Diagnostic);
673
674impl Deref for Error {
675 type Target = Diagnostic;
676
677 fn deref(&self) -> &Self::Target {
678 &self.0
679 }
680}
681
682impl DerefMut for Error {
683 fn deref_mut(&mut self) -> &mut Self::Target {
684 &mut self.0
685 }
686}
687
688impl Display for Error {
689 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
690 let out = DefaultRenderer::render_string(&self.0);
691 f.write_str(out.as_str())
692 }
693}
694
695impl Error {
696 pub fn diagnostic(self) -> Diagnostic {
697 self.0
698 }
699}
700
701impl error::Error for Error {}
702
703impl de::Error for Error {
704 fn custom<T: Display>(msg: T) -> Self {
705 TypeError::SerdeDeserialize {
706 message: msg.to_string(),
707 }
708 .into()
709 }
710}
711
712impl ser::Error for Error {
713 fn custom<T: Display>(msg: T) -> Self {
714 TypeError::SerdeSerialize {
715 message: msg.to_string(),
716 }
717 .into()
718 }
719}
720
721impl From<num::TryFromIntError> for Error {
722 fn from(err: num::TryFromIntError) -> Self {
723 TypeError::IntegerConversion {
724 message: err.to_string(),
725 }
726 .into()
727 }
728}
729
730impl From<TryFromSliceError> for Error {
731 fn from(err: TryFromSliceError) -> Self {
732 TypeError::ArrayConversion {
733 message: err.to_string(),
734 }
735 .into()
736 }
737}
738
739impl From<string::FromUtf8Error> for Error {
740 fn from(err: string::FromUtf8Error) -> Self {
741 TypeError::Utf8Conversion {
742 message: err.to_string(),
743 }
744 .into()
745 }
746}
747
748impl From<TypeError> for Error {
749 fn from(err: TypeError) -> Self {
750 Error(err.into_diagnostic())
751 }
752}
753
754impl From<num::TryFromIntError> for TypeError {
755 fn from(err: num::TryFromIntError) -> Self {
756 TypeError::IntegerConversion {
757 message: err.to_string(),
758 }
759 }
760}
761
762impl From<TryFromSliceError> for TypeError {
763 fn from(err: TryFromSliceError) -> Self {
764 TypeError::ArrayConversion {
765 message: err.to_string(),
766 }
767 }
768}
769
770impl From<string::FromUtf8Error> for TypeError {
771 fn from(err: string::FromUtf8Error) -> Self {
772 TypeError::Utf8Conversion {
773 message: err.to_string(),
774 }
775 }
776}
777
778impl de::Error for TypeError {
779 fn custom<T: Display>(msg: T) -> Self {
780 TypeError::SerdeDeserialize {
781 message: msg.to_string(),
782 }
783 }
784}
785
786impl ser::Error for TypeError {
787 fn custom<T: Display>(msg: T) -> Self {
788 TypeError::SerdeSerialize {
789 message: msg.to_string(),
790 }
791 }
792}