From a327790641f8aee6637f52c247529c30093d01dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Edelbo?= Date: Wed, 30 Sep 2020 10:28:11 +0200 Subject: [PATCH] Fix index lookup Constructing a ObjKey from a value read in the index went wrong. --- CHANGELOG.md | 2 +- src/realm/index_string.cpp | 28 ++++++++++++++-------------- src/realm/index_string.hpp | 2 -- src/realm/obj.cpp | 6 ++++++ src/realm/obj.hpp | 2 +- test/test_table.cpp | 17 +++++++++++++++++ 6 files changed, 39 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c50a545880..3bd77c495c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Fixed * ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?) -* None. +* Making a query in an indexed property may give a "Key not found" exception. ([#2025](https://github.com/realm/realm-dotnet/issues/2025), since v6.0.0) ### Breaking changes * None. diff --git a/src/realm/index_string.cpp b/src/realm/index_string.cpp index 88ce4ed9623..d824c95ca19 100644 --- a/src/realm/index_string.cpp +++ b/src/realm/index_string.cpp @@ -509,7 +509,7 @@ void IndexArray::index_string_all_ins(StringData value, std::vector& res // Get entry under key const size_t pos_refs = pos + 1; // first entry in refs points to offsets - const int64_t ref = get_direct(data, width, pos_refs); + const uint64_t ref = get_direct(data, width, pos_refs); if (is_inner_node) { // Set vars for next iteration @@ -525,7 +525,7 @@ void IndexArray::index_string_all_ins(StringData value, std::vector& res // Literal row index (tagged) if (ref & 1) { - ObjKey k = ObjKey(ref >> 1); + ObjKey k(int64_t(ref >> 1)); // The buffer is needed when for when this is an integer index. StringConversionBuffer buffer; @@ -537,12 +537,12 @@ void IndexArray::index_string_all_ins(StringData value, std::vector& res continue; } - const char* const sub_header = m_alloc.translate(to_ref(ref)); + const char* const sub_header = m_alloc.translate(ref_type(ref)); const bool sub_isindex = get_context_flag_from_header(sub_header); // List of row indices with common prefix up to this point, in sorted order. if (!sub_isindex) { - const IntegerColumn sub(m_alloc, to_ref(ref)); + const IntegerColumn sub(m_alloc, ref_type(ref)); from_list_all_ins(upper_value, result, sub, column); continue; } @@ -583,11 +583,11 @@ void IndexArray::index_string_all(StringData value, std::vector& result, // Get entry under key size_t pos_refs = pos + 1; // first entry in refs points to offsets - int64_t ref = get_direct(data, width, pos_refs); + uint64_t ref = get_direct(data, width, pos_refs); if (is_inner_node) { // Set vars for next iteration - header = m_alloc.translate(to_ref(ref)); + header = m_alloc.translate(ref_type(ref)); data = get_data_from_header(header); width = get_width_from_header(header); is_inner_node = get_is_inner_bptree_node_from_header(header); @@ -601,7 +601,7 @@ void IndexArray::index_string_all(StringData value, std::vector& result, // Literal row index (tagged) if (ref & 1) { - ObjKey k = ObjKey(ref >> 1); + ObjKey k(int64_t(ref >> 1)); // The buffer is needed when for when this is an integer index. StringConversionBuffer buffer; @@ -613,12 +613,12 @@ void IndexArray::index_string_all(StringData value, std::vector& result, return; } - const char* sub_header = m_alloc.translate(to_ref(ref)); + const char* sub_header = m_alloc.translate(ref_type(ref)); const bool sub_isindex = get_context_flag_from_header(sub_header); // List of row indices with common prefix up to this point, in sorted order. if (!sub_isindex) { - const IntegerColumn sub(m_alloc, to_ref(ref)); + const IntegerColumn sub(m_alloc, ref_type(ref)); return from_list_all(value, result, sub, column); } @@ -1182,22 +1182,22 @@ void StringIndex::distinct(BPlusTree& result) const } else { for (size_t i = 1; i < array_size; ++i) { - int64_t ref = m_array->get(i); + uint64_t ref = m_array->get(i); // low bit set indicate literal ref (shifted) if (ref & 1) { - ObjKey k = ObjKey((uint64_t(ref) >> 1)); + ObjKey k(int64_t(ref >> 1)); result.add(k); } else { // A real ref either points to a list or a subindex - char* header = alloc.translate(to_ref(ref)); + char* header = alloc.translate(ref_type(ref)); if (Array::get_context_flag_from_header(header)) { - StringIndex ndx(to_ref(ref), m_array.get(), i, m_target_column, alloc); + StringIndex ndx(ref_type(ref), m_array.get(), i, m_target_column, alloc); ndx.distinct(result); } else { - IntegerColumn sub(alloc, to_ref(ref)); // Throws + IntegerColumn sub(alloc, ref_type(ref)); // Throws if (sub.size() == 1) { // Optimization. ObjKey k = ObjKey(sub.get(0)); // get first match result.add(k); diff --git a/src/realm/index_string.hpp b/src/realm/index_string.hpp index a0394bc6698..69cf01bdf48 100644 --- a/src/realm/index_string.hpp +++ b/src/realm/index_string.hpp @@ -80,8 +80,6 @@ class IndexArray : public Array { } ObjKey index_string_find_first(StringData value, const ClusterColumn& column) const; - void index_string_find_all(IntegerColumn& result, StringData value, const ClusterColumn& column, - bool case_insensitive = false) const; void index_string_find_all(std::vector& result, StringData value, const ClusterColumn& column, bool case_insensitive = false) const; FindRes index_string_find_all_no_copy(StringData value, const ClusterColumn& column, diff --git a/src/realm/obj.cpp b/src/realm/obj.cpp index 330f8e3f0a7..f7713e46322 100644 --- a/src/realm/obj.cpp +++ b/src/realm/obj.cpp @@ -720,6 +720,12 @@ std::string ConstObj::to_string() const return ostr.str(); } +std::ostream& operator<<(std::ostream& ostr, const ConstObj& obj) +{ + obj.to_json(ostr, -1, nullptr); + return ostr; +} + /*********************************** Obj *************************************/ bool Obj::ensure_writeable() diff --git a/src/realm/obj.hpp b/src/realm/obj.hpp index 1a0a9861eef..9bf4d9c4662 100644 --- a/src/realm/obj.hpp +++ b/src/realm/obj.hpp @@ -208,6 +208,7 @@ class ConstObj { std::vector get_all_backlinks(ColKey backlink_col) const; }; +std::ostream& operator<<(std::ostream&, const ConstObj& obj); class Obj : public ConstObj { public: @@ -315,7 +316,6 @@ class Obj : public ConstObj { inline void set_spec(T&, ColKey); }; - inline Obj Obj::get_linked_object(ColKey link_col_key) { return ConstObj::get_linked_object(link_col_key); diff --git a/test/test_table.cpp b/test/test_table.cpp index 67f2b3cd40f..df2e2350675 100644 --- a/test/test_table.cpp +++ b/test/test_table.cpp @@ -4017,6 +4017,23 @@ TEST(Table_CreateObjectWithPrimaryKeyDidCreate) CHECK_NOT(did_create); } +TEST(Table_PrimaryKeyIndexBug) +{ + Group g; + TableRef table = g.add_table("table"); + TableRef origin = g.add_table("origin"); + auto col_id = table->add_column(type_String, "id"); + auto col_link = origin->add_column_link(type_Link, "link", *table); + table->add_search_index(col_id); + // Create an object where bit 62 is set in the ObkKey + auto obj = table->create_object(ObjKey(0x40083f0f9b0fb598)).set(col_id, "hallo"); + origin->create_object().set(col_link, obj.get_key()); + + auto q = origin->link(col_link).column(col_id) == "hallo"; + auto cnt = q.count(); + CHECK_EQUAL(cnt, 1); +} + TEST(Table_PrimaryKeyString) { #ifdef REALM_DEBUG