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