exceptions.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*************************************************************************
  2. *
  3. * Copyright 2016 Realm Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * 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, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_EXCEPTIONS_HPP
  19. #define REALM_EXCEPTIONS_HPP
  20. #include <realm/status.hpp>
  21. #include <stdexcept>
  22. #include <system_error>
  23. namespace realm {
  24. class Exception : public std::exception {
  25. public:
  26. Exception(ErrorCodes::Error err, std::string_view str);
  27. explicit Exception(Status status);
  28. const char* what() const noexcept final;
  29. const Status& to_status() const;
  30. std::string_view reason() const noexcept;
  31. ErrorCodes::Error code() const noexcept;
  32. ErrorCategory category() const noexcept;
  33. std::string_view code_string() const noexcept;
  34. private:
  35. Status m_status;
  36. };
  37. /*
  38. * This will convert an exception in a catch(...) block into a Status. For `Exception`s, it returns the
  39. * status held in the exception directly. Otherwise it returns a status with an UnknownError error code and a
  40. * reason string holding the exception type and message.
  41. *
  42. * Currently this works for exceptions that derive from std::exception or Exception only.
  43. */
  44. Status exception_to_status() noexcept;
  45. /// The UnsupportedFileFormatVersion exception is thrown by DB::open()
  46. /// constructor when opening a database that uses a deprecated file format
  47. /// and/or a deprecated history schema which this version of Realm cannot
  48. /// upgrade from.
  49. struct UnsupportedFileFormatVersion : Exception {
  50. UnsupportedFileFormatVersion(int version);
  51. ~UnsupportedFileFormatVersion() noexcept override;
  52. /// The unsupported version of the file.
  53. int source_version = 0;
  54. };
  55. /// Thrown when a key is already existing when trying to create a new object
  56. struct KeyAlreadyUsed : Exception {
  57. KeyAlreadyUsed(std::string_view msg)
  58. : Exception(ErrorCodes::KeyAlreadyUsed, msg)
  59. {
  60. }
  61. ~KeyAlreadyUsed() noexcept override;
  62. };
  63. /// The \c LogicError exception class is intended to be thrown only when
  64. /// applications (or bindings) violate rules that are stated (or ought to have
  65. /// been stated) in the documentation of the public API, and only in cases
  66. /// where the violation could have been easily and efficiently predicted by the
  67. /// application. In other words, this exception class is for the cases where
  68. /// the error is due to incorrect use of the public API.
  69. ///
  70. /// This class is not supposed to be caught by applications. It is not even
  71. /// supposed to be considered part of the public API, and therefore the
  72. /// documentation of the public API should **not** mention the \c LogicError
  73. /// exception class by name. Note how this contrasts with other exception
  74. /// classes, such as \c NoSuchTable, which are part of the public API, and are
  75. /// supposed to be mentioned in the documentation by name. The \c LogicError
  76. /// exception is part of Realm's private API.
  77. ///
  78. /// In other words, the \c LogicError class should exclusively be used in
  79. /// replacement (or in addition to) asserts (debug or not) in order to
  80. /// guarantee program interruption, while still allowing for complete
  81. /// test-cases to be written and run.
  82. ///
  83. /// To this effect, the special `CHECK_LOGIC_ERROR()` macro is provided as a
  84. /// test framework plugin to allow unit tests to check that the functions in
  85. /// the public API do throw \c LogicError when rules are violated.
  86. ///
  87. /// The reason behind hiding this class from the public API is to prevent users
  88. /// from getting used to the idea that "Undefined Behaviour" equates a specific
  89. /// exception being thrown. The whole point of properly documenting "Undefined
  90. /// Behaviour" cases is to help the user know what the limits are, without
  91. /// constraining the database to handle every and any use-case thrown at it.
  92. struct LogicError : Exception {
  93. LogicError(ErrorCodes::Error code, std::string_view msg);
  94. ~LogicError() noexcept override;
  95. };
  96. struct RuntimeError : Exception {
  97. RuntimeError(ErrorCodes::Error code, std::string_view msg);
  98. RuntimeError(Status&& status);
  99. ~RuntimeError() noexcept override;
  100. };
  101. /// Thrown when creating references that are too large to be contained in our ref_type (size_t)
  102. struct MaximumFileSizeExceeded : RuntimeError {
  103. MaximumFileSizeExceeded(std::string_view msg)
  104. : RuntimeError(ErrorCodes::MaximumFileSizeExceeded, msg)
  105. {
  106. }
  107. ~MaximumFileSizeExceeded() noexcept override;
  108. };
  109. /// Thrown when writing fails because the disk is full.
  110. struct OutOfDiskSpace : RuntimeError {
  111. OutOfDiskSpace(std::string_view msg)
  112. : RuntimeError(ErrorCodes::OutOfDiskSpace, msg)
  113. {
  114. }
  115. ~OutOfDiskSpace() noexcept override;
  116. };
  117. /// Thrown when a sync agent attempts to join a session in which there is
  118. /// already a sync agent. A session may only contain one sync agent at any given
  119. /// time.
  120. struct MultipleSyncAgents : RuntimeError {
  121. MultipleSyncAgents()
  122. : RuntimeError(ErrorCodes::MultipleSyncAgents, "Multiple sync agents attempted to join the same session")
  123. {
  124. }
  125. ~MultipleSyncAgents() noexcept override;
  126. };
  127. /// Thrown when memory can no longer be mapped to. When mmap/remap fails.
  128. struct AddressSpaceExhausted : RuntimeError {
  129. AddressSpaceExhausted(std::string_view msg)
  130. : RuntimeError(ErrorCodes::AddressSpaceExhausted, msg)
  131. {
  132. }
  133. ~AddressSpaceExhausted() noexcept override;
  134. };
  135. struct InvalidArgument : LogicError {
  136. InvalidArgument(std::string_view msg);
  137. InvalidArgument(ErrorCodes::Error code, std::string_view msg);
  138. ~InvalidArgument() noexcept override;
  139. };
  140. struct InvalidColumnKey : InvalidArgument {
  141. template <class T>
  142. InvalidColumnKey(const T& name)
  143. : InvalidArgument(ErrorCodes::InvalidProperty, util::format("Invalid property for object type %1", name))
  144. {
  145. }
  146. InvalidColumnKey()
  147. : InvalidArgument(ErrorCodes::InvalidProperty, "Invalid column key")
  148. {
  149. }
  150. ~InvalidColumnKey() noexcept override;
  151. };
  152. /// Thrown by various functions to indicate that a specified table does not
  153. /// exist.
  154. struct NoSuchTable : InvalidArgument {
  155. NoSuchTable()
  156. : InvalidArgument(ErrorCodes::NoSuchTable, "No such table exists")
  157. {
  158. }
  159. ~NoSuchTable() noexcept override;
  160. };
  161. /// Thrown by various functions to indicate that a specified table name is
  162. /// already in use.
  163. struct TableNameInUse : InvalidArgument {
  164. TableNameInUse()
  165. : InvalidArgument(ErrorCodes::TableNameInUse, "The specified table name is already in use")
  166. {
  167. }
  168. ~TableNameInUse() noexcept override;
  169. };
  170. /// Thrown when a key can not by found
  171. struct KeyNotFound : InvalidArgument {
  172. KeyNotFound(std::string_view msg)
  173. : InvalidArgument(ErrorCodes::KeyNotFound, msg)
  174. {
  175. }
  176. ~KeyNotFound() noexcept override;
  177. };
  178. struct NotNullable : InvalidArgument {
  179. NotNullable(std::string_view msg)
  180. : InvalidArgument(ErrorCodes::PropertyNotNullable, msg)
  181. {
  182. }
  183. template <class T, class U>
  184. NotNullable(const T& object_type, const U& property_name)
  185. : NotNullable(
  186. util::format("Invalid null value for non-nullable property '%1.%2'.", object_type, property_name))
  187. {
  188. }
  189. ~NotNullable() noexcept override;
  190. };
  191. struct PropertyTypeMismatch : InvalidArgument {
  192. template <class T, class U>
  193. PropertyTypeMismatch(const T& object_type, const U& property_name)
  194. : InvalidArgument(ErrorCodes::TypeMismatch,
  195. util::format("Type mismatch for property '%1.%2'.", object_type, property_name))
  196. {
  197. }
  198. ~PropertyTypeMismatch() noexcept override;
  199. };
  200. struct OutOfBounds : InvalidArgument {
  201. OutOfBounds(std::string_view msg, size_t idx, size_t sz);
  202. ~OutOfBounds() noexcept override;
  203. size_t index;
  204. size_t size;
  205. };
  206. struct InvalidEncryptionKey : InvalidArgument {
  207. InvalidEncryptionKey()
  208. : InvalidArgument(ErrorCodes::InvalidEncryptionKey, "Encryption key must be 64 bytes.")
  209. {
  210. }
  211. ~InvalidEncryptionKey() noexcept override;
  212. };
  213. struct StaleAccessor : LogicError {
  214. StaleAccessor(std::string_view msg)
  215. : LogicError(ErrorCodes::StaleAccessor, msg)
  216. {
  217. }
  218. ~StaleAccessor() noexcept override;
  219. };
  220. struct IllegalOperation : LogicError {
  221. IllegalOperation(std::string_view msg)
  222. : LogicError(ErrorCodes::IllegalOperation, msg)
  223. {
  224. }
  225. ~IllegalOperation() noexcept override;
  226. };
  227. struct NoSubscriptionForWrite : RuntimeError {
  228. NoSubscriptionForWrite(std::string_view msg)
  229. : RuntimeError(ErrorCodes::NoSubscriptionForWrite, msg)
  230. {
  231. }
  232. ~NoSubscriptionForWrite() noexcept override;
  233. };
  234. struct WrongTransactionState : LogicError {
  235. WrongTransactionState(std::string_view msg)
  236. : LogicError(ErrorCodes::WrongTransactionState, msg)
  237. {
  238. }
  239. ~WrongTransactionState() noexcept override;
  240. };
  241. struct InvalidTableRef : LogicError {
  242. InvalidTableRef(const char* cause)
  243. : LogicError(ErrorCodes::InvalidTableRef, cause)
  244. {
  245. }
  246. ~InvalidTableRef() noexcept override;
  247. };
  248. struct SerializationError : LogicError {
  249. SerializationError(std::string_view msg)
  250. : LogicError(ErrorCodes::SerializationError, msg)
  251. {
  252. }
  253. ~SerializationError() noexcept override;
  254. };
  255. struct NotImplemented : LogicError {
  256. NotImplemented()
  257. : LogicError(ErrorCodes::IllegalOperation, "Not implemented")
  258. {
  259. }
  260. ~NotImplemented() noexcept override;
  261. };
  262. struct MigrationFailed : LogicError {
  263. MigrationFailed(std::string_view msg)
  264. : LogicError(ErrorCodes::MigrationFailed, msg)
  265. {
  266. }
  267. ~MigrationFailed() noexcept override;
  268. };
  269. struct SyncSchemaMigrationFailed : LogicError {
  270. SyncSchemaMigrationFailed(std::string_view msg)
  271. : LogicError(ErrorCodes::SyncSchemaMigrationError, msg)
  272. {
  273. }
  274. ~SyncSchemaMigrationFailed() noexcept override;
  275. };
  276. struct ObjectAlreadyExists : RuntimeError {
  277. template <class T, class U>
  278. ObjectAlreadyExists(const U& object_type, T pk_val)
  279. : RuntimeError(
  280. ErrorCodes::ObjectAlreadyExists,
  281. util::format("Attempting to create an object of type '%1' with an existing primary key value '%2'",
  282. object_type, pk_val))
  283. {
  284. }
  285. ~ObjectAlreadyExists() noexcept override;
  286. };
  287. // Thrown by functions that require a table to **not** be the target of link
  288. // columns, unless those link columns are part of the table itself.
  289. struct CrossTableLinkTarget : LogicError {
  290. template <class T>
  291. CrossTableLinkTarget(T table_name)
  292. : LogicError(ErrorCodes::CrossTableLinkTarget,
  293. util::format("Cannot remove %1 that is target of outside links", table_name))
  294. {
  295. }
  296. ~CrossTableLinkTarget() noexcept override;
  297. };
  298. /// Used for any I/O related exception. Note the derived exception
  299. /// types that are used for various specific types of errors.
  300. class FileAccessError : public RuntimeError {
  301. public:
  302. FileAccessError(ErrorCodes::Error code, std::string_view msg, std::string_view path, int err = 0);
  303. ~FileAccessError() noexcept override;
  304. /// Return the associated file system path, or the empty string if there is
  305. /// no associated file system path, or if the file system path is unknown.
  306. std::string_view get_path() const
  307. {
  308. return m_path;
  309. }
  310. int get_errno() const
  311. {
  312. return m_errno;
  313. }
  314. private:
  315. std::string m_path;
  316. int m_errno = 0;
  317. };
  318. struct SystemError : RuntimeError {
  319. SystemError(std::error_code err, std::string_view msg)
  320. : RuntimeError(make_status(err, msg, false))
  321. {
  322. }
  323. SystemError(int err_no, std::string_view msg)
  324. : RuntimeError(make_status(std::error_code(err_no, std::generic_category()), msg, true))
  325. {
  326. }
  327. ~SystemError() noexcept override;
  328. private:
  329. static Status make_status(std::error_code err, std::string_view msg, bool msg_is_prefix)
  330. {
  331. return Status(ErrorCodes::SystemError,
  332. msg_is_prefix ? util::format("%1: %2 (%3)", msg, err.message(), err.value()) : msg);
  333. }
  334. };
  335. namespace query_parser {
  336. /// Exception thrown when parsing fails due to invalid syntax.
  337. struct SyntaxError : InvalidArgument {
  338. SyntaxError(std::string_view msg)
  339. : InvalidArgument(ErrorCodes::SyntaxError, msg)
  340. {
  341. }
  342. ~SyntaxError() noexcept override;
  343. };
  344. /// Exception thrown when binding a syntactically valid query string in a
  345. /// context where it does not make sense.
  346. struct InvalidQueryError : InvalidArgument {
  347. InvalidQueryError(std::string_view msg)
  348. : InvalidArgument(ErrorCodes::InvalidQuery, msg)
  349. {
  350. }
  351. ~InvalidQueryError() noexcept override;
  352. };
  353. /// Exception thrown when there is a problem accessing the arguments in a query string
  354. struct InvalidQueryArgError : InvalidArgument {
  355. InvalidQueryArgError(std::string_view msg)
  356. : InvalidArgument(ErrorCodes::InvalidQueryArg, msg)
  357. {
  358. }
  359. ~InvalidQueryArgError() noexcept override;
  360. };
  361. } // namespace query_parser
  362. namespace sync {
  363. // Exception thrown when the request/websocket URL is malformed
  364. class BadServerUrl : public Exception {
  365. public:
  366. BadServerUrl(std::string_view url)
  367. : Exception(ErrorCodes::BadServerUrl, util::format("Unable to parse server URL '%1'", url))
  368. {
  369. }
  370. };
  371. } // namespace sync
  372. } // namespace realm
  373. #endif // REALM_EXCEPTIONS_HPP