diff --git a/CHANGELOG.md b/CHANGELOG.md index 0440f6b525a..2c4759e8cf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,7 @@ * None. ### Fixed -* ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?) -* None. +* Fixed forgetting to insert a backlink when inserting a mixed link directly using Table::FieldValues. ([#4899](https://github.com/realm/realm-core/issues/4899) since the introduction of Mixed in v11.0.0) ### Breaking changes * None. diff --git a/src/realm/cluster.cpp b/src/realm/cluster.cpp index 309ced597b6..12d4fe02c70 100644 --- a/src/realm/cluster.cpp +++ b/src/realm/cluster.cpp @@ -272,6 +272,27 @@ inline void Cluster::do_insert_key(size_t ndx, ColKey col_key, Mixed init_val, O } } +inline void Cluster::do_insert_mixed(size_t ndx, ColKey col_key, Mixed init_value, ObjKey origin_key) +{ + ArrayMixed arr(m_alloc); + arr.set_parent(this, col_key.get_index().val + s_first_col_index); + arr.init_from_parent(); + arr.insert(ndx, init_value); + + // Insert backlink if needed + if (init_value.is_type(type_TypedLink)) { + // In case we are inserting in a Dictionary cluster, the backlink will + // be handled in Dictionary::insert function + if (Table* origin_table = const_cast(m_tree_top.get_owning_table())) { + ObjLink link = init_value.get(); + auto target_table = origin_table->get_parent_group()->get_table(link.get_table_key()); + + ColKey backlink_col_key = target_table->find_or_add_backlink_column(col_key, origin_table->get_key()); + target_table->get_object(link.get_obj_key()).add_backlink(backlink_col_key, origin_key); + } + } +} + inline void Cluster::do_insert_link(size_t ndx, ColKey col_key, Mixed init_val, ObjKey origin_key) { ObjLink target_link = init_val.is_null() ? ObjLink{} : init_val.get(); @@ -350,10 +371,7 @@ void Cluster::insert_row(size_t ndx, ObjKey k, const FieldValues& init_values) do_insert_row(ndx, col_key, init_value, nullable); break; case col_type_Mixed: { - ArrayMixed arr(m_alloc); - arr.set_parent(this, col_key.get_index().val + s_first_col_index); - arr.init_from_parent(); - arr.insert(ndx, init_value); + do_insert_mixed(ndx, col_key, init_value, ObjKey(k.value + get_offset())); break; } case col_type_Timestamp: diff --git a/src/realm/cluster.hpp b/src/realm/cluster.hpp index 83e7177519a..abf2a3b6029 100644 --- a/src/realm/cluster.hpp +++ b/src/realm/cluster.hpp @@ -307,6 +307,7 @@ class Cluster : public ClusterNode { void do_erase_key(size_t ndx, ColKey col, CascadeState& state); void do_insert_key(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key); void do_insert_link(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key); + void do_insert_mixed(size_t ndx, ColKey col_key, Mixed init_value, ObjKey origin_key); template void set_spec(T&, ColKey::Idx) const; template diff --git a/test/test_table.cpp b/test/test_table.cpp index d96f925b21a..708ec214eb2 100644 --- a/test/test_table.cpp +++ b/test/test_table.cpp @@ -5766,6 +5766,25 @@ TEST(Table_MixedNull) list.remove(0); } +TEST(Table_InsertWithMixedLink) +{ + Group g; + TableRef dest = g.add_table_with_primary_key("dest", type_Int, "value"); + TableRef source = g.add_table_with_primary_key("source", type_Int, "value"); + ColKey mixed_col = source->add_column(type_Mixed, "mixed"); + + Obj dest_obj = dest->create_object_with_primary_key(0); + + Mixed mixed_link = ObjLink{dest->get_key(), dest_obj.get_key()}; + FieldValues values = { + {mixed_col, mixed_link}, + }; + source->create_object_with_primary_key(0, std::move(values)); + + source->clear(); + dest->clear(); +} + TEST(Table_SortEncrypted) { SHARED_GROUP_TEST_PATH(path);