summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher/expression_parser.h
diff options
context:
space:
mode:
authorBlake Oler <blake.oler@10gen.com>2017-10-09 11:48:26 -0400
committerBlake Oler <blake.oler@10gen.com>2017-10-09 11:48:40 -0400
commit95fedb251673c87b5172269e1f8c116b5e05fb16 (patch)
treec0fbd29a89addfb6bf54d4630c76772abf6c1564 /src/mongo/db/matcher/expression_parser.h
parentd7a30a716243db13644a16618a939df6bc1344fc (diff)
downloadmongo-95fedb251673c87b5172269e1f8c116b5e05fb16.tar.gz
SERVER-31029 Add support for top-level $expr within $or and $and
Diffstat (limited to 'src/mongo/db/matcher/expression_parser.h')
-rw-r--r--src/mongo/db/matcher/expression_parser.h78
1 files changed, 60 insertions, 18 deletions
diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h
index 1adb7640ed1..6091d3f1426 100644
--- a/src/mongo/db/matcher/expression_parser.h
+++ b/src/mongo/db/matcher/expression_parser.h
@@ -36,8 +36,10 @@
#include "mongo/db/matcher/expression_leaf.h"
#include "mongo/db/matcher/expression_tree.h"
#include "mongo/db/matcher/expression_type.h"
+#include "mongo/db/matcher/expression_with_placeholder.h"
#include "mongo/db/matcher/extensions_callback.h"
#include "mongo/db/matcher/extensions_callback_noop.h"
+#include "mongo/db/matcher/schema/expression_internal_schema_allowed_properties.h"
#include "mongo/db/pipeline/expression.h"
#include "mongo/db/pipeline/expression_context.h"
#include "mongo/stdx/functional.h"
@@ -127,9 +129,8 @@ public:
const ExtensionsCallback& extensionsCallback = ExtensionsCallbackNoop(),
AllowedFeatureSet allowedFeatures = kDefaultSpecialFeatures) {
invariant(expCtx.get());
- const bool topLevelCall = true;
return MatchExpressionParser(&extensionsCallback)
- ._parse(obj, expCtx, allowedFeatures, topLevelCall);
+ ._parse(obj, expCtx, allowedFeatures, DocumentParseLevel::kPredicateTopLevel);
}
/**
@@ -154,6 +155,23 @@ public:
static StatusWith<long long> parseIntegerElementToLong(BSONElement elem);
private:
+ /**
+ * 'DocumentParseLevel' refers to the current position of the parser as it descends a
+ * MatchExpression tree.
+ */
+ enum class DocumentParseLevel {
+ // Indicates that the parser is looking at the root level of the BSON object containing the
+ // user's query predicate.
+ kPredicateTopLevel,
+ // Indicates that match expression nodes in this position will match against the complete
+ // user document, as opposed to matching against a nested document or a subdocument inside
+ // an array.
+ kUserDocumentTopLevel,
+ // Indicates that match expression nodes in this position will match against a nested
+ // document or a subdocument inside an array.
+ kUserSubDocument,
+ };
+
MatchExpressionParser(const ExtensionsCallback* extensionsCallback)
: _extensionsCallback(extensionsCallback) {}
@@ -179,26 +197,23 @@ private:
/**
* Parse 'obj' and return either a MatchExpression or an error.
- *
- * 'topLevel' indicates whether or not the we are at the top level of the tree across recursive
- * class to this function. This is used to apply special logic at the top level.
*/
StatusWithMatchExpression _parse(const BSONObj& obj,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
AllowedFeatureSet allowedFeatures,
- bool topLevel);
+ DocumentParseLevel currentLevel);
/**
* parses a field in a sub expression
* if the query is { x : { $gt : 5, $lt : 8 } }
- * e is { $gt : 5, $lt : 8 }
+ * obj is { $gt : 5, $lt : 8 }
*/
Status _parseSub(const char* name,
const BSONObj& obj,
AndMatchExpression* root,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
AllowedFeatureSet allowedFeatures,
- bool topLevel);
+ DocumentParseLevel currentLevel);
/**
* parses a single field in a sub expression
@@ -211,7 +226,7 @@ private:
const BSONElement& e,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
AllowedFeatureSet allowedFeatures,
- bool topLevel);
+ DocumentParseLevel currentLevel);
StatusWithMatchExpression _parseComparison(
const char* name,
@@ -247,14 +262,12 @@ private:
StatusWithMatchExpression _parseElemMatch(const char* name,
const BSONElement& e,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
- AllowedFeatureSet allowedFeatures,
- bool topLevel);
+ AllowedFeatureSet allowedFeatures);
StatusWithMatchExpression _parseAll(const char* name,
const BSONElement& e,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
- AllowedFeatureSet allowedFeatures,
- bool topLevel);
+ AllowedFeatureSet allowedFeatures);
// tree
@@ -262,13 +275,13 @@ private:
ListOfMatchExpression* out,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
AllowedFeatureSet allowedFeatures,
- bool topLevel);
+ DocumentParseLevel currentLevel);
StatusWithMatchExpression _parseNot(const char* name,
const BSONElement& e,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
AllowedFeatureSet allowedFeatures,
- bool topLevel);
+ DocumentParseLevel currentLevel);
/**
* Parses 'e' into a BitTestMatchExpression.
@@ -284,6 +297,29 @@ private:
StatusWithMatchExpression _parseInternalSchemaFmod(const char* name, const BSONElement& e);
/**
+ * Looks at the field named 'exprWithPlaceholderFieldName' within 'containingObject' and parses
+ * an ExpressionWithPlaceholder from that element. Fails if an error occurs during parsing, or
+ * if the ExpressionWithPlaceholder has a different name placeholder than 'expectedPlaceholder'.
+ * 'expressionName' is the name of the expression that requires the ExpressionWithPlaceholder
+ * and is used to generate helpful error messages.
+ */
+ StatusWith<std::unique_ptr<ExpressionWithPlaceholder>> _parseExprWithPlaceholder(
+ const BSONObj& containingObject,
+ StringData exprWithPlaceholderFieldName,
+ StringData expressionName,
+ StringData expectedPlaceholder,
+ const boost::intrusive_ptr<ExpressionContext>& expCtx,
+ AllowedFeatureSet allowedFeatures,
+ DocumentParseLevel currentLevel);
+
+ StatusWith<std::vector<InternalSchemaAllowedPropertiesMatchExpression::PatternSchema>>
+ _parsePatternProperties(BSONElement patternPropertiesElem,
+ StringData expectedPlaceholder,
+ const boost::intrusive_ptr<ExpressionContext>& expCtx,
+ AllowedFeatureSet allowedFeatures,
+ DocumentParseLevel currentLevel);
+
+ /**
* Parses a MatchExpression which takes a fixed-size array of MatchExpressions as arguments.
*/
template <class T>
@@ -291,7 +327,8 @@ private:
StringData name,
const BSONElement& elem,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
- AllowedFeatureSet allowedFeatures);
+ AllowedFeatureSet allowedFeatures,
+ DocumentParseLevel currentLevel);
/**
* Parses the given BSONElement into a single integer argument and creates a MatchExpression
@@ -315,10 +352,15 @@ private:
StatusWithMatchExpression _parseInternalSchemaMatchArrayIndex(
const char* path,
const BSONElement& elem,
- const boost::intrusive_ptr<ExpressionContext>& expCtx);
+ const boost::intrusive_ptr<ExpressionContext>& expCtx,
+ AllowedFeatureSet allowedFeatures,
+ DocumentParseLevel currentLevel);
StatusWithMatchExpression _parseInternalSchemaAllowedProperties(
- const BSONElement& elem, const boost::intrusive_ptr<ExpressionContext>& expCtx);
+ const BSONElement& elem,
+ const boost::intrusive_ptr<ExpressionContext>& expCtx,
+ AllowedFeatureSet allowedFeatures,
+ DocumentParseLevel currentLevel);
// Performs parsing for the match extensions. We do not own this pointer - it has to live
// as long as the parser is active.