Skip to main content

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<cell::BorrowMutError> for ParquetError {
112    fn from(e: cell::BorrowMutError) -> ParquetError {
113        ParquetError::External(Box::new(e))
114    }
115}
116
117impl From<str::Utf8Error> for ParquetError {
118    fn from(e: str::Utf8Error) -> ParquetError {
119        ParquetError::External(Box::new(e))
120    }
121}
122
123impl From<FromUtf8Error> for ParquetError {
124    fn from(e: FromUtf8Error) -> ParquetError {
125        ParquetError::External(Box::new(e))
126    }
127}
128
129#[cfg(feature = "arrow")]
130impl From<ArrowError> for ParquetError {
131    fn from(e: ArrowError) -> ParquetError {
132        ParquetError::External(Box::new(e))
133    }
134}
135
136#[cfg(feature = "object_store")]
137impl From<object_store::Error> for ParquetError {
138    fn from(e: object_store::Error) -> ParquetError {
139        ParquetError::External(Box::new(e))
140    }
141}
142
143#[cfg(feature = "encryption")]
144impl From<ring::error::Unspecified> for ParquetError {
145    fn from(e: ring::error::Unspecified) -> ParquetError {
146        ParquetError::External(Box::new(e))
147    }
148}
149
150/// A specialized `Result` for Parquet errors.
151pub type Result<T, E = ParquetError> = result::Result<T, E>;
152
153// ----------------------------------------------------------------------
154// Conversion from `ParquetError` to other types of `Error`s
155
156impl From<ParquetError> for io::Error {
157    fn from(e: ParquetError) -> Self {
158        io::Error::other(e)
159    }
160}
161
162// ----------------------------------------------------------------------
163// Convenient macros for different errors
164
165macro_rules! general_err {
166    ($fmt:expr) => (ParquetError::General($fmt.to_owned()));
167    ($fmt:expr, $($args:expr),*) => (ParquetError::General(format!($fmt, $($args),*)));
168    ($e:expr, $fmt:expr) => (ParquetError::General($fmt.to_owned(), $e));
169    ($e:ident, $fmt:expr, $($args:tt),*) => (
170        ParquetError::General(&format!($fmt, $($args),*), $e));
171}
172
173macro_rules! nyi_err {
174    ($fmt:expr) => (ParquetError::NYI($fmt.to_owned()));
175    ($fmt:expr, $($args:expr),*) => (ParquetError::NYI(format!($fmt, $($args),*)));
176}
177
178macro_rules! eof_err {
179    ($fmt:expr) => (ParquetError::EOF($fmt.to_owned()));
180    ($fmt:expr, $($args:expr),*) => (ParquetError::EOF(format!($fmt, $($args),*)));
181}
182
183#[cfg(feature = "arrow")]
184macro_rules! arrow_err {
185    ($fmt:expr) => (ParquetError::ArrowError($fmt.to_owned()));
186    ($fmt:expr, $($args:expr),*) => (ParquetError::ArrowError(format!($fmt, $($args),*)));
187    ($e:expr, $fmt:expr) => (ParquetError::ArrowError($fmt.to_owned(), $e));
188    ($e:ident, $fmt:expr, $($args:tt),*) => (
189        ParquetError::ArrowError(&format!($fmt, $($args),*), $e));
190}
191
192// ----------------------------------------------------------------------
193// Convert parquet error into other errors
194
195#[cfg(feature = "arrow")]
196impl From<ParquetError> for ArrowError {
197    fn from(p: ParquetError) -> Self {
198        Self::ParquetError(format!("{p}"))
199    }
200}