diff options
author | Tess Avitabile <tess.avitabile@mongodb.com> | 2017-09-05 17:34:32 -0400 |
---|---|---|
committer | Tess Avitabile <tess.avitabile@mongodb.com> | 2017-09-06 14:26:51 -0400 |
commit | 7dbfca42c49e27bc2d2b40e92d128fd0239041f7 (patch) | |
tree | 8eb0c4cfe1bceafcd48b38e3cb98b4586553e74d /src | |
parent | ed601dd01169b8c1fad9fb8d388da0523a1b48f5 (diff) | |
download | mongo-7dbfca42c49e27bc2d2b40e92d128fd0239041f7.tar.gz |
SERVER-30954 Remove support for expr constant expressions from ComparisonMatchExpression
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.h | 32 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf_test.cpp | 127 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser.cpp | 108 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser.h | 34 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_geo_test.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_leaf_test.cpp | 459 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_test.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_tree.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_with_placeholder_test.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/ops/modifier_pull_test.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/query/parsed_projection_test.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/update/pull_node_test.cpp | 3 | ||||
-rw-r--r-- | src/mongo/dbtests/extensions_callback_real_test.cpp | 9 |
14 files changed, 86 insertions, 776 deletions
diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp index 7ba272ea224..f3d00d40e01 100644 --- a/src/mongo/db/matcher/expression_leaf.cpp +++ b/src/mongo/db/matcher/expression_leaf.cpp @@ -59,15 +59,15 @@ bool ComparisonMatchExpression::equivalent(const MatchExpression* other) const { const StringData::ComparatorInterface* stringComparator = nullptr; BSONElementComparator eltCmp(BSONElementComparator::FieldNamesMode::kIgnore, stringComparator); - return path() == realOther->path() && eltCmp.evaluate(_rhsElem == realOther->_rhsElem); + return path() == realOther->path() && eltCmp.evaluate(_rhs == realOther->_rhs); } -Status ComparisonMatchExpression::_validate() { - if (!_rhsElem) { - return Status(ErrorCodes::BadValue, "need a real operand"); - } +Status ComparisonMatchExpression::init(StringData path, const BSONElement& rhs) { + _rhs = rhs; + + invariant(_rhs); - if (_rhsElem.type() == BSONType::Undefined) { + if (_rhs.type() == BSONType::Undefined) { return Status(ErrorCodes::BadValue, "cannot compare to undefined"); } @@ -82,50 +82,19 @@ Status ComparisonMatchExpression::_validate() { return Status(ErrorCodes::BadValue, "bad match type for ComparisonMatchExpression"); } - return Status::OK(); -} - -Status ComparisonMatchExpression::init(StringData path, - const boost::intrusive_ptr<Expression>& rhsExpr) { - auto exprConstant = dynamic_cast<ExpressionConstant*>(rhsExpr.get()); - if (exprConstant) { - BSONObjBuilder bob; - bob << path << exprConstant->getValue(); - _resolvedRhsExpr = bob.obj(); - _rhsElem = _resolvedRhsExpr.firstElement(); - } else { - return Status(ErrorCodes::BadValue, "$expr does not yet handle non-constant expressions"); - } - - auto status = _validate(); - if (!status.isOK()) { - return status; - } - - return setPath(path); -} - -Status ComparisonMatchExpression::init(StringData path, const BSONElement& rhs) { - _rhsElem = rhs; - - auto status = _validate(); - if (!status.isOK()) { - return status; - } - return setPath(path); } bool ComparisonMatchExpression::matchesSingleElement(const BSONElement& e, MatchDetails* details) const { - if (e.canonicalType() != _rhsElem.canonicalType()) { + if (e.canonicalType() != _rhs.canonicalType()) { // some special cases // jstNULL and undefined are treated the same - if (e.canonicalType() + _rhsElem.canonicalType() == 5) { + if (e.canonicalType() + _rhs.canonicalType() == 5) { return matchType() == EQ || matchType() == LTE || matchType() == GTE; } - if (_rhsElem.type() == MaxKey || _rhsElem.type() == MinKey) { + if (_rhs.type() == MaxKey || _rhs.type() == MinKey) { return matchType() != EQ; } return false; @@ -133,8 +102,8 @@ bool ComparisonMatchExpression::matchesSingleElement(const BSONElement& e, // Special case handling for NaN. NaN is equal to NaN but // otherwise always compares to false. - if (std::isnan(e.numberDouble()) || std::isnan(_rhsElem.numberDouble())) { - bool bothNaN = std::isnan(e.numberDouble()) && std::isnan(_rhsElem.numberDouble()); + if (std::isnan(e.numberDouble()) || std::isnan(_rhs.numberDouble())) { + bool bothNaN = std::isnan(e.numberDouble()) && std::isnan(_rhs.numberDouble()); switch (matchType()) { case LT: return false; @@ -153,7 +122,7 @@ bool ComparisonMatchExpression::matchesSingleElement(const BSONElement& e, } } - int x = compareElementValues(e, _rhsElem, _collator); + int x = compareElementValues(e, _rhs, _collator); switch (matchType()) { case LT: @@ -195,7 +164,7 @@ void ComparisonMatchExpression::debugString(StringBuilder& debug, int level) con default: invariant(false); } - debug << " " << _rhsElem.toString(false); + debug << " " << _rhs.toString(false); MatchExpression::TagData* td = getTag(); if (NULL != td) { @@ -228,7 +197,7 @@ void ComparisonMatchExpression::serialize(BSONObjBuilder* out) const { invariant(false); } - out->append(path(), BSON(opString << _rhsElem)); + out->append(path(), BSON(opString << _rhs)); } // --------------- diff --git a/src/mongo/db/matcher/expression_leaf.h b/src/mongo/db/matcher/expression_leaf.h index 75c6421ddd6..eb573debe5c 100644 --- a/src/mongo/db/matcher/expression_leaf.h +++ b/src/mongo/db/matcher/expression_leaf.h @@ -33,7 +33,6 @@ #include "mongo/bson/bsonobj.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_path.h" -#include "mongo/db/pipeline/expression.h" #include "mongo/db/query/collation/collator_interface.h" #include "mongo/stdx/memory.h" #include "mongo/stdx/unordered_map.h" @@ -69,7 +68,6 @@ public: explicit ComparisonMatchExpression(MatchType type) : LeafMatchExpression(type) {} Status init(StringData path, const BSONElement& rhs); - Status init(StringData path, const boost::intrusive_ptr<Expression>& rhsExpr); virtual ~ComparisonMatchExpression() {} @@ -77,19 +75,12 @@ public: virtual void debugString(StringBuilder& debug, int level = 0) const; - /** - * 'collator' must outlive the ComparisonMatchExpression and any clones made of it. - */ - virtual void _doSetCollator(const CollatorInterface* collator) { - _collator = collator; - } - virtual void serialize(BSONObjBuilder* out) const; virtual bool equivalent(const MatchExpression* other) const; const BSONElement& getData() const { - return _rhsElem; + return _rhs; } const CollatorInterface* getCollator() const { @@ -113,11 +104,14 @@ public: } protected: - Status _validate(); - - BSONElement _rhsElem; + /** + * 'collator' must outlive the ComparisonMatchExpression and any clones made of it. + */ + virtual void _doSetCollator(const CollatorInterface* collator) { + _collator = collator; + } - BSONObj _resolvedRhsExpr; + BSONElement _rhs; // Collator used to compare elements. By default, simple binary comparison will be used. const CollatorInterface* _collator = nullptr; @@ -128,7 +122,7 @@ public: EqualityMatchExpression() : ComparisonMatchExpression(EQ) {} virtual std::unique_ptr<MatchExpression> shallowClone() const { std::unique_ptr<ComparisonMatchExpression> e = stdx::make_unique<EqualityMatchExpression>(); - invariantOK(e->init(path(), _rhsElem)); + invariantOK(e->init(path(), _rhs)); if (getTag()) { e->setTag(getTag()->clone()); } @@ -142,7 +136,7 @@ public: LTEMatchExpression() : ComparisonMatchExpression(LTE) {} virtual std::unique_ptr<MatchExpression> shallowClone() const { std::unique_ptr<ComparisonMatchExpression> e = stdx::make_unique<LTEMatchExpression>(); - invariantOK(e->init(path(), _rhsElem)); + invariantOK(e->init(path(), _rhs)); if (getTag()) { e->setTag(getTag()->clone()); } @@ -156,7 +150,7 @@ public: LTMatchExpression() : ComparisonMatchExpression(LT) {} virtual std::unique_ptr<MatchExpression> shallowClone() const { std::unique_ptr<ComparisonMatchExpression> e = stdx::make_unique<LTMatchExpression>(); - invariantOK(e->init(path(), _rhsElem)); + invariantOK(e->init(path(), _rhs)); if (getTag()) { e->setTag(getTag()->clone()); } @@ -170,7 +164,7 @@ public: GTMatchExpression() : ComparisonMatchExpression(GT) {} virtual std::unique_ptr<MatchExpression> shallowClone() const { std::unique_ptr<ComparisonMatchExpression> e = stdx::make_unique<GTMatchExpression>(); - invariantOK(e->init(path(), _rhsElem)); + invariantOK(e->init(path(), _rhs)); if (getTag()) { e->setTag(getTag()->clone()); } @@ -184,7 +178,7 @@ public: GTEMatchExpression() : ComparisonMatchExpression(GTE) {} virtual std::unique_ptr<MatchExpression> shallowClone() const { std::unique_ptr<ComparisonMatchExpression> e = stdx::make_unique<GTEMatchExpression>(); - invariantOK(e->init(path(), _rhsElem)); + invariantOK(e->init(path(), _rhs)); if (getTag()) { e->setTag(getTag()->clone()); } diff --git a/src/mongo/db/matcher/expression_leaf_test.cpp b/src/mongo/db/matcher/expression_leaf_test.cpp index eddc44b9e0b..f49c586641a 100644 --- a/src/mongo/db/matcher/expression_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_leaf_test.cpp @@ -35,8 +35,8 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/pipeline/aggregation_context_fixture.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/unittest/death_test.h" namespace mongo { @@ -97,31 +97,10 @@ TEST(EqOp, MatchesElement) { ASSERT(eq.equivalent(&eq)); } -TEST(EqOp, ConstantAggExprMatchesElement) { - BSONObj operand = BSON("a" << BSON("$expr" - << "$$userVar")); - BSONObj match = BSON("a" << 5); - BSONObj notMatch = BSON("a" << 6); - - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(5)); - auto expr = Expression::parseOperand( - expCtx, operand.firstElement()["$expr"], expCtx->variablesParseState); - expr = expr->optimize(); - - EqualityMatchExpression eq; - ASSERT_OK(eq.init("a", expr)); - ASSERT(eq.matchesSingleElement(match.firstElement())); - ASSERT_FALSE(eq.matchesSingleElement(notMatch.firstElement())); - - ASSERT(eq.equivalent(&eq)); -} - -TEST(EqOp, InvalidEooOperand) { +DEATH_TEST(EqOp, InvalidEooOperand, "Invariant failure _rhs") { BSONObj operand; EqualityMatchExpression eq; - ASSERT_FALSE(eq.init("", operand.firstElement()).isOK()); + eq.init("", operand.firstElement()).ignore(); } TEST(EqOp, MatchesScalar) { @@ -339,10 +318,10 @@ TEST(LtOp, MatchesElement) { ASSERT(!lt.matchesSingleElement(notMatchWrongType.firstElement())); } -TEST(LtOp, InvalidEooOperand) { +DEATH_TEST(LtOp, InvalidEooOperand, "Invariant failure _rhs") { BSONObj operand; LTMatchExpression lt; - ASSERT(!lt.init("", operand.firstElement()).isOK()); + lt.init("", operand.firstElement()).ignore(); } TEST(LtOp, MatchesScalar) { @@ -440,27 +419,6 @@ TEST(LtOp, ElemMatchKey) { ASSERT_EQUALS("1", details.elemMatchKey()); } -TEST(LtOp, ConstantAggExprMatchesElement) { - BSONObj operand = BSON("a" << BSON("$lt" << BSON("$expr" - << "$$userVar"))); - BSONObj match = BSON("a" << 5); - BSONObj notMatch = BSON("a" << 10); - - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(6)); - auto expr = Expression::parseOperand( - expCtx, operand.firstElement()["$lt"]["$expr"], expCtx->variablesParseState); - expr = expr->optimize(); - - LTMatchExpression lt; - ASSERT_OK(lt.init("a", expr)); - ASSERT(lt.matchesSingleElement(match.firstElement())); - ASSERT_FALSE(lt.matchesSingleElement(notMatch.firstElement())); - - ASSERT(lt.equivalent(<)); -} - /** TEST( LtOp, MatchesIndexKeyScalar ) { BSONObj operand = BSON( "$lt" << 6 ); @@ -526,31 +484,10 @@ TEST(LteOp, MatchesElement) { ASSERT(!lte.matchesSingleElement(notMatchWrongType.firstElement())); } -TEST(LteOp, ConstantAggExprMatchesElement) { - BSONObj operand = BSON("a" << BSON("$lte" << BSON("$expr" - << "$$userVar"))); - BSONObj match = BSON("a" << 5); - BSONObj notMatch = BSON("a" << 10); - - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(6)); - auto expr = Expression::parseOperand( - expCtx, operand.firstElement()["$lte"]["$expr"], expCtx->variablesParseState); - expr = expr->optimize(); - - LTEMatchExpression lte; - ASSERT_OK(lte.init("a", expr)); - ASSERT(lte.matchesSingleElement(match.firstElement())); - ASSERT_FALSE(lte.matchesSingleElement(notMatch.firstElement())); - - ASSERT(lte.equivalent(<e)); -} - -TEST(LteOp, InvalidEooOperand) { +DEATH_TEST(LteOp, InvalidEooOperand, "Invariant failure _rhs") { BSONObj operand; LTEMatchExpression lte; - ASSERT(!lte.init("", operand.firstElement()).isOK()); + lte.init("", operand.firstElement()).ignore(); } TEST(LteOp, MatchesScalar) { @@ -706,10 +643,10 @@ TEST(LteOp, ElemMatchKey) { } */ -TEST(GtOp, InvalidEooOperand) { +DEATH_TEST(GtOp, InvalidEooOperand, "Invariant failure _rhs") { BSONObj operand; GTMatchExpression gt; - ASSERT(!gt.init("", operand.firstElement()).isOK()); + gt.init("", operand.firstElement()).ignore(); } TEST(GtOp, MatchesScalar) { @@ -801,27 +738,6 @@ TEST(GtOp, ElemMatchKey) { ASSERT_EQUALS("1", details.elemMatchKey()); } -TEST(GtOp, ConstantAggExprMatchesElement) { - BSONObj operand = BSON("a" << BSON("$gt" << BSON("$expr" - << "$$userVar"))); - BSONObj match = BSON("a" << 10); - BSONObj notMatch = BSON("a" << 0); - - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(5)); - auto expr = Expression::parseOperand( - expCtx, operand.firstElement()["$gt"]["$expr"], expCtx->variablesParseState); - expr = expr->optimize(); - - GTMatchExpression gt; - ASSERT_OK(gt.init("a", expr)); - ASSERT(gt.matchesSingleElement(match.firstElement())); - ASSERT_FALSE(gt.matchesSingleElement(notMatch.firstElement())); - - ASSERT(gt.equivalent(>)); -} - /** TEST( GtOp, MatchesIndexKeyScalar ) { BSONObj operand = BSON( "$gt" << 6 ); @@ -888,10 +804,10 @@ TEST(GteOp, MatchesElement) { ASSERT(!gte.matchesSingleElement(notMatchWrongType.firstElement())); } -TEST(GteOp, InvalidEooOperand) { +DEATH_TEST(GteOp, InvalidEooOperand, "Invariant failure _rhs") { BSONObj operand; GTEMatchExpression gte; - ASSERT(!gte.init("", operand.firstElement()).isOK()); + gte.init("", operand.firstElement()).ignore(); } TEST(GteOp, MatchesScalar) { @@ -982,27 +898,6 @@ TEST(GteOp, ElemMatchKey) { ASSERT_EQUALS("1", details.elemMatchKey()); } -TEST(GteOp, ConstantAggExprMatchesElement) { - BSONObj operand = BSON("a" << BSON("$gte" << BSON("$expr" - << "$$userVar"))); - BSONObj match = BSON("a" << 10); - BSONObj notMatch = BSON("a" << 0); - - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(5)); - auto expr = Expression::parseOperand( - expCtx, operand.firstElement()["$gte"]["$expr"], expCtx->variablesParseState); - expr = expr->optimize(); - - GTEMatchExpression gte; - ASSERT_OK(gte.init("a", expr)); - ASSERT(gte.matchesSingleElement(match.firstElement())); - ASSERT_FALSE(gte.matchesSingleElement(notMatch.firstElement())); - - ASSERT(gte.equivalent(>e)); -} - TEST(RegexMatchExpression, MatchesElementExact) { BSONObj match = BSON("a" << "b"); diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index 4f995fbfa4e..2f2263e841e 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -115,20 +115,9 @@ StatusWithMatchExpression MatchExpressionParser::_parseComparison( return {Status(ErrorCodes::BadValue, ss)}; } - if (_isAggExpression(e, expCtx)) { - auto expr = _parseAggExpression(e, expCtx, allowedFeatures); - if (!expr.isOK()) { - return expr.getStatus(); - } - auto s = temp->init(name, expr.getValue()); - if (!s.isOK()) { - return s; - } - } else { - auto s = temp->init(name, e); - if (!s.isOK()) { - return s; - } + auto s = temp->init(name, e); + if (!s.isOK()) { + return s; } temp->setCollator(collator); @@ -278,10 +267,10 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( } case PathAcceptingKeyword::TYPE: - return _parseType<TypeMatchExpression>(name, e, expCtx); + return _parseType<TypeMatchExpression>(name, e); case PathAcceptingKeyword::MOD: - return _parseMOD(name, e, expCtx); + return _parseMOD(name, e); case PathAcceptingKeyword::OPTIONS: { // TODO: try to optimize this @@ -299,7 +288,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( } case PathAcceptingKeyword::REGEX: { - return _parseRegexDocument(name, context, expCtx); + return _parseRegexDocument(name, context); } case PathAcceptingKeyword::ELEM_MATCH: @@ -319,19 +308,19 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( // Handles bitwise query operators. case PathAcceptingKeyword::BITS_ALL_SET: { - return _parseBitTest<BitsAllSetMatchExpression>(name, e, expCtx); + return _parseBitTest<BitsAllSetMatchExpression>(name, e); } case PathAcceptingKeyword::BITS_ALL_CLEAR: { - return _parseBitTest<BitsAllClearMatchExpression>(name, e, expCtx); + return _parseBitTest<BitsAllClearMatchExpression>(name, e); } case PathAcceptingKeyword::BITS_ANY_SET: { - return _parseBitTest<BitsAnySetMatchExpression>(name, e, expCtx); + return _parseBitTest<BitsAnySetMatchExpression>(name, e); } case PathAcceptingKeyword::BITS_ANY_CLEAR: { - return _parseBitTest<BitsAnyClearMatchExpression>(name, e, expCtx); + return _parseBitTest<BitsAnyClearMatchExpression>(name, e); } case PathAcceptingKeyword::INTERNAL_SCHEMA_FMOD: @@ -452,7 +441,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseSubField( } case PathAcceptingKeyword::INTERNAL_SCHEMA_TYPE: { - return _parseType<InternalSchemaTypeExpression>(name, e, expCtx); + return _parseType<InternalSchemaTypeExpression>(name, e); } } @@ -623,7 +612,7 @@ StatusWithMatchExpression MatchExpressionParser::_parse( continue; } - if (_isExpressionDocument(e, false, expCtx)) { + if (_isExpressionDocument(e, false)) { Status s = _parseSub(e.fieldName(), e.Obj(), root.get(), @@ -637,7 +626,7 @@ StatusWithMatchExpression MatchExpressionParser::_parse( } if (e.type() == RegEx) { - StatusWithMatchExpression result = _parseRegexElement(e.fieldName(), e, expCtx); + StatusWithMatchExpression result = _parseRegexElement(e.fieldName(), e); if (!result.isOK()) return result; root->add(result.getValue().release()); @@ -712,10 +701,7 @@ Status MatchExpressionParser::_parseSub(const char* name, return Status::OK(); } -bool MatchExpressionParser::_isExpressionDocument( - const BSONElement& e, - bool allowIncompleteDBRef, - const boost::intrusive_ptr<ExpressionContext>& expCtx) { +bool MatchExpressionParser::_isExpressionDocument(const BSONElement& e, bool allowIncompleteDBRef) { if (e.type() != Object) return false; @@ -731,10 +717,6 @@ bool MatchExpressionParser::_isExpressionDocument( return false; } - if (_isAggExpression(e, expCtx)) { - return false; - } - return true; } @@ -779,8 +761,7 @@ bool MatchExpressionParser::_isDBRefDocument(const BSONObj& obj, bool allowIncom return hasRef && hasID; } -StatusWithMatchExpression MatchExpressionParser::_parseMOD( - const char* name, const BSONElement& e, const boost::intrusive_ptr<ExpressionContext>& expCtx) { +StatusWithMatchExpression MatchExpressionParser::_parseMOD(const char* name, const BSONElement& e) { if (e.type() != Array) return {Status(ErrorCodes::BadValue, "malformed mod, needs to be an array")}; @@ -808,8 +789,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseMOD( return {std::move(temp)}; } -StatusWithMatchExpression MatchExpressionParser::_parseRegexElement( - const char* name, const BSONElement& e, const boost::intrusive_ptr<ExpressionContext>& expCtx) { +StatusWithMatchExpression MatchExpressionParser::_parseRegexElement(const char* name, + const BSONElement& e) { if (e.type() != RegEx) return {Status(ErrorCodes::BadValue, "not a regex")}; @@ -820,8 +801,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseRegexElement( return {std::move(temp)}; } -StatusWithMatchExpression MatchExpressionParser::_parseRegexDocument( - const char* name, const BSONObj& doc, const boost::intrusive_ptr<ExpressionContext>& expCtx) { +StatusWithMatchExpression MatchExpressionParser::_parseRegexDocument(const char* name, + const BSONObj& doc) { string regex; string regexOptions; @@ -874,7 +855,7 @@ Status MatchExpressionParser::_parseInExpression( BSONElement e = i.next(); // Allow DBRefs, but reject all fields with names starting with $. - if (_isExpressionDocument(e, false, expCtx)) { + if (_isExpressionDocument(e, false)) { return Status(ErrorCodes::BadValue, "cannot nest $ under $in"); } @@ -887,10 +868,6 @@ Status MatchExpressionParser::_parseInExpression( if (!s.isOK()) return s; } else { - if (_isAggExpression(e, expCtx)) { - return Status(ErrorCodes::BadValue, "$expr not supported for $in"); - } - equalities.push_back(e); } } @@ -898,10 +875,8 @@ Status MatchExpressionParser::_parseInExpression( } template <class T> -StatusWithMatchExpression MatchExpressionParser::_parseType( - const char* name, - const BSONElement& elt, - const boost::intrusive_ptr<ExpressionContext>& expCtx) { +StatusWithMatchExpression MatchExpressionParser::_parseType(const char* name, + const BSONElement& elt) { auto typeSet = MatcherTypeSet::parse(elt, MatcherTypeSet::kTypeAliasMap); if (!typeSet.isOK()) { return typeSet.getStatus(); @@ -943,7 +918,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( // 3) expression is not a WHERE operator. WHERE works on objects instead // of specific field. bool isElemMatchValue = false; - if (_isExpressionDocument(e, true, expCtx)) { + if (_isExpressionDocument(e, true)) { BSONObj o = e.Obj(); BSONElement elt = o.firstElement(); invariant(!elt.eoo()); @@ -1086,8 +1061,8 @@ StatusWithMatchExpression MatchExpressionParser::_parseAll( } template <class T> -StatusWithMatchExpression MatchExpressionParser::_parseBitTest( - const char* name, const BSONElement& e, const boost::intrusive_ptr<ExpressionContext>& expCtx) { +StatusWithMatchExpression MatchExpressionParser::_parseBitTest(const char* name, + const BSONElement& e) { std::unique_ptr<BitTestMatchExpression> bitTestMatchExpression = stdx::make_unique<T>(); if (e.type() == BSONType::Array) { @@ -1672,39 +1647,6 @@ StatusWithMatchExpression MatchExpressionParser::_parseGeo(const char* name, } } -bool MatchExpressionParser::_isAggExpression( - BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& expCtx) { - if (!expCtx) { - return false; - } - - if (BSONType::Object != elem.type()) { - return false; - } - - auto obj = elem.embeddedObject(); - if (obj.nFields() != 1) { - return false; - } - - return obj.firstElementFieldName() == kAggExpression; -} - -StatusWith<boost::intrusive_ptr<Expression>> MatchExpressionParser::_parseAggExpression( - BSONElement elem, - const boost::intrusive_ptr<ExpressionContext>& expCtx, - AllowedFeatureSet allowedFeatures) { - invariant(expCtx); - - if ((allowedFeatures & AllowedFeatures::kExpr) == 0u) { - return {Status(ErrorCodes::BadValue, "$expr is not allowed in this context")}; - } - - auto expr = Expression::parseOperand( - expCtx, elem.embeddedObject().firstElement(), expCtx->variablesParseState); - return expr->optimize(); -} - namespace { // Maps from query operator string name to operator PathAcceptingKeyword. std::unique_ptr<StringMap<PathAcceptingKeyword>> queryOperatorMap; diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h index 55ef95ddf4a..dc7b5041517 100644 --- a/src/mongo/db/matcher/expression_parser.h +++ b/src/mongo/db/matcher/expression_parser.h @@ -38,6 +38,7 @@ #include "mongo/db/matcher/expression_type.h" #include "mongo/db/matcher/extensions_callback.h" #include "mongo/db/matcher/extensions_callback_noop.h" +#include "mongo/db/pipeline/expression.h" #include "mongo/db/pipeline/expression_context.h" #include "mongo/stdx/functional.h" @@ -170,9 +171,7 @@ private: * { $id : "x" } = false (if incomplete DBRef is allowed) * { $db : "mydb" } = false (if incomplete DBRef is allowed) */ - bool _isExpressionDocument(const BSONElement& e, - bool allowIncompleteDBRef, - const boost::intrusive_ptr<ExpressionContext>& expCtx); + bool _isExpressionDocument(const BSONElement& e, bool allowIncompleteDBRef); /** * { $ref: "s", $id: "x" } = true @@ -232,19 +231,11 @@ private: const boost::intrusive_ptr<ExpressionContext>& expCtx, AllowedFeatureSet allowedFeatures); - StatusWithMatchExpression _parseMOD(const char* name, - const BSONElement& e, - const boost::intrusive_ptr<ExpressionContext>& expCtx); + StatusWithMatchExpression _parseMOD(const char* name, const BSONElement& e); - StatusWithMatchExpression _parseRegexElement( - const char* name, - const BSONElement& e, - const boost::intrusive_ptr<ExpressionContext>& expCtx); + StatusWithMatchExpression _parseRegexElement(const char* name, const BSONElement& e); - StatusWithMatchExpression _parseRegexDocument( - const char* name, - const BSONObj& doc, - const boost::intrusive_ptr<ExpressionContext>& expCtx); + StatusWithMatchExpression _parseRegexDocument(const char* name, const BSONObj& doc); Status _parseInExpression(InMatchExpression* entries, const BSONObj& theArray, @@ -252,9 +243,7 @@ private: const boost::intrusive_ptr<ExpressionContext>& expCtx); template <class T> - StatusWithMatchExpression _parseType(const char* name, - const BSONElement& elt, - const boost::intrusive_ptr<ExpressionContext>& expCtx); + StatusWithMatchExpression _parseType(const char* name, const BSONElement& elt); StatusWithMatchExpression _parseGeo(const char* name, PathAcceptingKeyword type, @@ -297,9 +286,7 @@ private: * Parses 'e' into a BitTestMatchExpression. */ template <class T> - StatusWithMatchExpression _parseBitTest(const char* name, - const BSONElement& e, - const boost::intrusive_ptr<ExpressionContext>& expCtx); + StatusWithMatchExpression _parseBitTest(const char* name, const BSONElement& e); /** * Converts 'theArray', a BSONArray of integers, into a std::vector of integers. @@ -341,13 +328,6 @@ private: StatusWithMatchExpression _parseInternalSchemaMatchArrayIndex( const char* path, const BSONElement& elem, const CollatorInterface* collator); - bool _isAggExpression(BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& expCtx); - - StatusWith<boost::intrusive_ptr<Expression>> _parseAggExpression( - BSONElement elem, - const boost::intrusive_ptr<ExpressionContext>& expCtx, - AllowedFeatureSet allowedFeatures); - StatusWithMatchExpression _parseInternalSchemaAllowedProperties( const BSONElement& elem, const CollatorInterface* collator); diff --git a/src/mongo/db/matcher/expression_parser_geo_test.cpp b/src/mongo/db/matcher/expression_parser_geo_test.cpp index b8a17a3ae2f..38ffdafe4da 100644 --- a/src/mongo/db/matcher/expression_parser_geo_test.cpp +++ b/src/mongo/db/matcher/expression_parser_geo_test.cpp @@ -59,23 +59,6 @@ TEST(MatchExpressionParserGeo, WithinBox) { ASSERT(result.getValue()->matchesBSON(fromjson("{a: {x: 5, y:5.1}}"))); } -TEST(MatchExpressionParserGeo, RejectsExprAsGeometry) { - const boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(fromjson("{type: 'Point', coordinates:[0,0]}}"))); - - BSONObj query = fromjson("{a:{$geoIntersects:{$geometry: {$expr: '$$userVar'} }}}"); - - const CollatorInterface* collator = nullptr; - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::kAllowAllSpecialFeatures); - ASSERT_NOT_OK(result.getStatus()); -} - TEST(MatchExpressionParserGeoNear, ParseNear) { BSONObj query = fromjson( "{loc:{$near:{$maxDistance:100, " diff --git a/src/mongo/db/matcher/expression_parser_leaf_test.cpp b/src/mongo/db/matcher/expression_parser_leaf_test.cpp index 6bf8a68857f..074825045b1 100644 --- a/src/mongo/db/matcher/expression_parser_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_parser_leaf_test.cpp @@ -34,7 +34,6 @@ #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/extensions_callback_noop.h" -#include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/platform/decimal128.h" #include "mongo/unittest/death_test.h" @@ -68,69 +67,6 @@ TEST(MatchExpressionParserLeafTest, Collation) { ASSERT_TRUE(match->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, ConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$expr" - << "$$userVar")); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); - - auto expr = result.getValue().get(); - - BSONObj match = BSON("x" << 123); - BSONObj notMatch = BSON("x" << 321); - - ASSERT_TRUE(expr->matchesBSON(match)); - ASSERT_FALSE(expr->matchesBSON(notMatch)); -} - -TEST(MatchExpressionParserLeafTest, ConstantExprFailsWithMissingVariable) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$expr" - << "$$userVar")); - - ASSERT_THROWS_CODE( - auto sw = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr), - AssertionException, - 17276); -} - -DEATH_TEST(MatchExpressionParserLeafTest, - ConstantExprFailsWithMissingExpressionContext, - "Invariant failure (allowedFeatures & AllowedFeatures::kExpr) == 0u") { - boost::intrusive_ptr<ExpressionContextForTest> nullExpCtx; - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$expr" - << "$$userVar")); - - auto result = MatchExpressionParser::parse(query, - collator, - nullExpCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - - ASSERT_NOT_OK(result.getStatus()); -} - TEST(MatchExpressionParserLeafTest, SimpleEQ2) { BSONObj query = BSON("x" << BSON("$eq" << 2)); const CollatorInterface* collator = nullptr; @@ -172,34 +108,6 @@ TEST(MatchExpressionParserLeafTest, EQCollation) { ASSERT_TRUE(match->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, EQConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$eq" << BSON("$expr" - << "$$userVar"))); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); - - auto expr = result.getValue().get(); - - BSONObj match = BSON("x" << 123); - BSONObj notMatch = BSON("x" << 321); - - ASSERT_TRUE(expr->matchesBSON(match)); - ASSERT_FALSE(expr->matchesBSON(notMatch)); -} - TEST(MatchExpressionParserLeafTest, SimpleGT1) { BSONObj query = BSON("x" << BSON("$gt" << 2)); const CollatorInterface* collator = nullptr; @@ -233,34 +141,6 @@ TEST(MatchExpressionParserLeafTest, GTCollation) { ASSERT_TRUE(match->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, GTConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$gt" << BSON("$expr" - << "$$userVar"))); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS(MatchExpression::GT, result.getValue()->matchType()); - - auto expr = result.getValue().get(); - - BSONObj match = BSON("x" << 500); - BSONObj notMatch = BSON("x" << 0); - - ASSERT_TRUE(expr->matchesBSON(match)); - ASSERT_FALSE(expr->matchesBSON(notMatch)); -} - TEST(MatchExpressionParserLeafTest, SimpleLT1) { BSONObj query = BSON("x" << BSON("$lt" << 2)); const CollatorInterface* collator = nullptr; @@ -295,34 +175,6 @@ TEST(MatchExpressionParserLeafTest, LTCollation) { ASSERT_TRUE(match->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, LTConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$lt" << BSON("$expr" - << "$$userVar"))); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS(MatchExpression::LT, result.getValue()->matchType()); - - auto expr = result.getValue().get(); - - BSONObj match = BSON("x" << 0); - BSONObj notMatch = BSON("x" << 500); - - ASSERT_TRUE(expr->matchesBSON(match)); - ASSERT_FALSE(expr->matchesBSON(notMatch)); -} - TEST(MatchExpressionParserLeafTest, SimpleGTE1) { BSONObj query = BSON("x" << BSON("$gte" << 2)); const CollatorInterface* collator = nullptr; @@ -357,36 +209,6 @@ TEST(MatchExpressionParserLeafTest, GTECollation) { ASSERT_TRUE(match->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, GTEConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$gte" << BSON("$expr" - << "$$userVar"))); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS(MatchExpression::GTE, result.getValue()->matchType()); - - auto expr = result.getValue().get(); - - BSONObj matchEq = BSON("x" << 123); - BSONObj matchGt = BSON("x" << 500); - BSONObj notMatch = BSON("x" << 0); - - ASSERT_TRUE(expr->matchesBSON(matchEq)); - ASSERT_TRUE(expr->matchesBSON(matchGt)); - ASSERT_FALSE(expr->matchesBSON(notMatch)); -} - TEST(MatchExpressionParserLeafTest, SimpleLTE1) { BSONObj query = BSON("x" << BSON("$lte" << 2)); const CollatorInterface* collator = nullptr; @@ -421,36 +243,6 @@ TEST(MatchExpressionParserLeafTest, LTECollation) { ASSERT_TRUE(match->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, LTEConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$lte" << BSON("$expr" - << "$$userVar"))); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS(MatchExpression::LTE, result.getValue()->matchType()); - - auto expr = result.getValue().get(); - - BSONObj matchEq = BSON("x" << 123); - BSONObj matchLt = BSON("x" << 0); - BSONObj notMatch = BSON("x" << 500); - - ASSERT_TRUE(expr->matchesBSON(matchEq)); - ASSERT_TRUE(expr->matchesBSON(matchLt)); - ASSERT_FALSE(expr->matchesBSON(notMatch)); -} - TEST(MatchExpressionParserLeafTest, SimpleNE1) { BSONObj query = BSON("x" << BSON("$ne" << 2)); const CollatorInterface* collator = nullptr; @@ -489,34 +281,6 @@ TEST(MatchExpressionParserLeafTest, NECollation) { ASSERT_TRUE(eqMatch->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, NEConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$ne" << BSON("$expr" - << "$$userVar"))); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS(MatchExpression::NOT, result.getValue()->matchType()); - - auto expr = result.getValue().get(); - - BSONObj match = BSON("x" << 0); - BSONObj notMatch = BSON("x" << 123); - - ASSERT_TRUE(expr->matchesBSON(match)); - ASSERT_FALSE(expr->matchesBSON(notMatch)); -} - TEST(MatchExpressionParserLeafTest, SimpleModBad1) { BSONObj query = BSON("x" << BSON("$mod" << BSON_ARRAY(3 << 2))); const CollatorInterface* collator = nullptr; @@ -568,25 +332,6 @@ TEST(MatchExpressionParserLeafTest, SimpleModNotNumber) { << "a"))); } -TEST(MatchExpressionParserLeafTest, ModConstantExprFails) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$mod" << BSON("$expr" - << "$$userVar"))); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(BSON_ARRAY(10 << 2))); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - ASSERT_NOT_OK(result.getStatus()); - ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); -} - TEST(MatchExpressionParserLeafTest, IdCollation) { BSONObj query = BSON("$id" << "string"); @@ -609,26 +354,6 @@ TEST(MatchExpressionParserLeafTest, IdNullCollation) { ASSERT_TRUE(match->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, IdConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("$id" << BSON("$expr" - << "$$userVar")); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - ASSERT_OK(result.getStatus()); - - ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); -} - TEST(MatchExpressionParserLeafTest, RefCollation) { BSONObj query = BSON("$ref" << "coll"); @@ -640,26 +365,6 @@ TEST(MatchExpressionParserLeafTest, RefCollation) { ASSERT_TRUE(match->getCollator() == nullptr); } -TEST(MatchExpressionParserLeafTest, RefConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("$ref" << BSON("$expr" - << "$$userVar")); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(std::string("colName"))); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - ASSERT_OK(result.getStatus()); - - ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); -} - TEST(MatchExpressionParserLeafTest, DbCollation) { BSONObj query = BSON("$db" << "db"); @@ -671,26 +376,6 @@ TEST(MatchExpressionParserLeafTest, DbCollation) { ASSERT_TRUE(match->getCollator() == nullptr); } -TEST(MatchExpressionParserLeafTest, DbConstantExpr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("$db" << BSON("$expr" - << "$$userVar")); - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(std::string("dbName"))); - - auto result = MatchExpressionParser::parse(query, - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - ASSERT_OK(result.getStatus()); - - ASSERT_EQUALS(MatchExpression::EQ, result.getValue()->matchType()); -} - TEST(MatchExpressionParserLeafTest, SimpleIN1) { BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(2 << 3))); const CollatorInterface* collator = nullptr; @@ -722,40 +407,6 @@ TEST(MatchExpressionParserLeafTest, INCollation) { ASSERT_TRUE(match->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, INConstantExprFails) { - CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - - // $expr represents entire $in array. - BSONObj query = BSON("x" << BSON("$in" << BSON("$expr" - << "userVar"))); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(BSON_ARRAY(1 << 2))); - - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, - &collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - ASSERT_NOT_OK(result.getStatus()); - ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); - - // $expr represents a single element of the $in array. - query = BSON("x" << BSON("$in" << BSON_ARRAY(1 << BSON("$expr" - << "userVar")))); - varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - result = MatchExpressionParser::parse(query, - &collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - ASSERT_NOT_OK(result.getStatus()); - ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); -} - TEST(MatchExpressionParserLeafTest, INSingleDBRef) { OID oid = OID::gen(); BSONObj query = BSON("x" << BSON("$in" << BSON_ARRAY(BSON("$ref" @@ -1173,40 +824,6 @@ TEST(MatchExpressionParserLeafTest, NINCollation) { ASSERT_TRUE(inMatch->getCollator() == &collator); } -TEST(MatchExpressionParserLeafTest, NINConstantExprFails) { - CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - - // $expr represents entire $in array. - BSONObj query = BSON("x" << BSON("$nin" << BSON("$expr" - << "userVar"))); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(BSON_ARRAY(1 << 2))); - - StatusWithMatchExpression result = - MatchExpressionParser::parse(query, - &collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - ASSERT_NOT_OK(result.getStatus()); - ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); - - // $expr represents a single element of the $in array. - query = BSON("x" << BSON("$nin" << BSON_ARRAY(1 << BSON("$expr" - << "userVar")))); - varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(123)); - - result = MatchExpressionParser::parse(query, - &collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr); - ASSERT_NOT_OK(result.getStatus()); - ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); -} - TEST(MatchExpressionParserLeafTest, Regex1) { BSONObjBuilder b; b.appendRegex("x", "abc", "i"); @@ -1300,33 +917,6 @@ TEST(MatchExpressionParserLeafTest, RegexEmbeddedNULByte) { << "a"))); } -TEST(MatchExpressionParserLeafTest, RegexWithConstantExprFails) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$options" << BSON("$expr" - << "userVar") - << "$regex" - << "abc")); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(std::string("i"))); - - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); - ASSERT_NOT_OK(result.getStatus()); - - - query = BSON("x" << BSON("$options" - << "i" - << "$regex" - << BSON("$expr" - << "userVar"))); - varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(std::string("abc"))); - - result = MatchExpressionParser::parse(query, collator); - ASSERT_NOT_OK(result.getStatus()); -} - TEST(MatchExpressionParserLeafTest, ExistsYes1) { BSONObjBuilder b; b.appendBool("$exists", true); @@ -1647,19 +1237,6 @@ TEST(MatchExpressionParserLeafTest, ValidTypeCodesParseSuccessfully) { } } -TEST(MatchExpressionParserLeafTest, TypeWithConstantExprFails) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - BSONObj query = BSON("x" << BSON("$type" << BSON("$expr" - << "userVar"))); - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(static_cast<int>(BSONType::NumberDouble))); - - StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator); - ASSERT_NOT_OK(result.getStatus()); -} - TEST(MatchExpressionParserTest, BitTestMatchExpressionValidMask) { const double k2Power53 = scalbn(1, 32); @@ -2110,40 +1687,4 @@ TEST(MatchExpressionParserTest, BitTestMatchExpressionInvalidArrayValue) { collator) .getStatus()); } - -TEST(MatchExpressionParserLeafTest, BitTestWithConstantExprFails) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - const CollatorInterface* collator = nullptr; - - auto varId = expCtx->variablesParseState.defineVariable("userVar"); - expCtx->variables.setValue(varId, Value(BSON_ARRAY(1 << 5))); - - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllSet: [{$expr: 'userVar'}]}}"), - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); - - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnySet: {$expr: 'userVar'}}}"), - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); - - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAllClear: {$expr: 'userVar'}}}"), - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); - - ASSERT_NOT_OK(MatchExpressionParser::parse(fromjson("{a: {$bitsAnyClear: {$expr: 'userVar'}}}"), - collator, - expCtx, - ExtensionsCallbackNoop(), - MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); -} } // namespace mongo diff --git a/src/mongo/db/matcher/expression_parser_test.cpp b/src/mongo/db/matcher/expression_parser_test.cpp index 9f0276b7028..e4d0e67b388 100644 --- a/src/mongo/db/matcher/expression_parser_test.cpp +++ b/src/mongo/db/matcher/expression_parser_test.cpp @@ -372,6 +372,8 @@ TEST(MatchExpressionParserTest, NearParsesSuccessfullyWhenAllowed) { .getStatus()); } +// TODO SERVER-30951: Convert these tests to use top-level $expr and enable them. +/* TEST(MatchExpressionParserTest, ExprFailsToParseWhenDisallowed) { auto query = fromjson("{a: {$expr: 5}}"); const CollatorInterface* collator = nullptr; @@ -389,4 +391,5 @@ TEST(MatchExpressionParserTest, ExprParsesSuccessfullyWhenAllowed) { MatchExpressionParser::AllowedFeatures::kExpr) .getStatus()); } +*/ } diff --git a/src/mongo/db/matcher/expression_parser_tree.cpp b/src/mongo/db/matcher/expression_parser_tree.cpp index 1e4290fcdc9..58365df9ff6 100644 --- a/src/mongo/db/matcher/expression_parser_tree.cpp +++ b/src/mongo/db/matcher/expression_parser_tree.cpp @@ -73,7 +73,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseNot( AllowedFeatureSet allowedFeatures, bool topLevel) { if (e.type() == RegEx) { - StatusWithMatchExpression s = _parseRegexElement(name, e, expCtx); + StatusWithMatchExpression s = _parseRegexElement(name, e); if (!s.isOK()) return s; std::unique_ptr<NotMatchExpression> n = stdx::make_unique<NotMatchExpression>(); diff --git a/src/mongo/db/matcher/expression_with_placeholder_test.cpp b/src/mongo/db/matcher/expression_with_placeholder_test.cpp index 06460455dc7..5609755d89b 100644 --- a/src/mongo/db/matcher/expression_with_placeholder_test.cpp +++ b/src/mongo/db/matcher/expression_with_placeholder_test.cpp @@ -236,12 +236,15 @@ TEST(ExpressionWithPlaceholderTest, GeoNearExpressionFailsToParse) { ASSERT_NOT_OK(status.getStatus()); } +// TODO SERVER-30951: Convert this test to use top-level $expr and enable it. +/* TEST(ExpressionWithPlaceholderTest, ExprExpressionFailsToParse) { const CollatorInterface* collator = nullptr; auto rawFilter = fromjson("{i: {$expr: 5}}"); auto status = ExpressionWithPlaceholder::parse(rawFilter, collator); ASSERT_NOT_OK(status.getStatus()); } +*/ TEST(ExpressionWithPlaceholderTest, EquivalentIfPlaceholderAndExpressionMatch) { constexpr auto collator = nullptr; diff --git a/src/mongo/db/ops/modifier_pull_test.cpp b/src/mongo/db/ops/modifier_pull_test.cpp index afefb4349ed..2870bf0ade1 100644 --- a/src/mongo/db/ops/modifier_pull_test.cpp +++ b/src/mongo/db/ops/modifier_pull_test.cpp @@ -121,6 +121,8 @@ TEST(SimpleMod, InitWithGeoNearObjectFails) { ASSERT_EQUALS(ErrorCodes::BadValue, status); } +// TODO SERVER-30951: Convert these tests to use top-level $expr and enable them. +/* TEST(SimpleMod, InitWithExprElemFails) { auto update = fromjson("{$pull: {a: {$expr: 5}}}"); const CollatorInterface* collator = nullptr; @@ -138,6 +140,7 @@ TEST(SimpleMod, InitWithExprObjectFails) { ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } +*/ TEST(SimpleMod, PrepareOKTargetNotFound) { Document doc(fromjson("{}")); diff --git a/src/mongo/db/query/parsed_projection_test.cpp b/src/mongo/db/query/parsed_projection_test.cpp index 22046f8b531..5d433bb4416 100644 --- a/src/mongo/db/query/parsed_projection_test.cpp +++ b/src/mongo/db/query/parsed_projection_test.cpp @@ -172,9 +172,12 @@ TEST(ParsedProjectionTest, InvalidElemMatchGeoNearProjection) { "{a: {$elemMatch: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}"); } +// TODO SERVER-30951: Convert this test to use top-level $expr and enable it. +/* TEST(ParsedProjectionTest, InvalidElemMatchExprProjection) { assertInvalidProjection("{}", "{a: {$elemMatch: {$expr: 5}}}"); } +*/ TEST(ParsedProjectionTest, ValidPositionalOperatorProjections) { createParsedProjection("{a: 1}", "{'a.$': 1}"); diff --git a/src/mongo/db/update/pull_node_test.cpp b/src/mongo/db/update/pull_node_test.cpp index 0fa4c83dcc0..a00a80e394e 100644 --- a/src/mongo/db/update/pull_node_test.cpp +++ b/src/mongo/db/update/pull_node_test.cpp @@ -101,6 +101,8 @@ TEST(PullNodeTest, InitWithGeoNearObjectFails) { ASSERT_EQUALS(ErrorCodes::BadValue, status); } +// TODO SERVER-30951: Convert these tests to use top-level $expr and enable them. +/* TEST(PullNodeTest, InitWithExprElemFails) { auto update = fromjson("{$pull: {a: {$expr: 5}}}"); const CollatorInterface* collator = nullptr; @@ -118,6 +120,7 @@ TEST(PullNodeTest, InitWithExprObjectFails) { ASSERT_NOT_OK(status); ASSERT_EQUALS(ErrorCodes::BadValue, status); } +*/ TEST_F(PullNodeTest, TargetNotFound) { auto update = fromjson("{$pull : {a: {$lt: 1}}}"); diff --git a/src/mongo/dbtests/extensions_callback_real_test.cpp b/src/mongo/dbtests/extensions_callback_real_test.cpp index 9c0105299d9..7ea4e6a4af0 100644 --- a/src/mongo/dbtests/extensions_callback_real_test.cpp +++ b/src/mongo/dbtests/extensions_callback_real_test.cpp @@ -86,15 +86,6 @@ TEST_F(ExtensionsCallbackRealTest, TextNoIndex) { ASSERT_EQ(ErrorCodes::IndexNotFound, result.getStatus()); } -TEST_F(ExtensionsCallbackRealTest, TextRejectsExpr) { - BSONObj query = fromjson("{$text: {$expr: '$$userVar'}}"); - StatusWithMatchExpression result = - ExtensionsCallbackReal(&_opCtx, &_nss).parseText(query.firstElement()); - - ASSERT_NOT_OK(result.getStatus()); - ASSERT_EQ(ErrorCodes::NoSuchKey, result.getStatus()); -} - TEST_F(ExtensionsCallbackRealTest, TextBasic) { ASSERT_OK(dbtests::createIndex(&_opCtx, _nss.ns(), |