summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/planner_access.cpp
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2014-04-30 13:02:47 -0400
committerDavid Storch <david.storch@10gen.com>2014-05-06 15:52:00 -0400
commiteb97470c0507020e3c0f1cc47751feaa777b5d2e (patch)
tree49d91ee161d6b61cda68314c463dd292c1f72cca /src/mongo/db/query/planner_access.cpp
parentb9e8c0fc3fb61f15fcd7516760ad4d49f32f5990 (diff)
downloadmongo-eb97470c0507020e3c0f1cc47751feaa777b5d2e.tar.gz
SERVER-13789 recursively build data access for subnodes beneath elemMatch
Diffstat (limited to 'src/mongo/db/query/planner_access.cpp')
-rw-r--r--src/mongo/db/query/planner_access.cpp48
1 files changed, 42 insertions, 6 deletions
diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp
index fc0fb1c2030..413860ac396 100644
--- a/src/mongo/db/query/planner_access.cpp
+++ b/src/mongo/db/query/planner_access.cpp
@@ -482,16 +482,20 @@ namespace mongo {
// static
void QueryPlannerAccess::findElemMatchChildren(const MatchExpression* node,
- vector<MatchExpression*>* out) {
+ vector<MatchExpression*>* out,
+ vector<MatchExpression*>* subnodesOut) {
for (size_t i = 0; i < node->numChildren(); ++i) {
MatchExpression* child = node->getChild(i);
- if (Indexability::nodeCanUseIndexOnOwnField(child) &&
+ if (Indexability::isBoundsGenerating(child) &&
NULL != child->getTag()) {
out->push_back(child);
}
else if (MatchExpression::AND == child->matchType() ||
Indexability::arrayUsesIndexOnChildren(child)) {
- findElemMatchChildren(child, out);
+ findElemMatchChildren(child, out, subnodesOut);
+ }
+ else if (NULL != child->getTag()) {
+ subnodesOut->push_back(child);
}
}
}
@@ -545,10 +549,42 @@ namespace mongo {
// predicates from inside the $elemMatch, and try to merge them with
// the current index scan.
- // Populate 'emChildren' with tagged predicates from inside the
- // tree rooted at 'child.
+ // Contains tagged predicates from inside the tree rooted at 'child'
+ // which are logically part of the AND.
vector<MatchExpression*> emChildren;
- findElemMatchChildren(child, &emChildren);
+
+ // Contains tagged nodes that are not logically part of the AND and
+ // cannot use the index directly (e.g. OR nodes which are tagged to
+ // be indexed).
+ vector<MatchExpression*> emSubnodes;
+
+ // Populate 'emChildren' and 'emSubnodes'.
+ findElemMatchChildren(child, &emChildren, &emSubnodes);
+
+ // Recursively build data access for the nodes inside 'emSubnodes'.
+ for (size_t i = 0; i < emSubnodes.size(); ++i) {
+ MatchExpression* subnode = emSubnodes[i];
+
+ if (!Indexability::isBoundsGenerating(subnode)) {
+ // Must pass true for 'inArrayOperator' because the subnode is
+ // beneath an ELEM_MATCH_OBJECT.
+ QuerySolutionNode* childSolution = buildIndexedDataAccess(query,
+ subnode,
+ true,
+ indices);
+
+ // buildIndexedDataAccess(...) returns NULL in error conditions, when
+ // it is unable to construct a query solution from a tagged match
+ // expression tree. If we are unable to construct a solution according
+ // to the instructions from the enumerator, then we bail out early
+ // (by returning false) rather than continuing on and potentially
+ // constructing an invalid solution tree.
+ if (NULL == childSolution) { return false; }
+
+ // Output the resulting solution tree.
+ out->push_back(childSolution);
+ }
+ }
// For each predicate in 'emChildren', try to merge it with the
// current index scan.