parquet/
errors.rs

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//! Common Parquet errors and macros.
19
20use core::num::TryFromIntError;
21use std::error::Error;
22use std::{cell, io, result, str};
23
24#[cfg(feature = "arrow")]
25use arrow_schema::ArrowError;
26
27/// Parquet error enumeration
28// Note: we don't implement PartialEq as the semantics for the
29// external variant are not well defined (#4469)
30#[derive(Debug)]
31#[non_exhaustive]
32pub enum ParquetError {
33    /// General Parquet error.
34    /// Returned when code violates normal workflow of working with Parquet files.
35    General(String),
36    /// "Not yet implemented" Parquet error.
37    /// Returned when functionality is not yet available.
38    NYI(String),
39    /// "End of file" Parquet error.
40    /// Returned when IO related failures occur, e.g. when there are not enough bytes to
41    /// decode.
42    EOF(String),
43    #[cfg(feature = "arrow")]
44    /// Arrow error.
45    /// Returned when reading into arrow or writing from arrow.
46    ArrowError(String),
47    /// Error when the requested column index is more than the
48    /// number of columns in the row group
49    IndexOutOfBound(usize, usize),
50    /// An external error variant
51    External(Box<dyn Error + Send + Sync>),
52    /// Returned when a function needs more data to complete properly. The `usize` field indicates
53    /// the total number of bytes required, not the number of additional bytes.
54    NeedMoreData(usize),
55    /// Returned when a function needs more data to complete properly.
56    /// The `Range<u64>` indicates the range of bytes that are needed.
57    NeedMoreDataRange(std::ops::Range<u64>),
58}
59
60impl std::fmt::Display for ParquetError {
61    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
62        match &self {
63            ParquetError::General(message) => {
64                write!(fmt, "Parquet error: {message}")
65            }
66            ParquetError::NYI(message) => write!(fmt, "NYI: {message}"),
67            ParquetError::EOF(message) => write!(fmt, "EOF: {message}"),
68            #[cfg(feature = "arrow")]
69            ParquetError::ArrowError(message) => write!(fmt, "Arrow: {message}"),
70            ParquetError::IndexOutOfBound(index, ref bound) => {
71                write!(fmt, "Index {index} out of bound: {bound}")
72            }
73            ParquetError::External(e) => write!(fmt, "External: {e}"),
74            ParquetError::NeedMoreData(needed) => write!(fmt, "NeedMoreData: {needed}"),
75            ParquetError::NeedMoreDataRange(range) => {
76                write!(fmt, "NeedMoreDataRange: {}..{}", range.start, range.end)
77            }
78        }
79    }
80}
81
82impl Error for ParquetError {
83    fn source(&self) -> Option<&(dyn Error + 'static)> {
84        match self {
85            ParquetError::External(e) => Some(e.as_ref()),
86            _ => None,
87        }
88    }
89}
90
91impl From<TryFromIntError> for ParquetError {
92    fn from(e: TryFromIntError) -> ParquetError {
93        ParquetError::General(format!("Integer overflow: {e}"))
94    }
95}
96
97impl From<io::Error> for ParquetError {
98    fn from(e: io::Error) -> ParquetError {
99        ParquetError::External(Box::new(e))
100    }
101}
102
103#[cfg(any(feature = "snap", test))]
104impl From<snap::Error> for ParquetError {
105    fn from(e: snap::Error) -> ParquetError {
106        ParquetError::External(Box::new(e))
107    }
108}
109
110impl From<thrift::Error> for ParquetError {
111    fn from(e: thrift::Error) -> ParquetError {
112        ParquetError::External(Box::new(e))
113    }
114}
115
116impl From<cell::BorrowMutError> for ParquetError {
117    fn from(e: cell::BorrowMutError) -> ParquetError {
118        ParquetError::External(Box::new(e))
119    }
120}
121
122impl From<str::Utf8Error> for ParquetError {
123    fn from(e: str::Utf8Error) -> ParquetError {
124        ParquetError::External(Box::new(e))
125    }
126}
127#[cfg(feature = "arrow")]
128impl From<ArrowError> for ParquetError {
129    fn from(e: ArrowError) -> ParquetError {
130        ParquetError::External(Box::new(e))
131    }
132}
133
134#[cfg(feature = "object_store")]
135impl From<object_store::Error> for ParquetError {
136    fn from(e: object_store::Error) -> ParquetError {
137        ParquetError::External(Box::new(e))
138    }
139}
140
141#[cfg(feature = "encryption")]
142impl From<ring::error::Unspecified> for ParquetError {
143    fn from(e: ring::error::Unspecified) -> ParquetError {
144        ParquetError::External(Box::new(e))
145    }
146}
147
148/// A specialized `Result` for Parquet errors.
149pub type Result<T, E = ParquetError> = result::Result<T, E>;
150
151// ----------------------------------------------------------------------
152// Conversion from `ParquetError` to other types of `Error`s
153
154impl From<ParquetError> for io::Error {
155    fn from(e: ParquetError) -> Self {
156        io::Error::other(e)
157    }
158}
159
160// ----------------------------------------------------------------------
161// Convenient macros for different errors
162
163macro_rules! general_err {
164    ($fmt:expr) => (ParquetError::General($fmt.to_owned()));
165    ($fmt:expr, $($args:expr),*) => (ParquetError::General(format!($fmt, $($args),*)));
166    ($e:expr, $fmt:expr) => (ParquetError::General($fmt.to_owned(), $e));
167    ($e:ident, $fmt:expr, $($args:tt),*) => (
168        ParquetError::General(&format!($fmt, $($args),*), $e));
169}
170
171macro_rules! nyi_err {
172    ($fmt:expr) => (ParquetError::NYI($fmt.to_owned()));
173    ($fmt:expr, $($args:expr),*) => (ParquetError::NYI(format!($fmt, $($args),*)));
174}
175
176macro_rules! eof_err {
177    ($fmt:expr) => (ParquetError::EOF($fmt.to_owned()));
178    ($fmt:expr, $($args:expr),*) => (ParquetError::EOF(format!($fmt, $($args),*)));
179}
180
181#[cfg(feature = "arrow")]
182macro_rules! arrow_err {
183    ($fmt:expr) => (ParquetError::ArrowError($fmt.to_owned()));
184    ($fmt:expr, $($args:expr),*) => (ParquetError::ArrowError(format!($fmt, $($args),*)));
185    ($e:expr, $fmt:expr) => (ParquetError::ArrowError($fmt.to_owned(), $e));
186    ($e:ident, $fmt:expr, $($args:tt),*) => (
187        ParquetError::ArrowError(&format!($fmt, $($args),*), $e));
188}
189
190// ----------------------------------------------------------------------
191// Convert parquet error into other errors
192
193#[cfg(feature = "arrow")]
194impl From<ParquetError> for ArrowError {
195    fn from(p: ParquetError) -> Self {
196        Self::ParquetError(format!("{p}"))
197    }
198}