Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a bunch of throw statements to use Realm exceptions #7141

Merged
merged 9 commits into from
Nov 27, 2023
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

### Fixed
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
* None.
* Update existing std exceptions thrown by the Sync Client to use Realm exceptions. ([#6255](https://github.com/realm/realm-core/issues/6255), since v10.2.0)

### Breaking changes
* None.
* Update existing std exceptions thrown by the Sync Client to use Realm exceptions. ([PR #7141](https://github.com/realm/realm-core/pull/7141/files))

### Compatibility
* Fileformat: Generates files with format v23. Reads and automatically upgrade from fileformat v5.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ static void error(emscripten_fetch_t* fetch)
emscripten_fetch_get_response_headers(fetch, packed_headers.data(), packed_headers.size());

std::unique_ptr<FetchState> state(reinterpret_cast<FetchState*>(fetch->userData));
state->completion_block({fetch->status, 0, parse_headers(packed_headers), std::string(fetch->data, size_t(fetch->numBytes)), ErrorCodes::HTTPError});
state->completion_block({fetch->status, 0, parse_headers(packed_headers),
std::string(fetch->data, size_t(fetch->numBytes)), ErrorCodes::HTTPError});
}

void EmscriptenNetworkTransport::send_request_to_server(
Expand Down
23 changes: 14 additions & 9 deletions src/realm/object-store/sync/impl/sync_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ uint8_t value_of_hex_digit(char hex_digit)
return 10 + hex_digit - 'a';
}
else {
throw std::invalid_argument("Cannot get the value of a character that isn't a hex digit.");
throw LogicError(ErrorCodes::InvalidArgument, "Cannot get the value of a character that isn't a hex digit.");
}
}

Expand All @@ -82,7 +82,8 @@ bool character_is_unreserved(char character)
char decoded_char_for(const std::string& percent_encoding, size_t index)
{
if (index + 2 >= percent_encoding.length()) {
throw std::invalid_argument("Malformed string: not enough characters after '%' before end of string.");
throw LogicError(ErrorCodes::InvalidArgument,
"Malformed string: not enough characters after '%' before end of string.");
}
REALM_ASSERT(percent_encoding[index] == '%');
return (16 * value_of_hex_digit(percent_encoding[index + 1])) + value_of_hex_digit(percent_encoding[index + 2]);
Expand Down Expand Up @@ -126,7 +127,8 @@ std::string make_raw_string(const std::string& percent_encoded_string)
else {
// No need to decode. +1.
if (!character_is_unreserved(current)) {
throw std::invalid_argument("Input string is invalid: contains reserved characters.");
throw LogicError(ErrorCodes::InvalidArgument,
"Input string is invalid: contains reserved characters.");
}
buffer.push_back(current);
idx++;
Expand Down Expand Up @@ -207,7 +209,9 @@ std::string reserve_unique_file_name(const std::string& path, const std::string&
int fd = mkstemp(&path_buffer[0]);
if (fd < 0) {
int err = errno;
throw std::system_error(err, std::system_category());
throw RuntimeError(ErrorCodes::FileOperationFailed,
util::format("Failed to make temporary path: %1 (%2)",
std::system_error(err, std::system_category()).what(), err));
}
// Remove the file so we can use the name for our own file.
#ifdef _WIN32
Expand All @@ -225,7 +229,8 @@ static std::string validate_and_clean_path(const std::string& path)
REALM_ASSERT(path.length() > 0);
std::string escaped_path = util::make_percent_encoded_string(path);
if (filename_is_reserved(escaped_path))
throw std::invalid_argument(
throw LogicError(
ErrorCodes::InvalidArgument,
util::format("A path can't have an identifier reserved by the filesystem: '%1'", escaped_path));
return escaped_path;
}
Expand Down Expand Up @@ -419,10 +424,10 @@ std::string SyncFileManager::realm_file_path(const std::string& user_identity,
}
catch (const FileAccessError& e_hashed) {
// hashed test path also failed, give up and report error to user.
throw std::logic_error(util::format("A valid realm path cannot be created for the "
"Realm identity '%1' at neither '%2' nor '%3'. %4",
realm_file_name, preferred_name_with_suffix, hashed_path,
e_hashed.what()));
throw LogicError(ErrorCodes::InvalidArgument,
util::format("A valid realm path cannot be created for the "
"Realm identity '%1' at neither '%2' nor '%3'. %4",
realm_file_name, preferred_name_with_suffix, hashed_path, e_hashed.what()));
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/realm/object-store/sync/sync_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <realm/util/sha_crypto.hpp>
#include <realm/util/hex_dump.hpp>

#include <realm/exceptions.hpp>

using namespace realm;
using namespace realm::_impl;

Expand Down Expand Up @@ -275,7 +277,8 @@ void SyncManager::set_logger_factory(SyncClientConfig::LoggerFactory factory)
m_config.logger_factory = std::move(factory);

if (m_sync_client)
throw std::logic_error("Cannot set the logger factory after creating the sync client");
throw LogicError(ErrorCodes::IllegalOperation,
"Cannot set the logger factory after creating the sync client");

// Create a new logger using the new factory
do_make_logger();
Expand Down Expand Up @@ -723,7 +726,8 @@ void SyncManager::set_session_multiplexing(bool allowed)
return; // Already enabled, we can ignore

if (m_sync_client)
throw std::logic_error("Cannot enable session multiplexing after creating the sync client");
throw LogicError(ErrorCodes::IllegalOperation,
"Cannot enable session multiplexing after creating the sync client");

m_config.multiplex_sessions = allowed;
}
Expand Down
4 changes: 2 additions & 2 deletions src/realm/sync/noinst/client_reset_recovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ InternDictKey InterningBuffer::get_interned_key(const std::string_view& str) con
return key;
}
}
throw std::runtime_error(
util::format("InterningBuffer::get_interned_key(%1) did not contain the requested key", str));
throw RuntimeError(ErrorCodes::InvalidArgument,
util::format("InterningBuffer::get_interned_key(%1) did not contain the requested key", str));
return {};
}

Expand Down
5 changes: 3 additions & 2 deletions src/realm/sync/noinst/migration_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ bool MigrationStore::load_data(bool read_only)
// Load the metadata schema unless it was just created
if (!m_migration_table) {
if (*schema_version != c_schema_version) {
throw std::runtime_error("Invalid schema version for flexible sync migration store metadata");
throw RuntimeError(ErrorCodes::UnsupportedFileFormatVersion,
"Invalid schema version for flexible sync migration store metadata");
}
load_sync_metadata_schema(tr, &internal_tables);
}
Expand Down Expand Up @@ -381,4 +382,4 @@ std::optional<int64_t> MigrationStore::get_sentinel_subscription_set_version()
return m_sentinel_subscription_set_version;
}

} // namespace realm::sync
} // namespace realm::sync
65 changes: 39 additions & 26 deletions src/realm/sync/noinst/sync_metadata_schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ void create_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetad
util::FlatMap<std::string_view, TableRef> found_tables;
for (auto& table : *tables) {
if (tr->has_table(table.name)) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("table %1 already existed when creating internal tables for sync", table.name));
}
TableRef table_ref;
Expand All @@ -64,18 +65,18 @@ void create_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetad
if (column.data_type == type_LinkList) {
auto target_table_it = found_tables.find(column.target_table);
if (target_table_it == found_tables.end()) {
throw std::runtime_error(
util::format("cannot link to non-existant table %1 from internal sync table %2",
column.target_table, table.name));
throw LogicError(ErrorCodes::InvalidArgument,
util::format("cannot link to non-existant table %1 from internal sync table %2",
column.target_table, table.name));
}
*column.key_out = table_ref->add_column_list(*target_table_it->second, column.name);
}
else if (column.data_type == type_Link) {
auto target_table_it = found_tables.find(column.target_table);
if (target_table_it == found_tables.end()) {
throw std::runtime_error(
util::format("cannot link to non-existant table %1 from internal sync table %2",
column.target_table, table.name));
throw LogicError(ErrorCodes::InvalidArgument,
util::format("cannot link to non-existant table %1 from internal sync table %2",
column.target_table, table.name));
}
*column.key_out = table_ref->add_column(*target_table_it->second, column.name);
}
Expand All @@ -91,63 +92,75 @@ void load_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetadat
for (auto& table : *tables) {
auto table_ref = tr->get_table(table.name);
if (!table_ref) {
throw std::runtime_error(util::format("could not find internal sync table %1", table.name));
throw RuntimeError(ErrorCodes::RuntimeError,
util::format("could not find internal sync table %1", table.name));
}

*table.key_out = table_ref->get_key();
if (table.pk_info) {
auto pk_col = table_ref->get_primary_key_column();
if (auto pk_name = table_ref->get_column_name(pk_col); pk_name != table.pk_info->name) {
throw std::runtime_error(util::format(
"primary key name of sync internal table %1 does not match (stored: %2, defined: %3)", table.name,
pk_name, table.pk_info->name));
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format(
"primary key name of sync internal table %1 does not match (stored: %2, defined: %3)",
table.name, pk_name, table.pk_info->name));
}
if (auto pk_type = table_ref->get_column_type(pk_col); pk_type != table.pk_info->data_type) {
throw std::runtime_error(util::format(
"primary key type of sync internal table %1 does not match (stored: %2, defined: %3)", table.name,
pk_type, table.pk_info->data_type));
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format(
"primary key type of sync internal table %1 does not match (stored: %2, defined: %3)",
table.name, pk_type, table.pk_info->data_type));
}
if (auto is_nullable = table_ref->is_nullable(pk_col); is_nullable != table.pk_info->is_optional) {
throw std::runtime_error(util::format(
"primary key nullabilty of sync internal table %1 does not match (stored: %2, defined: %3)",
table.name, is_nullable, table.pk_info->is_optional));
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format(
"primary key nullabilty of sync internal table %1 does not match (stored: %2, defined: %3)",
table.name, is_nullable, table.pk_info->is_optional));
}
*table.pk_info->key_out = pk_col;
}
else if (table.is_embedded && !table_ref->is_embedded()) {
throw std::runtime_error(
util::format("internal sync table %1 should be embedded, but is not", table.name));
throw RuntimeError(ErrorCodes::RuntimeError,
util::format("internal sync table %1 should be embedded, but is not", table.name));
}

if (table.columns.size() + size_t(table.pk_info ? 1 : 0) != table_ref->get_column_count()) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("sync internal table %1 has a different number of columns than its schema", table.name));
}

for (auto& col : table.columns) {
auto col_key = table_ref->get_column_key(col.name);
if (!col_key) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("column %1 is missing in sync internal table %2", col.name, table.name));
}

auto found_col_type = table_ref->get_column_type(col_key);
if (found_col_type != col.data_type) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("column %1 in sync internal table %2 is the wrong type", col.name, table.name));
}

if (col.is_optional != table_ref->is_nullable(col_key)) {
throw std::runtime_error(
throw RuntimeError(
ErrorCodes::RuntimeError,
util::format("column %1 in sync internal table %2 has different nullabilty than in its schema",
col.name, table.name));
}

if (col.data_type == type_LinkList &&
table_ref->get_link_target(col_key)->get_name() != col.target_table) {
throw std::runtime_error(
util::format("column %1 in sync internal table %2 links to the wrong table %3", col.name,
table.name, table_ref->get_link_target(col_key)->get_name()));
throw RuntimeError(ErrorCodes::RuntimeError,
util::format("column %1 in sync internal table %2 links to the wrong table %3",
col.name, table.name,
table_ref->get_link_target(col_key)->get_name()));
}
*col.key_out = col_key;
}
Expand Down
26 changes: 15 additions & 11 deletions src/realm/sync/subscriptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ SubscriptionSet::State state_from_storage(int64_t value)
case SubscriptionStateForStorage::Error:
return SubscriptionSet::State::Error;
default:
throw std::runtime_error(util::format("Invalid state for SubscriptionSet stored on disk: %1", value));
throw RuntimeError(ErrorCodes::InvalidArgument,
util::format("Invalid state for SubscriptionSet stored on disk: %1", value));
}
}

Expand Down Expand Up @@ -206,7 +207,7 @@ std::shared_ptr<const SubscriptionStore> SubscriptionSet::get_flx_subscription_s
if (auto mgr = m_mgr.lock()) {
return mgr;
}
throw std::logic_error("Active SubscriptionSet without a SubscriptionStore");
throw RuntimeError(ErrorCodes::BrokenInvariant, "Active SubscriptionSet without a SubscriptionStore");
}

int64_t SubscriptionSet::version() const
Expand Down Expand Up @@ -420,19 +421,21 @@ void MutableSubscriptionSet::update_state(State new_state, util::Optional<std::s
check_is_mutable();
auto old_state = state();
if (error_str && new_state != State::Error) {
throw std::logic_error("Cannot supply an error message for a subscription set when state is not Error");
throw LogicError(ErrorCodes::InvalidArgument,
"Cannot supply an error message for a subscription set when state is not Error");
}
switch (new_state) {
case State::Uncommitted:
throw std::logic_error("cannot set subscription set state to uncommitted");
throw LogicError(ErrorCodes::InvalidArgument, "cannot set subscription set state to uncommitted");

case State::Error:
if (old_state != State::Bootstrapping && old_state != State::Pending && old_state != State::Uncommitted) {
throw std::logic_error(
"subscription set must be in Bootstrapping or Pending to update state to error");
throw LogicError(ErrorCodes::InvalidArgument,
"subscription set must be in Bootstrapping or Pending to update state to error");
}
if (!error_str) {
throw std::logic_error("Must supply an error message when setting a subscription to the error state");
throw LogicError(ErrorCodes::InvalidArgument,
"Must supply an error message when setting a subscription to the error state");
}

m_state = new_state;
Expand All @@ -450,9 +453,9 @@ void MutableSubscriptionSet::update_state(State new_state, util::Optional<std::s
break;
}
case State::Superseded:
throw std::logic_error("Cannot set a subscription to the superseded state");
throw LogicError(ErrorCodes::InvalidArgument, "Cannot set a subscription to the superseded state");
case State::Pending:
throw std::logic_error("Cannot set subscription set to the pending state");
throw LogicError(ErrorCodes::InvalidArgument, "Cannot set subscription set to the pending state");
}
}

Expand Down Expand Up @@ -554,7 +557,7 @@ void MutableSubscriptionSet::process_notifications()
SubscriptionSet MutableSubscriptionSet::commit()
{
if (m_tr->get_transact_stage() != DB::transact_Writing) {
throw std::logic_error("SubscriptionSet is not in a commitable state");
throw RuntimeError(ErrorCodes::WrongTransactionState, "SubscriptionSet is not in a commitable state");
}
auto mgr = get_flx_subscription_store(); // Throws

Expand Down Expand Up @@ -690,7 +693,8 @@ SubscriptionStore::SubscriptionStore(DBRef db)
}
else {
if (*schema_version != c_flx_schema_version) {
throw std::runtime_error("Invalid schema version for flexible sync metadata");
throw RuntimeError(ErrorCodes::UnsupportedFileFormatVersion,
"Invalid schema version for flexible sync metadata");
}
load_sync_metadata_schema(tr, &internal_tables);
}
Expand Down
2 changes: 1 addition & 1 deletion test/test_sync_subscriptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ TEST(Sync_SubscriptionStoreRefreshSubscriptionSetInvalid)
store.reset();

// Throws since the SubscriptionStore is gone.
CHECK_THROW(latest->refresh(), std::logic_error);
CHECK_THROW(latest->refresh(), RuntimeError);
}

TEST(Sync_SubscriptionStoreInternalSchemaMigration)
Expand Down