void SortKeyGenerator::getBoundsForSort(OperationContext* txn, const BSONObj& queryObj, const BSONObj& sortObj) { QueryPlannerParams params; params.options = QueryPlannerParams::NO_TABLE_SCAN; // We're creating a "virtual index" with key pattern equal to the sort order. IndexEntry sortOrder(sortObj, IndexNames::BTREE, true, MultikeyPaths{}, false, false, "doesnt_matter", NULL, BSONObj()); params.indices.push_back(sortOrder); auto statusWithQueryForSort = CanonicalQuery::canonicalize( txn, NamespaceString("fake.ns"), queryObj, ExtensionsCallbackNoop()); verify(statusWithQueryForSort.isOK()); std::unique_ptr<CanonicalQuery> queryForSort = std::move(statusWithQueryForSort.getValue()); std::vector<QuerySolution*> solns; LOG(5) << "Sort key generation: Planning to obtain bounds for sort."; QueryPlanner::plan(*queryForSort, params, &solns); // TODO: are there ever > 1 solns? If so, do we look for a specific soln? if (1 == solns.size()) { IndexScanNode* ixScan = NULL; QuerySolutionNode* rootNode = solns[0]->root.get(); if (rootNode->getType() == STAGE_FETCH) { FetchNode* fetchNode = static_cast<FetchNode*>(rootNode); if (fetchNode->children[0]->getType() != STAGE_IXSCAN) { delete solns[0]; // No bounds. return; } ixScan = static_cast<IndexScanNode*>(fetchNode->children[0]); } else if (rootNode->getType() == STAGE_IXSCAN) { ixScan = static_cast<IndexScanNode*>(rootNode); } if (ixScan) { _bounds.fields.swap(ixScan->bounds.fields); _hasBounds = true; } } for (size_t i = 0; i < solns.size(); ++i) { delete solns[i]; } }
void SortStageKeyGenerator::getBoundsForSort(const BSONObj& queryObj, const BSONObj& sortObj) { QueryPlannerParams params; params.options = QueryPlannerParams::NO_TABLE_SCAN; // We're creating a "virtual index" with key pattern equal to the sort order. IndexEntry sortOrder(sortObj, IndexNames::BTREE, true, false, false, "doesnt_matter", BSONObj()); params.indices.push_back(sortOrder); CanonicalQuery* rawQueryForSort; verify(CanonicalQuery::canonicalize( "fake_ns", queryObj, &rawQueryForSort, WhereCallbackNoop()).isOK()); auto_ptr<CanonicalQuery> queryForSort(rawQueryForSort); vector<QuerySolution*> solns; QLOG() << "Sort stage: Planning to obtain bounds for sort." << endl; QueryPlanner::plan(*queryForSort, params, &solns); // TODO: are there ever > 1 solns? If so, do we look for a specific soln? if (1 == solns.size()) { IndexScanNode* ixScan = NULL; QuerySolutionNode* rootNode = solns[0]->root.get(); if (rootNode->getType() == STAGE_FETCH) { FetchNode* fetchNode = static_cast<FetchNode*>(rootNode); if (fetchNode->children[0]->getType() != STAGE_IXSCAN) { delete solns[0]; // No bounds. return; } ixScan = static_cast<IndexScanNode*>(fetchNode->children[0]); } else if (rootNode->getType() == STAGE_IXSCAN) { ixScan = static_cast<IndexScanNode*>(rootNode); } if (ixScan) { _bounds.fields.swap(ixScan->bounds.fields); _hasBounds = true; } } for (size_t i = 0; i < solns.size(); ++i) { delete solns[i]; } }
/** * If possible, turn the provided QuerySolution into a QuerySolution that uses a DistinctNode * to provide results for the distinct command. * * If the provided solution could be mutated successfully, returns true, otherwise returns * false. */ bool turnIxscanIntoDistinctIxscan(QuerySolution* soln, const string& field) { QuerySolutionNode* root = soln->root.get(); // We're looking for a project on top of an ixscan. if (STAGE_PROJECTION == root->getType() && (STAGE_IXSCAN == root->children[0]->getType())) { IndexScanNode* isn = static_cast<IndexScanNode*>(root->children[0]); // An additional filter must be applied to the data in the key, so we can't just skip // all the keys with a given value; we must examine every one to find the one that (may) // pass the filter. if (NULL != isn->filter.get()) { return false; } // We only set this when we have special query modifiers (.max() or .min()) or other // special cases. Don't want to handle the interactions between those and distinct. // Don't think this will ever really be true but if it somehow is, just ignore this // soln. if (isn->bounds.isSimpleRange) { return false; } // Make a new DistinctNode. We swap this for the ixscan in the provided solution. DistinctNode* dn = new DistinctNode(); dn->indexKeyPattern = isn->indexKeyPattern; dn->direction = isn->direction; dn->bounds = isn->bounds; // Figure out which field we're skipping to the next value of. TODO: We currently only // try to distinct-hack when there is an index prefixed by the field we're distinct-ing // over. Consider removing this code if we stick with that policy. dn->fieldNo = 0; BSONObjIterator it(isn->indexKeyPattern); while (it.more()) { if (field == it.next().fieldName()) { break; } dn->fieldNo++; } // Delete the old index scan, set the child of project to the fast distinct scan. delete root->children[0]; root->children[0] = dn; return true; } return false; }
//static bool StageBuilder::build(const QuerySolution& solution, PlanStage** rootOut, WorkingSet** wsOut) { QuerySolutionNode* root = solution.root.get(); if (NULL == root) { return false; } if (STAGE_COLLSCAN == root->getType()) { const CollectionScanNode* csn = static_cast<const CollectionScanNode*>(root); CollectionScanParams params; params.ns = csn->name; params.tailable = csn->tailable; params.direction = (csn->direction == 1) ? CollectionScanParams::FORWARD : CollectionScanParams::BACKWARD; *wsOut = new WorkingSet(); *rootOut = new CollectionScan(params, *wsOut, csn->filter); return true; } else { return false; } }