-
Notifications
You must be signed in to change notification settings - Fork 173
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
Support equal/not_equal on a link column against a Mixed value #4597
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -691,3 +691,72 @@ ExpressionNode::ExpressionNode(const ExpressionNode& from) | |||||
, m_expression(from.m_expression->clone()) | ||||||
{ | ||||||
} | ||||||
|
||||||
template <> | ||||||
size_t LinksToNode<Equal>::find_first_local(size_t start, size_t end) | ||||||
{ | ||||||
if (m_column_type == col_type_LinkList || m_condition_column_key.is_set()) { | ||||||
BPlusTree<ObjKey> links(m_table.unchecked_ptr()->get_alloc()); | ||||||
for (size_t i = start; i < end; i++) { | ||||||
if (ref_type ref = static_cast<const ArrayList*>(m_leaf_ptr)->get(i)) { | ||||||
links.init_from_ref(ref); | ||||||
for (auto& key : m_target_keys) { | ||||||
if (key) { | ||||||
if (links.find_first(key) != not_found) | ||||||
return i; | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
else if (m_column_type == col_type_Link) { | ||||||
for (auto& key : m_target_keys) { | ||||||
if (key) { | ||||||
// LinkColumn stores link to row N as the integer N + 1 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this comment has become stale and is not relevant to the code anymore, not related to your changes just noticing now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||||
auto pos = static_cast<const ArrayKey*>(m_leaf_ptr)->find_first(key, start, end); | ||||||
if (pos != realm::npos) { | ||||||
return pos; | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
return not_found; | ||||||
} | ||||||
|
||||||
template <> | ||||||
size_t LinksToNode<NotEqual>::find_first_local(size_t start, size_t end) | ||||||
{ | ||||||
// NotEqual only makes sense for a single value | ||||||
REALM_ASSERT(m_target_keys.size() == 1); | ||||||
ObjKey key = m_target_keys[0]; | ||||||
|
||||||
if (m_column_type == col_type_LinkList || m_condition_column_key.is_set()) { | ||||||
if (!key) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure if the query engine allows this or not, but maybe add an extra check to prevent matching null keys to an empty list
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure either. Anyway the early out should be removed. We should not have a match on an empty list. |
||||||
// Null key is never found in link lists | ||||||
return start; | ||||||
} | ||||||
BPlusTree<ObjKey> links(m_table.unchecked_ptr()->get_alloc()); | ||||||
for (size_t i = start; i < end; i++) { | ||||||
if (ref_type ref = static_cast<const ArrayList*>(m_leaf_ptr)->get(i)) { | ||||||
links.init_from_ref(ref); | ||||||
auto sz = links.size(); | ||||||
for (size_t j = 0; j < sz; j++) { | ||||||
if (links.get(j) != key) { | ||||||
return i; | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
else if (m_column_type == col_type_Link) { | ||||||
auto leaf = static_cast<const ArrayKey*>(m_leaf_ptr); | ||||||
for (size_t i = start; i < end; i++) { | ||||||
if (leaf->get(i) != key) { | ||||||
return i; | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
return not_found; | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5181,15 +5181,29 @@ TEST(Query_LinksTo) | |
|
||
source->get_object(source_keys[2]).set(col_link, target_keys[2]); | ||
source->get_object(source_keys[5]).set(col_link, target_keys[5]); | ||
source->get_object(source_keys[8]).set(col_link, target_keys[5]); | ||
source->get_object(source_keys[9]).set(col_link, target_keys[9]); | ||
|
||
q = source->column<Link>(col_link) == target->get_object(target_keys[2]); | ||
found_key = q.find(); | ||
CHECK_EQUAL(found_key, source_keys[2]); | ||
|
||
q = source->where().equal(col_link, Mixed(target_keys[2])); | ||
found_key = q.find(); | ||
CHECK_EQUAL(found_key, source_keys[2]); | ||
|
||
q = source->column<Link>(col_link) == target->get_object(target_keys[5]); | ||
found_key = q.find(); | ||
CHECK_EQUAL(found_key, source_keys[5]); | ||
q = source->where().equal(col_link, Mixed(target_keys[5])); | ||
auto tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 2); | ||
q = source->where().not_equal(col_link, Mixed(target_keys[5])); | ||
tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 8); | ||
q = source->where().equal(col_link, Mixed(ObjLink(source->get_key(), target_keys[5]))); // Wrong table | ||
tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 0); | ||
|
||
q = source->column<Link>(col_link) == target->get_object(target_keys[9]); | ||
found_key = q.find(); | ||
|
@@ -5200,8 +5214,8 @@ TEST(Query_LinksTo) | |
CHECK_EQUAL(found_key, null_key); | ||
|
||
q = source->column<Link>(col_link).is_null(); | ||
auto tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 7); | ||
tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 6); | ||
|
||
q = source->column<Link>(col_link) != null(); | ||
found_key = q.find(); | ||
|
@@ -5225,6 +5239,13 @@ TEST(Query_LinksTo) | |
q = source->column<Link>(col_linklist) != target->get_object(target_keys[6]); | ||
found_key = q.find(); | ||
CHECK_EQUAL(found_key, source_keys[2]); | ||
|
||
q = source->where().equal(col_linklist, Mixed(target_keys[0])); | ||
tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 2); | ||
q = source->where().not_equal(col_linklist, Mixed(target_keys[6])); | ||
tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 2); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add some checks for searching for == and != null, across linklist and link? Just making sure we haven't changed behaviour from before. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well - this is new functionality. We could not do this before. LinksToNode would never match on a null link. Added some more test involving null. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, good point. Thanks for adding tests anyhow 😄 |
||
} | ||
|
||
TEST(Query_Group_bug) | ||
|
@@ -5890,10 +5911,22 @@ TEST(Query_Mixed) | |
tv = (table->column<Mixed>(col_any) == table->column<Int>(col_int)).find_all(); | ||
CHECK_EQUAL(tv.size(), 72); | ||
|
||
tv = (origin->column<Mixed>(col_mixed) == Mixed(table->begin()->get_link())).find_all(); | ||
ObjLink link_to_first = table->begin()->get_link(); | ||
tv = (origin->column<Mixed>(col_mixed) == Mixed(link_to_first)).find_all(); | ||
CHECK_EQUAL(tv.size(), 4); | ||
tv = (origin->where().links_to(col_mixed, table->begin()->get_link())).find_all(); | ||
tv = (origin->where().links_to(col_mixed, link_to_first)).find_all(); | ||
CHECK_EQUAL(tv.size(), 4); | ||
tv = (origin->where().equal(col_link, Mixed(link_to_first))).find_all(); | ||
CHECK_EQUAL(tv.size(), 1); | ||
tv = (origin->where().equal(col_links, Mixed(link_to_first))).find_all(); | ||
CHECK_EQUAL(tv.size(), 1); | ||
auto q = origin->where().not_equal(col_links, Mixed(link_to_first)); | ||
auto d = q.get_description(); | ||
tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 10); | ||
q = origin->query(d); | ||
tv = q.find_all(); | ||
CHECK_EQUAL(tv.size(), 10); | ||
tv = (origin->link(col_links).column<Mixed>(col_any) > 50).find_all(); | ||
CHECK_EQUAL(tv.size(), 5); | ||
tv = (origin->link(col_link).column<Mixed>(col_any) > 50).find_all(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the tables don't match, this code will still create matches on null links, but I don't think we want to do that. For mismatching tables, should we also throw the type mismatch error? Or maybe we can allow it but make a FALSEPREDICATE node?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed to return a FalseExpression in case of mismatching tables.