1#[cfg(feature = "backtrace")]
38use std::backtrace::{Backtrace, BacktraceStatus};
39
40use std::borrow::Cow;
41use std::collections::VecDeque;
42use std::error::Error;
43use std::fmt::{Display, Formatter};
44use std::io;
45use std::result;
46use std::sync::Arc;
47
48use crate::utils::datafusion_strsim::{levenshtein, normalized_levenshtein};
49use crate::utils::quote_identifier;
50use crate::{Column, DFSchema, Diagnostic, TableReference};
51use arrow::error::ArrowError;
52#[cfg(feature = "parquet")]
53use parquet::errors::ParquetError;
54#[cfg(feature = "sql")]
55use sqlparser::parser::ParserError;
56use tokio::task::JoinError;
57
58pub type Result<T, E = DataFusionError> = result::Result<T, E>;
60
61pub type SharedResult<T> = result::Result<T, Arc<DataFusionError>>;
63
64pub type GenericError = Box<dyn Error + Send + Sync>;
66
67#[derive(Debug)]
69pub enum DataFusionError {
70 ArrowError(Box<ArrowError>, Option<String>),
74 #[cfg(feature = "parquet")]
76 ParquetError(Box<ParquetError>),
77 #[cfg(feature = "object_store")]
79 ObjectStore(Box<object_store::Error>),
80 IoError(io::Error),
82 #[cfg(feature = "sql")]
86 SQL(Box<ParserError>, Option<String>),
87 NotImplemented(String),
93 Internal(String),
110 Plan(String),
116 Configuration(String),
118 SchemaError(Box<SchemaError>, Box<Option<String>>),
126 Execution(String),
133 ExecutionJoin(Box<JoinError>),
137 ResourcesExhausted(String),
142 External(GenericError),
146 Context(String, Box<DataFusionError>),
148 Substrait(String),
151 Diagnostic(Box<Diagnostic>, Box<DataFusionError>),
156 Collection(Vec<DataFusionError>),
163 Shared(Arc<DataFusionError>),
169 Ffi(String),
173}
174
175#[macro_export]
176macro_rules! context {
177 ($desc:expr, $err:expr) => {
178 $err.context(format!("{} at {}:{}", $desc, file!(), line!()))
179 };
180}
181
182#[derive(Debug)]
184pub enum SchemaError {
185 AmbiguousReference { field: Box<Column> },
187 DuplicateQualifiedField {
189 qualifier: Box<TableReference>,
190 name: String,
191 },
192 DuplicateUnqualifiedField { name: String },
194 FieldNotFound {
196 field: Box<Column>,
197 valid_fields: Vec<Column>,
198 },
199}
200
201fn case_insensitive_field_match<'a>(
202 field: &Column,
203 valid_fields: &'a [Column],
204) -> Option<&'a Column> {
205 let field_name = field.name();
206 let field_flat_name = field.flat_name();
207 let field_name_lower = field_name.to_lowercase();
208 let field_flat_name_lower = field_flat_name.to_lowercase();
209
210 valid_fields.iter().find(|valid_field| {
211 let valid_field_name = valid_field.name();
212 let valid_field_flat_name = valid_field.flat_name();
213 let valid_field_name_lower = valid_field_name.to_lowercase();
214 let valid_field_flat_name_lower = valid_field_flat_name.to_lowercase();
215
216 let name_differs_only_by_case =
217 field_name_lower == valid_field_name_lower && field_name != valid_field_name;
218 let flat_name_differs_only_by_case = field_flat_name_lower
219 == valid_field_flat_name_lower
220 && field_flat_name != valid_field_flat_name;
221
222 name_differs_only_by_case || flat_name_differs_only_by_case
223 })
224}
225
226fn closest_valid_field<'a>(
229 field: &Column,
230 valid_fields: &'a [Column],
231) -> Option<&'a Column> {
232 let target_names = [
234 field.name().to_lowercase(),
235 field.flat_name().to_lowercase(),
236 ];
237
238 let mut best_match: Option<(usize, usize, usize, &Column)> = None;
239 for (index, valid_field) in valid_fields.iter().enumerate() {
240 let valid_names = [
241 valid_field.name().to_lowercase(),
242 valid_field.flat_name().to_lowercase(),
243 ];
244 for target in &target_names {
245 for valid_name in &valid_names {
246 let distance = levenshtein(target, valid_name);
247 let max_len = target.chars().count().max(valid_name.chars().count());
248 if max_len == 0 || distance * 2 > max_len {
251 continue;
252 }
253
254 let should_replace = best_match.is_none_or(
255 |(best_distance, best_max_len, best_index, _)| {
256 distance < best_distance
257 || distance == best_distance
258 && (max_len > best_max_len
259 || max_len == best_max_len && index < best_index)
260 },
261 );
262 if should_replace {
263 best_match = Some((distance, max_len, index, valid_field));
264 }
265 }
266 }
267 }
268
269 best_match.map(|(_, _, _, valid_field)| valid_field)
270}
271
272impl Display for SchemaError {
273 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
274 match self {
275 Self::FieldNotFound {
276 field,
277 valid_fields,
278 } => {
279 let closest_field = closest_valid_field(field, valid_fields);
280 let case_sensitive_match =
281 case_insensitive_field_match(field, valid_fields);
282
283 write!(f, "No field named {}", field.quoted_flat_name())?;
284 if let Some(matched) = closest_field {
285 write!(f, ". Did you mean '{}'?", matched.quoted_flat_name())?;
286 } else {
287 write!(f, ".")?;
288 }
289
290 if let Some(case_sensitive_match) = case_sensitive_match {
291 write!(
292 f,
293 "\nColumn names are case sensitive. You can use double quotes to refer to the {} column \
294 or disable the datafusion.sql_parser.enable_ident_normalization configuration.",
295 case_sensitive_match.quoted_flat_name()
296 )?;
297 }
298
299 if !valid_fields.is_empty() {
300 write!(
301 f,
302 "\nValid fields are {}.",
303 valid_fields
304 .iter()
305 .map(|field| field.quoted_flat_name())
306 .collect::<Vec<String>>()
307 .join(", ")
308 )
309 } else {
310 Ok(())
311 }
312 }
313 Self::DuplicateQualifiedField { qualifier, name } => {
314 write!(
315 f,
316 "Schema contains duplicate qualified field name {}.{}",
317 qualifier.to_quoted_string(),
318 quote_identifier(name)
319 )
320 }
321 Self::DuplicateUnqualifiedField { name } => {
322 write!(
323 f,
324 "Schema contains duplicate unqualified field name {}",
325 quote_identifier(name)
326 )
327 }
328 Self::AmbiguousReference { field } => {
329 if field.relation.is_some() {
330 write!(
331 f,
332 "Schema contains qualified field name {} and unqualified field name {} which would be ambiguous",
333 field.quoted_flat_name(),
334 quote_identifier(&field.name)
335 )
336 } else {
337 write!(
338 f,
339 "Ambiguous reference to unqualified field {}",
340 field.quoted_flat_name()
341 )
342 }
343 }
344 }
345 }
346}
347
348impl Error for SchemaError {}
349
350impl From<std::fmt::Error> for DataFusionError {
351 fn from(_e: std::fmt::Error) -> Self {
352 DataFusionError::Execution("Fail to format".to_string())
353 }
354}
355
356impl From<io::Error> for DataFusionError {
357 fn from(e: io::Error) -> Self {
358 DataFusionError::IoError(e)
359 }
360}
361
362impl From<ArrowError> for DataFusionError {
363 fn from(e: ArrowError) -> Self {
364 DataFusionError::ArrowError(Box::new(e), Some(DataFusionError::get_back_trace()))
365 }
366}
367
368impl From<DataFusionError> for ArrowError {
369 fn from(e: DataFusionError) -> Self {
370 match e {
371 DataFusionError::ArrowError(e, _) => *e,
372 DataFusionError::External(e) => ArrowError::ExternalError(e),
373 other => ArrowError::ExternalError(Box::new(other)),
374 }
375 }
376}
377
378impl From<&Arc<DataFusionError>> for DataFusionError {
379 fn from(e: &Arc<DataFusionError>) -> Self {
380 if let DataFusionError::Shared(e_inner) = e.as_ref() {
381 DataFusionError::Shared(Arc::clone(e_inner))
383 } else {
384 DataFusionError::Shared(Arc::clone(e))
385 }
386 }
387}
388
389#[cfg(feature = "parquet")]
390impl From<ParquetError> for DataFusionError {
391 fn from(e: ParquetError) -> Self {
392 DataFusionError::ParquetError(Box::new(e))
393 }
394}
395
396#[cfg(feature = "object_store")]
397impl From<object_store::Error> for DataFusionError {
398 fn from(e: object_store::Error) -> Self {
399 DataFusionError::ObjectStore(Box::new(e))
400 }
401}
402
403#[cfg(feature = "object_store")]
404impl From<object_store::path::Error> for DataFusionError {
405 fn from(e: object_store::path::Error) -> Self {
406 DataFusionError::ObjectStore(Box::new(e.into()))
407 }
408}
409
410#[cfg(feature = "sql")]
411impl From<ParserError> for DataFusionError {
412 fn from(e: ParserError) -> Self {
413 DataFusionError::SQL(Box::new(e), None)
414 }
415}
416
417impl From<GenericError> for DataFusionError {
418 fn from(err: GenericError) -> Self {
419 if err.is::<DataFusionError>() {
421 if let Ok(e) = err.downcast::<DataFusionError>() {
422 *e
423 } else {
424 unreachable!()
425 }
426 } else {
427 DataFusionError::External(err)
428 }
429 }
430}
431
432impl Display for DataFusionError {
433 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
434 let error_prefix = self.error_prefix();
435 let message = self.message();
436 write!(f, "{error_prefix}{message}")
437 }
438}
439
440impl Error for DataFusionError {
441 fn source(&self) -> Option<&(dyn Error + 'static)> {
442 match self {
443 DataFusionError::ArrowError(e, _) => Some(e.as_ref()),
444 #[cfg(feature = "parquet")]
445 DataFusionError::ParquetError(e) => Some(e.as_ref()),
446 #[cfg(feature = "object_store")]
447 DataFusionError::ObjectStore(e) => Some(e.as_ref()),
448 DataFusionError::IoError(e) => Some(e),
449 #[cfg(feature = "sql")]
450 DataFusionError::SQL(e, _) => Some(e.as_ref()),
451 DataFusionError::NotImplemented(_) => None,
452 DataFusionError::Internal(_) => None,
453 DataFusionError::Configuration(_) => None,
454 DataFusionError::Plan(_) => None,
455 DataFusionError::SchemaError(e, _) => Some(e.as_ref()),
456 DataFusionError::Execution(_) => None,
457 DataFusionError::ExecutionJoin(e) => Some(e.as_ref()),
458 DataFusionError::ResourcesExhausted(_) => None,
459 DataFusionError::External(e) => Some(e.as_ref()),
460 DataFusionError::Context(_, e) => Some(e.as_ref()),
461 DataFusionError::Substrait(_) => None,
462 DataFusionError::Diagnostic(_, e) => Some(e.as_ref()),
463 DataFusionError::Collection(errs) => errs.first().map(|e| e as &dyn Error),
471 DataFusionError::Shared(e) => Some(e.as_ref()),
472 DataFusionError::Ffi(_) => None,
473 }
474 }
475}
476
477impl From<DataFusionError> for io::Error {
478 fn from(e: DataFusionError) -> Self {
479 io::Error::other(e)
480 }
481}
482
483impl DataFusionError {
484 pub const BACK_TRACE_SEP: &'static str = "\n\nbacktrace: ";
486
487 pub fn find_root(&self) -> &Self {
503 let mut last_datafusion_error = self;
507 let mut root_error: &dyn Error = self;
508 while let Some(source) = root_error.source() {
509 root_error = source;
511 if let Some(e) = root_error.downcast_ref::<DataFusionError>() {
513 last_datafusion_error = e;
514 } else if let Some(e) = root_error.downcast_ref::<Arc<DataFusionError>>() {
515 last_datafusion_error = e.as_ref();
518 }
519 }
520 last_datafusion_error
522 }
523
524 pub fn context(self, description: impl Into<String>) -> Self {
526 Self::Context(description.into(), Box::new(self))
527 }
528
529 pub fn strip_backtrace(&self) -> String {
533 (*self
534 .to_string()
535 .split(Self::BACK_TRACE_SEP)
536 .collect::<Vec<&str>>()
537 .first()
538 .unwrap_or(&""))
539 .to_string()
540 }
541
542 #[inline(always)]
550 pub fn get_back_trace() -> String {
551 #[cfg(feature = "backtrace")]
552 {
553 let back_trace = Backtrace::capture();
554 if back_trace.status() == BacktraceStatus::Captured {
555 return format!("{}{}", Self::BACK_TRACE_SEP, back_trace);
556 }
557
558 "".to_owned()
559 }
560
561 #[cfg(not(feature = "backtrace"))]
562 "".to_owned()
563 }
564
565 pub fn builder() -> DataFusionErrorBuilder {
567 DataFusionErrorBuilder::default()
568 }
569
570 fn error_prefix(&self) -> &'static str {
571 match self {
572 DataFusionError::ArrowError(_, _) => "Arrow error: ",
573 #[cfg(feature = "parquet")]
574 DataFusionError::ParquetError(_) => "Parquet error: ",
575 #[cfg(feature = "object_store")]
576 DataFusionError::ObjectStore(_) => "Object Store error: ",
577 DataFusionError::IoError(_) => "IO error: ",
578 #[cfg(feature = "sql")]
579 DataFusionError::SQL(_, _) => "SQL error: ",
580 DataFusionError::NotImplemented(_) => {
581 "This feature is not implemented: "
582 }
583 DataFusionError::Internal(_) => "Internal error: ",
584 DataFusionError::Plan(_) => "Error during planning: ",
585 DataFusionError::Configuration(_) => {
586 "Invalid or Unsupported Configuration: "
587 }
588 DataFusionError::SchemaError(_, _) => "Schema error: ",
589 DataFusionError::Execution(_) => "Execution error: ",
590 DataFusionError::ExecutionJoin(_) => "ExecutionJoin error: ",
591 DataFusionError::ResourcesExhausted(_) => {
592 "Resources exhausted: "
593 }
594 DataFusionError::External(_) => "External error: ",
595 DataFusionError::Context(_, _) => "",
596 DataFusionError::Substrait(_) => "Substrait error: ",
597 DataFusionError::Diagnostic(_, _) => "",
598 DataFusionError::Collection(errs) => {
599 errs.first().expect("cannot construct DataFusionError::Collection with 0 errors, but got one such case").error_prefix()
600 }
601 DataFusionError::Shared(_) => "",
602 DataFusionError::Ffi(_) => "FFI error: ",
603 }
604 }
605
606 pub fn message(&self) -> Cow<'_, str> {
607 match *self {
608 DataFusionError::ArrowError(ref desc, ref backtrace) => {
609 let backtrace = backtrace.clone().unwrap_or_else(|| "".to_owned());
610 Cow::Owned(format!("{desc}{backtrace}"))
611 }
612 #[cfg(feature = "parquet")]
613 DataFusionError::ParquetError(ref desc) => Cow::Owned(desc.to_string()),
614 DataFusionError::IoError(ref desc) => Cow::Owned(desc.to_string()),
615 #[cfg(feature = "sql")]
616 DataFusionError::SQL(ref desc, ref backtrace) => {
617 let backtrace: String =
618 backtrace.clone().unwrap_or_else(|| "".to_owned());
619 Cow::Owned(format!("{desc:?}{backtrace}"))
620 }
621 DataFusionError::Configuration(ref desc) => Cow::Owned(desc.to_string()),
622 DataFusionError::NotImplemented(ref desc) => Cow::Owned(desc.to_string()),
623 DataFusionError::Internal(ref desc) => Cow::Owned(format!(
624 "{desc}.\nThis issue was likely caused by a bug in DataFusion's code. \
625 Please help us to resolve this by filing a bug report in our issue tracker: \
626 https://github.com/apache/datafusion/issues"
627 )),
628 DataFusionError::Plan(ref desc) => Cow::Owned(desc.to_string()),
629 DataFusionError::SchemaError(ref desc, ref backtrace) => {
630 let backtrace: &str =
631 &backtrace.as_ref().clone().unwrap_or_else(|| "".to_owned());
632 Cow::Owned(format!("{desc}{backtrace}"))
633 }
634 DataFusionError::Execution(ref desc) => Cow::Owned(desc.to_string()),
635 DataFusionError::ExecutionJoin(ref desc) => Cow::Owned(desc.to_string()),
636 DataFusionError::ResourcesExhausted(ref desc) => Cow::Owned(desc.to_string()),
637 DataFusionError::External(ref desc) => Cow::Owned(desc.to_string()),
638 #[cfg(feature = "object_store")]
639 DataFusionError::ObjectStore(ref desc) => Cow::Owned(desc.to_string()),
640 DataFusionError::Context(ref desc, ref err) => {
641 Cow::Owned(format!("{desc}\ncaused by\n{}", *err))
642 }
643 DataFusionError::Substrait(ref desc) => Cow::Owned(desc.to_string()),
644 DataFusionError::Diagnostic(_, ref err) => Cow::Owned(err.to_string()),
645 DataFusionError::Collection(ref errs) => errs
649 .first()
650 .expect("cannot construct DataFusionError::Collection with 0 errors")
651 .message(),
652 DataFusionError::Shared(ref desc) => Cow::Owned(desc.to_string()),
653 DataFusionError::Ffi(ref desc) => Cow::Owned(desc.to_string()),
654 }
655 }
656
657 pub fn with_diagnostic(self, diagnostic: Diagnostic) -> Self {
659 Self::Diagnostic(Box::new(diagnostic), Box::new(self))
660 }
661
662 pub fn with_diagnostic_fn<F: FnOnce(&DataFusionError) -> Diagnostic>(
666 self,
667 f: F,
668 ) -> Self {
669 let diagnostic = f(&self);
670 self.with_diagnostic(diagnostic)
671 }
672
673 pub fn diagnostic(&self) -> Option<&Diagnostic> {
676 struct DiagnosticsIterator<'a> {
677 head: &'a DataFusionError,
678 }
679
680 impl<'a> Iterator for DiagnosticsIterator<'a> {
681 type Item = &'a Diagnostic;
682
683 fn next(&mut self) -> Option<Self::Item> {
684 loop {
685 if let DataFusionError::Diagnostic(diagnostics, source) = self.head {
686 self.head = source.as_ref();
687 return Some(diagnostics);
688 }
689
690 {
691 let source = self.head.source().and_then(|source| {
692 source.downcast_ref::<DataFusionError>()
693 })?;
694 self.head = source;
695 }
696 }
697 }
698 }
699
700 DiagnosticsIterator { head: self }.next()
701 }
702
703 pub fn iter(&self) -> impl Iterator<Item = &DataFusionError> {
714 struct ErrorIterator<'a> {
715 queue: VecDeque<&'a DataFusionError>,
716 }
717
718 impl<'a> Iterator for ErrorIterator<'a> {
719 type Item = &'a DataFusionError;
720
721 fn next(&mut self) -> Option<Self::Item> {
722 loop {
723 let popped = self.queue.pop_front()?;
724 match popped {
725 DataFusionError::Collection(errs) => self.queue.extend(errs),
726 _ => return Some(popped),
727 }
728 }
729 }
730 }
731
732 let mut queue = VecDeque::new();
733 queue.push_back(self);
734 ErrorIterator { queue }
735 }
736}
737
738#[derive(Debug, Default)]
763pub struct DataFusionErrorBuilder(Vec<DataFusionError>);
764
765impl DataFusionErrorBuilder {
766 pub fn new() -> Self {
768 Default::default()
769 }
770
771 pub fn add_error(&mut self, error: DataFusionError) {
784 self.0.push(error);
785 }
786
787 pub fn with_error(mut self, error: DataFusionError) -> Self {
800 self.0.push(error);
801 self
802 }
803
804 pub fn error_or<T>(self, ok: T) -> Result<T, DataFusionError> {
807 match self.0.len() {
808 0 => Ok(ok),
809 1 => Err(self.0.into_iter().next().expect("length matched 1")),
810 _ => Err(DataFusionError::Collection(self.0)),
811 }
812 }
813}
814
815#[macro_export]
820macro_rules! unwrap_or_internal_err {
821 ($Value: ident) => {
822 $Value.ok_or_else(|| {
823 $crate::error::_internal_datafusion_err!(
824 "{} should not be None",
825 stringify!($Value)
826 )
827 })?
828 };
829}
830
831#[macro_export]
841macro_rules! assert_or_internal_err {
842 ($cond:expr) => {
843 if !$cond {
844 return Err($crate::error::_internal_datafusion_err!(
845 "Assertion failed: {}",
846 stringify!($cond)
847 ));
848 }
849 };
850 ($cond:expr, $($arg:tt)+) => {
851 if !$cond {
852 return Err($crate::error::_internal_datafusion_err!(
853 "Assertion failed: {}: {}",
854 stringify!($cond),
855 format!($($arg)+)
856 ));
857 }
858 };
859}
860
861#[macro_export]
871macro_rules! assert_eq_or_internal_err {
872 ($left:expr, $right:expr $(,)?) => {{
873 let left_val = &$left;
874 let right_val = &$right;
875 if left_val != right_val {
876 return Err($crate::error::_internal_datafusion_err!(
877 "Assertion failed: {} == {} (left: {:?}, right: {:?})",
878 stringify!($left),
879 stringify!($right),
880 left_val,
881 right_val
882 ));
883 }
884 }};
885 ($left:expr, $right:expr, $($arg:tt)+) => {{
886 let left_val = &$left;
887 let right_val = &$right;
888 if left_val != right_val {
889 return Err($crate::error::_internal_datafusion_err!(
890 "Assertion failed: {} == {} (left: {:?}, right: {:?}): {}",
891 stringify!($left),
892 stringify!($right),
893 left_val,
894 right_val,
895 format!($($arg)+)
896 ));
897 }
898 }};
899}
900
901#[macro_export]
911macro_rules! assert_ne_or_internal_err {
912 ($left:expr, $right:expr $(,)?) => {{
913 let left_val = &$left;
914 let right_val = &$right;
915 if left_val == right_val {
916 return Err($crate::error::_internal_datafusion_err!(
917 "Assertion failed: {} != {} (left: {:?}, right: {:?})",
918 stringify!($left),
919 stringify!($right),
920 left_val,
921 right_val
922 ));
923 }
924 }};
925 ($left:expr, $right:expr, $($arg:tt)+) => {{
926 let left_val = &$left;
927 let right_val = &$right;
928 if left_val == right_val {
929 return Err($crate::error::_internal_datafusion_err!(
930 "Assertion failed: {} != {} (left: {:?}, right: {:?}): {}",
931 stringify!($left),
932 stringify!($right),
933 left_val,
934 right_val,
935 format!($($arg)+)
936 ));
937 }
938 }};
939}
940
941macro_rules! make_error {
958 ($NAME_ERR:ident, $PREFIXED_NAME_ERR:ident, $NAME_DF_ERR:ident, $PREFIXED_NAME_DF_ERR:ident, $ERR:ident) => {
959 make_error!(@inner ($), $NAME_ERR, $PREFIXED_NAME_ERR, $NAME_DF_ERR, $PREFIXED_NAME_DF_ERR, $ERR);
960 };
961 (@inner ($d:tt), $NAME_ERR:ident, $PREFIXED_NAME_ERR:ident, $NAME_DF_ERR:ident, $PREFIXED_NAME_DF_ERR:ident, $ERR:ident) => {
962 #[macro_export]
964 macro_rules! $NAME_DF_ERR {
965 ($d($d args:expr),* $d(; diagnostic = $d DIAG:expr)?) => {{
966 let err = $crate::DataFusionError::$ERR(
967 ::std::format!(
968 "{}{}",
969 ::std::format!($d($d args),*),
970 $crate::DataFusionError::get_back_trace(),
971 ).into()
972 );
973 $d (
974 let err = err.with_diagnostic($d DIAG);
975 )?
976 err
977 }}
978 }
979
980 #[macro_export]
982 macro_rules! $NAME_ERR {
983 ($d($d args:expr),* $d(; diagnostic = $d DIAG:expr)?) => {{
984 let err = $crate::$PREFIXED_NAME_DF_ERR!($d($d args),*);
985 $d (
986 let err = err.with_diagnostic($d DIAG);
987 )?
988 Err(err)
989 }}
990 }
991
992 #[doc(hidden)]
993 pub use $NAME_ERR as $PREFIXED_NAME_ERR;
994 #[doc(hidden)]
995 pub use $NAME_DF_ERR as $PREFIXED_NAME_DF_ERR;
996 };
997}
998
999make_error!(
1001 plan_err,
1002 _plan_err,
1003 plan_datafusion_err,
1004 _plan_datafusion_err,
1005 Plan
1006);
1007
1008make_error!(
1010 internal_err,
1011 _internal_err,
1012 internal_datafusion_err,
1013 _internal_datafusion_err,
1014 Internal
1015);
1016
1017make_error!(
1019 not_impl_err,
1020 _not_impl_err,
1021 not_impl_datafusion_err,
1022 _not_impl_datafusion_err,
1023 NotImplemented
1024);
1025
1026make_error!(
1028 exec_err,
1029 _exec_err,
1030 exec_datafusion_err,
1031 _exec_datafusion_err,
1032 Execution
1033);
1034
1035make_error!(
1037 config_err,
1038 _config_err,
1039 config_datafusion_err,
1040 _config_datafusion_err,
1041 Configuration
1042);
1043
1044make_error!(
1046 substrait_err,
1047 _substrait_err,
1048 substrait_datafusion_err,
1049 _substrait_datafusion_err,
1050 Substrait
1051);
1052
1053make_error!(
1055 resources_err,
1056 _resources_err,
1057 resources_datafusion_err,
1058 _resources_datafusion_err,
1059 ResourcesExhausted
1060);
1061
1062make_error!(
1064 ffi_err,
1065 _ffi_err,
1066 ffi_datafusion_err,
1067 _ffi_datafusion_err,
1068 Ffi
1069);
1070
1071#[macro_export]
1073macro_rules! sql_datafusion_err {
1074 ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
1075 let err = $crate::DataFusionError::SQL(Box::new($ERR), Some($crate::DataFusionError::get_back_trace()));
1076 $(
1077 let err = err.with_diagnostic($DIAG);
1078 )?
1079 err
1080 }};
1081}
1082
1083#[macro_export]
1085macro_rules! sql_err {
1086 ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
1087 let err = $crate::sql_datafusion_err!($ERR);
1088 $(
1089 let err = err.with_diagnostic($DIAG);
1090 )?
1091 Err(err)
1092 }};
1093}
1094
1095#[macro_export]
1097macro_rules! arrow_datafusion_err {
1098 ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
1099 let err = $crate::DataFusionError::ArrowError(Box::new($ERR), Some($crate::DataFusionError::get_back_trace()));
1100 $(
1101 let err = err.with_diagnostic($DIAG);
1102 )?
1103 err
1104 }};
1105}
1106
1107#[macro_export]
1109macro_rules! arrow_err {
1110 ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {
1111 {
1112 let err = $crate::arrow_datafusion_err!($ERR);
1113 $(
1114 let err = err.with_diagnostic($DIAG);
1115 )?
1116 Err(err)
1117 }};
1118}
1119
1120#[macro_export]
1122macro_rules! schema_datafusion_err {
1123 ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
1124 let err = $crate::DataFusionError::SchemaError(
1125 Box::new($ERR),
1126 Box::new(Some($crate::DataFusionError::get_back_trace())),
1127 );
1128 $(
1129 let err = err.with_diagnostic($DIAG);
1130 )?
1131 err
1132 }};
1133}
1134
1135#[macro_export]
1137macro_rules! schema_err {
1138 ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
1139 let err = $crate::DataFusionError::SchemaError(
1140 Box::new($ERR),
1141 Box::new(Some($crate::DataFusionError::get_back_trace())),
1142 );
1143 $(
1144 let err = err.with_diagnostic($DIAG);
1145 )?
1146 Err(err)
1147 }
1148 };
1149}
1150
1151pub use schema_err as _schema_err;
1154
1155pub fn field_not_found<R: Into<TableReference>>(
1157 qualifier: Option<R>,
1158 name: &str,
1159 schema: &DFSchema,
1160) -> DataFusionError {
1161 schema_datafusion_err!(SchemaError::FieldNotFound {
1162 field: Box::new(Column::new(qualifier, name)),
1163 valid_fields: schema.columns().to_vec(),
1164 })
1165}
1166
1167pub fn unqualified_field_not_found(name: &str, schema: &DFSchema) -> DataFusionError {
1169 schema_datafusion_err!(SchemaError::FieldNotFound {
1170 field: Box::new(Column::new_unqualified(name)),
1171 valid_fields: schema.columns().to_vec(),
1172 })
1173}
1174
1175pub fn add_possible_columns_to_diag(
1176 diagnostic: &mut Diagnostic,
1177 field: &Column,
1178 valid_fields: &[Column],
1179) {
1180 let field_names: Vec<String> = valid_fields
1181 .iter()
1182 .filter_map(|f| {
1183 if normalized_levenshtein(f.name(), field.name()) >= 0.5 {
1184 Some(f.flat_name())
1185 } else {
1186 None
1187 }
1188 })
1189 .collect();
1190
1191 for name in field_names {
1192 diagnostic.add_note(format!("possible column {name}"), None);
1193 }
1194}
1195
1196#[cfg(test)]
1197mod test {
1198 use super::*;
1199
1200 use std::mem::size_of;
1201 use std::sync::Arc;
1202
1203 use arrow::error::ArrowError;
1204
1205 fn ok_result() -> Result<()> {
1206 Ok(())
1207 }
1208
1209 #[test]
1210 fn test_assert_eq_or_internal_err_passes() -> Result<()> {
1211 assert_eq_or_internal_err!(1, 1);
1212 ok_result()
1213 }
1214
1215 #[test]
1216 fn test_assert_eq_or_internal_err_fails() {
1217 fn check() -> Result<()> {
1218 assert_eq_or_internal_err!(1, 2, "expected equality");
1219 ok_result()
1220 }
1221
1222 let err = check().unwrap_err().strip_backtrace();
1223 assert!(err.starts_with("Internal error: Assertion failed: 1 == 2 (left: 1, right: 2): expected equality"));
1224 }
1225
1226 #[test]
1227 fn test_assert_ne_or_internal_err_passes() -> Result<()> {
1228 assert_ne_or_internal_err!(1, 2);
1229 ok_result()
1230 }
1231
1232 #[test]
1233 fn test_assert_ne_or_internal_err_fails() {
1234 fn check() -> Result<()> {
1235 assert_ne_or_internal_err!(3, 3, "values must differ");
1236 ok_result()
1237 }
1238
1239 let err = check().unwrap_err().strip_backtrace();
1240 assert!(err.starts_with("Internal error: Assertion failed: 3 != 3 (left: 3, right: 3): values must differ"));
1241 }
1242
1243 #[test]
1244 fn test_assert_or_internal_err_passes() -> Result<()> {
1245 assert_or_internal_err!(true);
1246 assert_or_internal_err!(true, "message");
1247 ok_result()
1248 }
1249
1250 #[test]
1251 fn test_assert_or_internal_err_fails_default() {
1252 fn check() -> Result<()> {
1253 assert_or_internal_err!(false);
1254 ok_result()
1255 }
1256
1257 let err = check().unwrap_err().strip_backtrace();
1258 assert!(err.starts_with("Internal error: Assertion failed: false"));
1259 }
1260
1261 #[test]
1262 fn test_assert_or_internal_err_fails_with_message() {
1263 fn check() -> Result<()> {
1264 assert_or_internal_err!(false, "custom message");
1265 ok_result()
1266 }
1267
1268 let err = check().unwrap_err().strip_backtrace();
1269 assert!(
1270 err.starts_with("Internal error: Assertion failed: false: custom message")
1271 );
1272 }
1273
1274 #[test]
1275 fn test_assert_or_internal_err_with_format_arguments() {
1276 fn check() -> Result<()> {
1277 assert_or_internal_err!(false, "custom {}", 42);
1278 ok_result()
1279 }
1280
1281 let err = check().unwrap_err().strip_backtrace();
1282 assert!(err.starts_with("Internal error: Assertion failed: false: custom 42"));
1283 }
1284
1285 #[test]
1286 fn test_error_size() {
1287 assert_eq!(size_of::<SchemaError>(), 40);
1290 assert_eq!(size_of::<DataFusionError>(), 40);
1291 }
1292
1293 #[test]
1294 fn datafusion_error_to_arrow() {
1295 let res = return_arrow_error().unwrap_err();
1296 assert!(
1297 res.to_string()
1298 .starts_with("External error: Error during planning: foo")
1299 );
1300 }
1301
1302 #[test]
1303 fn arrow_error_to_datafusion() {
1304 let res = return_datafusion_error().unwrap_err();
1305 assert_eq!(res.strip_backtrace(), "Arrow error: Schema error: bar");
1306 }
1307
1308 #[cfg(feature = "backtrace")]
1310 fn ensure_rust_backtrace_enabled() {
1311 match std::env::var("RUST_BACKTRACE") {
1312 Ok(val) if val == "1" => {}
1313 _ => panic!("Environment variable RUST_BACKTRACE must be set to 1"),
1314 };
1315 }
1316
1317 #[cfg(feature = "backtrace")]
1319 #[test]
1320 fn test_enabled_backtrace() {
1321 ensure_rust_backtrace_enabled();
1322
1323 let res: Result<(), DataFusionError> = plan_err!("Err");
1324 assert_error_have_message_and_backtrace(
1325 &res.unwrap_err(),
1326 "Error during planning: Err",
1327 );
1328 }
1329
1330 #[cfg(not(feature = "backtrace"))]
1331 #[test]
1332 fn test_disabled_backtrace() {
1333 let res: Result<(), DataFusionError> = plan_err!("Err");
1334 assert_err_without_backtrace_and_equal(
1335 &res.unwrap_err(),
1336 "Error during planning: Err",
1337 );
1338 }
1339
1340 #[cfg(not(feature = "backtrace"))]
1341 fn assert_err_without_backtrace_and_equal(
1342 err: &DataFusionError,
1343 expected_message: &str,
1344 ) {
1345 let err = err.to_string();
1346 assert!(!err.contains(DataFusionError::BACK_TRACE_SEP));
1347 assert_eq!(err, expected_message);
1348 }
1349
1350 #[cfg(not(feature = "backtrace"))]
1351 fn assert_internal_err_without_backtrace_and_equal(
1352 err: &DataFusionError,
1353 expected_message: &str,
1354 ) {
1355 let expected_message_before_backtrace = format!(
1356 "{expected_message}.\nThis issue was likely caused by a bug in DataFusion's code. \
1357 Please help us to resolve this by filing a bug report in our issue tracker: \
1358 https://github.com/apache/datafusion/issues"
1359 );
1360 assert_err_without_backtrace_and_equal(
1361 err,
1362 expected_message_before_backtrace.as_str(),
1363 );
1364 }
1365
1366 #[cfg(feature = "backtrace")]
1367 fn assert_error_have_message_and_backtrace(
1368 err: &DataFusionError,
1369 message_before_backtrace: &str,
1370 ) {
1371 let err = err.to_string();
1372 assert!(err.contains(DataFusionError::BACK_TRACE_SEP));
1373 assert!(
1374 !err.split(DataFusionError::BACK_TRACE_SEP)
1375 .collect::<Vec<&str>>()
1376 .get(1)
1377 .unwrap()
1378 .is_empty()
1379 );
1380 assert_eq!(
1381 err.split(DataFusionError::BACK_TRACE_SEP)
1382 .collect::<Vec<&str>>()
1383 .first()
1384 .copied()
1385 .unwrap(),
1386 message_before_backtrace,
1387 "full error is: {err}"
1388 );
1389 }
1390
1391 #[cfg(feature = "backtrace")]
1392 #[test]
1393 fn test_enabled_backtrace_for_unwrap_or_internal_err() {
1394 ensure_rust_backtrace_enabled();
1395
1396 fn get_error() -> Result<(), DataFusionError> {
1397 let item = None::<()>;
1398 unwrap_or_internal_err!(item);
1399
1400 unreachable!("should return error");
1401 }
1402
1403 let res: Result<(), DataFusionError> = get_error();
1404 assert_error_have_message_and_backtrace(
1405 &res.unwrap_err(),
1406 "Internal error: item should not be None",
1407 );
1408 }
1409
1410 #[cfg(not(feature = "backtrace"))]
1412 #[test]
1413 fn test_disabled_backtrace_for_unwrap_or_internal_err() {
1414 fn get_error() -> Result<(), DataFusionError> {
1415 let item = None::<()>;
1416 unwrap_or_internal_err!(item);
1417
1418 unreachable!("should return error");
1419 }
1420
1421 let res: Result<(), DataFusionError> = get_error();
1422 assert_internal_err_without_backtrace_and_equal(
1423 &res.unwrap_err(),
1424 "Internal error: item should not be None",
1425 );
1426 }
1427
1428 #[cfg(feature = "backtrace")]
1429 #[test]
1430 fn test_enabled_backtrace_for_assert_or_internal_err_without_args() {
1431 ensure_rust_backtrace_enabled();
1432
1433 fn get_error() -> Result<(), DataFusionError> {
1434 assert_or_internal_err!(false);
1435
1436 unreachable!("should return error");
1437 }
1438
1439 let res: Result<(), DataFusionError> = get_error();
1440 assert_error_have_message_and_backtrace(
1441 &res.unwrap_err(),
1442 "Internal error: Assertion failed: false",
1443 );
1444 }
1445
1446 #[cfg(feature = "backtrace")]
1447 #[test]
1448 fn test_enabled_backtrace_for_assert_or_internal_err_with_args() {
1449 ensure_rust_backtrace_enabled();
1450
1451 fn get_error() -> Result<(), DataFusionError> {
1452 assert_or_internal_err!(false, "my cool context");
1453
1454 unreachable!("should return error");
1455 }
1456
1457 let res: Result<(), DataFusionError> = get_error();
1458 assert_error_have_message_and_backtrace(
1459 &res.unwrap_err(),
1460 "Internal error: Assertion failed: false: my cool context",
1461 );
1462 }
1463
1464 #[cfg(not(feature = "backtrace"))]
1465 #[test]
1466 fn test_disabled_backtrace_for_assert_or_internal_err_without_args() {
1467 fn get_error() -> Result<(), DataFusionError> {
1468 assert_or_internal_err!(false);
1469
1470 unreachable!("should return error");
1471 }
1472
1473 let res: Result<(), DataFusionError> = get_error();
1474 assert_internal_err_without_backtrace_and_equal(
1475 &res.unwrap_err(),
1476 "Internal error: Assertion failed: false",
1477 );
1478 }
1479
1480 #[cfg(not(feature = "backtrace"))]
1481 #[test]
1482 fn test_disabled_backtrace_for_assert_or_internal_err_with_args() {
1483 fn get_error() -> Result<(), DataFusionError> {
1484 assert_or_internal_err!(false, "my cool context");
1485
1486 unreachable!("should return error");
1487 }
1488
1489 let res: Result<(), DataFusionError> = get_error();
1490 assert_internal_err_without_backtrace_and_equal(
1491 &res.unwrap_err(),
1492 "Internal error: Assertion failed: false: my cool context",
1493 );
1494 }
1495
1496 #[cfg(feature = "backtrace")]
1497 #[test]
1498 fn test_enabled_backtrace_for_assert_eq_or_internal_err_without_args() {
1499 ensure_rust_backtrace_enabled();
1500
1501 fn get_error() -> Result<(), DataFusionError> {
1502 let arg1 = 1;
1503 let arg2 = 2;
1504 assert_eq_or_internal_err!(arg1, arg2);
1505
1506 unreachable!("should return error");
1507 }
1508
1509 let res: Result<(), DataFusionError> = get_error();
1510 assert_error_have_message_and_backtrace(
1511 &res.unwrap_err(),
1512 "Internal error: Assertion failed: arg1 == arg2 (left: 1, right: 2)",
1513 );
1514 }
1515
1516 #[cfg(feature = "backtrace")]
1517 #[test]
1518 fn test_enabled_backtrace_for_assert_eq_or_internal_err_with_args() {
1519 ensure_rust_backtrace_enabled();
1520
1521 fn get_error() -> Result<(), DataFusionError> {
1522 let arg1 = 1;
1523 let arg2 = 2;
1524 assert_eq_or_internal_err!(arg1, arg2, "my cool context");
1525
1526 unreachable!("should return error");
1527 }
1528
1529 let res: Result<(), DataFusionError> = get_error();
1530 assert_error_have_message_and_backtrace(
1531 &res.unwrap_err(),
1532 "Internal error: Assertion failed: arg1 == arg2 (left: 1, right: 2): my cool context",
1533 );
1534 }
1535
1536 #[cfg(not(feature = "backtrace"))]
1537 #[test]
1538 fn test_disabled_backtrace_for_assert_eq_or_internal_err_without_args() {
1539 fn get_error() -> Result<(), DataFusionError> {
1540 let arg1 = 1;
1541 let arg2 = 2;
1542 assert_eq_or_internal_err!(arg1, arg2);
1543
1544 unreachable!("should return error");
1545 }
1546
1547 let res: Result<(), DataFusionError> = get_error();
1548 assert_internal_err_without_backtrace_and_equal(
1549 &res.unwrap_err(),
1550 "Internal error: Assertion failed: arg1 == arg2 (left: 1, right: 2)",
1551 );
1552 }
1553
1554 #[cfg(not(feature = "backtrace"))]
1555 #[test]
1556 fn test_disabled_backtrace_for_assert_eq_or_internal_err_with_args() {
1557 fn get_error() -> Result<(), DataFusionError> {
1558 let arg1 = 1;
1559 let arg2 = 2;
1560 assert_eq_or_internal_err!(arg1, arg2, "my cool context");
1561
1562 unreachable!("should return error");
1563 }
1564
1565 let res: Result<(), DataFusionError> = get_error();
1566 assert_internal_err_without_backtrace_and_equal(
1567 &res.unwrap_err(),
1568 "Internal error: Assertion failed: arg1 == arg2 (left: 1, right: 2): my cool context",
1569 );
1570 }
1571
1572 #[cfg(feature = "backtrace")]
1573 #[test]
1574 fn test_enabled_backtrace_for_assert_ne_or_internal_err_without_args() {
1575 ensure_rust_backtrace_enabled();
1576
1577 fn get_error() -> Result<(), DataFusionError> {
1578 let arg1 = 1;
1579 let arg2 = 1;
1580 assert_ne_or_internal_err!(arg1, arg2);
1581
1582 unreachable!("should return error");
1583 }
1584
1585 let res: Result<(), DataFusionError> = get_error();
1586 assert_error_have_message_and_backtrace(
1587 &res.unwrap_err(),
1588 "Internal error: Assertion failed: arg1 != arg2 (left: 1, right: 1)",
1589 );
1590 }
1591
1592 #[cfg(feature = "backtrace")]
1593 #[test]
1594 fn test_enabled_backtrace_for_assert_ne_or_internal_err_with_args() {
1595 ensure_rust_backtrace_enabled();
1596
1597 fn get_error() -> Result<(), DataFusionError> {
1598 let arg1 = 1;
1599 let arg2 = 1;
1600 assert_ne_or_internal_err!(arg1, arg2, "my cool context");
1601
1602 unreachable!("should return error");
1603 }
1604
1605 let res: Result<(), DataFusionError> = get_error();
1606 assert_error_have_message_and_backtrace(
1607 &res.unwrap_err(),
1608 "Internal error: Assertion failed: arg1 != arg2 (left: 1, right: 1): my cool context",
1609 );
1610 }
1611
1612 #[cfg(not(feature = "backtrace"))]
1613 #[test]
1614 fn test_disabled_backtrace_for_assert_ne_or_internal_err_without_args() {
1615 fn get_error() -> Result<(), DataFusionError> {
1616 let arg1 = 1;
1617 let arg2 = 1;
1618 assert_ne_or_internal_err!(arg1, arg2);
1619
1620 unreachable!("should return error");
1621 }
1622
1623 let res: Result<(), DataFusionError> = get_error();
1624 assert_internal_err_without_backtrace_and_equal(
1625 &res.unwrap_err(),
1626 "Internal error: Assertion failed: arg1 != arg2 (left: 1, right: 1)",
1627 );
1628 }
1629
1630 #[cfg(not(feature = "backtrace"))]
1631 #[test]
1632 fn test_disabled_backtrace_for_assert_ne_or_internal_err_with_args() {
1633 fn get_error() -> Result<(), DataFusionError> {
1634 let arg1 = 1;
1635 let arg2 = 1;
1636 assert_ne_or_internal_err!(arg1, arg2, "my cool context");
1637
1638 unreachable!("should return error");
1639 }
1640
1641 let res: Result<(), DataFusionError> = get_error();
1642 assert_internal_err_without_backtrace_and_equal(
1643 &res.unwrap_err(),
1644 "Internal error: Assertion failed: arg1 != arg2 (left: 1, right: 1): my cool context",
1645 );
1646 }
1647
1648 #[test]
1649 fn test_find_root_error() {
1650 do_root_test(
1651 DataFusionError::Context(
1652 "it happened!".to_string(),
1653 Box::new(DataFusionError::ResourcesExhausted("foo".to_string())),
1654 ),
1655 DataFusionError::ResourcesExhausted("foo".to_string()),
1656 );
1657
1658 do_root_test(
1659 DataFusionError::ArrowError(
1660 Box::new(ArrowError::ExternalError(Box::new(
1661 DataFusionError::ResourcesExhausted("foo".to_string()),
1662 ))),
1663 None,
1664 ),
1665 DataFusionError::ResourcesExhausted("foo".to_string()),
1666 );
1667
1668 do_root_test(
1669 DataFusionError::External(Box::new(DataFusionError::ResourcesExhausted(
1670 "foo".to_string(),
1671 ))),
1672 DataFusionError::ResourcesExhausted("foo".to_string()),
1673 );
1674
1675 do_root_test(
1676 DataFusionError::External(Box::new(ArrowError::ExternalError(Box::new(
1677 DataFusionError::ResourcesExhausted("foo".to_string()),
1678 )))),
1679 DataFusionError::ResourcesExhausted("foo".to_string()),
1680 );
1681
1682 do_root_test(
1683 DataFusionError::ArrowError(
1684 Box::new(ArrowError::ExternalError(Box::new(
1685 ArrowError::ExternalError(Box::new(
1686 DataFusionError::ResourcesExhausted("foo".to_string()),
1687 )),
1688 ))),
1689 None,
1690 ),
1691 DataFusionError::ResourcesExhausted("foo".to_string()),
1692 );
1693
1694 do_root_test(
1695 DataFusionError::External(Box::new(Arc::new(
1696 DataFusionError::ResourcesExhausted("foo".to_string()),
1697 ))),
1698 DataFusionError::ResourcesExhausted("foo".to_string()),
1699 );
1700
1701 do_root_test(
1702 DataFusionError::External(Box::new(Arc::new(ArrowError::ExternalError(
1703 Box::new(DataFusionError::ResourcesExhausted("foo".to_string())),
1704 )))),
1705 DataFusionError::ResourcesExhausted("foo".to_string()),
1706 );
1707 }
1708
1709 #[test]
1710 fn test_make_error_parse_input() {
1711 let res: Result<(), DataFusionError> = plan_err!("Err");
1712 let res = res.unwrap_err();
1713 assert_eq!(res.strip_backtrace(), "Error during planning: Err");
1714
1715 let extra1 = "extra1";
1716 let extra2 = "extra2";
1717
1718 let res: Result<(), DataFusionError> = plan_err!("Err {} {}", extra1, extra2);
1719 let res = res.unwrap_err();
1720 assert_eq!(
1721 res.strip_backtrace(),
1722 "Error during planning: Err extra1 extra2"
1723 );
1724
1725 let res: Result<(), DataFusionError> =
1726 plan_err!("Err {:?} {:#?}", extra1, extra2);
1727 let res = res.unwrap_err();
1728 assert_eq!(
1729 res.strip_backtrace(),
1730 "Error during planning: Err \"extra1\" \"extra2\""
1731 );
1732
1733 let res: Result<(), DataFusionError> = plan_err!("Err {extra1} {extra2}");
1734 let res = res.unwrap_err();
1735 assert_eq!(
1736 res.strip_backtrace(),
1737 "Error during planning: Err extra1 extra2"
1738 );
1739
1740 let res: Result<(), DataFusionError> = plan_err!("Err {extra1:?} {extra2:#?}");
1741 let res = res.unwrap_err();
1742 assert_eq!(
1743 res.strip_backtrace(),
1744 "Error during planning: Err \"extra1\" \"extra2\""
1745 );
1746 }
1747
1748 #[test]
1749 fn external_error() {
1750 let generic_error: GenericError =
1752 Box::new(DataFusionError::Plan("test".to_string()));
1753 let datafusion_error: DataFusionError = generic_error.into();
1754 println!("{}", datafusion_error.strip_backtrace());
1755 assert_eq!(
1756 datafusion_error.strip_backtrace(),
1757 "Error during planning: test"
1758 );
1759
1760 let generic_error: GenericError = Box::new(io::Error::other("io error"));
1762 let datafusion_error: DataFusionError = generic_error.into();
1763 println!("{}", datafusion_error.strip_backtrace());
1764 assert_eq!(
1765 datafusion_error.strip_backtrace(),
1766 "External error: io error"
1767 );
1768 }
1769
1770 #[test]
1771 fn external_error_no_recursive() {
1772 let generic_error_1: GenericError = Box::new(io::Error::other("io error"));
1773 let external_error_1: DataFusionError = generic_error_1.into();
1774 let generic_error_2: GenericError = Box::new(external_error_1);
1775 let external_error_2: DataFusionError = generic_error_2.into();
1776
1777 println!("{external_error_2}");
1778 assert!(
1779 external_error_2
1780 .to_string()
1781 .starts_with("External error: io error")
1782 );
1783 }
1784
1785 fn return_arrow_error() -> arrow::error::Result<()> {
1788 Err(DataFusionError::Plan("foo".to_string()).into())
1790 }
1791
1792 fn return_datafusion_error() -> Result<()> {
1795 Err(ArrowError::SchemaError("bar".to_string()).into())
1797 }
1798
1799 fn do_root_test(e: DataFusionError, exp: DataFusionError) {
1800 let e = e.find_root();
1801
1802 assert_eq!(e.strip_backtrace(), exp.strip_backtrace());
1804 assert_eq!(std::mem::discriminant(e), std::mem::discriminant(&exp),)
1805 }
1806
1807 #[test]
1808 fn test_iter() {
1809 let err = DataFusionError::Collection(vec![
1810 DataFusionError::Plan("a".to_string()),
1811 DataFusionError::Collection(vec![
1812 DataFusionError::Plan("b".to_string()),
1813 DataFusionError::Plan("c".to_string()),
1814 ]),
1815 ]);
1816 let errs = err.iter().collect::<Vec<_>>();
1817 assert_eq!(errs.len(), 3);
1818 assert_eq!(errs[0].strip_backtrace(), "Error during planning: a");
1819 assert_eq!(errs[1].strip_backtrace(), "Error during planning: b");
1820 assert_eq!(errs[2].strip_backtrace(), "Error during planning: c");
1821 }
1822}