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