diff options
author | David Storch <david.storch@10gen.com> | 2014-04-30 13:02:47 -0400 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2014-05-06 15:52:00 -0400 |
commit | eb97470c0507020e3c0f1cc47751feaa777b5d2e (patch) | |
tree | 49d91ee161d6b61cda68314c463dd292c1f72cca /src/mongo/db/query/planner_access.cpp | |
parent | b9e8c0fc3fb61f15fcd7516760ad4d49f32f5990 (diff) | |
download | mongo-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.cpp | 48 |
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. |