summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/matcher')
-rw-r--r--src/mongo/db/matcher/expression_expr.cpp4
-rw-r--r--src/mongo/db/matcher/expression_expr.h2
-rw-r--r--src/mongo/db/matcher/expression_expr_test.cpp23
-rw-r--r--src/mongo/db/matcher/expression_parser.cpp4
-rw-r--r--src/mongo/db/matcher/expression_parser.h3
-rw-r--r--src/mongo/db/matcher/expression_parser_test.cpp20
-rw-r--r--src/mongo/db/matcher/expression_with_placeholder.cpp3
-rw-r--r--src/mongo/db/matcher/expression_with_placeholder_test.cpp9
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) {