summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher/expression_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/matcher/expression_parser.cpp')
-rw-r--r--src/mongo/db/matcher/expression_parser.cpp141
1 files changed, 114 insertions, 27 deletions
diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp
index a9d64868e56..ab5df8b97ae 100644
--- a/src/mongo/db/matcher/expression_parser.cpp
+++ b/src/mongo/db/matcher/expression_parser.cpp
@@ -89,10 +89,38 @@ bool hasNode(const MatchExpression* root, MatchExpression::MatchType type) {
return false;
}
+/**
+ * Set of functions which create an ErrorAnnotation provided that a validator expression is being
+ * parsed.
+ */
+std::unique_ptr<MatchExpression::ErrorAnnotation> createAnnotation(
+ const boost::intrusive_ptr<ExpressionContext>& expCtx,
+ const std::string& operatorName,
+ const BSONObj& annotation) {
+ if (expCtx->isParsingCollectionValidator) {
+ return std::make_unique<MatchExpression::ErrorAnnotation>(operatorName, annotation);
+ } else {
+ return nullptr;
+ }
+}
+
+std::unique_ptr<MatchExpression::ErrorAnnotation> createAnnotation(
+ const boost::intrusive_ptr<ExpressionContext>& expCtx,
+ MatchExpression::ErrorAnnotation::Mode mode) {
+ if (expCtx->isParsingCollectionValidator) {
+ return std::make_unique<MatchExpression::ErrorAnnotation>(mode);
+ } else {
+ return nullptr;
+ }
+}
+
} // namespace
namespace mongo {
+using ErrorAnnotation = MatchExpression::ErrorAnnotation;
+using AnnotationMode = ErrorAnnotation::Mode;
+
constexpr StringData AlwaysFalseMatchExpression::kName;
constexpr StringData AlwaysTrueMatchExpression::kName;
constexpr StringData OrMatchExpression::kName;
@@ -299,12 +327,13 @@ StatusWithMatchExpression parse(const BSONObj& obj,
continue;
}
- auto eq =
- parseComparison(e.fieldNameStringData(),
- std::make_unique<EqualityMatchExpression>(e.fieldNameStringData(), e),
- e,
- expCtx,
- allowedFeatures);
+ auto eq = parseComparison(
+ e.fieldNameStringData(),
+ std::make_unique<EqualityMatchExpression>(
+ e.fieldNameStringData(), e, createAnnotation(expCtx, "$eq", e.wrap())),
+ e,
+ expCtx,
+ allowedFeatures);
if (!eq.isOK())
return eq;
@@ -1390,8 +1419,16 @@ StatusWithMatchExpression parseSubField(const BSONObj& context,
invariant(e);
if ("$eq"_sd == e.fieldNameStringData()) {
- return parseComparison(
- name, std::make_unique<EqualityMatchExpression>(name, e), e, expCtx, allowedFeatures);
+ return parseComparison(name,
+ std::make_unique<EqualityMatchExpression>(
+ name,
+ e,
+ createAnnotation(expCtx,
+ e.fieldNameStringData().toString(),
+ BSON(name << e.wrap()))),
+ e,
+ expCtx,
+ allowedFeatures);
}
if ("$not"_sd == e.fieldNameStringData()) {
@@ -1411,34 +1448,77 @@ StatusWithMatchExpression parseSubField(const BSONObj& context,
switch (*parseExpMatchType) {
case PathAcceptingKeyword::LESS_THAN:
- return parseComparison(
- name, std::make_unique<LTMatchExpression>(name, e), e, expCtx, allowedFeatures);
+ return parseComparison(name,
+ std::make_unique<LTMatchExpression>(
+ name,
+ e,
+ createAnnotation(expCtx,
+ e.fieldNameStringData().toString(),
+ BSON(name << e.wrap()))),
+ e,
+ expCtx,
+ allowedFeatures);
case PathAcceptingKeyword::LESS_THAN_OR_EQUAL:
- return parseComparison(
- name, std::make_unique<LTEMatchExpression>(name, e), e, expCtx, allowedFeatures);
+ return parseComparison(name,
+ std::make_unique<LTEMatchExpression>(
+ name,
+ e,
+ createAnnotation(expCtx,
+ e.fieldNameStringData().toString(),
+ BSON(name << e.wrap()))),
+ e,
+ expCtx,
+ allowedFeatures);
case PathAcceptingKeyword::GREATER_THAN:
- return parseComparison(
- name, std::make_unique<GTMatchExpression>(name, e), e, expCtx, allowedFeatures);
+ return parseComparison(name,
+ std::make_unique<GTMatchExpression>(
+ name,
+ e,
+ createAnnotation(expCtx,
+ e.fieldNameStringData().toString(),
+ BSON(name << e.wrap()))),
+ e,
+ expCtx,
+ allowedFeatures);
case PathAcceptingKeyword::GREATER_THAN_OR_EQUAL:
- return parseComparison(
- name, std::make_unique<GTEMatchExpression>(name, e), e, expCtx, allowedFeatures);
+ return parseComparison(name,
+ std::make_unique<GTEMatchExpression>(
+ name,
+ e,
+ createAnnotation(expCtx,
+ e.fieldNameStringData().toString(),
+ BSON(name << e.wrap()))),
+ e,
+ expCtx,
+ allowedFeatures);
case PathAcceptingKeyword::NOT_EQUAL: {
if (BSONType::RegEx == e.type()) {
// Just because $ne can be rewritten as the negation of an equality does not mean
// that $ne of a regex is allowed. See SERVER-1705.
return {Status(ErrorCodes::BadValue, "Can't have regex as arg to $ne.")};
}
- StatusWithMatchExpression s =
- parseComparison(name,
- std::make_unique<EqualityMatchExpression>(name, e),
- e,
- expCtx,
- allowedFeatures);
- return {std::make_unique<NotMatchExpression>(s.getValue().release())};
+ StatusWithMatchExpression s = parseComparison(
+ name,
+ std::make_unique<EqualityMatchExpression>(
+ name,
+ e,
+ createAnnotation(
+ expCtx, e.fieldNameStringData().toString(), BSON(name << e.wrap()))),
+ e,
+ expCtx,
+ allowedFeatures);
+ return {std::make_unique<NotMatchExpression>(
+ s.getValue().release(),
+ createAnnotation(expCtx, AnnotationMode::kIgnoreButDescend))};
}
case PathAcceptingKeyword::EQUALITY:
return parseComparison(name,
- std::make_unique<EqualityMatchExpression>(name, e),
+ std::make_unique<EqualityMatchExpression>(
+ name,
+ e,
+ createAnnotation(expCtx,
+ e.fieldNameStringData().toString(),
+ BSON(name << e.wrap()))),
e,
expCtx,
allowedFeatures);
@@ -1447,7 +1527,10 @@ StatusWithMatchExpression parseSubField(const BSONObj& context,
if (e.type() != BSONType::Array) {
return {Status(ErrorCodes::BadValue, "$in needs an array")};
}
- auto temp = std::make_unique<InMatchExpression>(name);
+ auto temp = std::make_unique<InMatchExpression>(
+ name,
+ createAnnotation(
+ expCtx, e.fieldNameStringData().toString(), BSON(name << e.wrap())));
auto parseStatus = parseInExpression(temp.get(), e.Obj(), expCtx);
if (!parseStatus.isOK()) {
return parseStatus;
@@ -1459,12 +1542,16 @@ StatusWithMatchExpression parseSubField(const BSONObj& context,
if (e.type() != Array) {
return {Status(ErrorCodes::BadValue, "$nin needs an array")};
}
- auto temp = std::make_unique<InMatchExpression>(name);
+ auto temp = std::make_unique<InMatchExpression>(
+ name,
+ createAnnotation(
+ expCtx, e.fieldNameStringData().toString(), BSON(name << e.wrap())));
auto parseStatus = parseInExpression(temp.get(), e.Obj(), expCtx);
if (!parseStatus.isOK()) {
return parseStatus;
}
- return {std::make_unique<NotMatchExpression>(temp.release())};
+ return {std::make_unique<NotMatchExpression>(
+ temp.release(), createAnnotation(expCtx, AnnotationMode::kIgnoreButDescend))};
}
case PathAcceptingKeyword::SIZE: {