## Coverage Report

#### Created: 2025-11-22 06:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

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

    Line
    Count
    Source
    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
    //! # Error Handling in DataFusion
    19
    //!
    20
    //! In DataFusion, there are two types of errors that can be raised:
    21
    //!
    22
    //! 1. Expected errors – These indicate invalid operations performed by the caller,
    23
    //!    such as attempting to open a non-existent file. Different categories exist to
    24
    //!    distinguish their sources (e.g., [`DataFusionError::ArrowError`],
    25
    //!    [`DataFusionError::IoError`], etc.).
    26
    //!
    27
    //! 2. Unexpected errors – Represented by [`DataFusionError::Internal`], these
    28
    //!    indicate that an internal invariant has been broken, suggesting a potential
    29
    //!    bug in the system.
    30
    //!
    31
    //! There are several convenient macros for throwing errors. For example, use
    32
    //! `exec_err!` for expected errors.
    33
    //! For invariant checks, you can use `assert_or_internal_err!`,
    34
    //! `assert_eq_or_internal_err!`, `assert_ne_or_internal_err!` for easier assertions.
    35
    //! On the performance-critical path, use `debug_assert!` instead to reduce overhead.
    36
    37
    #[cfg(feature = "backtrace")]
    38
    use std::backtrace::{Backtrace, BacktraceStatus};
    39
    40
    use std::borrow::Cow;
    41
    use std::collections::VecDeque;
    42
    use std::error::Error;
    43
    use std::fmt::{Display, Formatter};
    44
    use std::io;
    45
    use std::result;
    46
    use std::sync::Arc;
    47
    48
    use crate::utils::datafusion_strsim::normalized_levenshtein;
    49
    use crate::utils::quote_identifier;
    50
    use crate::{Column, DFSchema, Diagnostic, TableReference};
    51
    #[cfg(feature = "avro")]
    52
    use apache_avro::Error as AvroError;
    53
    use arrow::error::ArrowError;
    54
    #[cfg(feature = "parquet")]
    55
    use parquet::errors::ParquetError;
    56
    #[cfg(feature = "sql")]
    57
    use sqlparser::parser::ParserError;
    58
    use tokio::task::JoinError;
    59
    60
    /// Result type for operations that could result in an [DataFusionError]
    61
    pub type Result<T, E = DataFusionError> = result::Result<T, E>;
    62
    63
    /// Result type for operations that could result in an [DataFusionError] and needs to be shared (wrapped into `Arc`).
    64
    pub type SharedResult<T> = result::Result<T, Arc<DataFusionError>>;
    65
    66
    /// Error type for generic operations that could result in DataFusionError::External
    67
    pub type GenericError = Box<dyn Error + Send + Sync>;
    68
    69
    /// DataFusion error
    70
    #[derive(Debug)]
    71
    pub enum DataFusionError {
    72
        /// Error returned by arrow.
    73
        ///
    74
        /// 2nd argument is for optional backtrace
    75
        ArrowError(Box<ArrowError>, Option<String>),
    76
        /// Error when reading / writing Parquet data.
    77
        #[cfg(feature = "parquet")]
    78
        ParquetError(Box<ParquetError>),
    79
        /// Error when reading Avro data.
    80
        #[cfg(feature = "avro")]
    81
        AvroError(Box<AvroError>),
    82
        /// Error when reading / writing to / from an object_store (e.g. S3 or LocalFile)
    83
        #[cfg(feature = "object_store")]
    84
        ObjectStore(Box<object_store::Error>),
    85
        /// Error when an I/O operation fails
    86
        IoError(io::Error),
    87
        /// Error when SQL is syntactically incorrect.
    88
        ///
    89
        /// 2nd argument is for optional backtrace
    90
        #[cfg(feature = "sql")]
    91
        SQL(Box<ParserError>, Option<String>),
    92
        /// Error when a feature is not yet implemented.
    93
        ///
    94
        /// These errors are sometimes returned for features that are still in
    95
        /// development and are not entirely complete. Often, these errors are
    96
        /// tracked in our issue tracker.
    97
        NotImplemented(String),
    98
        /// Error due to bugs in DataFusion
    99
        ///
    100
        /// This error should not happen in normal usage of DataFusion. It results
    101
        /// from something that wasn't expected/anticipated by the implementation
    102
        /// and that is most likely a bug (the error message even encourages users
    103
        /// to open a bug report). A user should not be able to trigger internal
    104
        /// errors under normal circumstances by feeding in malformed queries, bad
    105
        /// data, etc.
    106
        ///
    107
        /// Note that I/O errors (or any error that happens due to external systems)
    108
        /// do NOT fall under this category. See other variants such as
    109
        /// [`Self::IoError`] and [`Self::External`].
    110
        ///
    111
        /// DataFusions has internal invariants that the compiler is not always able
    112
        /// to check. This error is raised when one of those invariants does not
    113
        /// hold for some reason.
    114
        Internal(String),
    115
        /// Error during planning of the query.
    116
        ///
    117
        /// This error happens when the user provides a bad query or plan, for
    118
        /// example the user attempts to call a function that doesn't exist, or if
    119
        /// the types of a function call are not supported.
    120
        Plan(String),
    121
        /// Error for invalid or unsupported configuration options.
    122
        Configuration(String),
    123
        /// Error when there is a problem with the query related to schema.
    124
        ///
    125
        /// This error can be returned in cases such as when schema inference is not
    126
        /// possible and when column names are not unique.
    127
        ///
    128
        /// 2nd argument is for optional backtrace
    129
        /// Boxing the optional backtrace to prevent <https://rust-lang.github.io/rust-clippy/master/index.html#/result_large_err>
    130
        SchemaError(Box<SchemaError>, Box<Option<String>>),
    131
        /// Error during execution of the query.
    132
        ///
    133
        /// This error is returned when an error happens during execution due to a
    134
        /// malformed input. For example, the user passed malformed arguments to a
    135
        /// SQL method, opened a CSV file that is broken, or tried to divide an
    136
        /// integer by zero.
    137
        Execution(String),
    138
        /// [`JoinError`] during execution of the query.
    139
        ///
    140
        /// This error can't occur for unjoined tasks, such as execution shutdown.
    141
        ExecutionJoin(Box<JoinError>),
    142
        /// Error when resources (such as memory of scratch disk space) are exhausted.
    143
        ///
    144
        /// This error is thrown when a consumer cannot acquire additional memory
    145
        /// or other resources needed to execute the query from the Memory Manager.
    146
        ResourcesExhausted(String),
    147
        /// Errors originating from outside DataFusion's core codebase.
    148
        ///
    149
        /// For example, a custom S3Error from the crate datafusion-objectstore-s3
    150
        External(GenericError),
    151
        /// Error with additional context
    152
        Context(String, Box<DataFusionError>),
    153
        /// Errors from either mapping LogicalPlans to/from Substrait plans
    154
        /// or serializing/deserializing protobytes to Substrait plans
    155
        Substrait(String),
    156
        /// Error wrapped together with additional contextual information intended
    157
        /// for end users, to help them understand what went wrong by providing
    158
        /// human-readable messages, and locations in the source query that relate
    159
        /// to the error in some way.
    160
        Diagnostic(Box<Diagnostic>, Box<DataFusionError>),
    161
        /// A collection of one or more [`DataFusionError`]. Useful in cases where
    162
        /// DataFusion can recover from an erroneous state, and produce more errors
    163
        /// before terminating. e.g. when planning a SELECT clause, DataFusion can
    164
        /// synchronize to the next `SelectItem` if the previous one had errors. The
    165
        /// end result is that the user can see errors about all `SelectItem`,
    166
        /// instead of just the first one.
    167
        Collection(Vec<DataFusionError>),
    168
        /// A [`DataFusionError`] which shares an underlying [`DataFusionError`].
    169
        ///
    170
        /// This is useful when the same underlying [`DataFusionError`] is passed
    171
        /// to multiple receivers. For example, when the source of a repartition
    172
        /// errors and the error is propagated to multiple consumers.
    173
        Shared(Arc<DataFusionError>),
    174
    }
    175
    176
    #[macro_export]
    177
    macro_rules! context {
    178
        ($desc:expr, $err:expr) => {
    179
            $err.context(format!("{} at {}:{}", $desc, file!(), line!()))
    180
        };
    181
    }
    182
    183
    /// Schema-related errors
    184
    #[derive(Debug)]
    185
    pub enum SchemaError {
    186
        /// Schema contains a (possibly) qualified and unqualified field with same unqualified name
    187
        AmbiguousReference { field: Box<Column> },
    188
        /// Schema contains duplicate qualified field name
    189
        DuplicateQualifiedField {
    190
            qualifier: Box<TableReference>,
    191
            name: String,
    192
        },
    193
        /// Schema contains duplicate unqualified field name
    194
        DuplicateUnqualifiedField { name: String },
    195
        /// No field with this name
    196
        FieldNotFound {
    197
            field: Box<Column>,
    198
            valid_fields: Vec<Column>,
    199
        },
    200
    }
    201
    202
    impl Display for SchemaError {
    203
    0
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    204
    0
            match self {
    205
                Self::FieldNotFound {
    206
    0
                    field,
    207
    0
                    valid_fields,
    208
                } => {
    209
    0
                    write!(f, "No field named {}", field.quoted_flat_name())?;
    210
    0
                    let lower_valid_fields = valid_fields
    211
    0
                        .iter()
    212
    0
                        .map(|column| column.flat_name().to_lowercase())
    213
    0
                        .collect::<Vec<String>>();
    214
    215
    0
                    let valid_fields_names = valid_fields
    216
    0
                        .iter()
    217
    0
                        .map(|column| column.flat_name())
    218
    0
                        .collect::<Vec<String>>();
    219
    0
                    if lower_valid_fields.contains(&field.flat_name().to_lowercase()) {
    220
    0
                        write!(
    221
    0
                            f,
    222
    0
                            ". Column names are case sensitive. You can use double quotes to refer to the \"{}\" column \
    223
    0
                            or set the datafusion.sql_parser.enable_ident_normalization configuration",
    224
    0
                            field.quoted_flat_name()
    225
    0
                        )?;
    226
    0
                    }
    227
    0
                    let field_name = field.name();
    228
    0
                    if let Some(matched) = valid_fields_names
    229
    0
                        .iter()
    230
    0
                        .filter(|str| normalized_levenshtein(str, field_name) >= 0.5)
    231
    0
                        .collect::<Vec<&String>>()
    232
    0
                        .first()
    233
                    {
    234
    0
                        write!(f, ". Did you mean '{matched}'?")?;
    235
    0
                    } else if !valid_fields.is_empty() {
    236
    0
                        write!(
    237
    0
                            f,
    238
    0
                            ". Valid fields are {}",
    239
    0
                            valid_fields
    240
    0
                                .iter()
    241
    0
                                .map(|field| field.quoted_flat_name())
    242
    0
                                .collect::<Vec<String>>()
    243
    0
                                .join(", ")
    244
    0
                        )?;
    245
    0
                    }
    246
    0
                    write!(f, ".")
    247
                }
    248
    0
                Self::DuplicateQualifiedField { qualifier, name } => {
    249
    0
                    write!(
    250
    0
                        f,
    251
    0
                        "Schema contains duplicate qualified field name {}.{}",
    252
    0
                        qualifier.to_quoted_string(),
    253
    0
                        quote_identifier(name)
    254
                    )
    255
                }
    256
    0
                Self::DuplicateUnqualifiedField { name } => {
    257
    0
                    write!(
    258
    0
                        f,
    259
    0
                        "Schema contains duplicate unqualified field name {}",
    260
    0
                        quote_identifier(name)
    261
                    )
    262
                }
    263
    0
                Self::AmbiguousReference { field } => {
    264
    0
                    if field.relation.is_some() {
    265
    0
                        write!(
    266
    0
                            f,
    267
    0
                            "Schema contains qualified field name {} and unqualified field name {} which would be ambiguous",
    268
    0
                            field.quoted_flat_name(),
    269
    0
                            quote_identifier(&field.name)
    270
                        )
    271
                    } else {
    272
    0
                        write!(
    273
    0
                            f,
    274
    0
                            "Ambiguous reference to unqualified field {}",
    275
    0
                            field.quoted_flat_name()
    276
                        )
    277
                    }
    278
                }
    279
            }
    280
    0
        }
    281
    }
    282
    283
    impl Error for SchemaError {}
    284
    285
    impl From<std::fmt::Error> for DataFusionError {
    286
    0
        fn from(_e: std::fmt::Error) -> Self {
    287
    0
            DataFusionError::Execution("Fail to format".to_string())
    288
    0
        }
    289
    }
    290
    291
    impl From<io::Error> for DataFusionError {
    292
    0
        fn from(e: io::Error) -> Self {
    293
    0
            DataFusionError::IoError(e)
    294
    0
        }
    295
    }
    296
    297
    impl From<ArrowError> for DataFusionError {
    298
    0
        fn from(e: ArrowError) -> Self {
    299
    0
            DataFusionError::ArrowError(Box::new(e), Some(DataFusionError::get_back_trace()))
    300
    0
        }
    301
    }
    302
    303
    impl From<DataFusionError> for ArrowError {
    304
    0
        fn from(e: DataFusionError) -> Self {
    305
    0
            match e {
    306
    0
                DataFusionError::ArrowError(e, _) => *e,
    307
    0
                DataFusionError::External(e) => ArrowError::ExternalError(e),
    308
    0
                other => ArrowError::ExternalError(Box::new(other)),
    309
            }
    310
    0
        }
    311
    }
    312
    313
    impl From<&Arc<DataFusionError>> for DataFusionError {
    314
    0
        fn from(e: &Arc<DataFusionError>) -> Self {
    315
    0
            if let DataFusionError::Shared(e_inner) = e.as_ref() {
    316
                // don't re-wrap
    317
    0
                DataFusionError::Shared(Arc::clone(e_inner))
    318
            } else {
    319
    0
                DataFusionError::Shared(Arc::clone(e))
    320
            }
    321
    0
        }
    322
    }
    323
    324
    #[cfg(feature = "parquet")]
    325
    impl From<ParquetError> for DataFusionError {
    326
        fn from(e: ParquetError) -> Self {
    327
            DataFusionError::ParquetError(Box::new(e))
    328
        }
    329
    }
    330
    331
    #[cfg(feature = "avro")]
    332
    impl From<AvroError> for DataFusionError {
    333
        fn from(e: AvroError) -> Self {
    334
            DataFusionError::AvroError(Box::new(e))
    335
        }
    336
    }
    337
    338
    #[cfg(feature = "object_store")]
    339
    impl From<object_store::Error> for DataFusionError {
    340
        fn from(e: object_store::Error) -> Self {
    341
            DataFusionError::ObjectStore(Box::new(e))
    342
        }
    343
    }
    344
    345
    #[cfg(feature = "object_store")]
    346
    impl From<object_store::path::Error> for DataFusionError {
    347
        fn from(e: object_store::path::Error) -> Self {
    348
            DataFusionError::ObjectStore(Box::new(e.into()))
    349
        }
    350
    }
    351
    352
    #[cfg(feature = "sql")]
    353
    impl From<ParserError> for DataFusionError {
    354
        fn from(e: ParserError) -> Self {
    355
            DataFusionError::SQL(Box::new(e), None)
    356
        }
    357
    }
    358
    359
    impl From<GenericError> for DataFusionError {
    360
    0
        fn from(err: GenericError) -> Self {
    361
            // If the error is already a DataFusionError, not wrapping it.
    362
    0
            if err.is::<DataFusionError>() {
    363
    0
                if let Ok(e) = err.downcast::<DataFusionError>() {
    364
    0
                    *e
    365
                } else {
    366
    0
                    unreachable!()
    367
                }
    368
            } else {
    369
    0
                DataFusionError::External(err)
    370
            }
    371
    0
        }
    372
    }
    373
    374
    impl Display for DataFusionError {
    375
    0
        fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
    376
    0
            let error_prefix = self.error_prefix();
    377
    0
            let message = self.message();
    378
    0
            write!(f, "{error_prefix}{message}")
    379
    0
        }
    380
    }
    381
    382
    impl Error for DataFusionError {
    383
    0
        fn source(&self) -> Option<&(dyn Error + 'static)> {
    384
    0
            match self {
    385
    0
                DataFusionError::ArrowError(e, _) => Some(e.as_ref()),
    386
                #[cfg(feature = "parquet")]
    387
                DataFusionError::ParquetError(e) => Some(e.as_ref()),
    388
                #[cfg(feature = "avro")]
    389
                DataFusionError::AvroError(e) => Some(e.as_ref()),
    390
                #[cfg(feature = "object_store")]
    391
                DataFusionError::ObjectStore(e) => Some(e.as_ref()),
    392
    0
                DataFusionError::IoError(e) => Some(e),
    393
                #[cfg(feature = "sql")]
    394
                DataFusionError::SQL(e, _) => Some(e.as_ref()),
    395
    0
                DataFusionError::NotImplemented(_) => None,
    396
    0
                DataFusionError::Internal(_) => None,
    397
    0
                DataFusionError::Configuration(_) => None,
    398
    0
                DataFusionError::Plan(_) => None,
    399
    0
                DataFusionError::SchemaError(e, _) => Some(e.as_ref()),
    400
    0
                DataFusionError::Execution(_) => None,
    401
    0
                DataFusionError::ExecutionJoin(e) => Some(e.as_ref()),
    402
    0
                DataFusionError::ResourcesExhausted(_) => None,
    403
    0
                DataFusionError::External(e) => Some(e.as_ref()),
    404
    0
                DataFusionError::Context(_, e) => Some(e.as_ref()),
    405
    0
                DataFusionError::Substrait(_) => None,
    406
    0
                DataFusionError::Diagnostic(_, e) => Some(e.as_ref()),
    407
                // Can't really make a Collection fit into the mold of "an error has
    408
                // at most one source", but returning the first one is probably good
    409
                // idea. Especially since `DataFusionError::Collection` is mostly
    410
                // meant for consumption by the end user, so shouldn't interfere
    411
                // with programmatic usage too much. Plus, having 1 or 5 errors
    412
                // doesn't really change the fact that the query is invalid and
    413
                // can't be executed.
    414
    0
                DataFusionError::Collection(errs) => errs.first().map(|e| e as &dyn Error),
    415
    0
                DataFusionError::Shared(e) => Some(e.as_ref()),
    416
            }
    417
    0
        }
    418
    }
    419
    420
    impl From<DataFusionError> for io::Error {
    421
    0
        fn from(e: DataFusionError) -> Self {
    422
    0
            io::Error::other(e)
    423
    0
        }
    424
    }
    425
    426
    impl DataFusionError {
    427
        /// The separator between the error message and the backtrace
    428
        pub const BACK_TRACE_SEP: &'static str = "\n\nbacktrace: ";
    429
    430
        /// Get deepest underlying [`DataFusionError`]
    431
        ///
    432
        /// [`DataFusionError`]s sometimes form a chain, such as `DataFusionError::ArrowError()` in order to conform
    433
        /// to the correct error signature. Thus sometimes there is a chain several layers deep that can obscure the
    434
        /// original error. This function finds the lowest level DataFusionError possible.
    435
        ///
    436
        /// For example,  `find_root` will return`DataFusionError::ResourceExhausted` given the input
    437
        /// ```text
    438
        /// DataFusionError::ArrowError
    439
        ///   ArrowError::External
    440
        ///    Box(DataFusionError::Context)
    441
        ///      DataFusionError::ResourceExhausted
    442
        /// ```
    443
        ///
    444
        /// This may be the same as `self`.
    445
    0
        pub fn find_root(&self) -> &Self {
    446
            // Note: This is a non-recursive algorithm so we do not run
    447
            // out of stack space, even for long error chains.
    448
    449
    0
            let mut last_datafusion_error = self;
    450
    0
            let mut root_error: &dyn Error = self;
    451
    0
            while let Some(source) = root_error.source() {
    452
                // walk the next level
    453
    0
                root_error = source;
    454
                // remember the lowest datafusion error so far
    455
    0
                if let Some(e) = root_error.downcast_ref::<DataFusionError>() {
    456
    0
                    last_datafusion_error = e;
    457
    0
                } else if let Some(e) = root_error.downcast_ref::<Arc<DataFusionError>>() {
    458
    0
                    // As `Arc<T>::source()` calls through to `T::source()` we need to
    459
    0
                    // explicitly match `Arc<DataFusionError>` to capture it
    460
    0
                    last_datafusion_error = e.as_ref();
    461
    0
                }
    462
            }
    463
            // return last checkpoint (which may be the original error)
    464
    0
            last_datafusion_error
    465
    0
        }
    466
    467
        /// wraps self in Self::Context with a description
    468
    0
        pub fn context(self, description: impl Into<String>) -> Self {
    469
    0
            Self::Context(description.into(), Box::new(self))
    470
    0
        }
    471
    472
        /// Strips backtrace out of the error message
    473
        /// If backtrace enabled then error has a format "message" [`Self::BACK_TRACE_SEP`] "backtrace"
    474
        /// The method strips the backtrace and outputs "message"
    475
    0
        pub fn strip_backtrace(&self) -> String {
    476
    0
            (*self
    477
    0
                .to_string()
    478
    0
                .split(Self::BACK_TRACE_SEP)
    479
    0
                .collect::<Vec<&str>>()
    480
    0
                .first()
    481
    0
                .unwrap_or(&""))
    482
    0
            .to_string()
    483
    0
        }
    484
    485
        /// To enable optional rust backtrace in DataFusion:
    486
        /// - [`Setup Env Variables`]<https://doc.rust-lang.org/std/backtrace/index.html#environment-variables>
    487
        /// - Enable `backtrace` cargo feature
    488
        ///
    489
        /// Example:
    490
        /// cargo build --features 'backtrace'
    491
        /// RUST_BACKTRACE=1 ./app
    492
        #[inline(always)]
    493
    12
        pub fn get_back_trace() -> String {
    494
            #[cfg(feature = "backtrace")]
    495
            {
    496
                let back_trace = Backtrace::capture();
    497
                if back_trace.status() == BacktraceStatus::Captured {
    498
                    return format!("{}{}", Self::BACK_TRACE_SEP, back_trace);
    499
                }
    500
    501
                "".to_owned()
    502
            }
    503
    504
            #[cfg(not(feature = "backtrace"))]
    505
    12
            "".to_owned()
    506
    12
        }
    507
    508
        /// Return a [`DataFusionErrorBuilder`] to build a [`DataFusionError`]
    509
    0
        pub fn builder() -> DataFusionErrorBuilder {
    510
    0
            DataFusionErrorBuilder::default()
    511
    0
        }
    512
    513
    0
        fn error_prefix(&self) -> &'static str {
    514
    0
            match self {
    515
    0
                DataFusionError::ArrowError(_, _) => "Arrow error: ",
    516
                #[cfg(feature = "parquet")]
    517
                DataFusionError::ParquetError(_) => "Parquet error: ",
    518
                #[cfg(feature = "avro")]
    519
                DataFusionError::AvroError(_) => "Avro error: ",
    520
                #[cfg(feature = "object_store")]
    521
                DataFusionError::ObjectStore(_) => "Object Store error: ",
    522
    0
                DataFusionError::IoError(_) => "IO error: ",
    523
                #[cfg(feature = "sql")]
    524
                DataFusionError::SQL(_, _) => "SQL error: ",
    525
                DataFusionError::NotImplemented(_) => {
    526
    0
                    "This feature is not implemented: "
    527
                }
    528
    0
                DataFusionError::Internal(_) => "Internal error: ",
    529
    0
                DataFusionError::Plan(_) => "Error during planning: ",
    530
                DataFusionError::Configuration(_) => {
    531
    0
                    "Invalid or Unsupported Configuration: "
    532
                }
    533
    0
                DataFusionError::SchemaError(_, _) => "Schema error: ",
    534
    0
                DataFusionError::Execution(_) => "Execution error: ",
    535
    0
                DataFusionError::ExecutionJoin(_) => "ExecutionJoin error: ",
    536
                DataFusionError::ResourcesExhausted(_) => {
    537
    0
                    "Resources exhausted: "
    538
                }
    539
    0
                DataFusionError::External(_) => "External error: ",
    540
    0
                DataFusionError::Context(_, _) => "",
    541
    0
                DataFusionError::Substrait(_) => "Substrait error: ",
    542
    0
                DataFusionError::Diagnostic(_, _) => "",
    543
    0
                DataFusionError::Collection(errs) => {
    544
    0
                    errs.first().expect("cannot construct DataFusionError::Collection with 0 errors, but got one such case").error_prefix()
    545
                }
    546
    0
                DataFusionError::Shared(_) => "",
    547
            }
    548
    0
        }
    549
    550
    0
        pub fn message(&self) -> Cow<'_, str> {
    551
    0
            match *self {
    552
    0
                DataFusionError::ArrowError(ref desc, ref backtrace) => {
    553
    0
                    let backtrace = backtrace.clone().unwrap_or_else(|| "".to_owned());
    554
    0
                    Cow::Owned(format!("{desc}{backtrace}"))
    555
                }
    556
                #[cfg(feature = "parquet")]
    557
                DataFusionError::ParquetError(ref desc) => Cow::Owned(desc.to_string()),
    558
                #[cfg(feature = "avro")]
    559
                DataFusionError::AvroError(ref desc) => Cow::Owned(desc.to_string()),
    560
    0
                DataFusionError::IoError(ref desc) => Cow::Owned(desc.to_string()),
    561
                #[cfg(feature = "sql")]
    562
                DataFusionError::SQL(ref desc, ref backtrace) => {
    563
                    let backtrace: String =
    564
                        backtrace.clone().unwrap_or_else(|| "".to_owned());
    565
                    Cow::Owned(format!("{desc:?}{backtrace}"))
    566
                }
    567
    0
                DataFusionError::Configuration(ref desc) => Cow::Owned(desc.to_string()),
    568
    0
                DataFusionError::NotImplemented(ref desc) => Cow::Owned(desc.to_string()),
    569
    0
                DataFusionError::Internal(ref desc) => Cow::Owned(format!(
    570
    0
                    "{desc}.\nThis issue was likely caused by a bug in DataFusion's code. \
    571
    0
                    Please help us to resolve this by filing a bug report in our issue tracker: \
    572
    0
                    https://github.com/apache/datafusion/issues"
    573
    0
                )),
    574
    0
                DataFusionError::Plan(ref desc) => Cow::Owned(desc.to_string()),
    575
    0
                DataFusionError::SchemaError(ref desc, ref backtrace) => {
    576
    0
                    let backtrace: &str =
    577
    0
                        &backtrace.as_ref().clone().unwrap_or_else(|| "".to_owned());
    578
    0
                    Cow::Owned(format!("{desc}{backtrace}"))
    579
                }
    580
    0
                DataFusionError::Execution(ref desc) => Cow::Owned(desc.to_string()),
    581
    0
                DataFusionError::ExecutionJoin(ref desc) => Cow::Owned(desc.to_string()),
    582
    0
                DataFusionError::ResourcesExhausted(ref desc) => Cow::Owned(desc.to_string()),
    583
    0
                DataFusionError::External(ref desc) => Cow::Owned(desc.to_string()),
    584
                #[cfg(feature = "object_store")]
    585
                DataFusionError::ObjectStore(ref desc) => Cow::Owned(desc.to_string()),
    586
    0
                DataFusionError::Context(ref desc, ref err) => {
    587
    0
                    Cow::Owned(format!("{desc}\ncaused by\n{}", *err))
    588
                }
    589
    0
                DataFusionError::Substrait(ref desc) => Cow::Owned(desc.to_string()),
    590
    0
                DataFusionError::Diagnostic(_, ref err) => Cow::Owned(err.to_string()),
    591
                // Returning the message of the first error is probably fine enough,
    592
                // and makes `DataFusionError::Collection` a transparent wrapped,
    593
                // unless the end user explicitly calls `DataFusionError::iter`.
    594
    0
                DataFusionError::Collection(ref errs) => errs
    595
    0
                    .first()
    596
    0
                    .expect("cannot construct DataFusionError::Collection with 0 errors")
    597
    0
                    .message(),
    598
    0
                DataFusionError::Shared(ref desc) => Cow::Owned(desc.to_string()),
    599
            }
    600
    0
        }
    601
    602
        /// Wraps the error with contextual information intended for end users
    603
    0
        pub fn with_diagnostic(self, diagnostic: Diagnostic) -> Self {
    604
    0
            Self::Diagnostic(Box::new(diagnostic), Box::new(self))
    605
    0
        }
    606
    607
        /// Wraps the error with contextual information intended for end users.
    608
        /// Takes a function that inspects the error and returns the diagnostic to
    609
        /// wrap it with.
    610
    0
        pub fn with_diagnostic_fn<F: FnOnce(&DataFusionError) -> Diagnostic>(
    611
    0
            self,
    612
    0
            f: F,
    613
    0
        ) -> Self {
    614
    0
            let diagnostic = f(&self);
    615
    0
            self.with_diagnostic(diagnostic)
    616
    0
        }
    617
    618
        /// Gets the [`Diagnostic`] associated with the error, if any. If there is
    619
        /// more than one, only the outermost [`Diagnostic`] is returned.
    620
    0
        pub fn diagnostic(&self) -> Option<&Diagnostic> {
    621
            struct DiagnosticsIterator<'a> {
    622
                head: &'a DataFusionError,
    623
            }
    624
    625
            impl<'a> Iterator for DiagnosticsIterator<'a> {
    626
                type Item = &'a Diagnostic;
    627
    628
    0
                fn next(&mut self) -> Option<Self::Item> {
    629
                    loop {
    630
    0
                        if let DataFusionError::Diagnostic(diagnostics, source) = self.head {
    631
    0
                            self.head = source.as_ref();
    632
    0
                            return Some(diagnostics);
    633
    0
                        }
    634
    635
    0
                        if let Some(source) = self
    636
    0
                            .head
    637
    0
                            .source()
    638
    0
                            .and_then(|source| source.downcast_ref::<DataFusionError>())
    639
    0
                        {
    640
    0
                            self.head = source;
    641
    0
                        } else {
    642
    0
                            return None;
    643
                        }
    644
                    }
    645
    0
                }
    646
            }
    647
    648
    0
            DiagnosticsIterator { head: self }.next()
    649
    0
        }
    650
    651
        /// Return an iterator over this [`DataFusionError`] and any other
    652
        /// [`DataFusionError`]s in a [`DataFusionError::Collection`].
    653
        ///
    654
        /// Sometimes DataFusion is able to collect multiple errors in a SQL query
    655
        /// before terminating, e.g. across different expressions in a SELECT
    656
        /// statements or different sides of a UNION. This method returns an
    657
        /// iterator over all the errors in the collection.
    658
        ///
    659
        /// For this to work, the top-level error must be a
    660
        /// `DataFusionError::Collection`, not something that contains it.
    661
    0
        pub fn iter(&self) -> impl Iterator<Item = &DataFusionError> {
    662
            struct ErrorIterator<'a> {
    663
                queue: VecDeque<&'a DataFusionError>,
    664
            }
    665
    666
            impl<'a> Iterator for ErrorIterator<'a> {
    667
                type Item = &'a DataFusionError;
    668
    669
    0
                fn next(&mut self) -> Option<Self::Item> {
    670
                    loop {
    671
    0
                        let popped = self.queue.pop_front()?;
    672
    0
                        match popped {
    673
    0
                            DataFusionError::Collection(errs) => self.queue.extend(errs),
    674
    0
                            _ => return Some(popped),
    675
                        }
    676
                    }
    677
    0
                }
    678
            }
    679
    680
    0
            let mut queue = VecDeque::new();
    681
    0
            queue.push_back(self);
    682
    0
            ErrorIterator { queue }
    683
    0
        }
    684
    }
    685
    686
    /// A builder for [`DataFusionError`]
    687
    ///
    688
    /// This builder can be used to collect multiple errors and return them as a
    689
    /// [`DataFusionError::Collection`].
    690
    ///
    691
    /// # Example: no errors
    692
    /// ```
    693
    /// # use datafusion_common::DataFusionError;
    694
    /// let mut builder = DataFusionError::builder();
    695
    /// // ok_or returns the value if no errors have been added
    696
    /// assert_eq!(builder.error_or(42).unwrap(), 42);
    697
    /// ```
    698
    ///
    699
    /// # Example: with errors
    700
    /// ```
    701
    /// # use datafusion_common::{assert_contains, DataFusionError};
    702
    /// let mut builder = DataFusionError::builder();
    703
    /// builder.add_error(DataFusionError::Internal("foo".to_owned()));
    704
    /// // ok_or returns the value if no errors have been added
    705
    /// assert_contains!(
    706
    ///     builder.error_or(42).unwrap_err().to_string(),
    707
    ///     "Internal error: foo"
    708
    /// );
    709
    /// ```
    710
    #[derive(Debug, Default)]
    711
    pub struct DataFusionErrorBuilder(Vec<DataFusionError>);
    712
    713
    impl DataFusionErrorBuilder {
    714
        /// Create a new [`DataFusionErrorBuilder`]
    715
    0
        pub fn new() -> Self {
    716
    0
            Default::default()
    717
    0
        }
    718
    719
        /// Add an error to the in progress list
    720
        ///
    721
        /// # Example
    722
        /// ```
    723
        /// # use datafusion_common::{assert_contains, DataFusionError};
    724
        /// let mut builder = DataFusionError::builder();
    725
        /// builder.add_error(DataFusionError::Internal("foo".to_owned()));
    726
        /// assert_contains!(
    727
        ///     builder.error_or(42).unwrap_err().to_string(),
    728
        ///     "Internal error: foo"
    729
        /// );
    730
        /// ```
    731
    0
        pub fn add_error(&mut self, error: DataFusionError) {
    732
    0
            self.0.push(error);
    733
    0
        }
    734
    735
        /// Add an error to the in progress list, returning the builder
    736
        ///
    737
        /// # Example
    738
        /// ```
    739
        /// # use datafusion_common::{assert_contains, DataFusionError};
    740
        /// let builder = DataFusionError::builder()
    741
        ///     .with_error(DataFusionError::Internal("foo".to_owned()));
    742
        /// assert_contains!(
    743
        ///     builder.error_or(42).unwrap_err().to_string(),
    744
        ///     "Internal error: foo"
    745
        /// );
    746
        /// ```
    747
    0
        pub fn with_error(mut self, error: DataFusionError) -> Self {
    748
    0
            self.0.push(error);
    749
    0
            self
    750
    0
        }
    751
    752
        /// Returns `Ok(ok)` if no errors were added to the builder,
    753
        /// otherwise returns a `Result::Err`
    754
    0
        pub fn error_or<T>(self, ok: T) -> Result<T, DataFusionError> {
    755
    0
            match self.0.len() {
    756
    0
                0 => Ok(ok),
    757
    0
                1 => Err(self.0.into_iter().next().expect("length matched 1")),
    758
    0
                _ => Err(DataFusionError::Collection(self.0)),
    759
            }
    760
    0
        }
    761
    }
    762
    763
    /// Unwrap an `Option` if possible. Otherwise return an `DataFusionError::Internal`.
    764
    /// In normal usage of DataFusion the unwrap should always succeed.
    765
    ///
    766
    /// Example: `let values = unwrap_or_internal_err!(values)`
    767
    #[macro_export]
    768
    macro_rules! unwrap_or_internal_err {
    769
        ($Value: ident) => {
    770
    0
            $Value.ok_or_else(|| {
    771
    0
                DataFusionError::Internal(format!(
    772
    0
                    "{} should not be None",
    773
    0
                    stringify!($Value)
    774
    0
                ))
    775
    0
            })?
    776
        };
    777
    }
    778
    779
    /// Assert a condition, returning `DataFusionError::Internal` on failure.
    780
    ///
    781
    /// # Examples
    782
    ///
    783
    /// ```text
    784
    /// assert_or_internal_err!(predicate);
    785
    /// assert_or_internal_err!(predicate, "human readable message");
    786
    /// assert_or_internal_err!(predicate, format!("details: {}", value));
    787
    /// ```
    788
    #[macro_export]
    789
    macro_rules! assert_or_internal_err {
    790
        ($cond:expr) => {
    791
            if !$cond {
    792
                return Err(DataFusionError::Internal(format!(
    793
                    "Assertion failed: {}",
    794
                    stringify!($cond)
    795
                )));
    796
            }
    797
        };
    798
        ($cond:expr, $($arg:tt)+) => {
    799
            if !$cond {
    800
                return Err(DataFusionError::Internal(format!(
    801
                    "Assertion failed: {}: {}",
    802
                    stringify!($cond),
    803
                    format!($($arg)+)
    804
                )));
    805
            }
    806
        };
    807
    }
    808
    809
    /// Assert equality, returning `DataFusionError::Internal` on failure.
    810
    ///
    811
    /// # Examples
    812
    ///
    813
    /// ```text
    814
    /// assert_eq_or_internal_err!(actual, expected);
    815
    /// assert_eq_or_internal_err!(left_expr, right_expr, "values must match");
    816
    /// assert_eq_or_internal_err!(lhs, rhs, "metadata: {}", extra);
    817
    /// ```
    818
    #[macro_export]
    819
    macro_rules! assert_eq_or_internal_err {
    820
        ($left:expr, $right:expr $(,)?) => {{
    821
            let left_val = &$left;
    822
            let right_val = &$right;
    823
            if left_val != right_val {
    824
                return Err(DataFusionError::Internal(format!(
    825
                    "Assertion failed: {} == {} (left: {:?}, right: {:?})",
    826
                    stringify!($left),
    827
                    stringify!($right),
    828
                    left_val,
    829
                    right_val
    830
                )));
    831
            }
    832
        }};
    833
        ($left:expr, $right:expr, $($arg:tt)+) => {{
    834
            let left_val = &$left;
    835
            let right_val = &$right;
    836
            if left_val != right_val {
    837
                return Err(DataFusionError::Internal(format!(
    838
                    "Assertion failed: {} == {} (left: {:?}, right: {:?}): {}",
    839
                    stringify!($left),
    840
                    stringify!($right),
    841
                    left_val,
    842
                    right_val,
    843
                    format!($($arg)+)
    844
                )));
    845
            }
    846
        }};
    847
    }
    848
    849
    /// Assert inequality, returning `DataFusionError::Internal` on failure.
    850
    ///
    851
    /// # Examples
    852
    ///
    853
    /// ```text
    854
    /// assert_ne_or_internal_err!(left, right);
    855
    /// assert_ne_or_internal_err!(lhs_expr, rhs_expr, "values must differ");
    856
    /// assert_ne_or_internal_err!(a, b, "context {}", info);
    857
    /// ```
    858
    #[macro_export]
    859
    macro_rules! assert_ne_or_internal_err {
    860
        ($left:expr, $right:expr $(,)?) => {{
    861
            let left_val = &$left;
    862
            let right_val = &$right;
    863
            if left_val == right_val {
    864
                return Err(DataFusionError::Internal(format!(
    865
                    "Assertion failed: {} != {} (left: {:?}, right: {:?})",
    866
                    stringify!($left),
    867
                    stringify!($right),
    868
                    left_val,
    869
                    right_val
    870
                )));
    871
            }
    872
        }};
    873
        ($left:expr, $right:expr, $($arg:tt)+) => {{
    874
            let left_val = &$left;
    875
            let right_val = &$right;
    876
            if left_val == right_val {
    877
                return Err(DataFusionError::Internal(format!(
    878
                    "Assertion failed: {} != {} (left: {:?}, right: {:?}): {}",
    879
                    stringify!($left),
    880
                    stringify!($right),
    881
                    left_val,
    882
                    right_val,
    883
                    format!($($arg)+)
    884
                )));
    885
            }
    886
        }};
    887
    }
    888
    889
    /// Add a macros for concise  DataFusionError::* errors declaration
    890
    /// supports placeholders the same way as `format!`
    891
    /// Examples:
    892
    ///     plan_err!("Error")
    893
    ///     plan_err!("Error {}", val)
    894
    ///     plan_err!("Error {:?}", val)
    895
    ///     plan_err!("Error {val}")
    896
    ///     plan_err!("Error {val:?}")
    897
    ///
    898
    /// `NAME_ERR` -  macro name for wrapping Err(DataFusionError::*)
    899
    /// `NAME_DF_ERR` -  macro name for wrapping DataFusionError::*. Needed to keep backtrace opportunity
    900
    /// in construction where DataFusionError::* used directly, like `map_err`, `ok_or_else`, etc
    901
    macro_rules! make_error {
    902
        ($NAME_ERR:ident, $NAME_DF_ERR: ident, $ERR:ident) => { make_error!(@inner ($), $NAME_ERR, $NAME_DF_ERR, $ERR); };
    903
        (@inner ($d:tt), $NAME_ERR:ident, $NAME_DF_ERR:ident, $ERR:ident) => {
    904
            ::paste::paste!{
    905
                /// Macro wraps `$ERR` to add backtrace feature
    906
                #[macro_export]
    907
                macro_rules! $NAME_DF_ERR {
    908
                    ($d($d args:expr),* $d(; diagnostic=$d DIAG:expr)?) => {{
    909
                        let err =$crate::DataFusionError::$ERR(
    910
                            ::std::format!(
    911
                                "{}{}",
    912
                                ::std::format!($d($d args),*),
    913
                                $crate::DataFusionError::get_back_trace(),
    914
                            ).into()
    915
                        );
    916
                        $d (
    917
                            let err = err.with_diagnostic($d DIAG);
    918
                        )?
    919
                        err
    920
                    }
    921
                }
    922
            }
    923
    924
                /// Macro wraps Err(`$ERR`) to add backtrace feature
    925
                #[macro_export]
    926
                macro_rules! $NAME_ERR {
    927
                    ($d($d args:expr),* $d(; diagnostic = $d DIAG:expr)?) => {{
    928
                        let err = $crate::[<_ $NAME_DF_ERR>]!($d($d args),*);
    929
                        $d (
    930
                            let err = err.with_diagnostic($d DIAG);
    931
                        )?
    932
                        Err(err)
    933
    934
                    }}
    935
                }
    936
    937
    938
                // Note: Certain macros are used in this  crate, but not all.
    939
                // This macro generates a use or all of them in case they are needed
    940
                // so we allow unused code to avoid warnings when they are not used
    941
                #[doc(hidden)]
    942
                #[allow(unused)]
    943
                pub use $NAME_ERR as [<_ $NAME_ERR>];
    944
                #[doc(hidden)]
    945
                #[allow(unused)]
    946
                pub use $NAME_DF_ERR as [<_ $NAME_DF_ERR>];
    947
            }
    948
        };
    949
    }
    950
    951
    // Exposes a macro to create `DataFusionError::Plan` with optional backtrace
    952
    make_error!(plan_err, plan_datafusion_err, Plan);
    953
    954
    // Exposes a macro to create `DataFusionError::Internal` with optional backtrace
    955
    make_error!(internal_err, internal_datafusion_err, Internal);
    956
    957
    // Exposes a macro to create `DataFusionError::NotImplemented` with optional backtrace
    958
    make_error!(not_impl_err, not_impl_datafusion_err, NotImplemented);
    959
    960
    // Exposes a macro to create `DataFusionError::Execution` with optional backtrace
    961
    make_error!(exec_err, exec_datafusion_err, Execution);
    962
    963
    // Exposes a macro to create `DataFusionError::Configuration` with optional backtrace
    964
    make_error!(config_err, config_datafusion_err, Configuration);
    965
    966
    // Exposes a macro to create `DataFusionError::Substrait` with optional backtrace
    967
    make_error!(substrait_err, substrait_datafusion_err, Substrait);
    968
    969
    // Exposes a macro to create `DataFusionError::ResourcesExhausted` with optional backtrace
    970
    make_error!(resources_err, resources_datafusion_err, ResourcesExhausted);
    971
    972
    // Exposes a macro to create `DataFusionError::SQL` with optional backtrace
    973
    #[macro_export]
    974
    macro_rules! sql_datafusion_err {
    975
        ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
    976
            let err = DataFusionError::SQL(Box::new($ERR), Some(DataFusionError::get_back_trace()));
    977
            $(
    978
                let err = err.with_diagnostic($DIAG);
    979
            )?
    980
            err
    981
        }};
    982
    }
    983
    984
    // Exposes a macro to create `Err(DataFusionError::SQL)` with optional backtrace
    985
    #[macro_export]
    986
    macro_rules! sql_err {
    987
        ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
    988
            let err = datafusion_common::sql_datafusion_err!($ERR);
    989
            $(
    990
                let err = err.with_diagnostic($DIAG);
    991
            )?
    992
            Err(err)
    993
        }};
    994
    }
    995
    996
    // Exposes a macro to create `DataFusionError::ArrowError` with optional backtrace
    997
    #[macro_export]
    998
    macro_rules! arrow_datafusion_err {
    999
        ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
    1000
            let err = DataFusionError::ArrowError(Box::new($ERR), Some(DataFusionError::get_back_trace()));
    1001
            $(
    1002
                let err = err.with_diagnostic($DIAG);
    1003
            )?
    1004
            err
    1005
        }};
    1006
    }
    1007
    1008
    // Exposes a macro to create `Err(DataFusionError::ArrowError)` with optional backtrace
    1009
    #[macro_export]
    1010
    macro_rules! arrow_err {
    1011
        ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {
    1012
        {
    1013
            let err = datafusion_common::arrow_datafusion_err!($ERR);
    1014
            $(
    1015
                let err = err.with_diagnostic($DIAG);
    1016
            )?
    1017
            Err(err)
    1018
        }};
    1019
    }
    1020
    1021
    // Exposes a macro to create `DataFusionError::SchemaError` with optional backtrace
    1022
    #[macro_export]
    1023
    macro_rules! schema_datafusion_err {
    1024
        ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
    1025
            let err = $crate::error::DataFusionError::SchemaError(
    1026
                Box::new($ERR),
    1027
                Box::new(Some($crate::error::DataFusionError::get_back_trace())),
    1028
            );
    1029
            $(
    1030
                let err = err.with_diagnostic($DIAG);
    1031
            )?
    1032
            err
    1033
        }};
    1034
    }
    1035
    1036
    // Exposes a macro to create `Err(DataFusionError::SchemaError)` with optional backtrace
    1037
    #[macro_export]
    1038
    macro_rules! schema_err {
    1039
        ($ERR:expr $(; diagnostic = $DIAG:expr)?) => {{
    1040
            let err = $crate::error::DataFusionError::SchemaError(
    1041
                Box::new($ERR),
    1042
                Box::new(Some($crate::error::DataFusionError::get_back_trace())),
    1043
            );
    1044
            $(
    1045
                let err = err.with_diagnostic($DIAG);
    1046
            )?
    1047
            Err(err)
    1048
        }
    1049
        };
    1050
    }
    1051
    1052
    // To avoid compiler error when using macro in the same crate:
    1053
    // macros from the current crate cannot be referred to by absolute paths
    1054
    pub use schema_err as _schema_err;
    1055
    1056
    /// Create a "field not found" DataFusion::SchemaError
    1057
    0
    pub fn field_not_found<R: Into<TableReference>>(
    1058
    0
        qualifier: Option<R>,
    1059
    0
        name: &str,
    1060
    0
        schema: &DFSchema,
    1061
    0
    ) -> DataFusionError {
    1062
    0
        schema_datafusion_err!(SchemaError::FieldNotFound {
    1063
    0
            field: Box::new(Column::new(qualifier, name)),
    1064
    0
            valid_fields: schema.columns().to_vec(),
    1065
    0
        })
    1066
    0
    }
    1067
    1068
    /// Convenience wrapper over [`field_not_found`] for when there is no qualifier
    1069
    0
    pub fn unqualified_field_not_found(name: &str, schema: &DFSchema) -> DataFusionError {
    1070
    0
        schema_datafusion_err!(SchemaError::FieldNotFound {
    1071
    0
            field: Box::new(Column::new_unqualified(name)),
    1072
    0
            valid_fields: schema.columns().to_vec(),
    1073
    0
        })
    1074
    0
    }
    1075
    1076
    0
    pub fn add_possible_columns_to_diag(
    1077
    0
        diagnostic: &mut Diagnostic,
    1078
    0
        field: &Column,
    1079
    0
        valid_fields: &[Column],
    1080
    0
    ) {
    1081
    0
        let field_names: Vec<String> = valid_fields
    1082
    0
            .iter()
    1083
    0
            .filter_map(|f| {
    1084
    0
                if normalized_levenshtein(f.name(), field.name()) >= 0.5 {
    1085
    0
                    Some(f.flat_name())
    1086
                } else {
    1087
    0
                    None
    1088
                }
    1089
    0
            })
    1090
    0
            .collect();
    1091
    1092
    0
        for name in field_names {
    1093
    0
            diagnostic.add_note(format!("possible column {name}"), None);
    1094
    0
        }
    1095
    0
    }
    1096
    1097
    #[cfg(test)]
    1098
    mod test {
    1099
        use super::*;
    1100
    1101
        use std::mem::size_of;
    1102
        use std::sync::Arc;
    1103
    1104
        use arrow::error::ArrowError;
    1105
        use insta::assert_snapshot;
    1106
    1107
        fn ok_result() -> Result<()> {
    1108
            Ok(())
    1109
        }
    1110
    1111
        #[test]
    1112
        fn test_assert_eq_or_internal_err_passes() -> Result<()> {
    1113
            assert_eq_or_internal_err!(1, 1);
    1114
            ok_result()
    1115
        }
    1116
    1117
        #[test]
    1118
        fn test_assert_eq_or_internal_err_fails() {
    1119
            fn check() -> Result<()> {
    1120
                assert_eq_or_internal_err!(1, 2, "expected equality");
    1121
                ok_result()
    1122
            }
    1123
    1124
            let err = check().unwrap_err();
    1125
            assert_snapshot!(
    1126
                err.to_string(),
    1127
                @r"
    1128
            Internal error: Assertion failed: 1 == 2 (left: 1, right: 2): expected equality.
    1129
            This issue was likely caused by a bug in DataFusion's code. Please help us to resolve this by filing a bug report in our issue tracker: https://github.com/apache/datafusion/issues
    1130
            "
    1131
            );
    1132
        }
    1133
    1134
        #[test]
    1135
        fn test_assert_ne_or_internal_err_passes() -> Result<()> {
    1136
            assert_ne_or_internal_err!(1, 2);
    1137
            ok_result()
    1138
        }
    1139
    1140
        #[test]
    1141
        fn test_assert_ne_or_internal_err_fails() {
    1142
            fn check() -> Result<()> {
    1143
                assert_ne_or_internal_err!(3, 3, "values must differ");
    1144
                ok_result()
    1145
            }
    1146
    1147
            let err = check().unwrap_err();
    1148
            assert_snapshot!(
    1149
                err.to_string(),
    1150
                @r"
    1151
            Internal error: Assertion failed: 3 != 3 (left: 3, right: 3): values must differ.
    1152
            This issue was likely caused by a bug in DataFusion's code. Please help us to resolve this by filing a bug report in our issue tracker: https://github.com/apache/datafusion/issues
    1153
            "
    1154
            );
    1155
        }
    1156
    1157
        #[test]
    1158
        fn test_assert_or_internal_err_passes() -> Result<()> {
    1159
            assert_or_internal_err!(true);
    1160
            assert_or_internal_err!(true, "message");
    1161
            ok_result()
    1162
        }
    1163
    1164
        #[test]
    1165
        fn test_assert_or_internal_err_fails_default() {
    1166
            fn check() -> Result<()> {
    1167
                assert_or_internal_err!(false);
    1168
                ok_result()
    1169
            }
    1170
    1171
            let err = check().unwrap_err();
    1172
            assert_snapshot!(
    1173
                err.to_string(),
    1174
                @r"
    1175
            Internal error: Assertion failed: false.
    1176
            This issue was likely caused by a bug in DataFusion's code. Please help us to resolve this by filing a bug report in our issue tracker: https://github.com/apache/datafusion/issues
    1177
            "
    1178
            );
    1179
        }
    1180
    1181
        #[test]
    1182
        fn test_assert_or_internal_err_fails_with_message() {
    1183
            fn check() -> Result<()> {
    1184
                assert_or_internal_err!(false, "custom message");
    1185
                ok_result()
    1186
            }
    1187
    1188
            let err = check().unwrap_err();
    1189
            assert_snapshot!(
    1190
                err.to_string(),
    1191
                @r"
    1192
            Internal error: Assertion failed: false: custom message.
    1193
            This issue was likely caused by a bug in DataFusion's code. Please help us to resolve this by filing a bug report in our issue tracker: https://github.com/apache/datafusion/issues
    1194
            "
    1195
            );
    1196
        }
    1197
    1198
        #[test]
    1199
        fn test_assert_or_internal_err_with_format_arguments() {
    1200
            fn check() -> Result<()> {
    1201
                assert_or_internal_err!(false, "custom {}", 42);
    1202
                ok_result()
    1203
            }
    1204
    1205
            let err = check().unwrap_err();
    1206
            assert_snapshot!(
    1207
                err.to_string(),
    1208
                @r"
    1209
            Internal error: Assertion failed: false: custom 42.
    1210
            This issue was likely caused by a bug in DataFusion's code. Please help us to resolve this by filing a bug report in our issue tracker: https://github.com/apache/datafusion/issues
    1211
            "
    1212
            );
    1213
        }
    1214
    1215
        #[test]
    1216
        fn test_error_size() {
    1217
            // Since Errors influence the size of Result which influence the size of the stack
    1218
            // please don't allow this to grow larger
    1219
            assert_eq!(size_of::<SchemaError>(), 40);
    1220
            assert_eq!(size_of::<DataFusionError>(), 40);
    1221
        }
    1222
    1223
        #[test]
    1224
        fn datafusion_error_to_arrow() {
    1225
            let res = return_arrow_error().unwrap_err();
    1226
            assert!(res
    1227
                .to_string()
    1228
                .starts_with("External error: Error during planning: foo"));
    1229
        }
    1230
    1231
        #[test]
    1232
        fn arrow_error_to_datafusion() {
    1233
            let res = return_datafusion_error().unwrap_err();
    1234
            assert_eq!(res.strip_backtrace(), "Arrow error: Schema error: bar");
    1235
        }
    1236
    1237
        // To pass the test the environment variable RUST_BACKTRACE should be set to 1 to enforce backtrace
    1238
        #[cfg(feature = "backtrace")]
    1239
        #[test]
    1240
        #[allow(clippy::unnecessary_literal_unwrap)]
    1241
        fn test_enabled_backtrace() {
    1242
            match std::env::var("RUST_BACKTRACE") {
    1243
                Ok(val) if val == "1" => {}
    1244
                _ => panic!("Environment variable RUST_BACKTRACE must be set to 1"),
    1245
            };
    1246
    1247
            let res: Result<(), DataFusionError> = plan_err!("Err");
    1248
            let err = res.unwrap_err().to_string();
    1249
            assert!(err.contains(DataFusionError::BACK_TRACE_SEP));
    1250
            assert_eq!(
    1251
                err.split(DataFusionError::BACK_TRACE_SEP)
    1252
                    .collect::<Vec<&str>>()
    1253
                    .first()
    1254
                    .unwrap(),
    1255
                &"Error during planning: Err"
    1256
            );
    1257
            assert!(!err
    1258
                .split(DataFusionError::BACK_TRACE_SEP)
    1259
                .collect::<Vec<&str>>()
    1260
                .get(1)
    1261
                .unwrap()
    1262
                .is_empty());
    1263
        }
    1264
    1265
        #[cfg(not(feature = "backtrace"))]
    1266
        #[test]
    1267
        #[allow(clippy::unnecessary_literal_unwrap)]
    1268
        fn test_disabled_backtrace() {
    1269
            let res: Result<(), DataFusionError> = plan_err!("Err");
    1270
            let res = res.unwrap_err().to_string();
    1271
            assert!(!res.contains(DataFusionError::BACK_TRACE_SEP));
    1272
            assert_eq!(res, "Error during planning: Err");
    1273
        }
    1274
    1275
        #[test]
    1276
        fn test_find_root_error() {
    1277
            do_root_test(
    1278
                DataFusionError::Context(
    1279
                    "it happened!".to_string(),
    1280
                    Box::new(DataFusionError::ResourcesExhausted("foo".to_string())),
    1281
                ),
    1282
                DataFusionError::ResourcesExhausted("foo".to_string()),
    1283
            );
    1284
    1285
            do_root_test(
    1286
                DataFusionError::ArrowError(
    1287
                    Box::new(ArrowError::ExternalError(Box::new(
    1288
                        DataFusionError::ResourcesExhausted("foo".to_string()),
    1289
                    ))),
    1290
                    None,
    1291
                ),
    1292
                DataFusionError::ResourcesExhausted("foo".to_string()),
    1293
            );
    1294
    1295
            do_root_test(
    1296
                DataFusionError::External(Box::new(DataFusionError::ResourcesExhausted(
    1297
                    "foo".to_string(),
    1298
                ))),
    1299
                DataFusionError::ResourcesExhausted("foo".to_string()),
    1300
            );
    1301
    1302
            do_root_test(
    1303
                DataFusionError::External(Box::new(ArrowError::ExternalError(Box::new(
    1304
                    DataFusionError::ResourcesExhausted("foo".to_string()),
    1305
                )))),
    1306
                DataFusionError::ResourcesExhausted("foo".to_string()),
    1307
            );
    1308
    1309
            do_root_test(
    1310
                DataFusionError::ArrowError(
    1311
                    Box::new(ArrowError::ExternalError(Box::new(
    1312
                        ArrowError::ExternalError(Box::new(
    1313
                            DataFusionError::ResourcesExhausted("foo".to_string()),
    1314
                        )),
    1315
                    ))),
    1316
                    None,
    1317
                ),
    1318
                DataFusionError::ResourcesExhausted("foo".to_string()),
    1319
            );
    1320
    1321
            do_root_test(
    1322
                DataFusionError::External(Box::new(Arc::new(
    1323
                    DataFusionError::ResourcesExhausted("foo".to_string()),
    1324
                ))),
    1325
                DataFusionError::ResourcesExhausted("foo".to_string()),
    1326
            );
    1327
    1328
            do_root_test(
    1329
                DataFusionError::External(Box::new(Arc::new(ArrowError::ExternalError(
    1330
                    Box::new(DataFusionError::ResourcesExhausted("foo".to_string())),
    1331
                )))),
    1332
                DataFusionError::ResourcesExhausted("foo".to_string()),
    1333
            );
    1334
        }
    1335
    1336
        #[test]
    1337
        #[allow(clippy::unnecessary_literal_unwrap)]
    1338
        fn test_make_error_parse_input() {
    1339
            let res: Result<(), DataFusionError> = plan_err!("Err");
    1340
            let res = res.unwrap_err();
    1341
            assert_eq!(res.strip_backtrace(), "Error during planning: Err");
    1342
    1343
            let extra1 = "extra1";
    1344
            let extra2 = "extra2";
    1345
    1346
            let res: Result<(), DataFusionError> = plan_err!("Err {} {}", extra1, extra2);
    1347
            let res = res.unwrap_err();
    1348
            assert_eq!(
    1349
                res.strip_backtrace(),
    1350
                "Error during planning: Err extra1 extra2"
    1351
            );
    1352
    1353
            let res: Result<(), DataFusionError> =
    1354
                plan_err!("Err {:?} {:#?}", extra1, extra2);
    1355
            let res = res.unwrap_err();
    1356
            assert_eq!(
    1357
                res.strip_backtrace(),
    1358
                "Error during planning: Err \"extra1\" \"extra2\""
    1359
            );
    1360
    1361
            let res: Result<(), DataFusionError> = plan_err!("Err {extra1} {extra2}");
    1362
            let res = res.unwrap_err();
    1363
            assert_eq!(
    1364
                res.strip_backtrace(),
    1365
                "Error during planning: Err extra1 extra2"
    1366
            );
    1367
    1368
            let res: Result<(), DataFusionError> = plan_err!("Err {extra1:?} {extra2:#?}");
    1369
            let res = res.unwrap_err();
    1370
            assert_eq!(
    1371
                res.strip_backtrace(),
    1372
                "Error during planning: Err \"extra1\" \"extra2\""
    1373
            );
    1374
        }
    1375
    1376
        #[test]
    1377
        fn external_error() {
    1378
            // assert not wrapping DataFusionError
    1379
            let generic_error: GenericError =
    1380
                Box::new(DataFusionError::Plan("test".to_string()));
    1381
            let datafusion_error: DataFusionError = generic_error.into();
    1382
            println!("{}", datafusion_error.strip_backtrace());
    1383
            assert_eq!(
    1384
                datafusion_error.strip_backtrace(),
    1385
                "Error during planning: test"
    1386
            );
    1387
    1388
            // assert wrapping other Error
    1389
            let generic_error: GenericError = Box::new(io::Error::other("io error"));
    1390
            let datafusion_error: DataFusionError = generic_error.into();
    1391
            println!("{}", datafusion_error.strip_backtrace());
    1392
            assert_eq!(
    1393
                datafusion_error.strip_backtrace(),
    1394
                "External error: io error"
    1395
            );
    1396
        }
    1397
    1398
        #[test]
    1399
        fn external_error_no_recursive() {
    1400
            let generic_error_1: GenericError = Box::new(io::Error::other("io error"));
    1401
            let external_error_1: DataFusionError = generic_error_1.into();
    1402
            let generic_error_2: GenericError = Box::new(external_error_1);
    1403
            let external_error_2: DataFusionError = generic_error_2.into();
    1404
    1405
            println!("{external_error_2}");
    1406
            assert!(external_error_2
    1407
                .to_string()
    1408
                .starts_with("External error: io error"));
    1409
        }
    1410
    1411
        /// Model what happens when implementing SendableRecordBatchStream:
    1412
        /// DataFusion code needs to return an ArrowError
    1413
        fn return_arrow_error() -> arrow::error::Result<()> {
    1414
            // Expect the '?' to work
    1415
            Err(DataFusionError::Plan("foo".to_string()).into())
    1416
        }
    1417
    1418
        /// Model what happens when using arrow kernels in DataFusion
    1419
        /// code: need to turn an ArrowError into a DataFusionError
    1420
        fn return_datafusion_error() -> Result<()> {
    1421
            // Expect the '?' to work
    1422
            Err(ArrowError::SchemaError("bar".to_string()).into())
    1423
        }
    1424
    1425
        fn do_root_test(e: DataFusionError, exp: DataFusionError) {
    1426
            let e = e.find_root();
    1427
    1428
            // DataFusionError does not implement Eq, so we use a string comparison + some cheap "same variant" test instead
    1429
            assert_eq!(e.strip_backtrace(), exp.strip_backtrace());
    1430
            assert_eq!(std::mem::discriminant(e), std::mem::discriminant(&exp),)
    1431
        }
    1432
    1433
        #[test]
    1434
        fn test_iter() {
    1435
            let err = DataFusionError::Collection(vec![
    1436
                DataFusionError::Plan("a".to_string()),
    1437
                DataFusionError::Collection(vec![
    1438
                    DataFusionError::Plan("b".to_string()),
    1439
                    DataFusionError::Plan("c".to_string()),
    1440
                ]),
    1441
            ]);
    1442
            let errs = err.iter().collect::<Vec<_>>();
    1443
            assert_eq!(errs.len(), 3);
    1444
            assert_eq!(errs[0].strip_backtrace(), "Error during planning: a");
    1445
            assert_eq!(errs[1].strip_backtrace(), "Error during planning: b");
    1446
            assert_eq!(errs[2].strip_backtrace(), "Error during planning: c");
    1447
        }
    1448
    }