diff options
Diffstat (limited to 'src/mongo/db/matcher')
-rw-r--r-- | src/mongo/db/matcher/expression_expr.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_expr.h | 2 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_expr_test.cpp | 23 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser.h | 3 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_test.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_with_placeholder.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_with_placeholder_test.cpp | 9 |
8 files changed, 51 insertions, 17 deletions
diff --git a/src/mongo/db/matcher/expression_expr.cpp b/src/mongo/db/matcher/expression_expr.cpp index 8963dd003d8..77349430e46 100644 --- a/src/mongo/db/matcher/expression_expr.cpp +++ b/src/mongo/db/matcher/expression_expr.cpp @@ -64,6 +64,10 @@ bool ExprMatchExpression::equivalent(const MatchExpression* other) const { realOther->_expression->serialize(false)); } +void ExprMatchExpression::_doSetCollator(const CollatorInterface* collator) { + _expCtx->setCollator(collator); +} + std::unique_ptr<MatchExpression> ExprMatchExpression::shallowClone() const { // TODO SERVER-31003: Replace Expression clone via serialization with Expression::clone(). diff --git a/src/mongo/db/matcher/expression_expr.h b/src/mongo/db/matcher/expression_expr.h index e97cce982dc..1a09e2a9334 100644 --- a/src/mongo/db/matcher/expression_expr.h +++ b/src/mongo/db/matcher/expression_expr.h @@ -85,6 +85,8 @@ public: private: ExpressionOptimizerFunc getOptimizer() const final; + void _doSetCollator(const CollatorInterface* collator) final; + void _doAddDependencies(DepsTracker* deps) const final { if (_expression) { _expression->addDependencies(deps); diff --git a/src/mongo/db/matcher/expression_expr_test.cpp b/src/mongo/db/matcher/expression_expr_test.cpp index 3ad0ac4340e..e89ef9a5c39 100644 --- a/src/mongo/db/matcher/expression_expr_test.cpp +++ b/src/mongo/db/matcher/expression_expr_test.cpp @@ -32,12 +32,15 @@ #include "mongo/db/matcher/expression_expr.h" #include "mongo/db/matcher/matcher.h" #include "mongo/db/pipeline/expression_context_for_test.h" +#include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace { +using unittest::assertGet; + TEST(ExprMatchExpression, ComparisonToConstantMatchesCorrectly) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto match = BSON("a" << 5); @@ -148,5 +151,25 @@ TEST(ExprMatchExpression, ShallowClonedExpressionIsEquivalentToOriginal) { ASSERT_TRUE(pipelineExpr.equivalent(shallowClone.get())); } +TEST(ExprMatchExpression, SetCollatorChangesCollationUsedForComparisons) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto match = BSON("a" + << "abc"); + auto notMatch = BSON("a" + << "ABC"); + + auto expression = BSON("$expr" << BSON("$eq" << BSON_ARRAY("$a" + << "abc"))); + auto matchExpression = assertGet(MatchExpressionParser::parse(expression, expCtx)); + ASSERT_TRUE(matchExpression->matchesBSON(match)); + ASSERT_FALSE(matchExpression->matchesBSON(notMatch)); + + CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); + matchExpression->setCollator(&collator); + + ASSERT_TRUE(matchExpression->matchesBSON(match)); + ASSERT_TRUE(matchExpression->matchesBSON(notMatch)); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index de8d2717a96..ddb6491739b 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -598,7 +598,7 @@ StatusWithMatchExpression MatchExpressionParser::_parse( root->add(maxPropsExpr.getValue().release()); } else if (mongoutils::str::equals("jsonSchema", rest)) { if ((allowedFeatures & AllowedFeatures::kJSONSchema) == 0u) { - return Status(ErrorCodes::JSONSchemaNotAllowed, + return Status(ErrorCodes::QueryFeatureNotAllowed, "$jsonSchema is not allowed in this context"); } @@ -1692,7 +1692,7 @@ StatusWithMatchExpression MatchExpressionParser::_parseExpr( AllowedFeatureSet allowedFeatures, const boost::intrusive_ptr<ExpressionContext>& expCtx) { if ((allowedFeatures & AllowedFeatures::kExpr) == 0u) { - return {Status(ErrorCodes::BadValue, "$expr is not allowed in this context")}; + return {Status(ErrorCodes::QueryFeatureNotAllowed, "$expr is not allowed in this context")}; } invariant(expCtx); diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h index 44ffd4ae9a0..1adb7640ed1 100644 --- a/src/mongo/db/matcher/expression_parser.h +++ b/src/mongo/db/matcher/expression_parser.h @@ -99,7 +99,8 @@ public: static constexpr AllowedFeatureSet kBanAllSpecialFeatures = 0; static constexpr AllowedFeatureSet kAllowAllSpecialFeatures = std::numeric_limits<unsigned long long>::max(); - static constexpr AllowedFeatureSet kDefaultSpecialFeatures = AllowedFeatures::kJSONSchema; + static constexpr AllowedFeatureSet kDefaultSpecialFeatures = + AllowedFeatures::kExpr | AllowedFeatures::kJSONSchema; /** * Constant double representation of 2^63. diff --git a/src/mongo/db/matcher/expression_parser_test.cpp b/src/mongo/db/matcher/expression_parser_test.cpp index ce520064261..3c8796833b6 100644 --- a/src/mongo/db/matcher/expression_parser_test.cpp +++ b/src/mongo/db/matcher/expression_parser_test.cpp @@ -367,33 +367,27 @@ TEST(MatchExpressionParserTest, NearParsesSuccessfullyWhenAllowed) { TEST(MatchExpressionParserTest, ExprFailsToParseWhenDisallowed) { auto query = fromjson("{$expr: {$eq: ['$a', 5]}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ASSERT_NOT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); + ASSERT_NOT_OK( + MatchExpressionParser::parse( + query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kBanAllSpecialFeatures) + .getStatus()); } TEST(MatchExpressionParserTest, ExprParsesSuccessfullyWhenAllowed) { auto query = fromjson("{$expr: {$eq: ['$a', 5]}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ASSERT_OK( - MatchExpressionParser::parse( - query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); + ASSERT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } TEST(MatchExpressionParserTest, ExprParsesSuccessfullyWithAdditionalTopLevelPredicates) { auto query = fromjson("{x: 1, $expr: {$eq: ['$a', 5]}, y: 1}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ASSERT_OK( - MatchExpressionParser::parse( - query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); + ASSERT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } TEST(MatchExpressionParserTest, ExprFailsToParseWithinTopLevelOr) { auto query = fromjson("{$or: [{x: 1}, {$expr: {$eq: ['$a', 5]}}]}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - ASSERT_NOT_OK( - MatchExpressionParser::parse( - query, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::AllowedFeatures::kExpr) - .getStatus()); + ASSERT_NOT_OK(MatchExpressionParser::parse(query, expCtx).getStatus()); } } diff --git a/src/mongo/db/matcher/expression_with_placeholder.cpp b/src/mongo/db/matcher/expression_with_placeholder.cpp index cd68587b057..bb878e05cfa 100644 --- a/src/mongo/db/matcher/expression_with_placeholder.cpp +++ b/src/mongo/db/matcher/expression_with_placeholder.cpp @@ -90,7 +90,8 @@ const std::regex ExpressionWithPlaceholder::placeholderRegex("^[a-z][a-zA-Z0-9]* // static StatusWith<std::unique_ptr<ExpressionWithPlaceholder>> ExpressionWithPlaceholder::parse( BSONObj rawFilter, const boost::intrusive_ptr<ExpressionContext>& expCtx) { - StatusWithMatchExpression statusWithFilter = MatchExpressionParser::parse(rawFilter, expCtx); + StatusWithMatchExpression statusWithFilter = MatchExpressionParser::parse( + rawFilter, expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kBanAllSpecialFeatures); if (!statusWithFilter.isOK()) { return statusWithFilter.getStatus(); diff --git a/src/mongo/db/matcher/expression_with_placeholder_test.cpp b/src/mongo/db/matcher/expression_with_placeholder_test.cpp index 7bd19b12d00..27a2a1d549c 100644 --- a/src/mongo/db/matcher/expression_with_placeholder_test.cpp +++ b/src/mongo/db/matcher/expression_with_placeholder_test.cpp @@ -245,6 +245,15 @@ TEST(ExpressionWithPlaceholderTest, ExprExpressionFailsToParse) { auto rawFilter = fromjson("{$expr: {$eq: ['$i', 5]}}"); auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); ASSERT_NOT_OK(status.getStatus()); + ASSERT_EQ(status.getStatus().code(), ErrorCodes::QueryFeatureNotAllowed); +} + +TEST(ExpressionWithPlaceholderTest, JSONSchemaExpressionFailsToParse) { + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto rawFilter = fromjson("{$jsonSchema: {}}"); + auto status = ExpressionWithPlaceholder::parse(rawFilter, expCtx); + ASSERT_NOT_OK(status.getStatus()); + ASSERT_EQ(status.getStatus().code(), ErrorCodes::QueryFeatureNotAllowed); } TEST(ExpressionWithPlaceholderTest, EquivalentIfPlaceholderAndExpressionMatch) { |