summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/query_planner_test_lib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/query/query_planner_test_lib.cpp')
-rw-r--r--src/mongo/db/query/query_planner_test_lib.cpp803
1 files changed, 429 insertions, 374 deletions
diff --git a/src/mongo/db/query/query_planner_test_lib.cpp b/src/mongo/db/query/query_planner_test_lib.cpp
index d81fc0f27e9..6ff080a767f 100644
--- a/src/mongo/db/query/query_planner_test_lib.cpp
+++ b/src/mongo/db/query/query_planner_test_lib.cpp
@@ -43,465 +43,520 @@
namespace {
- using namespace mongo;
+using namespace mongo;
- using std::string;
+using std::string;
- bool filterMatches(const BSONObj& testFilter,
- const QuerySolutionNode* trueFilterNode) {
- if (NULL == trueFilterNode->filter) { return false; }
- StatusWithMatchExpression swme = MatchExpressionParser::parse(testFilter);
- if (!swme.isOK()) {
- return false;
- }
- const std::unique_ptr<MatchExpression> root(swme.getValue());
- CanonicalQuery::sortTree(root.get());
- std::unique_ptr<MatchExpression> trueFilter(trueFilterNode->filter->shallowClone());
- CanonicalQuery::sortTree(trueFilter.get());
- return trueFilter->equivalent(root.get());
+bool filterMatches(const BSONObj& testFilter, const QuerySolutionNode* trueFilterNode) {
+ if (NULL == trueFilterNode->filter) {
+ return false;
}
-
- void appendIntervalBound(BSONObjBuilder& bob, BSONElement& el) {
- if (el.type() == String) {
- std::string data = el.String();
- if (data == "MaxKey") {
- bob.appendMaxKey("");
- }
- else if (data == "MinKey") {
- bob.appendMinKey("");
- }
- else {
- bob.appendAs(el, "");
- }
- }
- else {
+ StatusWithMatchExpression swme = MatchExpressionParser::parse(testFilter);
+ if (!swme.isOK()) {
+ return false;
+ }
+ const std::unique_ptr<MatchExpression> root(swme.getValue());
+ CanonicalQuery::sortTree(root.get());
+ std::unique_ptr<MatchExpression> trueFilter(trueFilterNode->filter->shallowClone());
+ CanonicalQuery::sortTree(trueFilter.get());
+ return trueFilter->equivalent(root.get());
+}
+
+void appendIntervalBound(BSONObjBuilder& bob, BSONElement& el) {
+ if (el.type() == String) {
+ std::string data = el.String();
+ if (data == "MaxKey") {
+ bob.appendMaxKey("");
+ } else if (data == "MinKey") {
+ bob.appendMinKey("");
+ } else {
bob.appendAs(el, "");
}
+ } else {
+ bob.appendAs(el, "");
}
+}
- bool intervalMatches(const BSONObj& testInt, const Interval trueInt) {
- BSONObjIterator it(testInt);
- if (!it.more()) { return false; }
- BSONElement low = it.next();
- if (!it.more()) { return false; }
- BSONElement high = it.next();
- if (!it.more()) { return false; }
- bool startInclusive = it.next().Bool();
- if (!it.more()) { return false; }
- bool endInclusive = it.next().Bool();
- if (it.more()) { return false; }
-
- BSONObjBuilder bob;
- appendIntervalBound(bob, low);
- appendIntervalBound(bob, high);
- Interval toCompare(bob.obj(), startInclusive, endInclusive);
-
- return Interval::INTERVAL_EQUALS == trueInt.compare(toCompare);
+bool intervalMatches(const BSONObj& testInt, const Interval trueInt) {
+ BSONObjIterator it(testInt);
+ if (!it.more()) {
+ return false;
+ }
+ BSONElement low = it.next();
+ if (!it.more()) {
+ return false;
+ }
+ BSONElement high = it.next();
+ if (!it.more()) {
+ return false;
+ }
+ bool startInclusive = it.next().Bool();
+ if (!it.more()) {
+ return false;
+ }
+ bool endInclusive = it.next().Bool();
+ if (it.more()) {
+ return false;
}
- /**
- * Returns whether the BSON representation of the index bounds in
- * 'testBounds' matches 'trueBounds'.
- *
- * 'testBounds' should be of the following format:
- * {<field 1>: <oil 1>, <field 2>: <oil 2>, ...}
- * Each ordered interval list (e.g. <oil 1>) is an array of arrays of
- * the format:
- * [[<low 1>,<high 1>,<lowInclusive 1>,<highInclusive 1>], ...]
- *
- * For example,
- * {a: [[1,2,true,false], [3,4,false,true]], b: [[-Infinity, Infinity]]}
- * Means that the index bounds on field 'a' consist of the two intervals
- * [1, 2) and (3, 4] and the index bounds on field 'b' are [-Infinity, Infinity].
- */
- bool boundsMatch(const BSONObj& testBounds, const IndexBounds trueBounds) {
- // Iterate over the fields on which we have index bounds.
- BSONObjIterator fieldIt(testBounds);
- int fieldItCount = 0;
- while (fieldIt.more()) {
- BSONElement arrEl = fieldIt.next();
- if (arrEl.type() != Array) {
+ BSONObjBuilder bob;
+ appendIntervalBound(bob, low);
+ appendIntervalBound(bob, high);
+ Interval toCompare(bob.obj(), startInclusive, endInclusive);
+
+ return Interval::INTERVAL_EQUALS == trueInt.compare(toCompare);
+}
+
+/**
+ * Returns whether the BSON representation of the index bounds in
+ * 'testBounds' matches 'trueBounds'.
+ *
+ * 'testBounds' should be of the following format:
+ * {<field 1>: <oil 1>, <field 2>: <oil 2>, ...}
+ * Each ordered interval list (e.g. <oil 1>) is an array of arrays of
+ * the format:
+ * [[<low 1>,<high 1>,<lowInclusive 1>,<highInclusive 1>], ...]
+ *
+ * For example,
+ * {a: [[1,2,true,false], [3,4,false,true]], b: [[-Infinity, Infinity]]}
+ * Means that the index bounds on field 'a' consist of the two intervals
+ * [1, 2) and (3, 4] and the index bounds on field 'b' are [-Infinity, Infinity].
+ */
+bool boundsMatch(const BSONObj& testBounds, const IndexBounds trueBounds) {
+ // Iterate over the fields on which we have index bounds.
+ BSONObjIterator fieldIt(testBounds);
+ int fieldItCount = 0;
+ while (fieldIt.more()) {
+ BSONElement arrEl = fieldIt.next();
+ if (arrEl.type() != Array) {
+ return false;
+ }
+ // Iterate over an ordered interval list for
+ // a particular field.
+ BSONObjIterator oilIt(arrEl.Obj());
+ int oilItCount = 0;
+ while (oilIt.more()) {
+ BSONElement intervalEl = oilIt.next();
+ if (intervalEl.type() != Array) {
return false;
}
- // Iterate over an ordered interval list for
- // a particular field.
- BSONObjIterator oilIt(arrEl.Obj());
- int oilItCount = 0;
- while (oilIt.more()) {
- BSONElement intervalEl = oilIt.next();
- if (intervalEl.type() != Array) {
- return false;
- }
- Interval trueInt = trueBounds.getInterval(fieldItCount, oilItCount);
- if (!intervalMatches(intervalEl.Obj(), trueInt)) {
- return false;
- }
- ++oilItCount;
+ Interval trueInt = trueBounds.getInterval(fieldItCount, oilItCount);
+ if (!intervalMatches(intervalEl.Obj(), trueInt)) {
+ return false;
}
- ++fieldItCount;
+ ++oilItCount;
}
-
- return true;
+ ++fieldItCount;
}
-} // namespace
+ return true;
+}
+
+} // namespace
namespace mongo {
- /**
- * Looks in the children stored in the 'nodes' field of 'testSoln'
- * to see if thet match the 'children' field of 'trueSoln'.
- *
- * This does an unordered comparison, i.e. childrenMatch returns
- * true as long as the set of subtrees in testSoln's 'nodes' matches
- * the set of subtrees in trueSoln's 'children' vector.
- */
- static bool childrenMatch(const BSONObj& testSoln, const QuerySolutionNode* trueSoln) {
- BSONElement children = testSoln["nodes"];
- if (children.eoo() || !children.isABSONObj()) { return false; }
-
- // The order of the children array in testSoln might not match
- // the order in trueSoln, so we have to check all combos with
- // these nested loops.
- BSONObjIterator i(children.Obj());
- while (i.more()) {
- BSONElement child = i.next();
- if (child.eoo() || !child.isABSONObj()) { return false; }
-
- // try to match against one of the QuerySolutionNode's children
- bool found = false;
- for (size_t j = 0; j < trueSoln->children.size(); ++j) {
- if (QueryPlannerTestLib::solutionMatches(child.Obj(), trueSoln->children[j])) {
- found = true;
- break;
- }
- }
+/**
+ * Looks in the children stored in the 'nodes' field of 'testSoln'
+ * to see if thet match the 'children' field of 'trueSoln'.
+ *
+ * This does an unordered comparison, i.e. childrenMatch returns
+ * true as long as the set of subtrees in testSoln's 'nodes' matches
+ * the set of subtrees in trueSoln's 'children' vector.
+ */
+static bool childrenMatch(const BSONObj& testSoln, const QuerySolutionNode* trueSoln) {
+ BSONElement children = testSoln["nodes"];
+ if (children.eoo() || !children.isABSONObj()) {
+ return false;
+ }
- // we couldn't match child
- if (!found) { return false; }
+ // The order of the children array in testSoln might not match
+ // the order in trueSoln, so we have to check all combos with
+ // these nested loops.
+ BSONObjIterator i(children.Obj());
+ while (i.more()) {
+ BSONElement child = i.next();
+ if (child.eoo() || !child.isABSONObj()) {
+ return false;
}
- return true;
+ // try to match against one of the QuerySolutionNode's children
+ bool found = false;
+ for (size_t j = 0; j < trueSoln->children.size(); ++j) {
+ if (QueryPlannerTestLib::solutionMatches(child.Obj(), trueSoln->children[j])) {
+ found = true;
+ break;
+ }
+ }
+
+ // we couldn't match child
+ if (!found) {
+ return false;
+ }
}
- // static
- bool QueryPlannerTestLib::solutionMatches(const BSONObj& testSoln,
- const QuerySolutionNode* trueSoln) {
- //
- // leaf nodes
- //
- if (STAGE_COLLSCAN == trueSoln->getType()) {
- const CollectionScanNode* csn = static_cast<const CollectionScanNode*>(trueSoln);
- BSONElement el = testSoln["cscan"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj csObj = el.Obj();
-
- BSONElement dir = csObj["dir"];
- if (dir.eoo() || !dir.isNumber()) { return false; }
- if (dir.numberInt() != csn->direction) { return false; }
-
- BSONElement filter = csObj["filter"];
- if (filter.eoo()) {
- return true;
- }
- else if (filter.isNull()) {
- return NULL == csn->filter;
- }
- else if (!filter.isABSONObj()) {
- return false;
- }
- return filterMatches(filter.Obj(), trueSoln);
+ return true;
+}
+
+// static
+bool QueryPlannerTestLib::solutionMatches(const BSONObj& testSoln,
+ const QuerySolutionNode* trueSoln) {
+ //
+ // leaf nodes
+ //
+ if (STAGE_COLLSCAN == trueSoln->getType()) {
+ const CollectionScanNode* csn = static_cast<const CollectionScanNode*>(trueSoln);
+ BSONElement el = testSoln["cscan"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
}
- else if (STAGE_IXSCAN == trueSoln->getType()) {
- const IndexScanNode* ixn = static_cast<const IndexScanNode*>(trueSoln);
- BSONElement el = testSoln["ixscan"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj ixscanObj = el.Obj();
+ BSONObj csObj = el.Obj();
- BSONElement pattern = ixscanObj["pattern"];
- if (pattern.eoo() || !pattern.isABSONObj()) { return false; }
- if (pattern.Obj() != ixn->indexKeyPattern) { return false; }
+ BSONElement dir = csObj["dir"];
+ if (dir.eoo() || !dir.isNumber()) {
+ return false;
+ }
+ if (dir.numberInt() != csn->direction) {
+ return false;
+ }
- BSONElement bounds = ixscanObj["bounds"];
- if (!bounds.eoo()) {
- if (!bounds.isABSONObj()) {
- return false;
- }
- else if (!boundsMatch(bounds.Obj(), ixn->bounds)) {
- return false;
- }
- }
+ BSONElement filter = csObj["filter"];
+ if (filter.eoo()) {
+ return true;
+ } else if (filter.isNull()) {
+ return NULL == csn->filter;
+ } else if (!filter.isABSONObj()) {
+ return false;
+ }
+ return filterMatches(filter.Obj(), trueSoln);
+ } else if (STAGE_IXSCAN == trueSoln->getType()) {
+ const IndexScanNode* ixn = static_cast<const IndexScanNode*>(trueSoln);
+ BSONElement el = testSoln["ixscan"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj ixscanObj = el.Obj();
- BSONElement dir = ixscanObj["dir"];
- if (!dir.eoo() && NumberInt == dir.type()) {
- if (dir.numberInt() != ixn->direction) {
- return false;
- }
- }
+ BSONElement pattern = ixscanObj["pattern"];
+ if (pattern.eoo() || !pattern.isABSONObj()) {
+ return false;
+ }
+ if (pattern.Obj() != ixn->indexKeyPattern) {
+ return false;
+ }
- BSONElement filter = ixscanObj["filter"];
- if (filter.eoo()) {
- return true;
- }
- else if (filter.isNull()) {
- return NULL == ixn->filter;
+ BSONElement bounds = ixscanObj["bounds"];
+ if (!bounds.eoo()) {
+ if (!bounds.isABSONObj()) {
+ return false;
+ } else if (!boundsMatch(bounds.Obj(), ixn->bounds)) {
+ return false;
}
- else if (!filter.isABSONObj()) {
+ }
+
+ BSONElement dir = ixscanObj["dir"];
+ if (!dir.eoo() && NumberInt == dir.type()) {
+ if (dir.numberInt() != ixn->direction) {
return false;
}
- return filterMatches(filter.Obj(), trueSoln);
- }
- else if (STAGE_GEO_NEAR_2D == trueSoln->getType()) {
- const GeoNear2DNode* node = static_cast<const GeoNear2DNode*>(trueSoln);
- BSONElement el = testSoln["geoNear2d"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj geoObj = el.Obj();
- return geoObj == node->indexKeyPattern;
- }
- else if (STAGE_GEO_NEAR_2DSPHERE == trueSoln->getType()) {
- const GeoNear2DSphereNode* node = static_cast<const GeoNear2DSphereNode*>(trueSoln);
- BSONElement el = testSoln["geoNear2dsphere"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj geoObj = el.Obj();
- return geoObj == node->indexKeyPattern;
- }
- else if (STAGE_TEXT == trueSoln->getType()) {
- // {text: {search: "somestr", language: "something", filter: {blah: 1}}}
- const TextNode* node = static_cast<const TextNode*>(trueSoln);
- BSONElement el = testSoln["text"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj textObj = el.Obj();
-
- BSONElement searchElt = textObj["search"];
- if (!searchElt.eoo()) {
- if (searchElt.String() != node->query) {
- return false;
- }
+ }
+
+ BSONElement filter = ixscanObj["filter"];
+ if (filter.eoo()) {
+ return true;
+ } else if (filter.isNull()) {
+ return NULL == ixn->filter;
+ } else if (!filter.isABSONObj()) {
+ return false;
+ }
+ return filterMatches(filter.Obj(), trueSoln);
+ } else if (STAGE_GEO_NEAR_2D == trueSoln->getType()) {
+ const GeoNear2DNode* node = static_cast<const GeoNear2DNode*>(trueSoln);
+ BSONElement el = testSoln["geoNear2d"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj geoObj = el.Obj();
+ return geoObj == node->indexKeyPattern;
+ } else if (STAGE_GEO_NEAR_2DSPHERE == trueSoln->getType()) {
+ const GeoNear2DSphereNode* node = static_cast<const GeoNear2DSphereNode*>(trueSoln);
+ BSONElement el = testSoln["geoNear2dsphere"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj geoObj = el.Obj();
+ return geoObj == node->indexKeyPattern;
+ } else if (STAGE_TEXT == trueSoln->getType()) {
+ // {text: {search: "somestr", language: "something", filter: {blah: 1}}}
+ const TextNode* node = static_cast<const TextNode*>(trueSoln);
+ BSONElement el = testSoln["text"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj textObj = el.Obj();
+
+ BSONElement searchElt = textObj["search"];
+ if (!searchElt.eoo()) {
+ if (searchElt.String() != node->query) {
+ return false;
}
+ }
- BSONElement languageElt = textObj["language"];
- if (!languageElt.eoo()) {
- if (languageElt.String() != node->language) {
- return false;
- }
+ BSONElement languageElt = textObj["language"];
+ if (!languageElt.eoo()) {
+ if (languageElt.String() != node->language) {
+ return false;
}
+ }
- BSONElement caseSensitiveElt = textObj["caseSensitive"];
- if (!caseSensitiveElt.eoo()) {
- if (caseSensitiveElt.trueValue() != node->caseSensitive) {
- return false;
- }
+ BSONElement caseSensitiveElt = textObj["caseSensitive"];
+ if (!caseSensitiveElt.eoo()) {
+ if (caseSensitiveElt.trueValue() != node->caseSensitive) {
+ return false;
}
+ }
- BSONElement indexPrefix = textObj["prefix"];
- if (!indexPrefix.eoo()) {
- if (!indexPrefix.isABSONObj()) {
- return false;
- }
+ BSONElement indexPrefix = textObj["prefix"];
+ if (!indexPrefix.eoo()) {
+ if (!indexPrefix.isABSONObj()) {
+ return false;
+ }
- if (0 != indexPrefix.Obj().woCompare(node->indexPrefix)) {
- return false;
- }
+ if (0 != indexPrefix.Obj().woCompare(node->indexPrefix)) {
+ return false;
}
+ }
- BSONElement filter = textObj["filter"];
- if (!filter.eoo()) {
- if (filter.isNull()) {
- if (NULL != node->filter) { return false; }
- }
- else if (!filter.isABSONObj()) {
- return false;
- }
- else if (!filterMatches(filter.Obj(), trueSoln)) {
+ BSONElement filter = textObj["filter"];
+ if (!filter.eoo()) {
+ if (filter.isNull()) {
+ if (NULL != node->filter) {
return false;
}
+ } else if (!filter.isABSONObj()) {
+ return false;
+ } else if (!filterMatches(filter.Obj(), trueSoln)) {
+ return false;
}
-
- return true;
}
- //
- // internal nodes
- //
- if (STAGE_FETCH == trueSoln->getType()) {
- const FetchNode* fn = static_cast<const FetchNode*>(trueSoln);
+ return true;
+ }
- BSONElement el = testSoln["fetch"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj fetchObj = el.Obj();
+ //
+ // internal nodes
+ //
+ if (STAGE_FETCH == trueSoln->getType()) {
+ const FetchNode* fn = static_cast<const FetchNode*>(trueSoln);
- BSONElement filter = fetchObj["filter"];
- if (!filter.eoo()) {
- if (filter.isNull()) {
- if (NULL != fn->filter) { return false; }
- }
- else if (!filter.isABSONObj()) {
- return false;
- }
- else if (!filterMatches(filter.Obj(), trueSoln)) {
- return false;
- }
- }
+ BSONElement el = testSoln["fetch"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj fetchObj = el.Obj();
- BSONElement child = fetchObj["node"];
- if (child.eoo() || !child.isABSONObj()) { return false; }
- return solutionMatches(child.Obj(), fn->children[0]);
- }
- else if (STAGE_OR == trueSoln->getType()) {
- const OrNode * orn = static_cast<const OrNode*>(trueSoln);
- BSONElement el = testSoln["or"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj orObj = el.Obj();
- return childrenMatch(orObj, orn);
- }
- else if (STAGE_AND_HASH == trueSoln->getType()) {
- const AndHashNode* ahn = static_cast<const AndHashNode*>(trueSoln);
- BSONElement el = testSoln["andHash"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj andHashObj = el.Obj();
-
- BSONElement filter = andHashObj["filter"];
- if (!filter.eoo()) {
- if (filter.isNull()) {
- if (NULL != ahn->filter) { return false; }
- }
- else if (!filter.isABSONObj()) {
- return false;
- }
- else if (!filterMatches(filter.Obj(), trueSoln)) {
+ BSONElement filter = fetchObj["filter"];
+ if (!filter.eoo()) {
+ if (filter.isNull()) {
+ if (NULL != fn->filter) {
return false;
}
+ } else if (!filter.isABSONObj()) {
+ return false;
+ } else if (!filterMatches(filter.Obj(), trueSoln)) {
+ return false;
}
+ }
- return childrenMatch(andHashObj, ahn);
+ BSONElement child = fetchObj["node"];
+ if (child.eoo() || !child.isABSONObj()) {
+ return false;
+ }
+ return solutionMatches(child.Obj(), fn->children[0]);
+ } else if (STAGE_OR == trueSoln->getType()) {
+ const OrNode* orn = static_cast<const OrNode*>(trueSoln);
+ BSONElement el = testSoln["or"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj orObj = el.Obj();
+ return childrenMatch(orObj, orn);
+ } else if (STAGE_AND_HASH == trueSoln->getType()) {
+ const AndHashNode* ahn = static_cast<const AndHashNode*>(trueSoln);
+ BSONElement el = testSoln["andHash"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
}
- else if (STAGE_AND_SORTED == trueSoln->getType()) {
- const AndSortedNode* asn = static_cast<const AndSortedNode*>(trueSoln);
- BSONElement el = testSoln["andSorted"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj andSortedObj = el.Obj();
+ BSONObj andHashObj = el.Obj();
- BSONElement filter = andSortedObj["filter"];
- if (!filter.eoo()) {
- if (filter.isNull()) {
- if (NULL != asn->filter) { return false; }
- }
- else if (!filter.isABSONObj()) {
- return false;
- }
- else if (!filterMatches(filter.Obj(), trueSoln)) {
+ BSONElement filter = andHashObj["filter"];
+ if (!filter.eoo()) {
+ if (filter.isNull()) {
+ if (NULL != ahn->filter) {
return false;
}
+ } else if (!filter.isABSONObj()) {
+ return false;
+ } else if (!filterMatches(filter.Obj(), trueSoln)) {
+ return false;
}
-
- return childrenMatch(andSortedObj, asn);
}
- else if (STAGE_PROJECTION == trueSoln->getType()) {
- const ProjectionNode* pn = static_cast<const ProjectionNode*>(trueSoln);
- BSONElement el = testSoln["proj"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj projObj = el.Obj();
+ return childrenMatch(andHashObj, ahn);
+ } else if (STAGE_AND_SORTED == trueSoln->getType()) {
+ const AndSortedNode* asn = static_cast<const AndSortedNode*>(trueSoln);
+ BSONElement el = testSoln["andSorted"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj andSortedObj = el.Obj();
- BSONElement projType = projObj["type"];
- if (!projType.eoo()) {
- string projTypeStr = projType.str();
- if (!((pn->projType == ProjectionNode::DEFAULT && projTypeStr == "default") ||
- (pn->projType == ProjectionNode::SIMPLE_DOC && projTypeStr == "simple") ||
- (pn->projType == ProjectionNode::COVERED_ONE_INDEX &&
- projTypeStr == "coveredIndex"))) {
+ BSONElement filter = andSortedObj["filter"];
+ if (!filter.eoo()) {
+ if (filter.isNull()) {
+ if (NULL != asn->filter) {
return false;
}
+ } else if (!filter.isABSONObj()) {
+ return false;
+ } else if (!filterMatches(filter.Obj(), trueSoln)) {
+ return false;
}
+ }
- BSONElement spec = projObj["spec"];
- if (spec.eoo() || !spec.isABSONObj()) { return false; }
- BSONElement child = projObj["node"];
- if (child.eoo() || !child.isABSONObj()) { return false; }
+ return childrenMatch(andSortedObj, asn);
+ } else if (STAGE_PROJECTION == trueSoln->getType()) {
+ const ProjectionNode* pn = static_cast<const ProjectionNode*>(trueSoln);
- return (spec.Obj() == pn->projection)
- && solutionMatches(child.Obj(), pn->children[0]);
+ BSONElement el = testSoln["proj"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj projObj = el.Obj();
+
+ BSONElement projType = projObj["type"];
+ if (!projType.eoo()) {
+ string projTypeStr = projType.str();
+ if (!((pn->projType == ProjectionNode::DEFAULT && projTypeStr == "default") ||
+ (pn->projType == ProjectionNode::SIMPLE_DOC && projTypeStr == "simple") ||
+ (pn->projType == ProjectionNode::COVERED_ONE_INDEX &&
+ projTypeStr == "coveredIndex"))) {
+ return false;
+ }
}
- else if (STAGE_SORT == trueSoln->getType()) {
- const SortNode* sn = static_cast<const SortNode*>(trueSoln);
- BSONElement el = testSoln["sort"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj sortObj = el.Obj();
- BSONElement patternEl = sortObj["pattern"];
- if (patternEl.eoo() || !patternEl.isABSONObj()) { return false; }
- BSONElement limitEl = sortObj["limit"];
- if (!limitEl.isNumber()) { return false; }
- BSONElement child = sortObj["node"];
- if (child.eoo() || !child.isABSONObj()) { return false; }
+ BSONElement spec = projObj["spec"];
+ if (spec.eoo() || !spec.isABSONObj()) {
+ return false;
+ }
+ BSONElement child = projObj["node"];
+ if (child.eoo() || !child.isABSONObj()) {
+ return false;
+ }
- size_t expectedLimit = limitEl.numberInt();
- return (patternEl.Obj() == sn->pattern)
- && (expectedLimit == sn->limit)
- && solutionMatches(child.Obj(), sn->children[0]);
+ return (spec.Obj() == pn->projection) && solutionMatches(child.Obj(), pn->children[0]);
+ } else if (STAGE_SORT == trueSoln->getType()) {
+ const SortNode* sn = static_cast<const SortNode*>(trueSoln);
+ BSONElement el = testSoln["sort"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj sortObj = el.Obj();
+
+ BSONElement patternEl = sortObj["pattern"];
+ if (patternEl.eoo() || !patternEl.isABSONObj()) {
+ return false;
}
- else if (STAGE_SORT_MERGE == trueSoln->getType()) {
- const MergeSortNode* msn = static_cast<const MergeSortNode*>(trueSoln);
- BSONElement el = testSoln["mergeSort"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj mergeSortObj = el.Obj();
- return childrenMatch(mergeSortObj, msn);
+ BSONElement limitEl = sortObj["limit"];
+ if (!limitEl.isNumber()) {
+ return false;
+ }
+ BSONElement child = sortObj["node"];
+ if (child.eoo() || !child.isABSONObj()) {
+ return false;
}
- else if (STAGE_SKIP == trueSoln->getType()) {
- const SkipNode* sn = static_cast<const SkipNode*>(trueSoln);
- BSONElement el = testSoln["skip"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj sortObj = el.Obj();
- BSONElement skipEl = sortObj["n"];
- if (!skipEl.isNumber()) { return false; }
- BSONElement child = sortObj["node"];
- if (child.eoo() || !child.isABSONObj()) { return false; }
+ size_t expectedLimit = limitEl.numberInt();
+ return (patternEl.Obj() == sn->pattern) && (expectedLimit == sn->limit) &&
+ solutionMatches(child.Obj(), sn->children[0]);
+ } else if (STAGE_SORT_MERGE == trueSoln->getType()) {
+ const MergeSortNode* msn = static_cast<const MergeSortNode*>(trueSoln);
+ BSONElement el = testSoln["mergeSort"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj mergeSortObj = el.Obj();
+ return childrenMatch(mergeSortObj, msn);
+ } else if (STAGE_SKIP == trueSoln->getType()) {
+ const SkipNode* sn = static_cast<const SkipNode*>(trueSoln);
+ BSONElement el = testSoln["skip"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj sortObj = el.Obj();
- return (skipEl.numberInt() == sn->skip)
- && solutionMatches(child.Obj(), sn->children[0]);
+ BSONElement skipEl = sortObj["n"];
+ if (!skipEl.isNumber()) {
+ return false;
+ }
+ BSONElement child = sortObj["node"];
+ if (child.eoo() || !child.isABSONObj()) {
+ return false;
}
- else if (STAGE_LIMIT == trueSoln->getType()) {
- const LimitNode* ln = static_cast<const LimitNode*>(trueSoln);
- BSONElement el = testSoln["limit"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj sortObj = el.Obj();
- BSONElement limitEl = sortObj["n"];
- if (!limitEl.isNumber()) { return false; }
- BSONElement child = sortObj["node"];
- if (child.eoo() || !child.isABSONObj()) { return false; }
+ return (skipEl.numberInt() == sn->skip) && solutionMatches(child.Obj(), sn->children[0]);
+ } else if (STAGE_LIMIT == trueSoln->getType()) {
+ const LimitNode* ln = static_cast<const LimitNode*>(trueSoln);
+ BSONElement el = testSoln["limit"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj sortObj = el.Obj();
- return (limitEl.numberInt() == ln->limit)
- && solutionMatches(child.Obj(), ln->children[0]);
+ BSONElement limitEl = sortObj["n"];
+ if (!limitEl.isNumber()) {
+ return false;
+ }
+ BSONElement child = sortObj["node"];
+ if (child.eoo() || !child.isABSONObj()) {
+ return false;
}
- else if (STAGE_KEEP_MUTATIONS == trueSoln->getType()) {
- const KeepMutationsNode* kn = static_cast<const KeepMutationsNode*>(trueSoln);
- BSONElement el = testSoln["keep"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj keepObj = el.Obj();
+ return (limitEl.numberInt() == ln->limit) && solutionMatches(child.Obj(), ln->children[0]);
+ } else if (STAGE_KEEP_MUTATIONS == trueSoln->getType()) {
+ const KeepMutationsNode* kn = static_cast<const KeepMutationsNode*>(trueSoln);
- // Doesn't have any parameters really.
- BSONElement child = keepObj["node"];
- if (child.eoo() || !child.isABSONObj()) { return false; }
+ BSONElement el = testSoln["keep"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj keepObj = el.Obj();
- return solutionMatches(child.Obj(), kn->children[0]);
+ // Doesn't have any parameters really.
+ BSONElement child = keepObj["node"];
+ if (child.eoo() || !child.isABSONObj()) {
+ return false;
}
- else if (STAGE_SHARDING_FILTER == trueSoln->getType()) {
- const ShardingFilterNode* fn = static_cast<const ShardingFilterNode*>(trueSoln);
- BSONElement el = testSoln["sharding_filter"];
- if (el.eoo() || !el.isABSONObj()) { return false; }
- BSONObj keepObj = el.Obj();
+ return solutionMatches(child.Obj(), kn->children[0]);
+ } else if (STAGE_SHARDING_FILTER == trueSoln->getType()) {
+ const ShardingFilterNode* fn = static_cast<const ShardingFilterNode*>(trueSoln);
- BSONElement child = keepObj["node"];
- if (child.eoo() || !child.isABSONObj()) { return false; }
+ BSONElement el = testSoln["sharding_filter"];
+ if (el.eoo() || !el.isABSONObj()) {
+ return false;
+ }
+ BSONObj keepObj = el.Obj();
- return solutionMatches(child.Obj(), fn->children[0]);
+ BSONElement child = keepObj["node"];
+ if (child.eoo() || !child.isABSONObj()) {
+ return false;
}
- return false;
+ return solutionMatches(child.Obj(), fn->children[0]);
}
+ return false;
+}
+
} // namespace mongo