## Coverage Report

#### Created: 2024-10-13 08:39

    /Users/andrewlamb/Software/datafusion/datafusion/common/src/error.rs

    Line
    Count
    Source (jump to first uncovered line)
    1
    // Licensed to the Apache Software Foundation (ASF) under one
    2
    // or more contributor license agreements.  See the NOTICE file
    3
    // distributed with this work for additional information
    4
    // regarding copyright ownership.  The ASF licenses this file
    5
    // to you under the Apache License, Version 2.0 (the
    6
    // "License"); you may not use this file except in compliance
    7
    // with the License.  You may obtain a copy of the License at
    8
    //
    9
    //   http://www.apache.org/licenses/LICENSE-2.0
    10
    //
    11
    // Unless required by applicable law or agreed to in writing,
    12
    // software distributed under the License is distributed on an
    13
    // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14
    // KIND, either express or implied.  See the License for the
    15
    // specific language governing permissions and limitations
    16
    // under the License.
    17
    18
    //! DataFusion error types
    19
    #[cfg(feature = "backtrace")]
    20
    use std::backtrace::{Backtrace, BacktraceStatus};
    21
    22
    use std::borrow::Cow;
    23
    use std::error::Error;
    24
    use std::fmt::{Display, Formatter};
    25
    use std::io;
    26
    use std::result;
    27
    use std::sync::Arc;
    28
    29
    use crate::utils::quote_identifier;
    30
    use crate::{Column, DFSchema, TableReference};
    31
    #[cfg(feature = "avro")]
    32
    use apache_avro::Error as AvroError;
    33
    use arrow::error::ArrowError;
    34
    #[cfg(feature = "parquet")]
    35
    use parquet::errors::ParquetError;
    36
    use sqlparser::parser::ParserError;
    37
    use tokio::task::JoinError;
    38
    39
    /// Result type for operations that could result in an [DataFusionError]
    40
    pub type Result<T, E = DataFusionError> = result::Result<T, E>;
    41
    42
    /// Result type for operations that could result in an [DataFusionError] and needs to be shared (wrapped into `Arc`).
    43
    pub type SharedResult<T> = result::Result<T, Arc<DataFusionError>>;
    44
    45
    /// Error type for generic operations that could result in DataFusionError::External
    46
    pub type GenericError = Box<dyn Error + Send + Sync>;
    47
    48
    /// DataFusion error
    49
    #[derive(Debug)]
    50
    pub enum DataFusionError {
    51
        /// Error returned by arrow.
    52
        ///
    53
        /// 2nd argument is for optional backtrace
    54
        ArrowError(ArrowError, Option<String>),
    55
        /// Error when reading / writing Parquet data.
    56
        #[cfg(feature = "parquet")]
    57
        ParquetError(ParquetError),
    58
        /// Error when reading Avro data.
    59
        #[cfg(feature = "avro")]
    60
        AvroError(AvroError),
    61
        /// Error when reading / writing to / from an object_store (e.g. S3 or LocalFile)
    62
        #[cfg(feature = "object_store")]
    63
        ObjectStore(object_store::Error),
    64
        /// Error when an I/O operation fails
    65
        IoError(io::Error),
    66
        /// Error when SQL is syntactically incorrect.
    67
        ///
    68
        /// 2nd argument is for optional backtrace
    69
        SQL(ParserError, Option<String>),
    70
        /// Error when a feature is not yet implemented.
    71
        ///
    72
        /// These errors are sometimes returned for features that are still in
    73
        /// development and are not entirely complete. Often, these errors are
    74
        /// tracked in our issue tracker.
    75
        NotImplemented(String),
    76
        /// Error due to bugs in DataFusion
    77
        ///
    78
        /// This error should not happen in normal usage of DataFusion. It results
    79
        /// from something that wasn't expected/anticipated by the implementation
    80
        /// and that is most likely a bug (the error message even encourages users
    81
        /// to open a bug report). A user should not be able to trigger internal
    82
        /// errors under normal circumstances by feeding in malformed queries, bad
    83
        /// data, etc.
    84
        ///
    85
        /// Note that I/O errors (or any error that happens due to external systems)
    86
        /// do NOT fall under this category. See other variants such as
    87
        /// [`Self::IoError`] and [`Self::External`].
    88
        ///
    89
        /// DataFusions has internal invariants that the compiler is not always able
    90
        /// to check. This error is raised when one of those invariants does not
    91
        /// hold for some reason.
    92
        Internal(String),
    93
        /// Error during planning of the query.
    94
        ///
    95
        /// This error happens when the user provides a bad query or plan, for
    96
        /// example the user attempts to call a function that doesn't exist, or if
    97
        /// the types of a function call are not supported.
    98
        Plan(String),
    99
        /// Error for invalid or unsupported configuration options.
    100
        Configuration(String),
    101
        /// Error when there is a problem with the query related to schema.
    102
        ///
    103
        /// This error can be returned in cases such as when schema inference is not
    104
        /// possible and when column names are not unique.
    105
        ///
    106
        /// 2nd argument is for optional backtrace
    107
        /// Boxing the optional backtrace to prevent <https://rust-lang.github.io/rust-clippy/master/index.html#/result_large_err>
    108
        SchemaError(SchemaError, Box<Option<String>>),
    109
        /// Error during execution of the query.
    110
        ///
    111
        /// This error is returned when an error happens during execution due to a
    112
        /// malformed input. For example, the user passed malformed arguments to a
    113
        /// SQL method, opened a CSV file that is broken, or tried to divide an
    114
        /// integer by zero.
    115
        Execution(String),
    116
        /// [`JoinError`] during execution of the query.
    117
        ///
    118
        /// This error can unoccur for unjoined tasks, such as execution shutdown.
    119
        ExecutionJoin(JoinError),
    120
        /// Error when resources (such as memory of scratch disk space) are exhausted.
    121
        ///
    122
        /// This error is thrown when a consumer cannot acquire additional memory
    123
        /// or other resources needed to execute the query from the Memory Manager.
    124
        ResourcesExhausted(String),
    125
        /// Errors originating from outside DataFusion's core codebase.
    126
        ///
    127
        /// For example, a custom S3Error from the crate datafusion-objectstore-s3
    128
        External(GenericError),
    129
        /// Error with additional context
    130
        Context(String, Box<DataFusionError>),
    131
        /// Errors from either mapping LogicalPlans to/from Substrait plans
    132
        /// or serializing/deserializing protobytes to Substrait plans
    133
        Substrait(String),
    134
    }
    135
    136
    #[macro_export]
    137
    macro_rules! context {
    138
        ($desc:expr, $err:expr) => {
    139
            $err.context(format!("{} at {}:{}", $desc, file!(), line!()))
    140
        };
    141
    }
    142
    143
    /// Schema-related errors
    144
    #[derive(Debug)]
    145
    pub enum SchemaError {
    146
        /// Schema contains a (possibly) qualified and unqualified field with same unqualified name
    147
        AmbiguousReference { field: Column },
    148
        /// Schema contains duplicate qualified field name
    149
        DuplicateQualifiedField {
    150
            qualifier: Box<TableReference>,
    151
            name: String,
    152
        },
    153
        /// Schema contains duplicate unqualified field name
    154
        DuplicateUnqualifiedField { name: String },
    155
        /// No field with this name
    156
        FieldNotFound {
    157
            field: Box<Column>,
    158
            valid_fields: Vec<Column>,
    159
        },
    160
    }
    161
    162
    impl Display for SchemaError {
    163
    0
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    164
    0
            match self {
    165
                Self::FieldNotFound {
    166
    0
                    field,
    167
    0
                    valid_fields,
    168
    0
                } => {
    169
    0
                    write!(f, "No field named {}", field.quoted_flat_name())?;
    170
    0
                    if !valid_fields.is_empty() {
    171
    0
                        write!(
    172
    0
                            f,
    173
    0
                            ". Valid fields are {}",
    174
    0
                            valid_fields
    175
    0
                                .iter()
    176
    0
                                .map(|field| field.quoted_flat_name())
    177
    0
                                .collect::<Vec<String>>()
    178
    0
                                .join(", ")
    179
    0
                        )?;
    180
    0
                    }
    181
    0
                    write!(f, ".")
    182
                }
    183
    0
                Self::DuplicateQualifiedField { qualifier, name } => {
    184
    0
                    write!(
    185
    0
                        f,
    186
    0
                        "Schema contains duplicate qualified field name {}.{}",
    187
    0
                        qualifier.to_quoted_string(),
    188
    0
                        quote_identifier(name)
    189
    0
                    )
    190
                }
    191
    0
                Self::DuplicateUnqualifiedField { name } => {
    192
    0
                    write!(
    193
    0
                        f,
    194
    0
                        "Schema contains duplicate unqualified field name {}",
    195
    0
                        quote_identifier(name)
    196
    0
                    )
    197
                }
    198
    0
                Self::AmbiguousReference { field } => {
    199
    0
                    if field.relation.is_some() {
    200
    0
                        write!(
    201
    0
                            f,
    202
    0
                            "Schema contains qualified field name {} and unqualified field name {} which would be ambiguous",
    203
    0
                            field.quoted_flat_name(),
    204
    0
                            quote_identifier(&field.name)
    205
    0
                        )
    206
                    } else {
    207
    0
                        write!(
    208
    0
                            f,
    209
    0
                            "Ambiguous reference to unqualified field {}",
    210
    0
                            field.quoted_flat_name()
    211
    0
                        )
    212
                    }
    213
                }
    214
            }
    215
    0
        }
    216
    }
    217
    218
    impl Error for SchemaError {}
    219
    220
    impl From<std::fmt::Error> for DataFusionError {
    221
    0
        fn from(_e: std::fmt::Error) -> Self {
    222
    0
            DataFusionError::Execution("Fail to format".to_string())
    223
    0
        }
    224
    }
    225
    226
    impl From<io::Error> for DataFusionError {
    227
    0
        fn from(e: io::Error) -> Self {
    228
    0
            DataFusionError::IoError(e)
    229
    0
        }
    230
    }
    231
    232
    impl From<ArrowError> for DataFusionError {
    233
    2
        fn from(e: ArrowError) -> Self {
    234
    2
            DataFusionError::ArrowError(e, None)
    235
    2
        }
    236
    }
    237
    238
    impl From<DataFusionError> for ArrowError {
    239
    5
        fn from(e: DataFusionError) -> Self {
    240
    5
            match e {
    241
    0
                DataFusionError::ArrowError(e, _) => e,
    242
    5
                DataFusionError::External(e) => ArrowError::ExternalError(e),
    243
    0
                other => ArrowError::ExternalError(Box::new(other)),
    244
            }
    245
    5
        }
    246
    }
    247
    248
    #[cfg(feature = "parquet")]
    249
    impl From<ParquetError> for DataFusionError {
    250
        fn from(e: ParquetError) -> Self {
    251
            DataFusionError::ParquetError(e)
    252
        }
    253
    }
    254
    255
    #[cfg(feature = "avro")]
    256
    impl From<AvroError> for DataFusionError {
    257
        fn from(e: AvroError) -> Self {
    258
            DataFusionError::AvroError(e)
    259
        }
    260
    }
    261
    262
    #[cfg(feature = "object_store")]
    263
    impl From<object_store::Error> for DataFusionError {
    264
        fn from(e: object_store::Error) -> Self {
    265
            DataFusionError::ObjectStore(e)
    266
        }
    267
    }
    268
    269
    #[cfg(feature = "object_store")]
    270
    impl From<object_store::path::Error> for DataFusionError {
    271
        fn from(e: object_store::path::Error) -> Self {
    272
            DataFusionError::ObjectStore(e.into())
    273
        }
    274
    }
    275
    276
    impl From<ParserError> for DataFusionError {
    277
    0
        fn from(e: ParserError) -> Self {
    278
    0
            DataFusionError::SQL(e, None)
    279
    0
        }
    280
    }
    281
    282
    impl From<GenericError> for DataFusionError {
    283
    0
        fn from(err: GenericError) -> Self {
    284
    0
            DataFusionError::External(err)
    285
    0
        }
    286
    }
    287
    288
    impl Display for DataFusionError {
    289
    102
        fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
    290
    102
            let error_prefix = self.error_prefix();
    291
    102
            let message = self.message();
    292
    102
            write!(f, "{error_prefix}{message}")
    293
    102
        }
    294
    }
    295
    296
    impl Error for DataFusionError {
    297
    12
        fn source(&self) -> Option<&(dyn Error + 'static)> {
    298
    12
            match self {
    299
    6
                DataFusionError::ArrowError(e, _) => Some(e),
    300
                #[cfg(feature = "parquet")]
    301
                DataFusionError::ParquetError(e) => Some(e),
    302
                #[cfg(feature = "avro")]
    303
                DataFusionError::AvroError(e) => Some(e),
    304
                #[cfg(feature = "object_store")]
    305
                DataFusionError::ObjectStore(e) => Some(e),
    306
    0
                DataFusionError::IoError(e) => Some(e),
    307
    0
                DataFusionError::SQL(e, _) => Some(e),
    308
    0
                DataFusionError::NotImplemented(_) => None,
    309
    0
                DataFusionError::Internal(_) => None,
    310
    0
                DataFusionError::Configuration(_) => None,
    311
    0
                DataFusionError::Plan(_) => None,
    312
    0
                DataFusionError::SchemaError(e, _) => Some(e),
    313
    0
                DataFusionError::Execution(_) => None,
    314
    0
                DataFusionError::ExecutionJoin(e) => Some(e),
    315
    6
                DataFusionError::ResourcesExhausted(_) => None,
    316
    0
                DataFusionError::External(e) => Some(e.as_ref()),
    317
    0
                DataFusionError::Context(_, e) => Some(e.as_ref()),
    318
    0
                DataFusionError::Substrait(_) => None,
    319
            }
    320
    12
        }
    321
    }
    322
    323
    impl From<DataFusionError> for io::Error {
    324
        fn from(e: DataFusionError) -> Self {
    325
            io::Error::new(io::ErrorKind::Other, e)
    326
        }
    327
    }
    328
    329
    impl DataFusionError {
    330
        /// The separator between the error message and the backtrace
    331
        pub const BACK_TRACE_SEP: &'static str = "\n\nbacktrace: ";
    332
    333
        /// Get deepest underlying [`DataFusionError`]
    334
        ///
    335
        /// [`DataFusionError`]s sometimes form a chain, such as `DataFusionError::ArrowError()` in order to conform
    336
        /// to the correct error signature. Thus sometimes there is a chain several layers deep that can obscure the
    337
        /// original error. This function finds the lowest level DataFusionError possible.
    338
        ///
    339
        /// For example,  `find_root` will return`DataFusionError::ResourceExhausted` given the input
    340
        /// ```text
    341
        /// DataFusionError::ArrowError
    342
        ///   ArrowError::External
    343
        ///    Box(DataFusionError::Context)
    344
        ///      DataFusionError::ResourceExhausted
    345
        /// ```
    346
        ///
    347
        /// This may be the same as `self`.
    348
    7
        pub fn find_root(&self) -> &Self {
    349
    7
            // Note: This is a non-recursive algorithm so we do not run
    350
    7
            // out of stack space, even for long error chains.
    351
    7
    352
    7
            let mut last_datafusion_error = self;
    353
    7
            let mut root_error: &dyn Error = self;
    354
    18
            while let Some(source11) = root_error.source() {
    355
                // walk the next level
    356
    11
                root_error = source;
    357
                // remember the lowest datafusion error so far
    358
    11
                if let Some(e0) = root_error.downcast_ref::<DataFusionError>() {
    359
    0
                    last_datafusion_error = e;
    360
    11
                } else if let Some(e5) = root_error.downcast_ref::<Arc<DataFusionError>>() {
    361
    5
                    // As `Arc<T>::source()` calls through to `T::source()` we need to
    362
    5
                    // explicitly match `Arc<DataFusionError>` to capture it
    363
    5
                    last_datafusion_error = e.as_ref();
    364
    6
                }
    365
            }
    366
            // return last checkpoint (which may be the original error)
    367
    7
            last_datafusion_error
    368
    7
        }
    369
    370
        /// wraps self in Self::Context with a description
    371
    0
        pub fn context(self, description: impl Into<String>) -> Self {
    372
    0
            Self::Context(description.into(), Box::new(self))
    373
    0
        }
    374
    375
        /// Strips backtrace out of the error message
    376
        /// If backtrace enabled then error has a format "message" [`Self::BACK_TRACE_SEP`] "backtrace"
    377
        /// The method strips the backtrace and outputs "message"
    378
    1
        pub fn strip_backtrace(&self) -> String {
    379
    1
            self.to_string()
    380
    1
                .split(Self::BACK_TRACE_SEP)
    381
    1
                .collect::<Vec<&str>>()
    382
    1
                .first()
    383
    1
                .unwrap_or(&"")
    384
    1
                .to_string()
    385
    1
        }
    386
    387
        /// To enable optional rust backtrace in DataFusion:
    388
        /// - [`Setup Env Variables`]<https://doc.rust-lang.org/std/backtrace/index.html#environment-variables>
    389
        /// - Enable `backtrace` cargo feature
    390
        ///
    391
        /// Example:
    392
        /// cargo build --features 'backtrace'
    393
        /// RUST_BACKTRACE=1 ./app
    394
        #[inline(always)]
    395
    235
        pub fn get_back_trace() -> String {
    396
    235
            #[cfg(feature = "backtrace")]
    397
    235
            {
    398
    235
                let back_trace = Backtrace::capture();
    399
    235
                if back_trace.status() == BacktraceStatus::Captured {
    400
    235
                    return format!("{}{}", Self::BACK_TRACE_SEP, back_trace);
    401
    235
                }
    402
    235
    403
    235
                "".to_owned()
    404
    235
            }
    405
    235
    406
    235
            #[cfg(not(feature = "backtrace"))]
    407
    235
            "".to_owned()
    408
    235
        }
    409
    410
    102
        fn error_prefix(&self) -> &'static str {
    411
    102
            match self {
    412
    0
                DataFusionError::ArrowError(_, _) => "Arrow error: ",
    413
                #[cfg(feature = "parquet")]
    414
                DataFusionError::ParquetError(_) => "Parquet error: ",
    415
                #[cfg(feature = "avro")]
    416
                DataFusionError::AvroError(_) => "Avro error: ",
    417
                #[cfg(feature = "object_store")]
    418
                DataFusionError::ObjectStore(_) => "Object Store error: ",
    419
    0
                DataFusionError::IoError(_) => "IO error: ",
    420
    0
                DataFusionError::SQL(_, _) => "SQL error: ",
    421
    1
                DataFusionError::NotImplemented(_) => "This feature is not implemented: ",
    422
    2
                DataFusionError::Internal(_) => "Internal error: ",
    423
    0
                DataFusionError::Plan(_) => "Error during planning: ",
    424
    0
                DataFusionError::Configuration(_) => "Invalid or Unsupported Configuration: ",
    425
    0
                DataFusionError::SchemaError(_, _) => "Schema error: ",
    426
    46
                DataFusionError::Execution(_) => "Execution error: ",
    427
    0
                DataFusionError::ExecutionJoin(_) => "ExecutionJoin error: ",
    428
    25
                DataFusionError::ResourcesExhausted(_) => "Resources exhausted: ",
    429
    28
                DataFusionError::External(_) => "External error: ",
    430
    0
                DataFusionError::Context(_, _) => "",
    431
    0
                DataFusionError::Substrait(_) => "Substrait error: ",
    432
            }
    433
    102
        }
    434
    435
    114
        pub fn message(&self) -> Cow<str> {
    436
    114
            match *self {
    437
    0
                DataFusionError::ArrowError(ref desc, ref backtrace) => {
    438
    0
                    let backtrace = backtrace.clone().unwrap_or("".to_owned());
    439
    0
                    Cow::Owned(format!("{desc}{backtrace}"))
    440
                }
    441
                #[cfg(feature = "parquet")]
    442
                DataFusionError::ParquetError(ref desc) => Cow::Owned(desc.to_string()),
    443
                #[cfg(feature = "avro")]
    444
                DataFusionError::AvroError(ref desc) => Cow::Owned(desc.to_string()),
    445
    0
                DataFusionError::IoError(ref desc) => Cow::Owned(desc.to_string()),
    446
    0
                DataFusionError::SQL(ref desc, ref backtrace) => {
    447
    0
                    let backtrace: String = backtrace.clone().unwrap_or("".to_owned());
    448
    0
                    Cow::Owned(format!("{desc:?}{backtrace}"))
    449
                }
    450
    0
                DataFusionError::Configuration(ref desc) => Cow::Owned(desc.to_string()),
    451
    1
                DataFusionError::NotImplemented(ref desc) => Cow::Owned(desc.to_string()),
    452
    2
                DataFusionError::Internal(ref desc) => Cow::Owned(format!(
    453
    2
                    "{desc}.\nThis was likely caused by a bug in DataFusion's \
    454
    2
                code and we would welcome that you file an bug report in our issue tracker"
    455
    2
                )),
    456
    0
                DataFusionError::Plan(ref desc) => Cow::Owned(desc.to_string()),
    457
    0
                DataFusionError::SchemaError(ref desc, ref backtrace) => {
    458
    0
                    let backtrace: &str =
    459
    0
                        &backtrace.as_ref().clone().unwrap_or("".to_owned());
    460
    0
                    Cow::Owned(format!("{desc}{backtrace}"))
    461
                }
    462
    46
                DataFusionError::Execution(ref desc) => Cow::Owned(desc.to_string()),
    463
    0
                DataFusionError::ExecutionJoin(ref desc) => Cow::Owned(desc.to_string()),
    464
    37
                DataFusionError::ResourcesExhausted(ref desc) => Cow::Owned(desc.to_string()),
    465
    28
                DataFusionError::External(ref desc) => Cow::Owned(desc.to_string()),
    466
                #[cfg(feature = "object_store")]
    467
                DataFusionError::ObjectStore(ref desc) => Cow::Owned(desc.to_string()),
    468
    0
                DataFusionError::Context(ref desc, ref err) => {
    469
    0
                    Cow::Owned(format!("{desc}\ncaused by\n{}", *err))
    470
                }
    471
    0
                DataFusionError::Substrait(ref desc) => Cow::Owned(desc.to_string()),
    472
            }
    473
    114
        }
    474
    }
    475
    476
    /// Unwrap an `Option` if possible. Otherwise return an `DataFusionError::Internal`.
    477
    /// In normal usage of DataFusion the unwrap should always succeed.
    478
    ///
    479
    /// Example: `let values = unwrap_or_internal_err!(values)`
    480
    #[macro_export]
    481
    macro_rules! unwrap_or_internal_err {
    482
        ($Value: ident) => {
    483
    0
            $Value.ok_or_else(|| {
    484
    0
                DataFusionError::Internal(format!(
    485
    0
                    "{} should not be None",
    486
    0
                    stringify!($Value)
    487
    0
                ))
    488
    0
            })?
    489
        };
    490
    }
    491
    492
    /// Add a macros for concise  DataFusionError::* errors declaration
    493
    /// supports placeholders the same way as `format!`
    494
    /// Examples:
    495
    ///     plan_err!("Error")
    496
    ///     plan_err!("Error {}", val)
    497
    ///     plan_err!("Error {:?}", val)
    498
    ///     plan_err!("Error {val}")
    499
    ///     plan_err!("Error {val:?}")
    500
    ///
    501
    /// `NAME_ERR` -  macro name for wrapping Err(DataFusionError::*)
    502
    /// `NAME_DF_ERR` -  macro name for wrapping DataFusionError::*. Needed to keep backtrace opportunity
    503
    /// in construction where DataFusionError::* used directly, like `map_err`, `ok_or_else`, etc
    504
    macro_rules! make_error {
    505
        ($NAME_ERR:ident, $NAME_DF_ERR: ident, $ERR:ident) => { make_error!(@inner ($), $NAME_ERR, $NAME_DF_ERR, $ERR); };
    506
        (@inner ($d:tt), $NAME_ERR:ident, $NAME_DF_ERR:ident, $ERR:ident) => {
    507
            ::paste::paste!{
    508
                /// Macro wraps `$ERR` to add backtrace feature
    509
                #[macro_export]
    510
                macro_rules! $NAME_DF_ERR {
    511
                    ($d($d args:expr),*) => {
    512
                        $crate::DataFusionError::$ERR(
    513
                            ::std::format!(
    514
                                "{}{}",
    515
                                ::std::format!($d($d args),*),
    516
                                $crate::DataFusionError::get_back_trace(),
    517
                            ).into()
    518
                        )
    519
                    }
    520
                }
    521
    522
                /// Macro wraps Err(`$ERR`) to add backtrace feature
    523
                #[macro_export]
    524
                macro_rules! $NAME_ERR {
    525
                    ($d($d args:expr),*) => {
    526
                        Err($crate::[<_ $NAME_DF_ERR>]!($d($d args),*))
    527
                    }
    528
                }
    529
    530
    531
                // Note: Certain macros are used in this  crate, but not all.
    532
                // This macro generates a use or all of them in case they are needed
    533
                // so we allow unused code to avoid warnings when they are not used
    534
                #[doc(hidden)]
    535
                #[allow(unused)]
    536
                pub use $NAME_ERR as [<_ $NAME_ERR>];
    537
                #[doc(hidden)]
    538
                #[allow(unused)]
    539
                pub use $NAME_DF_ERR as [<_ $NAME_DF_ERR>];
    540
            }
    541
        };
    542
    }
    543
    544
    // Exposes a macro to create `DataFusionError::Plan` with optional backtrace
    545
    make_error!(plan_err, plan_datafusion_err, Plan);
    546
    547
    // Exposes a macro to create `DataFusionError::Internal` with optional backtrace
    548
    make_error!(internal_err, internal_datafusion_err, Internal);
    549
    550
    // Exposes a macro to create `DataFusionError::NotImplemented` with optional backtrace
    551
    make_error!(not_impl_err, not_impl_datafusion_err, NotImplemented);
    552
    553
    // Exposes a macro to create `DataFusionError::Execution` with optional backtrace
    554
    make_error!(exec_err, exec_datafusion_err, Execution);
    555
    556
    // Exposes a macro to create `DataFusionError::Configuration` with optional backtrace
    557
    make_error!(config_err, config_datafusion_err, Configuration);
    558
    559
    // Exposes a macro to create `DataFusionError::Substrait` with optional backtrace
    560
    make_error!(substrait_err, substrait_datafusion_err, Substrait);
    561
    562
    // Exposes a macro to create `DataFusionError::ResourcesExhausted` with optional backtrace
    563
    make_error!(resources_err, resources_datafusion_err, ResourcesExhausted);
    564
    565
    // Exposes a macro to create `DataFusionError::SQL` with optional backtrace
    566
    #[macro_export]
    567
    macro_rules! sql_datafusion_err {
    568
        ($ERR:expr) => {
    569
            DataFusionError::SQL($ERR, Some(DataFusionError::get_back_trace()))
    570
        };
    571
    }
    572
    573
    // Exposes a macro to create `Err(DataFusionError::SQL)` with optional backtrace
    574
    #[macro_export]
    575
    macro_rules! sql_err {
    576
        ($ERR:expr) => {
    577
            Err(datafusion_common::sql_datafusion_err!($ERR))
    578
        };
    579
    }
    580
    581
    // Exposes a macro to create `DataFusionError::ArrowError` with optional backtrace
    582
    #[macro_export]
    583
    macro_rules! arrow_datafusion_err {
    584
        ($ERR:expr) => {
    585
            DataFusionError::ArrowError($ERR, Some(DataFusionError::get_back_trace()))
    586
        };
    587
    }
    588
    589
    // Exposes a macro to create `Err(DataFusionError::ArrowError)` with optional backtrace
    590
    #[macro_export]
    591
    macro_rules! arrow_err {
    592
        ($ERR:expr) => {
    593
            Err(datafusion_common::arrow_datafusion_err!($ERR))
    594
        };
    595
    }
    596
    597
    // Exposes a macro to create `DataFusionError::SchemaError` with optional backtrace
    598
    #[macro_export]
    599
    macro_rules! schema_datafusion_err {
    600
        ($ERR:expr) => {
    601
            DataFusionError::SchemaError(
    602
                $ERR,
    603
                Box::new(Some(DataFusionError::get_back_trace())),
    604
            )
    605
        };
    606
    }
    607
    608
    // Exposes a macro to create `Err(DataFusionError::SchemaError)` with optional backtrace
    609
    #[macro_export]
    610
    macro_rules! schema_err {
    611
        ($ERR:expr) => {
    612
            Err(DataFusionError::SchemaError(
    613
                $ERR,
    614
                Box::new(Some(DataFusionError::get_back_trace())),
    615
            ))
    616
        };
    617
    }
    618
    619
    // To avoid compiler error when using macro in the same crate:
    620
    // macros from the current crate cannot be referred to by absolute paths
    621
    pub use schema_err as _schema_err;
    622
    623
    /// Create a "field not found" DataFusion::SchemaError
    624
    0
    pub fn field_not_found<R: Into<TableReference>>(
    625
    0
        qualifier: Option<R>,
    626
    0
        name: &str,
    627
    0
        schema: &DFSchema,
    628
    0
    ) -> DataFusionError {
    629
    0
        schema_datafusion_err!(SchemaError::FieldNotFound {
    630
    0
            field: Box::new(Column::new(qualifier, name)),
    631
    0
            valid_fields: schema.columns().to_vec(),
    632
    0
        })
    633
    0
    }
    634
    635
    /// Convenience wrapper over [`field_not_found`] for when there is no qualifier
    636
    0
    pub fn unqualified_field_not_found(name: &str, schema: &DFSchema) -> DataFusionError {
    637
    0
        schema_datafusion_err!(SchemaError::FieldNotFound {
    638
    0
            field: Box::new(Column::new_unqualified(name)),
    639
    0
            valid_fields: schema.columns().to_vec(),
    640
    0
        })
    641
    0
    }
    642
    643
    #[cfg(test)]
    644
    mod test {
    645
        use std::sync::Arc;
    646
    647
        use crate::error::DataFusionError;
    648
        use arrow::error::ArrowError;
    649
    650
        #[test]
    651
        fn datafusion_error_to_arrow() {
    652
            let res = return_arrow_error().unwrap_err();
    653
            assert!(res
    654
                .to_string()
    655
                .starts_with("External error: Error during planning: foo"));
    656
        }
    657
    658
        #[test]
    659
        fn arrow_error_to_datafusion() {
    660
            let res = return_datafusion_error().unwrap_err();
    661
            assert_eq!(res.strip_backtrace(), "Arrow error: Schema error: bar");
    662
        }
    663
    664
        // To pass the test the environment variable RUST_BACKTRACE should be set to 1 to enforce backtrace
    665
        #[cfg(feature = "backtrace")]
    666
        #[test]
    667
        #[allow(clippy::unnecessary_literal_unwrap)]
    668
        fn test_enabled_backtrace() {
    669
            match std::env::var("RUST_BACKTRACE") {
    670
                Ok(val) if val == "1" => {}
    671
                _ => panic!("Environment variable RUST_BACKTRACE must be set to 1"),
    672
            };
    673
    674
            let res: Result<(), DataFusionError> = plan_err!("Err");
    675
            let err = res.unwrap_err().to_string();
    676
            assert!(err.contains(DataFusionError::BACK_TRACE_SEP));
    677
            assert_eq!(
    678
                err.split(DataFusionError::BACK_TRACE_SEP)
    679
                    .collect::<Vec<&str>>()
    680
                    .first()
    681
                    .unwrap(),
    682
                &"Error during planning: Err"
    683
            );
    684
            assert!(!err
    685
                .split(DataFusionError::BACK_TRACE_SEP)
    686
                .collect::<Vec<&str>>()
    687
                .get(1)
    688
                .unwrap()
    689
                .is_empty());
    690
        }
    691
    692
        #[cfg(not(feature = "backtrace"))]
    693
        #[test]
    694
        #[allow(clippy::unnecessary_literal_unwrap)]
    695
        fn test_disabled_backtrace() {
    696
            let res: Result<(), DataFusionError> = plan_err!("Err");
    697
            let res = res.unwrap_err().to_string();
    698
            assert!(!res.contains(DataFusionError::BACK_TRACE_SEP));
    699
            assert_eq!(res, "Error during planning: Err");
    700
        }
    701
    702
        #[test]
    703
        fn test_find_root_error() {
    704
            do_root_test(
    705
                DataFusionError::Context(
    706
                    "it happened!".to_string(),
    707
                    Box::new(DataFusionError::ResourcesExhausted("foo".to_string())),
    708
                ),
    709
                DataFusionError::ResourcesExhausted("foo".to_string()),
    710
            );
    711
    712
            do_root_test(
    713
                DataFusionError::ArrowError(
    714
                    ArrowError::ExternalError(Box::new(DataFusionError::ResourcesExhausted(
    715
                        "foo".to_string(),
    716
                    ))),
    717
                    None,
    718
                ),
    719
                DataFusionError::ResourcesExhausted("foo".to_string()),
    720
            );
    721
    722
            do_root_test(
    723
                DataFusionError::External(Box::new(DataFusionError::ResourcesExhausted(
    724
                    "foo".to_string(),
    725
                ))),
    726
                DataFusionError::ResourcesExhausted("foo".to_string()),
    727
            );
    728
    729
            do_root_test(
    730
                DataFusionError::External(Box::new(ArrowError::ExternalError(Box::new(
    731
                    DataFusionError::ResourcesExhausted("foo".to_string()),
    732
                )))),
    733
                DataFusionError::ResourcesExhausted("foo".to_string()),
    734
            );
    735
    736
            do_root_test(
    737
                DataFusionError::ArrowError(
    738
                    ArrowError::ExternalError(Box::new(ArrowError::ExternalError(Box::new(
    739
                        DataFusionError::ResourcesExhausted("foo".to_string()),
    740
                    )))),
    741
                    None,
    742
                ),
    743
                DataFusionError::ResourcesExhausted("foo".to_string()),
    744
            );
    745
    746
            do_root_test(
    747
                DataFusionError::External(Box::new(Arc::new(
    748
                    DataFusionError::ResourcesExhausted("foo".to_string()),
    749
                ))),
    750
                DataFusionError::ResourcesExhausted("foo".to_string()),
    751
            );
    752
    753
            do_root_test(
    754
                DataFusionError::External(Box::new(Arc::new(ArrowError::ExternalError(
    755
                    Box::new(DataFusionError::ResourcesExhausted("foo".to_string())),
    756
                )))),
    757
                DataFusionError::ResourcesExhausted("foo".to_string()),
    758
            );
    759
        }
    760
    761
        #[test]
    762
        #[allow(clippy::unnecessary_literal_unwrap)]
    763
        fn test_make_error_parse_input() {
    764
            let res: Result<(), DataFusionError> = plan_err!("Err");
    765
            let res = res.unwrap_err();
    766
            assert_eq!(res.strip_backtrace(), "Error during planning: Err");
    767
    768
            let extra1 = "extra1";
    769
            let extra2 = "extra2";
    770
    771
            let res: Result<(), DataFusionError> = plan_err!("Err {} {}", extra1, extra2);
    772
            let res = res.unwrap_err();
    773
            assert_eq!(
    774
                res.strip_backtrace(),
    775
                "Error during planning: Err extra1 extra2"
    776
            );
    777
    778
            let res: Result<(), DataFusionError> =
    779
                plan_err!("Err {:?} {:#?}", extra1, extra2);
    780
            let res = res.unwrap_err();
    781
            assert_eq!(
    782
                res.strip_backtrace(),
    783
                "Error during planning: Err \"extra1\" \"extra2\""
    784
            );
    785
    786
            let res: Result<(), DataFusionError> = plan_err!("Err {extra1} {extra2}");
    787
            let res = res.unwrap_err();
    788
            assert_eq!(
    789
                res.strip_backtrace(),
    790
                "Error during planning: Err extra1 extra2"
    791
            );
    792
    793
            let res: Result<(), DataFusionError> = plan_err!("Err {extra1:?} {extra2:#?}");
    794
            let res = res.unwrap_err();
    795
            assert_eq!(
    796
                res.strip_backtrace(),
    797
                "Error during planning: Err \"extra1\" \"extra2\""
    798
            );
    799
        }
    800
    801
        /// Model what happens when implementing SendableRecordBatchStream:
    802
        /// DataFusion code needs to return an ArrowError
    803
        fn return_arrow_error() -> arrow::error::Result<()> {
    804
            // Expect the '?' to work
    805
            Err(DataFusionError::Plan("foo".to_string()).into())
    806
        }
    807
    808
        /// Model what happens when using arrow kernels in DataFusion
    809
        /// code: need to turn an ArrowError into a DataFusionError
    810
        fn return_datafusion_error() -> crate::error::Result<()> {
    811
            // Expect the '?' to work
    812
            Err(ArrowError::SchemaError("bar".to_string()).into())
    813
        }
    814
    815
        fn do_root_test(e: DataFusionError, exp: DataFusionError) {
    816
            let e = e.find_root();
    817
    818
            // DataFusionError does not implement Eq, so we use a string comparison + some cheap "same variant" test instead
    819
            assert_eq!(e.strip_backtrace(), exp.strip_backtrace());
    820
            assert_eq!(std::mem::discriminant(e), std::mem::discriminant(&exp),)
    821
        }
    822
    }