17
17
18
18
//! DataFusion error types
19
19
20
+ use std:: backtrace:: { Backtrace , BacktraceStatus } ;
20
21
use std:: error:: Error ;
21
22
use std:: fmt:: { Display , Formatter } ;
22
23
use std:: io;
@@ -278,7 +279,9 @@ impl From<GenericError> for DataFusionError {
278
279
impl Display for DataFusionError {
279
280
fn fmt ( & self , f : & mut Formatter ) -> std:: fmt:: Result {
280
281
match * self {
281
- DataFusionError :: ArrowError ( ref desc) => write ! ( f, "Arrow error: {desc}" ) ,
282
+ DataFusionError :: ArrowError ( ref desc) => {
283
+ write ! ( f, "Arrow error: {desc}" )
284
+ }
282
285
#[ cfg( feature = "parquet" ) ]
283
286
DataFusionError :: ParquetError ( ref desc) => {
284
287
write ! ( f, "Parquet error: {desc}" )
@@ -287,7 +290,9 @@ impl Display for DataFusionError {
287
290
DataFusionError :: AvroError ( ref desc) => {
288
291
write ! ( f, "Avro error: {desc}" )
289
292
}
290
- DataFusionError :: IoError ( ref desc) => write ! ( f, "IO error: {desc}" ) ,
293
+ DataFusionError :: IoError ( ref desc) => {
294
+ write ! ( f, "IO error: {desc}" )
295
+ }
291
296
DataFusionError :: SQL ( ref desc) => {
292
297
write ! ( f, "SQL error: {desc:?}" )
293
298
}
@@ -298,7 +303,7 @@ impl Display for DataFusionError {
298
303
write ! ( f, "This feature is not implemented: {desc}" )
299
304
}
300
305
DataFusionError :: Internal ( ref desc) => {
301
- write ! ( f, "Internal error: {desc}. This was likely caused by a bug in DataFusion's \
306
+ write ! ( f, "Internal error: {desc}.\n This was likely caused by a bug in DataFusion's \
302
307
code and we would welcome that you file an bug report in our issue tracker")
303
308
}
304
309
DataFusionError :: Plan ( ref desc) => {
@@ -404,6 +409,24 @@ impl DataFusionError {
404
409
pub fn context ( self , description : impl Into < String > ) -> Self {
405
410
Self :: Context ( description. into ( ) , Box :: new ( self ) )
406
411
}
412
+
413
+ pub fn strip_backtrace ( & self ) -> String {
414
+ self . to_string ( )
415
+ . split ( "\n \n backtrace: " )
416
+ . collect :: < Vec < & str > > ( )
417
+ . first ( )
418
+ . unwrap_or ( & "" )
419
+ . to_string ( )
420
+ }
421
+
422
+ pub fn get_back_trace ( ) -> String {
423
+ let back_trace = Backtrace :: capture ( ) ;
424
+ if back_trace. status ( ) == BacktraceStatus :: Captured {
425
+ return format ! ( "\n \n backtrace: {}" , back_trace) ;
426
+ }
427
+
428
+ "" . to_string ( )
429
+ }
407
430
}
408
431
409
432
/// Unwrap an `Option` if possible. Otherwise return an `DataFusionError::Internal`.
@@ -444,7 +467,7 @@ macro_rules! make_error {
444
467
#[ macro_export]
445
468
macro_rules! $NAME {
446
469
( $d( $d args: expr) , * ) => {
447
- Err ( DataFusionError :: $ERR( format!( $d( $d args) , * ) . into( ) ) )
470
+ Err ( DataFusionError :: $ERR( format!( "{}{}" , format! ( $d( $d args) , * ) , DataFusionError :: get_back_trace ( ) ) . into( ) ) )
448
471
}
449
472
}
450
473
}
@@ -464,6 +487,14 @@ make_error!(not_impl_err, NotImplemented);
464
487
// Exposes a macro to create `DataFusionError::Execution`
465
488
make_error ! ( exec_err, Execution ) ;
466
489
490
+ // Exposes a macro to create `DataFusionError::SQL`
491
+ #[ macro_export]
492
+ macro_rules! sql_err {
493
+ ( $ERR: expr) => {
494
+ Err ( DataFusionError :: SQL ( $ERR) )
495
+ } ;
496
+ }
497
+
467
498
// To avoid compiler error when using macro in the same crate:
468
499
// macros from the current crate cannot be referred to by absolute paths
469
500
pub use exec_err as _exec_err;
@@ -478,18 +509,17 @@ mod test {
478
509
use arrow:: error:: ArrowError ;
479
510
480
511
#[ test]
481
- fn arrow_error_to_datafusion ( ) {
512
+ fn datafusion_error_to_arrow ( ) {
482
513
let res = return_arrow_error ( ) . unwrap_err ( ) ;
483
- assert_eq ! (
484
- res. to_string( ) ,
485
- "External error: Error during planning: foo"
486
- ) ;
514
+ assert ! ( res
515
+ . to_string( )
516
+ . starts_with( "External error: Error during planning: foo" ) ) ;
487
517
}
488
518
489
519
#[ test]
490
- fn datafusion_error_to_arrow ( ) {
520
+ fn arrow_error_to_datafusion ( ) {
491
521
let res = return_datafusion_error ( ) . unwrap_err ( ) ;
492
- assert_eq ! ( res. to_string ( ) , "Arrow error: Schema error: bar" ) ;
522
+ assert_eq ! ( res. strip_backtrace ( ) , "Arrow error: Schema error: bar" ) ;
493
523
}
494
524
495
525
#[ test]
@@ -552,31 +582,37 @@ mod test {
552
582
fn test_make_error_parse_input ( ) {
553
583
let res: Result < ( ) , DataFusionError > = plan_err ! ( "Err" ) ;
554
584
let res = res. unwrap_err ( ) ;
555
- assert_eq ! ( res. to_string ( ) , "Error during planning: Err" ) ;
585
+ assert_eq ! ( res. strip_backtrace ( ) , "Error during planning: Err" ) ;
556
586
557
587
let extra1 = "extra1" ;
558
588
let extra2 = "extra2" ;
559
589
560
590
let res: Result < ( ) , DataFusionError > = plan_err ! ( "Err {} {}" , extra1, extra2) ;
561
591
let res = res. unwrap_err ( ) ;
562
- assert_eq ! ( res. to_string( ) , "Error during planning: Err extra1 extra2" ) ;
592
+ assert_eq ! (
593
+ res. strip_backtrace( ) ,
594
+ "Error during planning: Err extra1 extra2"
595
+ ) ;
563
596
564
597
let res: Result < ( ) , DataFusionError > =
565
598
plan_err ! ( "Err {:?} {:#?}" , extra1, extra2) ;
566
599
let res = res. unwrap_err ( ) ;
567
600
assert_eq ! (
568
- res. to_string ( ) ,
601
+ res. strip_backtrace ( ) ,
569
602
"Error during planning: Err \" extra1\" \" extra2\" "
570
603
) ;
571
604
572
605
let res: Result < ( ) , DataFusionError > = plan_err ! ( "Err {extra1} {extra2}" ) ;
573
606
let res = res. unwrap_err ( ) ;
574
- assert_eq ! ( res. to_string( ) , "Error during planning: Err extra1 extra2" ) ;
607
+ assert_eq ! (
608
+ res. strip_backtrace( ) ,
609
+ "Error during planning: Err extra1 extra2"
610
+ ) ;
575
611
576
612
let res: Result < ( ) , DataFusionError > = plan_err ! ( "Err {extra1:?} {extra2:#?}" ) ;
577
613
let res = res. unwrap_err ( ) ;
578
614
assert_eq ! (
579
- res. to_string ( ) ,
615
+ res. strip_backtrace ( ) ,
580
616
"Error during planning: Err \" extra1\" \" extra2\" "
581
617
) ;
582
618
}
@@ -599,7 +635,7 @@ mod test {
599
635
let e = e. find_root ( ) ;
600
636
601
637
// DataFusionError does not implement Eq, so we use a string comparison + some cheap "same variant" test instead
602
- assert_eq ! ( e. to_string ( ) , exp. to_string ( ) , ) ;
638
+ assert_eq ! ( e. strip_backtrace ( ) , exp. strip_backtrace ( ) ) ;
603
639
assert_eq ! ( std:: mem:: discriminant( e) , std:: mem:: discriminant( & exp) , )
604
640
}
605
641
}
0 commit comments