diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a1b2542013..c861a3c4785 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * Added a method to check if a file needs upgrade. ([#7140](https://github.com/realm/realm-core/issues/7140)) ### Fixed +* Fixed queries like `indexed_property == NONE {x}` which mistakenly matched on only x instead of not x. This only applies when an indexed property with equality (==, or IN) matches with `NONE` on a list of one item. If the constant list contained more than one value then it was working correctly. ([realm-js #7862](https://github.com/realm/realm-java/issues/7862), since v12.5.0) * Uploading the changesets recovered during an automatic client reset recovery may lead to 'Bad server version' errors and a new client reset. ([#7279](https://github.com/realm/realm-core/issues/7279), since v13.24.1) * Fixed invalid data in error reason string when registering a subscription change notification after the subscription has already failed. ([#6839](https://github.com/realm/realm-core/issues/6839), since v11.8.0) * Fixed crash in fulltext index using prefix search with no matches ([#7309](https://github.com/realm/realm-core/issues/7309), since v13.18.0) diff --git a/src/realm/query_expression.hpp b/src/realm/query_expression.hpp index b1e70c65123..5ccd30f49a4 100644 --- a/src/realm/query_expression.hpp +++ b/src/realm/query_expression.hpp @@ -4262,18 +4262,22 @@ class Compare : public CompareBase { // finding all matches up front. Mixed const_value; Subexpr* column; + std::optional const_value_cmp_type; if (m_left->has_single_value()) { const_value = m_left->get_mixed(); + const_value_cmp_type = m_left->get_comparison_type(); column = m_right.get(); } else { const_value = m_right->get_mixed(); + const_value_cmp_type = m_right->get_comparison_type(); column = m_left.get(); } if (column->has_search_index() && column->get_comparison_type().value_or(ExpressionComparisonType::Any) == - ExpressionComparisonType::Any) { + ExpressionComparisonType::Any && + const_value_cmp_type.value_or(ExpressionComparisonType::Any) != ExpressionComparisonType::None) { if (const_value.is_null()) { const ObjPropertyBase* prop = dynamic_cast(m_right.get()); // when checking for null across links, null links are considered matches, diff --git a/test/test_parser.cpp b/test/test_parser.cpp index 843f965e60b..c811fec22f0 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -723,7 +723,37 @@ TEST_TYPES(Parser_Numerics, Prop, Nullable, Indexed, NullableInde verify_query(test_context, t, out.str(), 1); verify_query_sub(test_context, t, util::format("values == $%1", i), args, 1); } + size_t sz = t->size(); verify_query(test_context, t, "values == null", nullable ? 1 : 0); + verify_query(test_context, t, "values == ANY {-1, 0, 1}", 3); + verify_query(test_context, t, "values == ANY {0, 1}", 2); + verify_query(test_context, t, "values == ANY {1}", 1); + verify_query(test_context, t, "values == ANY {}", 0); + + verify_query(test_context, t, "values == NONE {-1, 0, 1}", sz - 3); + verify_query(test_context, t, "values == NONE {-1, 0}", sz - 2); + verify_query(test_context, t, "values == NONE {-1}", sz - 1); + verify_query(test_context, t, "values == NONE {}", sz); + + verify_query(test_context, t, "values == ALL {-1, 0, 1}", 0); + verify_query(test_context, t, "values == ALL {-1, 0}", 0); + verify_query(test_context, t, "values == ALL {-1}", 1); + verify_query(test_context, t, "values == ALL {}", sz); + + verify_query(test_context, t, "values != NONE {-1, 0, 1}", 0); + verify_query(test_context, t, "values != NONE {-1, 0}", 0); + verify_query(test_context, t, "values != NONE {-1}", 1); + verify_query(test_context, t, "values != NONE {}", sz); + + verify_query(test_context, t, "values != ANY {-1, 0, 1}", sz); + verify_query(test_context, t, "values != ANY {0, 1}", sz); + verify_query(test_context, t, "values != ANY {1}", sz - 1); + verify_query(test_context, t, "values != ANY {}", 0); + + verify_query(test_context, t, "values != ALL {-1, 0, 1}", sz - 3); + verify_query(test_context, t, "values != ALL {-1, 0}", sz - 2); + verify_query(test_context, t, "values != ALL {-1}", sz - 1); + verify_query(test_context, t, "values != ALL {}", sz); } TEST(Parser_LinksToSameTable)