diff options
-rw-r--r-- | src/mongo/bson/bson_comparator_interface_base.h | 11 | ||||
-rw-r--r-- | src/mongo/bson/bsonelement_comparator_interface.h | 13 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.cpp | 1 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.h | 4 | ||||
-rw-r--r-- | src/mongo/db/bson/dotted_path_support.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/bson/dotted_path_support.h | 3 | ||||
-rw-r--r-- | src/mongo/db/index/expression_keys_private.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.cpp | 36 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.h | 22 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf_test.cpp | 66 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/query/canonical_query_test.cpp | 3 |
12 files changed, 110 insertions, 63 deletions
diff --git a/src/mongo/bson/bson_comparator_interface_base.h b/src/mongo/bson/bson_comparator_interface_base.h index f70bec7b872..29d80916f72 100644 --- a/src/mongo/bson/bson_comparator_interface_base.h +++ b/src/mongo/bson/bson_comparator_interface_base.h @@ -28,9 +28,11 @@ #pragma once +#include <boost/container/flat_set.hpp> #include <initializer_list> #include <map> #include <set> +#include <vector> #include "mongo/base/disallow_copying.h" #include "mongo/base/string_data_comparator_interface.h" @@ -51,6 +53,9 @@ class BSONComparatorInterfaceBase { MONGO_DISALLOW_COPYING(BSONComparatorInterfaceBase); public: + BSONComparatorInterfaceBase(BSONComparatorInterfaceBase&& other) = default; + BSONComparatorInterfaceBase& operator=(BSONComparatorInterfaceBase&& other) = default; + /** * A deferred comparison between two objects of type T, which can be converted into a boolean * via the evaluate() method. @@ -122,6 +127,8 @@ public: using Set = std::set<T, LessThan>; + using FlatSet = boost::container::flat_set<T, LessThan>; + using UnorderedSet = stdx::unordered_set<T, Hasher, EqualTo>; template <typename ValueType> @@ -207,6 +214,10 @@ protected: return Set(init, LessThan(this)); } + FlatSet makeFlatSet(const std::vector<T>& elements) const { + return FlatSet(elements.begin(), elements.end(), LessThan(this)); + } + UnorderedSet makeUnorderedSet(std::initializer_list<T> init = {}) const { return UnorderedSet(init, 0, Hasher(this), EqualTo(this)); } diff --git a/src/mongo/bson/bsonelement_comparator_interface.h b/src/mongo/bson/bsonelement_comparator_interface.h index c6223a2d352..d69397a68db 100644 --- a/src/mongo/bson/bsonelement_comparator_interface.h +++ b/src/mongo/bson/bsonelement_comparator_interface.h @@ -33,6 +33,9 @@ namespace mongo { +typedef std::set<BSONElement, BSONElementCmpWithoutField> BSONElementSet; +typedef std::multiset<BSONElement, BSONElementCmpWithoutField> BSONElementMultiSet; + /** * A BSONElement::ComparatorInterface is an abstract class for comparing BSONElement objects. Usage * for comparing two BSON elements, 'lhs' and 'rhs', where 'comparator' is an instance of a class @@ -61,6 +64,14 @@ public: } /** + * Constructs a BSONEltFlatSet whose equivalence classes are given by this comparator. This + * comparator must outlive the returned set. + */ + FlatSet makeBSONEltFlatSet(const std::vector<BSONElement>& elements) const { + return makeFlatSet(elements); + } + + /** * Constructs a BSONEltUnorderedSet whose equivalence classes are given by this * comparator. This comparator must outlive the returned set. */ @@ -91,6 +102,8 @@ public: using BSONEltSet = BSONComparatorInterfaceBase<BSONElement>::Set; +using BSONEltFlatSet = BSONComparatorInterfaceBase<BSONElement>::FlatSet; + using BSONEltUnorderedSet = BSONComparatorInterfaceBase<BSONElement>::UnorderedSet; template <typename ValueType> diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp index 06f446c9c05..12bcb5f6747 100644 --- a/src/mongo/bson/bsonobj.cpp +++ b/src/mongo/bson/bsonobj.cpp @@ -33,6 +33,7 @@ #include "mongo/base/data_range.h" #include "mongo/bson/bson_validate.h" +#include "mongo/bson/bsonelement_comparator_interface.h" #include "mongo/db/json.h" #include "mongo/util/allocator.h" #include "mongo/util/hex.h" diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h index 4344995b23c..a6d7abea953 100644 --- a/src/mongo/bson/bsonobj.h +++ b/src/mongo/bson/bsonobj.h @@ -42,7 +42,6 @@ #include "mongo/base/string_data_comparator_interface.h" #include "mongo/bson/bson_comparator_interface_base.h" #include "mongo/bson/bsonelement.h" -#include "mongo/bson/bsonelement_comparator_interface.h" #include "mongo/bson/bsontypes.h" #include "mongo/bson/oid.h" #include "mongo/bson/timestamp.h" @@ -53,9 +52,6 @@ namespace mongo { -typedef std::set<BSONElement, BSONElementCmpWithoutField> BSONElementSet; -typedef std::multiset<BSONElement, BSONElementCmpWithoutField> BSONElementMSet; - /** C++ representation of a "BSON" object -- that is, an extended JSON-style object in a binary representation. diff --git a/src/mongo/db/bson/dotted_path_support.cpp b/src/mongo/db/bson/dotted_path_support.cpp index 5e6bc1f32e3..665f8515f8f 100644 --- a/src/mongo/db/bson/dotted_path_support.cpp +++ b/src/mongo/db/bson/dotted_path_support.cpp @@ -172,7 +172,7 @@ void extractAllElementsAlongPath(const BSONObj& obj, void extractAllElementsAlongPath(const BSONObj& obj, StringData path, - BSONElementMSet& elements, + BSONElementMultiSet& elements, bool expandArrayOnTrailingField, std::set<size_t>* arrayComponents) { const size_t initialDepth = 0; diff --git a/src/mongo/db/bson/dotted_path_support.h b/src/mongo/db/bson/dotted_path_support.h index 4d34901338c..8d560a01d33 100644 --- a/src/mongo/db/bson/dotted_path_support.h +++ b/src/mongo/db/bson/dotted_path_support.h @@ -31,6 +31,7 @@ #include <cstddef> #include <set> +#include "mongo/bson/bsonelement_comparator_interface.h" #include "mongo/bson/bsonobj.h" namespace mongo { @@ -104,7 +105,7 @@ void extractAllElementsAlongPath(const BSONObj& obj, void extractAllElementsAlongPath(const BSONObj& obj, StringData path, - BSONElementMSet& elements, + BSONElementMultiSet& elements, bool expandArrayOnTrailingField = true, std::set<std::size_t>* arrayComponents = nullptr); diff --git a/src/mongo/db/index/expression_keys_private.cpp b/src/mongo/db/index/expression_keys_private.cpp index aa0fe975008..5dde439e1a8 100644 --- a/src/mongo/db/index/expression_keys_private.cpp +++ b/src/mongo/db/index/expression_keys_private.cpp @@ -32,6 +32,7 @@ #include <utility> +#include "mongo/bson/bsonelement_comparator_interface.h" #include "mongo/bson/simple_bsonobj_comparator.h" #include "mongo/db/bson/dotted_path_support.h" #include "mongo/db/field_ref.h" @@ -236,7 +237,7 @@ void ExpressionKeysPrivate::get2DKeys(const BSONObj& obj, const TwoDIndexingParams& params, BSONObjSet* keys, std::vector<BSONObj>* locs) { - BSONElementMSet bSet; + BSONElementMultiSet bSet; // Get all the nested location fields, but don't return individual elements from // the last array, if it exists. @@ -245,7 +246,7 @@ void ExpressionKeysPrivate::get2DKeys(const BSONObj& obj, if (bSet.empty()) return; - for (BSONElementMSet::iterator setI = bSet.begin(); setI != bSet.end(); ++setI) { + for (BSONElementMultiSet::iterator setI = bSet.begin(); setI != bSet.end(); ++setI) { BSONElement geo = *setI; if (geo.eoo() || !geo.isABSONObj()) diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp index a07c8ada9c5..4a0a4598927 100644 --- a/src/mongo/db/matcher/expression_leaf.cpp +++ b/src/mongo/db/matcher/expression_leaf.cpp @@ -593,29 +593,31 @@ bool InMatchExpression::equivalent(const MatchExpression* other) const { void InMatchExpression::_doSetCollator(const CollatorInterface* collator) { _collator = collator; + _eltCmp = BSONElementComparator(BSONElementComparator::FieldNamesMode::kIgnore, _collator); // We need to re-compute '_equalitySet', since our set comparator has changed. - BSONElementSet equalitiesWithNewComparator( - _originalEqualityVector.begin(), _originalEqualityVector.end(), collator); - _equalitySet = std::move(equalitiesWithNewComparator); + _equalitySet = _eltCmp.makeBSONEltFlatSet(_originalEqualityVector); } -Status InMatchExpression::addEquality(const BSONElement& elt) { - if (elt.type() == BSONType::RegEx) { - return Status(ErrorCodes::BadValue, "InMatchExpression equality cannot be a regex"); - } - if (elt.type() == BSONType::Undefined) { - return Status(ErrorCodes::BadValue, "InMatchExpression equality cannot be undefined"); - } +Status InMatchExpression::setEqualities(std::vector<BSONElement> equalities) { + for (auto&& equality : equalities) { + if (equality.type() == BSONType::RegEx) { + return Status(ErrorCodes::BadValue, "InMatchExpression equality cannot be a regex"); + } + if (equality.type() == BSONType::Undefined) { + return Status(ErrorCodes::BadValue, "InMatchExpression equality cannot be undefined"); + } - if (elt.type() == BSONType::jstNULL) { - _hasNull = true; - } - if (elt.type() == BSONType::Array && elt.Obj().isEmpty()) { - _hasEmptyArray = true; + if (equality.type() == BSONType::jstNULL) { + _hasNull = true; + } else if (equality.type() == BSONType::Array && equality.Obj().isEmpty()) { + _hasEmptyArray = true; + } } - _equalitySet.insert(elt); - _originalEqualityVector.push_back(elt); + _originalEqualityVector = std::move(equalities); + + _equalitySet = _eltCmp.makeBSONEltFlatSet(_originalEqualityVector); + return Status::OK(); } diff --git a/src/mongo/db/matcher/expression_leaf.h b/src/mongo/db/matcher/expression_leaf.h index c61fdd25ddc..984fc4653ca 100644 --- a/src/mongo/db/matcher/expression_leaf.h +++ b/src/mongo/db/matcher/expression_leaf.h @@ -28,10 +28,12 @@ #pragma once +#include "mongo/bson/bsonelement_comparator.h" #include "mongo/bson/bsonmisc.h" #include "mongo/bson/bsonobj.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_path.h" +#include "mongo/db/query/collation/collator_interface.h" #include "mongo/stdx/memory.h" #include "mongo/stdx/unordered_map.h" @@ -298,7 +300,10 @@ public: */ class InMatchExpression : public LeafMatchExpression { public: - InMatchExpression() : LeafMatchExpression(MATCH_IN) {} + InMatchExpression() + : LeafMatchExpression(MATCH_IN), + _eltCmp(BSONElementComparator::FieldNamesMode::kIgnore, _collator), + _equalitySet(_eltCmp.makeBSONEltFlatSet(_originalEqualityVector)) {} Status init(StringData path); @@ -317,11 +322,11 @@ public: */ virtual void _doSetCollator(const CollatorInterface* collator); - Status addEquality(const BSONElement& elt); + Status setEqualities(std::vector<BSONElement> equalities); Status addRegex(std::unique_ptr<RegexMatchExpression> expr); - const BSONElementSet& getEqualities() const { + const BSONEltFlatSet& getEqualities() const { return _equalitySet; } @@ -348,17 +353,20 @@ private: // Whether or not '_equalities' has an empty array element in it. bool _hasEmptyArray = false; - // Collator used to compare elements. By default, simple binary comparison will be used. + // Collator used to construct '_eltCmp'; const CollatorInterface* _collator = nullptr; - // Set of equality elements associated with this expression. '_collator' is used as a comparator - // for this set. - BSONElementSet _equalitySet; + // Comparator used to compare elements. By default, simple binary comparison will be used. + BSONElementComparator _eltCmp; // Original container of equality elements, including duplicates. Needed for re-computing // '_equalitySet' in case '_collator' changes after elements have been added. std::vector<BSONElement> _originalEqualityVector; + // Set of equality elements associated with this expression. '_eltCmp' is used as a comparator + // for this set. + BSONEltFlatSet _equalitySet; + // Container of regex elements this object owns. std::vector<std::unique_ptr<RegexMatchExpression>> _regexes; }; diff --git a/src/mongo/db/matcher/expression_leaf_test.cpp b/src/mongo/db/matcher/expression_leaf_test.cpp index 67274319ced..3d1c87fbd26 100644 --- a/src/mongo/db/matcher/expression_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_leaf_test.cpp @@ -1470,7 +1470,8 @@ TEST(InMatchExpression, MatchesElementSingle) { BSONObj match = BSON("a" << 1); BSONObj notMatch = BSON("a" << 2); InMatchExpression in; - in.addEquality(operand.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.matchesSingleElement(match["a"])); ASSERT(!in.matchesSingleElement(notMatch["a"])); } @@ -1488,10 +1489,8 @@ TEST(InMatchExpression, MatchesEmpty) { TEST(InMatchExpression, MatchesElementMultiple) { BSONObj operand = BSON_ARRAY(1 << "r" << true << 1); InMatchExpression in; - in.addEquality(operand[0]).transitional_ignore(); - in.addEquality(operand[1]).transitional_ignore(); - in.addEquality(operand[2]).transitional_ignore(); - in.addEquality(operand[3]).transitional_ignore(); + std::vector<BSONElement> equalities{operand[0], operand[1], operand[2], operand[3]}; + ASSERT_OK(in.setEqualities(std::move(equalities))); BSONObj matchFirst = BSON("a" << 1); BSONObj matchSecond = BSON("a" @@ -1509,7 +1508,8 @@ TEST(InMatchExpression, MatchesScalar) { BSONObj operand = BSON_ARRAY(5); InMatchExpression in; in.init("a").transitional_ignore(); - in.addEquality(operand.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.matchesBSON(BSON("a" << 5.0), NULL)); ASSERT(!in.matchesBSON(BSON("a" << 4), NULL)); @@ -1519,7 +1519,8 @@ TEST(InMatchExpression, MatchesArrayValue) { BSONObj operand = BSON_ARRAY(5); InMatchExpression in; in.init("a").transitional_ignore(); - in.addEquality(operand.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.matchesBSON(BSON("a" << BSON_ARRAY(5.0 << 6)), NULL)); ASSERT(!in.matchesBSON(BSON("a" << BSON_ARRAY(6 << 7)), NULL)); @@ -1531,7 +1532,8 @@ TEST(InMatchExpression, MatchesNull) { InMatchExpression in; in.init("a").transitional_ignore(); - in.addEquality(operand.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.matchesBSON(BSONObj(), NULL)); ASSERT(in.matchesBSON(BSON("a" << BSONNULL), NULL)); @@ -1545,15 +1547,16 @@ TEST(InMatchExpression, MatchesUndefined) { InMatchExpression in; in.init("a").transitional_ignore(); - Status s = in.addEquality(operand.firstElement()); - ASSERT_NOT_OK(s); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_NOT_OK(in.setEqualities(std::move(equalities))); } TEST(InMatchExpression, MatchesMinKey) { BSONObj operand = BSON_ARRAY(MinKey); InMatchExpression in; in.init("a").transitional_ignore(); - in.addEquality(operand.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.matchesBSON(BSON("a" << MinKey), NULL)); ASSERT(!in.matchesBSON(BSON("a" << MaxKey), NULL)); @@ -1564,7 +1567,8 @@ TEST(InMatchExpression, MatchesMaxKey) { BSONObj operand = BSON_ARRAY(MaxKey); InMatchExpression in; in.init("a").transitional_ignore(); - in.addEquality(operand.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.matchesBSON(BSON("a" << MaxKey), NULL)); ASSERT(!in.matchesBSON(BSON("a" << MinKey), NULL)); @@ -1575,9 +1579,8 @@ TEST(InMatchExpression, MatchesFullArray) { BSONObj operand = BSON_ARRAY(BSON_ARRAY(1 << 2) << 4 << 5); InMatchExpression in; in.init("a").transitional_ignore(); - in.addEquality(operand[0]).transitional_ignore(); - in.addEquality(operand[1]).transitional_ignore(); - in.addEquality(operand[2]).transitional_ignore(); + std::vector<BSONElement> equalities{operand[0], operand[1], operand[2]}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.matchesBSON(BSON("a" << BSON_ARRAY(1 << 2)), NULL)); ASSERT(!in.matchesBSON(BSON("a" << BSON_ARRAY(1 << 2 << 3)), NULL)); @@ -1589,8 +1592,8 @@ TEST(InMatchExpression, ElemMatchKey) { BSONObj operand = BSON_ARRAY(5 << 2); InMatchExpression in; in.init("a").transitional_ignore(); - in.addEquality(operand[0]).transitional_ignore(); - in.addEquality(operand[1]).transitional_ignore(); + std::vector<BSONElement> equalities{operand[0], operand[1]}; + ASSERT_OK(in.setEqualities(std::move(equalities))); MatchDetails details; details.requestElemMatchKey(); @@ -1608,7 +1611,8 @@ TEST(InMatchExpression, InMatchExpressionsWithDifferentNumbersOfElementsAreUnequ << "string"); InMatchExpression eq1; InMatchExpression eq2; - eq1.addEquality(obj.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{obj.firstElement()}; + ASSERT_OK(eq1.setEqualities(std::move(equalities))); ASSERT(!eq1.equivalent(&eq2)); } @@ -1644,8 +1648,12 @@ TEST(InMatchExpression, InMatchExpressionsWithCollationEquivalentElementsAreEqua InMatchExpression eq2; eq2.setCollator(&collator2); - eq1.addEquality(obj1.firstElement()).transitional_ignore(); - eq2.addEquality(obj2.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities1{obj1.firstElement()}; + ASSERT_OK(eq1.setEqualities(std::move(equalities1))); + + std::vector<BSONElement> equalities2{obj2.firstElement()}; + ASSERT_OK(eq2.setEqualities(std::move(equalities2))); + ASSERT(eq1.equivalent(&eq2)); } @@ -1661,8 +1669,12 @@ TEST(InMatchExpression, InMatchExpressionsWithCollationNonEquivalentElementsAreU InMatchExpression eq2; eq2.setCollator(&collator2); - eq1.addEquality(obj1.firstElement()).transitional_ignore(); - eq2.addEquality(obj2.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities1{obj1.firstElement()}; + ASSERT_OK(eq1.setEqualities(std::move(equalities1))); + + std::vector<BSONElement> equalities2{obj2.firstElement()}; + ASSERT_OK(eq2.setEqualities(std::move(equalities2))); + ASSERT(!eq1.equivalent(&eq2)); } @@ -1671,7 +1683,8 @@ TEST(InMatchExpression, StringMatchingWithNullCollatorUsesBinaryComparison) { BSONObj notMatch = BSON("a" << "string2"); InMatchExpression in; - in.addEquality(operand.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(!in.matchesSingleElement(notMatch["a"])); } @@ -1682,7 +1695,8 @@ TEST(InMatchExpression, StringMatchingRespectsCollation) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); InMatchExpression in; in.setCollator(&collator); - in.addEquality(operand.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{operand.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.matchesSingleElement(match["a"])); } @@ -1695,8 +1709,8 @@ TEST(InMatchExpression, ChangingCollationAfterAddingEqualitiesPreservesEqualitie CollatorInterfaceMock collatorReverseString(CollatorInterfaceMock::MockType::kReverseString); InMatchExpression in; in.setCollator(&collatorAlwaysEqual); - in.addEquality(obj1.firstElement()).transitional_ignore(); - in.addEquality(obj2.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{obj1.firstElement(), obj2.firstElement()}; + ASSERT_OK(in.setEqualities(std::move(equalities))); ASSERT(in.getEqualities().size() == 1); in.setCollator(&collatorReverseString); ASSERT(in.getEqualities().size() == 2); diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index c58aca06229..85c21e13bfc 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -729,6 +729,7 @@ Status MatchExpressionParser::_parseInExpression(InMatchExpression* inExpression const BSONObj& theArray, const CollatorInterface* collator) { inExpression->setCollator(collator); + std::vector<BSONElement> equalities; BSONObjIterator i(theArray); while (i.more()) { BSONElement e = i.next(); @@ -747,12 +748,10 @@ Status MatchExpressionParser::_parseInExpression(InMatchExpression* inExpression if (!s.isOK()) return s; } else { - Status s = inExpression->addEquality(e); - if (!s.isOK()) - return s; + equalities.push_back(e); } } - return Status::OK(); + return inExpression->setEqualities(std::move(equalities)); } StatusWith<std::unique_ptr<TypeMatchExpression>> MatchExpressionParser::parseTypeFromAlias( diff --git a/src/mongo/db/query/canonical_query_test.cpp b/src/mongo/db/query/canonical_query_test.cpp index 5428386103f..542f1ac2477 100644 --- a/src/mongo/db/query/canonical_query_test.cpp +++ b/src/mongo/db/query/canonical_query_test.cpp @@ -550,7 +550,8 @@ TEST(CanonicalQueryTest, NormalizeWithInPreservesCollator) { BSONObj obj = fromjson("{'': 'string'}"); auto inMatchExpression = stdx::make_unique<InMatchExpression>(); inMatchExpression->setCollator(&collator); - inMatchExpression->addEquality(obj.firstElement()).transitional_ignore(); + std::vector<BSONElement> equalities{obj.firstElement()}; + ASSERT_OK(inMatchExpression->setEqualities(std::move(equalities))); unique_ptr<MatchExpression> matchExpression( CanonicalQuery::normalizeTree(inMatchExpression.release())); ASSERT(matchExpression->matchType() == MatchExpression::MatchType::EQ); |