Handle allowed schema changes in the transaction log observer
This commit is contained in:
parent
5e71c4178e
commit
d5e00c9315
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#include "transact_log_handler.hpp"
|
#include "transact_log_handler.hpp"
|
||||||
|
|
||||||
#include "../binding_context.hpp"
|
#include "binding_context.hpp"
|
||||||
|
|
||||||
#include <realm/commit_log.hpp>
|
#include <realm/commit_log.hpp>
|
||||||
#include <realm/group_shared.hpp>
|
#include <realm/group_shared.hpp>
|
||||||
|
@ -41,6 +41,10 @@ class TransactLogHandler {
|
||||||
// Change information for the currently selected LinkList, if any
|
// Change information for the currently selected LinkList, if any
|
||||||
ColumnInfo* m_active_linklist = nullptr;
|
ColumnInfo* m_active_linklist = nullptr;
|
||||||
|
|
||||||
|
// Tables which were created during the transaction being processed, which
|
||||||
|
// can have columns inserted without a schema version bump
|
||||||
|
std::vector<size_t> m_new_tables;
|
||||||
|
|
||||||
// Get the change info for the given column, creating it if needed
|
// Get the change info for the given column, creating it if needed
|
||||||
static ColumnInfo& get_change(ObserverState& state, size_t i)
|
static ColumnInfo& get_change(ObserverState& state, size_t i)
|
||||||
{
|
{
|
||||||
|
@ -80,6 +84,21 @@ class TransactLogHandler {
|
||||||
m_observers.erase(m_observers.begin() + (o - &m_observers[0]));
|
m_observers.erase(m_observers.begin() + (o - &m_observers[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REALM_NORETURN
|
||||||
|
REALM_NOINLINE
|
||||||
|
void schema_error()
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Schema mismatch detected: another process has modified the Realm file's schema in an incompatible way");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool schema_error_unless_new_table()
|
||||||
|
{
|
||||||
|
if (std::find(begin(m_new_tables), end(m_new_tables), m_current_table) == end(m_new_tables)) {
|
||||||
|
schema_error();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
TransactLogHandler(BindingContext* binding_context, SharedGroup& sg, Func&& func)
|
TransactLogHandler(BindingContext* binding_context, SharedGroup& sg, Func&& func)
|
||||||
|
@ -111,21 +130,36 @@ public:
|
||||||
m_binding_context->will_change(m_observers, invalidated);
|
m_binding_context->will_change(m_observers, invalidated);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These would require having an observer before schema init
|
// Schema changes which don't involve a change in the schema version are
|
||||||
// Maybe do something here to throw an error when multiple processes have different schemas?
|
// allowed
|
||||||
bool insert_group_level_table(size_t, size_t, StringData) { return false; }
|
bool add_search_index(size_t) { return true; }
|
||||||
bool erase_group_level_table(size_t, size_t) { return false; }
|
bool remove_search_index(size_t) { return true; }
|
||||||
bool rename_group_level_table(size_t, StringData) { return false; }
|
|
||||||
bool insert_column(size_t, DataType, StringData, bool) { return false; }
|
// Creating entirely new tables without a schema version bump is allowed, so
|
||||||
bool insert_link_column(size_t, DataType, StringData, size_t, size_t) { return false; }
|
// we need to track if new columns are being added to a new table or an
|
||||||
bool erase_column(size_t) { return false; }
|
// existing one
|
||||||
bool erase_link_column(size_t, size_t, size_t) { return false; }
|
bool insert_group_level_table(size_t table_ndx, size_t, StringData)
|
||||||
bool rename_column(size_t, StringData) { return false; }
|
{
|
||||||
bool add_search_index(size_t) { return false; }
|
for (auto& observer : m_observers) {
|
||||||
bool remove_search_index(size_t) { return false; }
|
if (observer.table_ndx >= table_ndx)
|
||||||
bool add_primary_key(size_t) { return false; }
|
++observer.table_ndx;
|
||||||
bool remove_primary_key() { return false; }
|
}
|
||||||
bool set_link_type(size_t, LinkType) { return false; }
|
m_new_tables.push_back(table_ndx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool insert_column(size_t, DataType, StringData, bool) { return schema_error_unless_new_table(); }
|
||||||
|
bool insert_link_column(size_t, DataType, StringData, size_t, size_t) { return schema_error_unless_new_table(); }
|
||||||
|
bool add_primary_key(size_t) { return schema_error_unless_new_table(); }
|
||||||
|
bool set_link_type(size_t, LinkType) { return schema_error_unless_new_table(); }
|
||||||
|
|
||||||
|
// Schema changes which are never allowed while a file is open
|
||||||
|
bool erase_group_level_table(size_t, size_t) { schema_error(); }
|
||||||
|
bool rename_group_level_table(size_t, StringData) { schema_error(); }
|
||||||
|
bool erase_column(size_t) { schema_error(); }
|
||||||
|
bool erase_link_column(size_t, size_t, size_t) { schema_error(); }
|
||||||
|
bool rename_column(size_t, StringData) { schema_error(); }
|
||||||
|
bool remove_primary_key() { schema_error(); }
|
||||||
|
|
||||||
bool select_table(size_t group_level_ndx, int, const size_t*) noexcept
|
bool select_table(size_t group_level_ndx, int, const size_t*) noexcept
|
||||||
{
|
{
|
||||||
|
@ -306,6 +340,8 @@ public:
|
||||||
bool nullify_link(size_t col, size_t row, size_t) { return mark_dirty(row, col); }
|
bool nullify_link(size_t col, size_t row, size_t) { return mark_dirty(row, col); }
|
||||||
bool set_int_unique(size_t col, size_t row, int_fast64_t) { return mark_dirty(row, col); }
|
bool set_int_unique(size_t col, size_t row, int_fast64_t) { return mark_dirty(row, col); }
|
||||||
bool set_string_unique(size_t col, size_t row, StringData) { return mark_dirty(row, col); }
|
bool set_string_unique(size_t col, size_t row, StringData) { return mark_dirty(row, col); }
|
||||||
|
bool insert_substring(size_t col, size_t row, size_t, StringData) { return mark_dirty(row, col); }
|
||||||
|
bool erase_substring(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); }
|
||||||
|
|
||||||
// Doesn't change any data
|
// Doesn't change any data
|
||||||
bool optimize_table() { return true; }
|
bool optimize_table() { return true; }
|
||||||
|
@ -314,8 +350,6 @@ public:
|
||||||
bool select_descriptor(int, const size_t*) { return false; }
|
bool select_descriptor(int, const size_t*) { return false; }
|
||||||
|
|
||||||
// Not implemented
|
// Not implemented
|
||||||
bool insert_substring(size_t, size_t, size_t, StringData) { return false; }
|
|
||||||
bool erase_substring(size_t, size_t, size_t, size_t) { return false; }
|
|
||||||
bool swap_rows(size_t, size_t) { return false; }
|
bool swap_rows(size_t, size_t) { return false; }
|
||||||
bool move_column(size_t, size_t) { return false; }
|
bool move_column(size_t, size_t) { return false; }
|
||||||
bool move_group_level_table(size_t, size_t) { return false; }
|
bool move_group_level_table(size_t, size_t) { return false; }
|
||||||
|
|
Loading…
Reference in New Issue