diff options
author | Benety Goh <benety@mongodb.com> | 2014-04-10 12:26:03 -0400 |
---|---|---|
committer | Dan Pasette <dan@mongodb.com> | 2014-04-16 10:14:15 -0400 |
commit | b39c5ee1eaf1507e7f9149330520e01d5c060340 (patch) | |
tree | f588fb92b0482c19db4f1380fdba3126e914b12d | |
parent | f0e41e169c8b38578c774af0b9cf38dd79e5ad23 (diff) | |
download | mongo-b39c5ee1eaf1507e7f9149330520e01d5c060340.tar.gz |
SERVER-13503 disallow $where under $elemMatch value
(cherry picked from commit 5aac10481a602c2ca3ce1d24a0c97e3602e33814)
-rw-r--r-- | jstests/core/where1.js | 11 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser.cpp | 39 |
2 files changed, 49 insertions, 1 deletions
diff --git a/jstests/core/where1.js b/jstests/core/where1.js index 7ff20a53620..6e3d693b996 100644 --- a/jstests/core/where1.js +++ b/jstests/core/where1.js @@ -26,3 +26,14 @@ assert.throws( function() { assert.throws( function() { t.find( { a: 3, "b.c": { $where : "this.a;" } } ).itcount(); } ); + +// SERVER-13503 +assert.throws( function() { + t.find( { a: { $elemMatch : { $where : "this.a;", b : 1 } } } ).itcount(); +} ); +assert.throws( function() { + t.find( { a: { $elemMatch : { b : 1, $where : "this.a;" } } } ).itcount(); +} ); +assert.throws( function() { + t.find( { a: { $elemMatch : { $and : [ { b : 1 }, { $where : "this.a;" } ] } } } ).itcount(); +} ); diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index bfc363ceda1..e97165b59fa 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -41,6 +41,27 @@ #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" +namespace { + + using namespace mongo; + + /** + * Returns true if subtree contains MatchExpression 'type'. + */ + bool hasNode(const MatchExpression* root, MatchExpression::MatchType type) { + if (type == root->matchType()) { + return true; + } + for (size_t i = 0; i < root->numChildren(); ++i) { + if (hasNode(root->getChild(i), type)) { + return true; + } + } + return false; + } + +} // namespace + namespace mongo { StatusWithMatchExpression MatchExpressionParser::_parseComparison( const char* name, @@ -80,6 +101,12 @@ namespace mongo { int x = e.getGtLtOp(-1); switch ( x ) { case -1: + // $where cannot be a sub-expression because it works on top-level documents only. + if ( mongoutils::str::equals( "$where", e.fieldName() ) ) { + return StatusWithMatchExpression( ErrorCodes::BadValue, + "$where cannot be applied to a field" ); + } + return StatusWithMatchExpression( ErrorCodes::BadValue, mongoutils::str::stream() << "unknown operator: " << e.fieldName() ); @@ -619,6 +646,8 @@ namespace mongo { // 1) the argument is an expression document; and // 2) expression is not a AND/NOR/OR logical operator. Children of // these logical operators are initialized with field names. + // 3) expression is not a WHERE operator. WHERE works on objects instead + // of specific field. bool isElemMatchValue = false; if ( _isExpressionDocument( e, true ) ) { BSONObj o = e.Obj(); @@ -627,7 +656,8 @@ namespace mongo { isElemMatchValue = !mongoutils::str::equals( "$and", elt.fieldName() ) && !mongoutils::str::equals( "$nor", elt.fieldName() ) && - !mongoutils::str::equals( "$or", elt.fieldName() ); + !mongoutils::str::equals( "$or", elt.fieldName() ) && + !mongoutils::str::equals( "$where", elt.fieldName() ); } if ( isElemMatchValue ) { @@ -661,6 +691,13 @@ namespace mongo { if ( !sub.isOK() ) return sub; + // $where is not supported under $elemMatch because $where + // applies to top-level document, not array elements in a field. + if ( hasNode( sub.getValue(), MatchExpression::WHERE ) ) { + return StatusWithMatchExpression( ErrorCodes::BadValue, + "$elemMatch cannot contain $where expression" ); + } + std::auto_ptr<ElemMatchObjectMatchExpression> temp( new ElemMatchObjectMatchExpression() ); Status status = temp->init( name, sub.getValue() ); if ( !status.isOK() ) |