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 #pragma once
19
20 #include <exception>
21 #include <sstream>
22 #include <string>
23 #include <utility>
24
25 #include "arrow/type_fwd.h"
26 #include "arrow/util/string_builder.h"
27 #include "parquet/platform.h"
28
29 // PARQUET-1085
30 #if !defined(ARROW_UNUSED)
31 #define ARROW_UNUSED(x) UNUSED(x)
32 #endif
33
34 // Parquet exception to Arrow Status
35
36 #define BEGIN_PARQUET_CATCH_EXCEPTIONS try {
37 #define END_PARQUET_CATCH_EXCEPTIONS \
38 } \
39 catch (const ::parquet::ParquetStatusException& e) { \
40 return e.status(); \
41 } \
42 catch (const ::parquet::ParquetException& e) { \
43 return ::arrow::Status::IOError(e.what()); \
44 }
45
46 // clang-format off
47
48 #define PARQUET_CATCH_NOT_OK(s) \
49 BEGIN_PARQUET_CATCH_EXCEPTIONS \
50 (s); \
51 END_PARQUET_CATCH_EXCEPTIONS
52
53 // clang-format on
54
55 #define PARQUET_CATCH_AND_RETURN(s) \
56 BEGIN_PARQUET_CATCH_EXCEPTIONS \
57 return (s); \
58 END_PARQUET_CATCH_EXCEPTIONS
59
60 // Arrow Status to Parquet exception
61
62 #define PARQUET_IGNORE_NOT_OK(s) \
63 do { \
64 ::arrow::Status _s = ::arrow::internal::GenericToStatus(s); \
65 ARROW_UNUSED(_s); \
66 } while (0)
67
68 #define PARQUET_THROW_NOT_OK(s) \
69 do { \
70 ::arrow::Status _s = ::arrow::internal::GenericToStatus(s); \
71 if (!_s.ok()) { \
72 throw ::parquet::ParquetStatusException(std::move(_s)); \
73 } \
74 } while (0)
75
76 #define PARQUET_ASSIGN_OR_THROW_IMPL(status_name, lhs, rexpr) \
77 auto status_name = (rexpr); \
78 PARQUET_THROW_NOT_OK(status_name.status()); \
79 lhs = std::move(status_name).ValueOrDie();
80
81 #define PARQUET_ASSIGN_OR_THROW(lhs, rexpr) \
82 PARQUET_ASSIGN_OR_THROW_IMPL(ARROW_ASSIGN_OR_RAISE_NAME(_error_or_value, __COUNTER__), \
83 lhs, rexpr);
84
85 namespace parquet {
86
87 class ParquetException : public std::exception {
88 public:
89 PARQUET_NORETURN static void EofException(const std::string& msg = "") {
90 static std::string prefix = "Unexpected end of stream";
91 if (msg.empty()) {
92 throw ParquetException(prefix);
93 }
94 throw ParquetException(prefix, ": ", msg);
95 }
96
97 PARQUET_NORETURN static void NYI(const std::string& msg = "") {
98 throw ParquetException("Not yet implemented: ", msg, ".");
99 }
100
101 template <typename... Args>
ParquetException(Args &&...args)102 explicit ParquetException(Args&&... args)
103 : msg_(::arrow::util::StringBuilder(std::forward<Args>(args)...)) {}
104
ParquetException(std::string msg)105 explicit ParquetException(std::string msg) : msg_(std::move(msg)) {}
106
ParquetException(const char * msg,const std::exception &)107 explicit ParquetException(const char* msg, const std::exception&) : msg_(msg) {}
108
109 ParquetException(const ParquetException&) = default;
110 ParquetException& operator=(const ParquetException&) = default;
111 ParquetException(ParquetException&&) = default;
112 ParquetException& operator=(ParquetException&&) = default;
113
what()114 const char* what() const noexcept override { return msg_.c_str(); }
115
116 private:
117 std::string msg_;
118 };
119
120 // Support printing a ParquetException.
121 // This is needed for clang-on-MSVC as there operator<< is not defined for
122 // std::exception.
123 PARQUET_EXPORT
124 std::ostream& operator<<(std::ostream& os, const ParquetException& exception);
125
126 class ParquetStatusException : public ParquetException {
127 public:
ParquetStatusException(::arrow::Status status)128 explicit ParquetStatusException(::arrow::Status status)
129 : ParquetException(status.ToString()), status_(std::move(status)) {}
130
status()131 const ::arrow::Status& status() const { return status_; }
132
133 private:
134 ::arrow::Status status_;
135 };
136
137 // This class exists for the purpose of detecting an invalid or corrupted file.
138 class ParquetInvalidOrCorruptedFileException : public ParquetStatusException {
139 public:
140 ParquetInvalidOrCorruptedFileException(const ParquetInvalidOrCorruptedFileException&) =
141 default;
142
143 template <typename Arg,
144 typename std::enable_if<
145 !std::is_base_of<ParquetInvalidOrCorruptedFileException, Arg>::value,
146 int>::type = 0,
147 typename... Args>
ParquetInvalidOrCorruptedFileException(Arg arg,Args &&...args)148 explicit ParquetInvalidOrCorruptedFileException(Arg arg, Args&&... args)
149 : ParquetStatusException(::arrow::Status::Invalid(std::forward<Arg>(arg),
150 std::forward<Args>(args)...)) {}
151 };
152
153 template <typename StatusReturnBlock>
ThrowNotOk(StatusReturnBlock && b)154 void ThrowNotOk(StatusReturnBlock&& b) {
155 PARQUET_THROW_NOT_OK(b());
156 }
157
158 } // namespace parquet
159