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