• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / github_pull_request_281750

30 Oct 2023 03:37PM UTC coverage: 90.528% (-1.0%) from 91.571%
github_pull_request_281750

Pull #6073

Evergreen

jedelbo
Log free space and history sizes when opening file
Pull Request #6073: Merge next-major

95488 of 175952 branches covered (0.0%)

8973 of 12277 new or added lines in 149 files covered. (73.09%)

622 existing lines in 51 files now uncovered.

233503 of 257934 relevant lines covered (90.53%)

6533720.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.29
/src/realm/exceptions.hpp
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

19
#ifndef REALM_EXCEPTIONS_HPP
20
#define REALM_EXCEPTIONS_HPP
21

22
#include <realm/status.hpp>
23

24
#include <stdexcept>
25
#include <system_error>
26

27
namespace realm {
28

29
class Exception : public std::exception {
30
public:
31
    Exception(ErrorCodes::Error err, std::string_view str);
32
    explicit Exception(Status status);
33

34
    const char* what() const noexcept final;
35
    const Status& to_status() const;
36
    std::string_view reason() const noexcept;
37
    ErrorCodes::Error code() const noexcept;
38
    ErrorCategory category() const noexcept;
39
    std::string_view code_string() const noexcept;
40

41
private:
42
    Status m_status;
43
};
44

45
/*
46
 * This will convert an exception in a catch(...) block into a Status. For `Exception`s, it returns the
47
 * status held in the exception directly. Otherwise it returns a status with an UnknownError error code and a
48
 * reason string holding the exception type and message.
49
 *
50
 * Currently this works for exceptions that derive from std::exception or Exception only.
51
 */
52
Status exception_to_status() noexcept;
53

54

55
/// The UnsupportedFileFormatVersion exception is thrown by DB::open()
56
/// constructor when opening a database that uses a deprecated file format
57
/// and/or a deprecated history schema which this version of Realm cannot
58
/// upgrade from.
59
struct UnsupportedFileFormatVersion : Exception {
60
    UnsupportedFileFormatVersion(int version);
61
    ~UnsupportedFileFormatVersion() noexcept override;
62
    /// The unsupported version of the file.
63
    int source_version = 0;
64
};
65

66

67
/// Thrown when a key is already existing when trying to create a new object
68
struct KeyAlreadyUsed : Exception {
69
    KeyAlreadyUsed(std::string_view msg)
70
        : Exception(ErrorCodes::KeyAlreadyUsed, msg)
71
    {
18✔
72
    }
18✔
73
    ~KeyAlreadyUsed() noexcept override;
74
};
75

76
/// The \c LogicError exception class is intended to be thrown only when
77
/// applications (or bindings) violate rules that are stated (or ought to have
78
/// been stated) in the documentation of the public API, and only in cases
79
/// where the violation could have been easily and efficiently predicted by the
80
/// application. In other words, this exception class is for the cases where
81
/// the error is due to incorrect use of the public API.
82
///
83
/// This class is not supposed to be caught by applications. It is not even
84
/// supposed to be considered part of the public API, and therefore the
85
/// documentation of the public API should **not** mention the \c LogicError
86
/// exception class by name. Note how this contrasts with other exception
87
/// classes, such as \c NoSuchTable, which are part of the public API, and are
88
/// supposed to be mentioned in the documentation by name. The \c LogicError
89
/// exception is part of Realm's private API.
90
///
91
/// In other words, the \c LogicError class should exclusively be used in
92
/// replacement (or in addition to) asserts (debug or not) in order to
93
/// guarantee program interruption, while still allowing for complete
94
/// test-cases to be written and run.
95
///
96
/// To this effect, the special `CHECK_LOGIC_ERROR()` macro is provided as a
97
/// test framework plugin to allow unit tests to check that the functions in
98
/// the public API do throw \c LogicError when rules are violated.
99
///
100
/// The reason behind hiding this class from the public API is to prevent users
101
/// from getting used to the idea that "Undefined Behaviour" equates a specific
102
/// exception being thrown. The whole point of properly documenting "Undefined
103
/// Behaviour" cases is to help the user know what the limits are, without
104
/// constraining the database to handle every and any use-case thrown at it.
105
struct LogicError : Exception {
106
    LogicError(ErrorCodes::Error code, std::string_view msg);
107
    ~LogicError() noexcept override;
108
};
109

110
struct RuntimeError : Exception {
111
    RuntimeError(ErrorCodes::Error code, std::string_view msg);
112
    RuntimeError(Status&& status);
113
    ~RuntimeError() noexcept override;
114
};
115

116
/// Thrown when creating references that are too large to be contained in our ref_type (size_t)
117
struct MaximumFileSizeExceeded : RuntimeError {
118
    MaximumFileSizeExceeded(std::string_view msg)
119
        : RuntimeError(ErrorCodes::MaximumFileSizeExceeded, msg)
120
    {
×
121
    }
×
122
    ~MaximumFileSizeExceeded() noexcept override;
123
};
124

125
/// Thrown when writing fails because the disk is full.
126
struct OutOfDiskSpace : RuntimeError {
127
    OutOfDiskSpace(std::string_view msg)
128
        : RuntimeError(ErrorCodes::OutOfDiskSpace, msg)
129
    {
×
130
    }
×
131
    ~OutOfDiskSpace() noexcept override;
132
};
133

134
/// Thrown when a sync agent attempts to join a session in which there is
135
/// already a sync agent. A session may only contain one sync agent at any given
136
/// time.
137
struct MultipleSyncAgents : RuntimeError {
138
    MultipleSyncAgents()
139
        : RuntimeError(ErrorCodes::MultipleSyncAgents, "Multiple sync agents attempted to join the same session")
140
    {
18✔
141
    }
18✔
142
    ~MultipleSyncAgents() noexcept override;
143
};
144

145

146
/// Thrown when memory can no longer be mapped to. When mmap/remap fails.
147
struct AddressSpaceExhausted : RuntimeError {
148
    AddressSpaceExhausted(std::string_view msg)
149
        : RuntimeError(ErrorCodes::AddressSpaceExhausted, msg)
150
    {
×
151
    }
×
152
    ~AddressSpaceExhausted() noexcept override;
153
};
154

155
struct InvalidArgument : LogicError {
156
    InvalidArgument(std::string_view msg);
157
    InvalidArgument(ErrorCodes::Error code, std::string_view msg);
158
    ~InvalidArgument() noexcept override;
159
};
160

161
struct InvalidColumnKey : InvalidArgument {
162
    template <class T>
163
    InvalidColumnKey(const T& name)
164
        : InvalidArgument(ErrorCodes::InvalidProperty, util::format("Invalid property for object type: %1", name))
165
    {
14✔
166
    }
14✔
167
    InvalidColumnKey()
168
        : InvalidArgument(ErrorCodes::InvalidProperty, "Invalid column key")
169
    {
330✔
170
    }
330✔
171
    ~InvalidColumnKey() noexcept override;
172
};
173

174
/// Thrown by various functions to indicate that a specified table does not
175
/// exist.
176
struct NoSuchTable : InvalidArgument {
177
    NoSuchTable()
178
        : InvalidArgument(ErrorCodes::NoSuchTable, "No such table exists")
179
    {
54✔
180
    }
54✔
181
    ~NoSuchTable() noexcept override;
182
};
183

184
/// Thrown by various functions to indicate that a specified table name is
185
/// already in use.
186
struct TableNameInUse : InvalidArgument {
187
    TableNameInUse()
188
        : InvalidArgument(ErrorCodes::TableNameInUse, "The specified table name is already in use")
189
    {
12✔
190
    }
12✔
191
    ~TableNameInUse() noexcept override;
192
};
193

194

195
/// Thrown when a key can not by found
196
struct KeyNotFound : InvalidArgument {
197
    KeyNotFound(std::string_view msg)
198
        : InvalidArgument(ErrorCodes::KeyNotFound, msg)
199
    {
870✔
200
    }
870✔
201
    ~KeyNotFound() noexcept override;
202
};
203

204

205
struct NotNullable : InvalidArgument {
206
    NotNullable(std::string_view msg)
207
        : InvalidArgument(ErrorCodes::PropertyNotNullable, msg)
208
    {
78✔
209
    }
78✔
210
    template <class T, class U>
211
    NotNullable(const T& object_type, const U& property_name)
212
        : NotNullable(
213
              util::format("Invalid null value for non-nullable property '%1.%2'.", object_type, property_name))
214
    {
74✔
215
    }
74✔
216
    ~NotNullable() noexcept override;
217
};
218

219
struct PropertyTypeMismatch : InvalidArgument {
220
    template <class T, class U>
221
    PropertyTypeMismatch(const T& object_type, const U& property_name)
222
        : InvalidArgument(ErrorCodes::TypeMismatch,
223
                          util::format("Type mismatch for property '%1.%2'.", object_type, property_name))
224
    {
20✔
225
    }
20✔
226
    ~PropertyTypeMismatch() noexcept override;
227
};
228

229
struct OutOfBounds : InvalidArgument {
230
    OutOfBounds(std::string_view msg, size_t idx, size_t sz);
231
    ~OutOfBounds() noexcept override;
232
    size_t index;
233
    size_t size;
234
};
235

236
struct InvalidEncryptionKey : InvalidArgument {
237
    InvalidEncryptionKey()
238
        : InvalidArgument(ErrorCodes::InvalidEncryptionKey, "Encryption key must be 64 bytes.")
239
    {
4✔
240
    }
4✔
241
    ~InvalidEncryptionKey() noexcept override;
242
};
243

244
struct StaleAccessor : LogicError {
245
    StaleAccessor(std::string_view msg)
246
        : LogicError(ErrorCodes::StaleAccessor, msg)
247
    {
204✔
248
    }
204✔
249
    ~StaleAccessor() noexcept override;
250
};
251

252
struct IllegalOperation : LogicError {
253
    IllegalOperation(std::string_view msg)
254
        : LogicError(ErrorCodes::IllegalOperation, msg)
255
    {
4,422✔
256
    }
4,422✔
257
    ~IllegalOperation() noexcept override;
258
};
259

260
struct NoSubscriptionForWrite : RuntimeError {
261
    NoSubscriptionForWrite(std::string_view msg)
262
        : RuntimeError(ErrorCodes::NoSubscriptionForWrite, msg)
263
    {
2✔
264
    }
2✔
265
    ~NoSubscriptionForWrite() noexcept override;
266
};
267

268

269
struct WrongTransactionState : LogicError {
270
    WrongTransactionState(std::string_view msg)
271
        : LogicError(ErrorCodes::WrongTransactionState, msg)
272
    {
1,026✔
273
    }
1,026✔
274
    ~WrongTransactionState() noexcept override;
275
};
276

277
struct InvalidTableRef : LogicError {
278
    InvalidTableRef(const char* cause)
279
        : LogicError(ErrorCodes::InvalidTableRef, cause)
280
    {
42✔
281
    }
42✔
282
    ~InvalidTableRef() noexcept override;
283
};
284

285
struct SerializationError : LogicError {
286
    SerializationError(std::string_view msg)
287
        : LogicError(ErrorCodes::SerializationError, msg)
UNCOV
288
    {
×
UNCOV
289
    }
×
290
    ~SerializationError() noexcept override;
291
};
292

293
struct NotImplemented : LogicError {
294
    NotImplemented()
295
        : LogicError(ErrorCodes::IllegalOperation, "Not implemented")
296
    {
×
297
    }
×
298
    ~NotImplemented() noexcept override;
299
};
300

301
struct MigrationFailed : LogicError {
302
    MigrationFailed(std::string_view msg)
303
        : LogicError(ErrorCodes::MigrationFailed, msg)
304
    {
30✔
305
    }
30✔
306
    ~MigrationFailed() noexcept override;
307
};
308

309
struct ObjectAlreadyExists : RuntimeError {
310
    template <class T, class U>
311
    ObjectAlreadyExists(const U& object_type, T pk_val)
312
        : RuntimeError(
313
              ErrorCodes::ObjectAlreadyExists,
314
              util::format("Attempting to create an object of type '%1' with an existing primary key value '%2'",
315
                           object_type, pk_val))
316
    {
16✔
317
    }
16✔
318
    ~ObjectAlreadyExists() noexcept override;
319
};
320

321
// Thrown by functions that require a table to **not** be the target of link
322
// columns, unless those link columns are part of the table itself.
323
struct CrossTableLinkTarget : LogicError {
324
    template <class T>
325
    CrossTableLinkTarget(T table_name)
326
        : LogicError(ErrorCodes::CrossTableLinkTarget,
327
                     util::format("Cannot remove %1 that is target of outside links", table_name))
328
    {
24✔
329
    }
24✔
330
    ~CrossTableLinkTarget() noexcept override;
331
};
332

333

334
/// Used for any I/O related exception. Note the derived exception
335
/// types that are used for various specific types of errors.
336
class FileAccessError : public RuntimeError {
337
public:
338
    FileAccessError(ErrorCodes::Error code, std::string_view msg, std::string_view path, int err = 0);
339
    ~FileAccessError() noexcept override;
340

341
    /// Return the associated file system path, or the empty string if there is
342
    /// no associated file system path, or if the file system path is unknown.
343
    std::string_view get_path() const
344
    {
66✔
345
        return m_path;
66✔
346
    }
66✔
347
    int get_errno() const
348
    {
72✔
349
        return m_errno;
72✔
350
    }
72✔
351

352
private:
353
    std::string m_path;
354
    int m_errno = 0;
355
};
356

357
struct SystemError : RuntimeError {
358
    SystemError(std::error_code err, std::string_view msg)
359
        : RuntimeError(make_status(err, msg, false))
360
    {
2✔
361
    }
2✔
362

363
    SystemError(int err_no, std::string_view msg)
364
        : RuntimeError(make_status(std::error_code(err_no, std::generic_category()), msg, true))
365
    {
30✔
366
    }
30✔
367

368
    ~SystemError() noexcept override;
369

370
private:
371
    static Status make_status(std::error_code err, std::string_view msg, bool msg_is_prefix)
372
    {
36✔
373
        return Status(ErrorCodes::SystemError,
36✔
374
                      msg_is_prefix ? util::format("%1: %2 (%3)", msg, err.message(), err.value()) : msg);
33✔
375
    }
36✔
376
};
377

378
namespace query_parser {
379

380
/// Exception thrown when parsing fails due to invalid syntax.
381
struct SyntaxError : InvalidArgument {
382
    SyntaxError(std::string_view msg)
383
        : InvalidArgument(ErrorCodes::SyntaxError, msg)
384
    {
744✔
385
    }
744✔
386
    ~SyntaxError() noexcept override;
387
};
388

389
/// Exception thrown when binding a syntactically valid query string in a
390
/// context where it does not make sense.
391
struct InvalidQueryError : InvalidArgument {
392
    InvalidQueryError(std::string_view msg)
393
        : InvalidArgument(ErrorCodes::InvalidQuery, msg)
394
    {
2,010✔
395
    }
2,010✔
396
    ~InvalidQueryError() noexcept override;
397
};
398

399
/// Exception thrown when there is a problem accessing the arguments in a query string
400
struct InvalidQueryArgError : InvalidArgument {
401
    InvalidQueryArgError(std::string_view msg)
402
        : InvalidArgument(ErrorCodes::InvalidQueryArg, msg)
403
    {
114✔
404
    }
114✔
405
    ~InvalidQueryArgError() noexcept override;
406
};
407

408
} // namespace query_parser
409
} // namespace realm
410

411
#endif // REALM_EXCEPTIONS_HPP
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc