diff options
author | Ian Boros <ian.boros@mongodb.com> | 2020-01-30 13:10:55 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-02-28 22:16:41 +0000 |
commit | cfa5c05fa1855fb1a04cb3a6e2eb10a7e82bf726 (patch) | |
tree | 7ab1e1ce8e2edd6837952c131fe14d43a0633235 /src/mongo/db/query | |
parent | 793ae32c597f197b6445750aa9bfdaabc206132d (diff) | |
download | mongo-cfa5c05fa1855fb1a04cb3a6e2eb10a7e82bf726.tar.gz |
SERVER-45406 Plumb ExpressionContext through PlanStage
This patch includes also moves ownership of the collator to the ExpressionContext.
Diffstat (limited to 'src/mongo/db/query')
-rw-r--r-- | src/mongo/db/query/canonical_query.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/query/canonical_query.h | 5 | ||||
-rw-r--r-- | src/mongo/db/query/get_executor.cpp | 108 | ||||
-rw-r--r-- | src/mongo/db/query/get_executor.h | 20 | ||||
-rw-r--r-- | src/mongo/db/query/internal_plans.cpp | 74 | ||||
-rw-r--r-- | src/mongo/db/query/internal_plans.h | 28 | ||||
-rw-r--r-- | src/mongo/db/query/plan_cache_indexability_test.cpp | 37 | ||||
-rw-r--r-- | src/mongo/db/query/projection_test.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_partialidx_test.cpp | 24 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_test_fixture.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_test_fixture.h | 13 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_test_lib.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/query/query_solution_test.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/query/stage_builder.cpp | 39 |
14 files changed, 239 insertions, 168 deletions
diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index 5d977f17737..fdb8cc496ec 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -152,8 +152,8 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( // Make MatchExpression. boost::intrusive_ptr<ExpressionContext> newExpCtx; if (!expCtx.get()) { - newExpCtx.reset( - new ExpressionContext(opCtx, collator.get(), qr->nss(), qr->getRuntimeConstants())); + newExpCtx = make_intrusive<ExpressionContext>( + opCtx, std::move(collator), qr->nss(), qr->getRuntimeConstants()); } else { newExpCtx = expCtx; invariant(CollatorInterface::collatorsMatch(collator.get(), expCtx->getCollator())); @@ -175,7 +175,6 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( std::move(qr), parsingCanProduceNoopMatchNodes(extensionsCallback, allowedFeatures), std::move(me), - std::move(collator), projectionPolicies); if (!initStatus.isOK()) { @@ -200,11 +199,6 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( return qrStatus; } - std::unique_ptr<CollatorInterface> collator; - if (baseQuery.getCollator()) { - collator = baseQuery.getCollator()->clone(); - } - // Make the CQ we'll hopefully return. std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery()); Status initStatus = cq->init(opCtx, @@ -212,7 +206,6 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( std::move(qr), baseQuery.canHaveNoopMatchNodes(), root->shallowClone(), - std::move(collator), ProjectionPolicies::findProjectionPolicies()); if (!initStatus.isOK()) { @@ -226,11 +219,9 @@ Status CanonicalQuery::init(OperationContext* opCtx, std::unique_ptr<QueryRequest> qr, bool canHaveNoopMatchNodes, std::unique_ptr<MatchExpression> root, - std::unique_ptr<CollatorInterface> collator, const ProjectionPolicies& projectionPolicies) { _expCtx = expCtx; _qr = std::move(qr); - _collator = std::move(collator); _canHaveNoopMatchNodes = canHaveNoopMatchNodes; @@ -305,15 +296,13 @@ void CanonicalQuery::initSortPattern(QueryMetadataBitSet unavailableMetadata) { } void CanonicalQuery::setCollator(std::unique_ptr<CollatorInterface> collator) { - _collator = std::move(collator); + auto collatorRaw = collator.get(); + // We must give the ExpressionContext the same collator. + _expCtx->setCollator(std::move(collator)); // The collator associated with the match expression tree is now invalid, since we have reset - // the object owned by '_collator'. We must associate the match expression tree with the new - // value of '_collator'. - _root->setCollator(_collator.get()); - - // In a similar vein, we must give the ExpressionContext the same collator. - _expCtx->setCollator(_collator.get()); + // the collator owned by the ExpressionContext. + _root->setCollator(collatorRaw); } // static diff --git a/src/mongo/db/query/canonical_query.h b/src/mongo/db/query/canonical_query.h index 2598ac3157c..e1261805e20 100644 --- a/src/mongo/db/query/canonical_query.h +++ b/src/mongo/db/query/canonical_query.h @@ -154,7 +154,7 @@ public: } const CollatorInterface* getCollator() const { - return _collator.get(); + return _expCtx->getCollator(); } /** @@ -227,7 +227,6 @@ private: std::unique_ptr<QueryRequest> qr, bool canHaveNoopMatchNodes, std::unique_ptr<MatchExpression> root, - std::unique_ptr<CollatorInterface> collator, const ProjectionPolicies& projectionPolicies); // Initializes '_sortPattern', adding any metadata dependencies implied by the sort. @@ -250,8 +249,6 @@ private: // Keeps track of what metadata has been explicitly requested. QueryMetadataBitSet _metadataDeps; - std::unique_ptr<CollatorInterface> _collator; - bool _canHaveNoopMatchNodes = false; }; diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index cba75f67e00..6388f5986b0 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -97,6 +97,19 @@ using std::string; using std::unique_ptr; using std::vector; +boost::intrusive_ptr<ExpressionContext> makeExpressionContextForGetExecutor( + OperationContext* opCtx, const BSONObj& requestCollation, const NamespaceString& nss) { + invariant(opCtx); + + auto expCtx = make_intrusive<ExpressionContext>(opCtx, nullptr, nss); + if (!requestCollation.isEmpty()) { + auto statusWithCollator = CollatorFactoryInterface::get(expCtx->opCtx->getServiceContext()) + ->makeFromBSON(requestCollation); + expCtx->setCollator(uassertStatusOK(std::move(statusWithCollator))); + } + return expCtx; +} + // static void filterAllowedIndexEntries(const AllowedIndicesFilter& allowedIndicesFilter, std::vector<IndexEntry>* indexEntries) { @@ -368,7 +381,7 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, "Collection {ns} does not exist. Using EOF plan: {canonicalQuery_Short}", "ns"_attr = ns, "canonicalQuery_Short"_attr = redact(canonicalQuery->toStringShort())); - root = std::make_unique<EOFStage>(opCtx); + root = std::make_unique<EOFStage>(canonicalQuery->getExpCtx().get()); return PrepareExecutionResult(std::move(canonicalQuery), nullptr, std::move(root)); } @@ -377,10 +390,10 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, plannerParams.options = plannerOptions; fillOutPlannerParams(opCtx, collection, canonicalQuery.get(), &plannerParams); - // If the canonical query does not have a user-specified collation, set it from the collection - // default. + // If the canonical query does not have a user-specified collation and no one has given the + // CanonicalQuery a collation already, set it from the collection default. if (canonicalQuery->getQueryRequest().getCollation().isEmpty() && - collection->getDefaultCollator()) { + canonicalQuery->getCollator() == nullptr && collection->getDefaultCollator()) { canonicalQuery->setCollator(collection->getDefaultCollator()->clone()); } @@ -393,12 +406,13 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, "Using idhack: {canonicalQuery_Short}", "canonicalQuery_Short"_attr = redact(canonicalQuery->toStringShort())); - root = std::make_unique<IDHackStage>(opCtx, canonicalQuery.get(), ws, descriptor); + root = std::make_unique<IDHackStage>( + canonicalQuery->getExpCtx().get(), canonicalQuery.get(), ws, descriptor); // Might have to filter out orphaned docs. if (plannerParams.options & QueryPlannerParams::INCLUDE_SHARD_FILTER) { root = std::make_unique<ShardFilterStage>( - opCtx, + canonicalQuery->getExpCtx().get(), CollectionShardingState::get(opCtx, canonicalQuery->nss()) ->getOwnershipFilter(opCtx), ws, @@ -410,7 +424,7 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, // Add a SortKeyGeneratorStage if the query requested sortKey metadata. if (canonicalQuery->metadataDeps()[DocumentMetadataFields::kSortKey]) { root = std::make_unique<SortKeyGeneratorStage>( - canonicalQuery->getExpCtx(), + canonicalQuery->getExpCtx().get(), std::move(root), ws, canonicalQuery->getQueryRequest().getSort()); @@ -422,7 +436,7 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, // the exception the $meta sortKey projection, which can be used along with the // returnKey. root = std::make_unique<ReturnKeyStage>( - opCtx, + canonicalQuery->getExpCtx().get(), cqProjection ? QueryPlannerCommon::extractSortKeyMetaFieldsFromProjection(*cqProjection) : std::vector<FieldPath>{}, @@ -443,7 +457,7 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, std::move(root)); } else { root = std::make_unique<ProjectionStageSimple>( - canonicalQuery->getExpCtx(), + canonicalQuery->getExpCtx().get(), canonicalQuery->getQueryRequest().getProj(), canonicalQuery->getProj(), ws, @@ -498,13 +512,14 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, // // 'decisionWorks' is used to determine whether the existing cache entry should // be evicted, and the query replanned. - auto cachedPlanStage = std::make_unique<CachedPlanStage>(opCtx, - collection, - ws, - canonicalQuery.get(), - plannerParams, - cs->decisionWorks, - std::move(root)); + auto cachedPlanStage = + std::make_unique<CachedPlanStage>(canonicalQuery->getExpCtx().get(), + collection, + ws, + canonicalQuery.get(), + plannerParams, + cs->decisionWorks, + std::move(root)); return PrepareExecutionResult(std::move(canonicalQuery), std::move(querySolution), std::move(cachedPlanStage)); @@ -520,7 +535,7 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, "canonicalQuery_Short"_attr = redact(canonicalQuery->toStringShort())); root = std::make_unique<SubplanStage>( - opCtx, collection, ws, plannerParams, canonicalQuery.get()); + canonicalQuery->getExpCtx().get(), collection, ws, plannerParams, canonicalQuery.get()); return PrepareExecutionResult(std::move(canonicalQuery), nullptr, std::move(root)); } @@ -572,8 +587,8 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, } else { // Many solutions. Create a MultiPlanStage to pick the best, update the cache, // and so on. The working set will be shared by all candidate plans. - auto multiPlanStage = - std::make_unique<MultiPlanStage>(opCtx, collection, canonicalQuery.get()); + auto multiPlanStage = std::make_unique<MultiPlanStage>( + canonicalQuery->getExpCtx().get(), collection, canonicalQuery.get()); for (size_t ix = 0; ix < solutions.size(); ++ix) { if (solutions[ix]->cacheData.get()) { @@ -715,11 +730,12 @@ StatusWith<unique_ptr<PlanStage>> applyProjection(OperationContext* opCtx, // StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( - OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedDelete* parsedDelete, boost::optional<ExplainOptions::Verbosity> verbosity) { + auto expCtx = parsedDelete->expCtx(); + OperationContext* opCtx = expCtx->opCtx; const DeleteRequest* request = parsedDelete->getRequest(); const NamespaceString& nss(request->getNamespaceString()); @@ -763,7 +779,7 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( "nss_ns"_attr = nss.ns(), "request_getQuery"_attr = redact(request->getQuery())); return PlanExecutor::make( - opCtx, std::move(ws), std::make_unique<EOFStage>(opCtx), nullptr, policy, nss); + opCtx, std::move(ws), std::make_unique<EOFStage>(expCtx.get()), nullptr, policy, nss); } if (!parsedDelete->hasParsedQuery()) { @@ -794,9 +810,13 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( "unparsedQuery"_attr = redact(unparsedQuery)); auto idHackStage = std::make_unique<IDHackStage>( - opCtx, unparsedQuery["_id"].wrap(), ws.get(), descriptor); - unique_ptr<DeleteStage> root = std::make_unique<DeleteStage>( - opCtx, std::move(deleteStageParams), ws.get(), collection, idHackStage.release()); + expCtx.get(), unparsedQuery["_id"].wrap(), ws.get(), descriptor); + unique_ptr<DeleteStage> root = + std::make_unique<DeleteStage>(expCtx.get(), + std::move(deleteStageParams), + ws.get(), + collection, + idHackStage.release()); return PlanExecutor::make(opCtx, std::move(ws), std::move(root), collection, policy); } @@ -831,7 +851,7 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( invariant(root); root = std::make_unique<DeleteStage>( - opCtx, std::move(deleteStageParams), ws.get(), collection, root.release()); + cq->getExpCtx().get(), std::move(deleteStageParams), ws.get(), collection, root.release()); if (!request->getProj().isEmpty()) { invariant(request->shouldReturnDeleted()); @@ -861,11 +881,13 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( // StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate( - OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedUpdate* parsedUpdate, boost::optional<ExplainOptions::Verbosity> verbosity) { + auto expCtx = parsedUpdate->expCtx(); + OperationContext* opCtx = expCtx->opCtx; + const UpdateRequest* request = parsedUpdate->getRequest(); UpdateDriver* driver = parsedUpdate->getDriver(); @@ -918,7 +940,7 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate( "nss_ns"_attr = nss.ns(), "request_getQuery"_attr = redact(request->getQuery())); return PlanExecutor::make( - opCtx, std::move(ws), std::make_unique<EOFStage>(opCtx), nullptr, policy, nss); + opCtx, std::move(ws), std::make_unique<EOFStage>(expCtx.get()), nullptr, policy, nss); } // Pass index information to the update driver, so that it can determine for us whether the @@ -937,7 +959,7 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate( const IndexDescriptor* descriptor = collection->getIndexCatalog()->findIdIndex(opCtx); const bool hasCollectionDefaultCollation = CollatorInterface::collatorsMatch( - parsedUpdate->getCollator(), collection->getDefaultCollator()); + expCtx->getCollator(), collection->getDefaultCollator()); if (descriptor && CanonicalQuery::isSimpleIdQuery(unparsedQuery) && request->getProj().isEmpty() && hasCollectionDefaultCollation) { @@ -988,10 +1010,12 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate( updateStageParams.canonicalQuery = cq.get(); const bool isUpsert = updateStageParams.request->isUpsert(); - root = (isUpsert ? std::make_unique<UpsertStage>( - opCtx, updateStageParams, ws.get(), collection, root.release()) - : std::make_unique<UpdateStage>( - opCtx, updateStageParams, ws.get(), collection, root.release())); + root = + (isUpsert + ? std::make_unique<UpsertStage>( + cq->getExpCtx().get(), updateStageParams, ws.get(), collection, root.release()) + : std::make_unique<UpdateStage>( + cq->getExpCtx().get(), updateStageParams, ws.get(), collection, root.release())); if (!request->getProj().isEmpty()) { invariant(request->shouldReturnAnyDocs()); @@ -1157,11 +1181,12 @@ bool getDistinctNodeIndex(const std::vector<IndexEntry>& indices, } // namespace StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCount( - OperationContext* opCtx, + const boost::intrusive_ptr<ExpressionContext>& expCtx, Collection* collection, const CountCommand& request, bool explain, const NamespaceString& nss) { + OperationContext* opCtx = expCtx->opCtx; unique_ptr<WorkingSet> ws = std::make_unique<WorkingSet>(); auto qr = std::make_unique<QueryRequest>(nss); @@ -1171,7 +1196,6 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCount( qr->setHint(request.getHint()); qr->setExplain(explain); - const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize( opCtx, std::move(qr), @@ -1197,7 +1221,7 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCount( // machinery always assumes that the root stage for a count operation is a CountStage, so in // this case we put a CountStage on top of an EOFStage. unique_ptr<PlanStage> root = std::make_unique<CountStage>( - opCtx, collection, limit, skip, ws.get(), new EOFStage(opCtx)); + expCtx.get(), collection, limit, skip, ws.get(), new EOFStage(expCtx.get())); return PlanExecutor::make(opCtx, std::move(ws), std::move(root), nullptr, yieldPolicy, nss); } @@ -1212,7 +1236,7 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCount( if (useRecordStoreCount) { unique_ptr<PlanStage> root = - std::make_unique<RecordStoreFastCountStage>(opCtx, collection, skip, limit); + std::make_unique<RecordStoreFastCountStage>(expCtx.get(), collection, skip, limit); return PlanExecutor::make(opCtx, std::move(ws), std::move(root), nullptr, yieldPolicy, nss); } @@ -1233,7 +1257,8 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCount( invariant(root); // Make a CountStage to be the new root. - root = std::make_unique<CountStage>(opCtx, collection, limit, skip, ws.get(), root.release()); + root = std::make_unique<CountStage>( + expCtx.get(), collection, limit, skip, ws.get(), root.release()); // We must have a tree of stages in order to have a valid plan executor, but the query // solution may be NULL. Takes ownership of all args other than 'collection' and 'opCtx' return PlanExecutor::make(std::move(cq), @@ -1641,10 +1666,9 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorWithoutPr } // namespace StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDistinct( - OperationContext* opCtx, - Collection* collection, - size_t plannerOptions, - ParsedDistinct* parsedDistinct) { + Collection* collection, size_t plannerOptions, ParsedDistinct* parsedDistinct) { + auto expCtx = parsedDistinct->getQuery()->getExpCtx(); + OperationContext* opCtx = expCtx->opCtx; const auto yieldPolicy = opCtx->inMultiDocumentTransaction() ? PlanExecutor::INTERRUPT_ONLY : PlanExecutor::YIELD_AUTO; @@ -1652,7 +1676,7 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDistinct( // Treat collections that do not exist as empty collections. return PlanExecutor::make(parsedDistinct->releaseQuery(), std::make_unique<WorkingSet>(), - std::make_unique<EOFStage>(opCtx), + std::make_unique<EOFStage>(expCtx.get()), collection, yieldPolicy); } diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h index 99e1657c6a7..4390557ef05 100644 --- a/src/mongo/db/query/get_executor.h +++ b/src/mongo/db/query/get_executor.h @@ -49,6 +49,17 @@ class Collection; class CountRequest; /** + * Make an ExpressionContext to be used for non-aggregate commands. The result of this can be passed + * into any of the getExecutor* functions. + * + * Note that the getExecutor* functions may change the collation on the returned ExpressionContext + * if the collection has a default collation and no collation was specifically requested + * ('requestCollation' is empty). + */ +boost::intrusive_ptr<ExpressionContext> makeExpressionContextForGetExecutor( + OperationContext* opCtx, const BSONObj& requestCollation, const NamespaceString& nss); + +/** * Filter indexes retrieved from index catalog by * allowed indices in query settings. * Used by getExecutor(). @@ -192,10 +203,7 @@ bool turnIxscanIntoDistinctIxscan(QuerySolution* soln, * distinct. */ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDistinct( - OperationContext* opCtx, - Collection* collection, - size_t plannerOptions, - ParsedDistinct* parsedDistinct); + Collection* collection, size_t plannerOptions, ParsedDistinct* parsedDistinct); /* * Get a PlanExecutor for a query executing as part of a count command. @@ -205,7 +213,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDist * executing a count. */ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCount( - OperationContext* opCtx, + const boost::intrusive_ptr<ExpressionContext>& expCtx, Collection* collection, const CountCommand& request, bool explain, @@ -231,7 +239,6 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCoun * If the query cannot be executed, returns a Status indicating why. */ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( - OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedDelete* parsedDelete, @@ -258,7 +265,6 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDele * If the query cannot be executed, returns a Status indicating why. */ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate( - OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedUpdate* parsedUpdate, diff --git a/src/mongo/db/query/internal_plans.cpp b/src/mongo/db/query/internal_plans.cpp index a9bc1b5021a..238f6636e0f 100644 --- a/src/mongo/db/query/internal_plans.cpp +++ b/src/mongo/db/query/internal_plans.cpp @@ -55,8 +55,11 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::collection const Direction direction) { std::unique_ptr<WorkingSet> ws = std::make_unique<WorkingSet>(); + auto expCtx = make_intrusive<ExpressionContext>( + opCtx, std::unique_ptr<CollatorInterface>(nullptr), NamespaceString(ns)); + if (nullptr == collection) { - auto eof = std::make_unique<EOFStage>(opCtx); + auto eof = std::make_unique<EOFStage>(expCtx.get()); // Takes ownership of 'ws' and 'eof'. auto statusWithPlanExecutor = PlanExecutor::make( opCtx, std::move(ws), std::move(eof), nullptr, yieldPolicy, NamespaceString(ns)); @@ -66,7 +69,7 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::collection invariant(ns == collection->ns().ns()); - auto cs = _collectionScan(opCtx, ws.get(), collection, direction); + auto cs = _collectionScan(expCtx, ws.get(), collection, direction); // Takes ownership of 'ws' and 'cs'. auto statusWithPlanExecutor = @@ -84,10 +87,13 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::deleteWith invariant(collection); auto ws = std::make_unique<WorkingSet>(); - auto root = _collectionScan(opCtx, ws.get(), collection, direction); + auto expCtx = make_intrusive<ExpressionContext>( + opCtx, std::unique_ptr<CollatorInterface>(nullptr), collection->ns()); + + auto root = _collectionScan(expCtx, ws.get(), collection, direction); root = std::make_unique<DeleteStage>( - opCtx, std::move(params), ws.get(), collection, root.release()); + expCtx.get(), std::move(params), ws.get(), collection, root.release()); auto executor = PlanExecutor::make(opCtx, std::move(ws), std::move(root), collection, yieldPolicy); @@ -108,7 +114,10 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::indexScan( int options) { auto ws = std::make_unique<WorkingSet>(); - std::unique_ptr<PlanStage> root = _indexScan(opCtx, + auto expCtx = make_intrusive<ExpressionContext>( + opCtx, std::unique_ptr<CollatorInterface>(nullptr), collection->ns()); + + std::unique_ptr<PlanStage> root = _indexScan(expCtx, ws.get(), collection, descriptor, @@ -137,7 +146,10 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::deleteWith invariant(collection); auto ws = std::make_unique<WorkingSet>(); - std::unique_ptr<PlanStage> root = _indexScan(opCtx, + auto expCtx = make_intrusive<ExpressionContext>( + opCtx, std::unique_ptr<CollatorInterface>(nullptr), collection->ns()); + + std::unique_ptr<PlanStage> root = _indexScan(expCtx, ws.get(), collection, descriptor, @@ -148,7 +160,7 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::deleteWith InternalPlanner::IXSCAN_FETCH); root = std::make_unique<DeleteStage>( - opCtx, std::move(params), ws.get(), collection, root.release()); + expCtx.get(), std::move(params), ws.get(), collection, root.release()); auto executor = PlanExecutor::make(opCtx, std::move(ws), std::move(root), collection, yieldPolicy); @@ -166,13 +178,16 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::updateWith invariant(collection); auto ws = std::make_unique<WorkingSet>(); - auto idHackStage = std::make_unique<IDHackStage>(opCtx, key, ws.get(), descriptor); + auto expCtx = make_intrusive<ExpressionContext>( + opCtx, std::unique_ptr<CollatorInterface>(nullptr), collection->ns()); + + auto idHackStage = std::make_unique<IDHackStage>(expCtx.get(), key, ws.get(), descriptor); const bool isUpsert = params.request->isUpsert(); auto root = (isUpsert ? std::make_unique<UpsertStage>( - opCtx, params, ws.get(), collection, idHackStage.release()) + expCtx.get(), params, ws.get(), collection, idHackStage.release()) : std::make_unique<UpdateStage>( - opCtx, params, ws.get(), collection, idHackStage.release())); + expCtx.get(), params, ws.get(), collection, idHackStage.release())); auto executor = PlanExecutor::make(opCtx, std::move(ws), std::move(root), collection, yieldPolicy); @@ -180,14 +195,16 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::updateWith return std::move(executor.getValue()); } -std::unique_ptr<PlanStage> InternalPlanner::_collectionScan(OperationContext* opCtx, - WorkingSet* ws, - const Collection* collection, - Direction direction) { +std::unique_ptr<PlanStage> InternalPlanner::_collectionScan( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + WorkingSet* ws, + const Collection* collection, + Direction direction) { invariant(collection); CollectionScanParams params; - params.shouldWaitForOplogVisibility = shouldWaitForOplogVisibility(opCtx, collection, false); + params.shouldWaitForOplogVisibility = + shouldWaitForOplogVisibility(expCtx->opCtx, collection, false); if (FORWARD == direction) { params.direction = CollectionScanParams::FORWARD; @@ -195,22 +212,23 @@ std::unique_ptr<PlanStage> InternalPlanner::_collectionScan(OperationContext* op params.direction = CollectionScanParams::BACKWARD; } - return std::make_unique<CollectionScan>(opCtx, collection, params, ws, nullptr); + return std::make_unique<CollectionScan>(expCtx.get(), collection, params, ws, nullptr); } -std::unique_ptr<PlanStage> InternalPlanner::_indexScan(OperationContext* opCtx, - WorkingSet* ws, - const Collection* collection, - const IndexDescriptor* descriptor, - const BSONObj& startKey, - const BSONObj& endKey, - BoundInclusion boundInclusion, - Direction direction, - int options) { +std::unique_ptr<PlanStage> InternalPlanner::_indexScan( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + WorkingSet* ws, + const Collection* collection, + const IndexDescriptor* descriptor, + const BSONObj& startKey, + const BSONObj& endKey, + BoundInclusion boundInclusion, + Direction direction, + int options) { invariant(collection); invariant(descriptor); - IndexScanParams params(opCtx, descriptor); + IndexScanParams params(expCtx->opCtx, descriptor); params.direction = direction; params.bounds.isSimpleRange = true; params.bounds.startKey = startKey; @@ -219,10 +237,10 @@ std::unique_ptr<PlanStage> InternalPlanner::_indexScan(OperationContext* opCtx, params.shouldDedup = descriptor->isMultikey(); std::unique_ptr<PlanStage> root = - std::make_unique<IndexScan>(opCtx, std::move(params), ws, nullptr); + std::make_unique<IndexScan>(expCtx.get(), std::move(params), ws, nullptr); if (InternalPlanner::IXSCAN_FETCH & options) { - root = std::make_unique<FetchStage>(opCtx, ws, std::move(root), nullptr, collection); + root = std::make_unique<FetchStage>(expCtx.get(), ws, std::move(root), nullptr, collection); } return root; diff --git a/src/mongo/db/query/internal_plans.h b/src/mongo/db/query/internal_plans.h index a846a55b60b..228f6f4fd97 100644 --- a/src/mongo/db/query/internal_plans.h +++ b/src/mongo/db/query/internal_plans.h @@ -130,25 +130,27 @@ private: * * Used as a helper for collectionScan() and deleteWithCollectionScan(). */ - static std::unique_ptr<PlanStage> _collectionScan(OperationContext* opCtx, - WorkingSet* ws, - const Collection* collection, - Direction direction); + static std::unique_ptr<PlanStage> _collectionScan( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + WorkingSet* ws, + const Collection* collection, + Direction direction); /** * Returns a plan stage that is either an index scan or an index scan with a fetch stage. * * Used as a helper for indexScan() and deleteWithIndexScan(). */ - static std::unique_ptr<PlanStage> _indexScan(OperationContext* opCtx, - WorkingSet* ws, - const Collection* collection, - const IndexDescriptor* descriptor, - const BSONObj& startKey, - const BSONObj& endKey, - BoundInclusion boundInclusion, - Direction direction = FORWARD, - int options = IXSCAN_DEFAULT); + static std::unique_ptr<PlanStage> _indexScan( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + WorkingSet* ws, + const Collection* collection, + const IndexDescriptor* descriptor, + const BSONObj& startKey, + const BSONObj& endKey, + BoundInclusion boundInclusion, + Direction direction = FORWARD, + int options = IXSCAN_DEFAULT); }; } // namespace mongo diff --git a/src/mongo/db/query/plan_cache_indexability_test.cpp b/src/mongo/db/query/plan_cache_indexability_test.cpp index 471e57bfafb..2748bfd85ac 100644 --- a/src/mongo/db/query/plan_cache_indexability_test.cpp +++ b/src/mongo/db/query/plan_cache_indexability_test.cpp @@ -41,10 +41,19 @@ namespace mongo { namespace { -std::unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj, - const CollatorInterface* collator = nullptr) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - expCtx->setCollator(collator); +/** + * Produce a MatchExpression from BSON. + * + * If the caller would like the MatchExpression to have a collation associated with it, they may + * pass in an ExpressionContext owning the collation. Otherwise the caller may pass nullptr and a + * default-constructed ExpressionContextForTest will be used. + */ +std::unique_ptr<MatchExpression> parseMatchExpression( + const BSONObj& obj, boost::intrusive_ptr<ExpressionContext> expCtx = nullptr) { + if (!expCtx) { + expCtx = make_intrusive<ExpressionContextForTest>(); + } + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, std::move(expCtx)); if (!status.isOK()) { FAIL(str::stream() << "failed to parse query: " << obj.toString() @@ -400,6 +409,9 @@ TEST(PlanCacheIndexabilityTest, DiscriminatorForCollationIndicatesWhenCollations entry.collator = &collator; state.updateDiscriminators({entry}); + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(collator.clone()); + auto discriminators = state.getDiscriminators("a"); ASSERT_EQ(1U, discriminators.size()); ASSERT(discriminators.find("a_1") != discriminators.end()); @@ -409,14 +421,13 @@ TEST(PlanCacheIndexabilityTest, DiscriminatorForCollationIndicatesWhenCollations // Index collator matches query collator. ASSERT_EQ(true, disc.isMatchCompatibleWithIndex( - parseMatchExpression(fromjson("{a: 'abc'}"), &collator).get())); + parseMatchExpression(fromjson("{a: 'abc'}"), expCtx).get())); ASSERT_EQ(true, disc.isMatchCompatibleWithIndex( - parseMatchExpression(fromjson("{a: {$in: ['abc', 'xyz']}}"), &collator).get())); - ASSERT_EQ( - true, - disc.isMatchCompatibleWithIndex( - parseMatchExpression(fromjson("{a: {$_internalExprEq: 'abc'}}}"), &collator).get())); + parseMatchExpression(fromjson("{a: {$in: ['abc', 'xyz']}}"), expCtx).get())); + ASSERT_EQ(true, + disc.isMatchCompatibleWithIndex( + parseMatchExpression(fromjson("{a: {$_internalExprEq: 'abc'}}}"), expCtx).get())); // Expression is not a ComparisonMatchExpression, InternalExprEqMatchExpression or // InMatchExpression. @@ -547,6 +558,10 @@ TEST(PlanCacheIndexabilityTest, WildcardWithCollationDiscriminator) { auto entryProjExecPair = makeWildcardEntry(BSON("a.$**" << 1)); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); entryProjExecPair.first.collator = &collator; + + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + expCtx->setCollator(collator.clone()); + state.updateDiscriminators({entryProjExecPair.first}); const auto unindexedPathDiscriminators = state.buildWildcardDiscriminators("notIndexed"); @@ -563,7 +578,7 @@ TEST(PlanCacheIndexabilityTest, WildcardWithCollationDiscriminator) { parseMatchExpression(fromjson("{a: \"hello world\"}"), nullptr).get())); // Match expression which uses the same collation as the index is. ASSERT_TRUE(disc.isMatchCompatibleWithIndex( - parseMatchExpression(fromjson("{a: \"hello world\"}"), &collator).get())); + parseMatchExpression(fromjson("{a: \"hello world\"}"), expCtx).get())); } TEST(PlanCacheIndexabilityTest, WildcardPartialIndexDiscriminator) { diff --git a/src/mongo/db/query/projection_test.cpp b/src/mongo/db/query/projection_test.cpp index b52d27bfb80..9050416deef 100644 --- a/src/mongo/db/query/projection_test.cpp +++ b/src/mongo/db/query/projection_test.cpp @@ -55,9 +55,8 @@ projection_ast::Projection createProjection(const BSONObj& query, ProjectionPolicies policies = {}) { QueryTestServiceContext serviceCtx; auto opCtx = serviceCtx.makeOperationContext(); - const CollatorInterface* collator = nullptr; const boost::intrusive_ptr<ExpressionContext> expCtx( - new ExpressionContext(opCtx.get(), collator, kTestNss)); + new ExpressionContext(opCtx.get(), std::unique_ptr<CollatorInterface>(nullptr), kTestNss)); StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(query, std::move(expCtx)); ASSERT_OK(statusWithMatcher.getStatus()); @@ -85,9 +84,8 @@ void assertInvalidProjection(const char* queryStr, const char* projStr) { BSONObj projObj = fromjson(projStr); QueryTestServiceContext serviceCtx; auto opCtx = serviceCtx.makeOperationContext(); - const CollatorInterface* collator = nullptr; const boost::intrusive_ptr<ExpressionContext> expCtx( - new ExpressionContext(opCtx.get(), collator, kTestNss)); + new ExpressionContext(opCtx.get(), std::unique_ptr<CollatorInterface>(nullptr), kTestNss)); StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(query, std::move(expCtx)); ASSERT_OK(statusWithMatcher.getStatus()); diff --git a/src/mongo/db/query/query_planner_partialidx_test.cpp b/src/mongo/db/query/query_planner_partialidx_test.cpp index 124b75c7518..ecb574fa728 100644 --- a/src/mongo/db/query/query_planner_partialidx_test.cpp +++ b/src/mongo/db/query/query_planner_partialidx_test.cpp @@ -36,6 +36,8 @@ namespace mongo { namespace { +const static NamespaceString kNs("db.dummyNs"); + TEST_F(QueryPlannerTest, PartialIndexEq) { params.options = QueryPlannerParams::NO_TABLE_SCAN; BSONObj filterObj(fromjson("{a: {$gt: 0}}")); @@ -448,9 +450,14 @@ TEST_F(QueryPlannerTest, PartialIndexNor) { TEST_F(QueryPlannerTest, PartialIndexStringComparisonMatchingCollators) { params.options = QueryPlannerParams::NO_TABLE_SCAN; BSONObj filterObj(fromjson("{a: {$gt: 'cba'}}")); - CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - std::unique_ptr<MatchExpression> filterExpr = parseMatchExpression(filterObj, &collator); - addIndex(fromjson("{a: 1}"), filterExpr.get(), &collator); + + auto expCtxForPartialFilter = make_intrusive<ExpressionContext>( + opCtx.get(), + std::make_unique<CollatorInterfaceMock>(CollatorInterfaceMock::MockType::kReverseString), + kNs); + std::unique_ptr<MatchExpression> filterExpr = + parseMatchExpression(filterObj, expCtxForPartialFilter); + addIndex(fromjson("{a: 1}"), filterExpr.get(), expCtxForPartialFilter->getCollator()); runQueryAsCommand( fromjson("{find: 'testns', filter: {a: 'abc'}, collation: {locale: 'reverse'}}")); @@ -468,9 +475,14 @@ TEST_F(QueryPlannerTest, PartialIndexStringComparisonMatchingCollators) { TEST_F(QueryPlannerTest, PartialIndexNoStringComparisonNonMatchingCollators) { params.options = QueryPlannerParams::NO_TABLE_SCAN; BSONObj filterObj(fromjson("{a: {$gt: 0}}")); - CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual); - std::unique_ptr<MatchExpression> filterExpr = parseMatchExpression(filterObj, &collator); - addIndex(fromjson("{a: 1}"), filterExpr.get(), &collator); + + auto expCtxForPartialFilter = make_intrusive<ExpressionContext>( + opCtx.get(), + std::make_unique<CollatorInterfaceMock>(CollatorInterfaceMock::MockType::kReverseString), + kNs); + std::unique_ptr<MatchExpression> filterExpr = + parseMatchExpression(filterObj, expCtxForPartialFilter); + addIndex(fromjson("{a: 1}"), filterExpr.get(), expCtxForPartialFilter->getCollator()); runQueryAsCommand(fromjson("{find: 'testns', filter: {a: 1}, collation: {locale: 'reverse'}}")); assertNumSolutions(1U); diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp index 0ea76a16783..805fccdbc1f 100644 --- a/src/mongo/db/query/query_planner_test_fixture.cpp +++ b/src/mongo/db/query/query_planner_test_fixture.cpp @@ -53,6 +53,8 @@ const NamespaceString QueryPlannerTest::nss("test.collection"); void QueryPlannerTest::setUp() { opCtx = serviceContext.makeOperationContext(); + expCtx = make_intrusive<ExpressionContext>( + opCtx.get(), std::unique_ptr<CollatorInterface>(nullptr), nss); internalQueryPlannerEnableHashIntersection.store(true); params.options = QueryPlannerParams::INCLUDE_COLLSCAN; addIndex(BSON("_id" << 1)); @@ -62,6 +64,7 @@ void QueryPlannerTest::clearState() { plannerStatus = Status::OK(); solns.clear(); cq.reset(); + expCtx.reset(); relaxBoundsCheck = false; } @@ -327,7 +330,6 @@ void QueryPlannerTest::runQueryFull(const BSONObj& query, qr->setHint(hint); qr->setMin(minObj); qr->setMax(maxObj); - const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -408,7 +410,6 @@ void QueryPlannerTest::runInvalidQueryFull(const BSONObj& query, qr->setHint(hint); qr->setMin(minObj); qr->setMax(maxObj); - const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -432,7 +433,6 @@ void QueryPlannerTest::runQueryAsCommand(const BSONObj& cmdObj) { std::unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); - const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -456,7 +456,6 @@ void QueryPlannerTest::runInvalidQueryAsCommand(const BSONObj& cmdObj) { std::unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); - const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx.get(), std::move(qr), @@ -550,10 +549,13 @@ void QueryPlannerTest::assertHasOnlyCollscan() const { } std::unique_ptr<MatchExpression> QueryPlannerTest::parseMatchExpression( - const BSONObj& obj, const CollatorInterface* collator) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - expCtx->setCollator(collator); - StatusWithMatchExpression status = MatchExpressionParser::parse(obj, std::move(expCtx)); + const BSONObj& obj, const boost::intrusive_ptr<ExpressionContext>& optionalExpCtx) { + auto expCtx = optionalExpCtx; + if (!expCtx.get()) { + expCtx = make_intrusive<ExpressionContextForTest>(); + } + + StatusWithMatchExpression status = MatchExpressionParser::parse(obj, expCtx); if (!status.isOK()) { FAIL(str::stream() << "failed to parse query: " << obj.toString() << ". Reason: " << status.getStatus().toString()); diff --git a/src/mongo/db/query/query_planner_test_fixture.h b/src/mongo/db/query/query_planner_test_fixture.h index 4743f505fa2..d133a83002c 100644 --- a/src/mongo/db/query/query_planner_test_fixture.h +++ b/src/mongo/db/query/query_planner_test_fixture.h @@ -222,9 +222,16 @@ protected: /** * Helper function to parse a MatchExpression. + * + * If the caller wants a collator to be used with the match expression, pass an expression + * context owning that collator as the second argument. The expression context passed must + * outlive the returned match expression. + * + * If no ExpressionContext is passed a default-constructed ExpressionContextForTest will be + * used. */ - static std::unique_ptr<MatchExpression> parseMatchExpression( - const BSONObj& obj, const CollatorInterface* collator = nullptr); + std::unique_ptr<MatchExpression> parseMatchExpression( + const BSONObj& obj, const boost::intrusive_ptr<ExpressionContext>& expCtx = nullptr); // // Data members. @@ -234,6 +241,8 @@ protected: QueryTestServiceContext serviceContext; ServiceContext::UniqueOperationContext opCtx; + boost::intrusive_ptr<ExpressionContext> expCtx; + BSONObj queryObj; std::unique_ptr<CanonicalQuery> cq; QueryPlannerParams params; diff --git a/src/mongo/db/query/query_planner_test_lib.cpp b/src/mongo/db/query/query_planner_test_lib.cpp index dc1ee631607..2abe9e00aa0 100644 --- a/src/mongo/db/query/query_planner_test_lib.cpp +++ b/src/mongo/db/query/query_planner_test_lib.cpp @@ -76,9 +76,8 @@ bool filterMatches(const BSONObj& testFilter, } boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - expCtx->setCollator(testCollator.get()); - StatusWithMatchExpression statusWithMatcher = - MatchExpressionParser::parse(testFilter, std::move(expCtx)); + expCtx->setCollator(std::move(testCollator)); + StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(testFilter, expCtx); if (!statusWithMatcher.isOK()) { return false; } diff --git a/src/mongo/db/query/query_solution_test.cpp b/src/mongo/db/query/query_solution_test.cpp index 142ed16fd2a..fb79d1e69b6 100644 --- a/src/mongo/db/query/query_solution_test.cpp +++ b/src/mongo/db/query/query_solution_test.cpp @@ -717,9 +717,8 @@ TEST(QuerySolutionTest, IndexScanNodeHasFieldExcludesSimpleBoundsStringFieldWhen auto createMatchExprAndProjection(const BSONObj& query, const BSONObj& projObj) { QueryTestServiceContext serviceCtx; auto opCtx = serviceCtx.makeOperationContext(); - const CollatorInterface* collator = nullptr; - const boost::intrusive_ptr<ExpressionContext> expCtx( - new ExpressionContext(opCtx.get(), collator, NamespaceString("test.dummy"))); + const boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext( + opCtx.get(), std::unique_ptr<CollatorInterface>(nullptr), NamespaceString("test.dummy"))); StatusWithMatchExpression queryMatchExpr = MatchExpressionParser::parse(query, std::move(expCtx)); ASSERT(queryMatchExpr.isOK()); diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index 907f8018f27..01005defd04 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -74,6 +74,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, const QuerySolution& qsol, const QuerySolutionNode* root, WorkingSet* ws) { + auto* const expCtx = cq.getExpCtx().get(); switch (root->getType()) { case STAGE_COLLSCAN: { const CollectionScanNode* csn = static_cast<const CollectionScanNode*>(root); @@ -89,7 +90,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, params.resumeAfterRecordId = csn->resumeAfterRecordId; params.stopApplyingFilterAfterFirstMatch = csn->stopApplyingFilterAfterFirstMatch; return std::make_unique<CollectionScan>( - opCtx, collection, params, ws, csn->filter.get()); + expCtx, collection, params, ws, csn->filter.get()); } case STAGE_IXSCAN: { const IndexScanNode* ixn = static_cast<const IndexScanNode*>(root); @@ -113,13 +114,13 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, params.direction = ixn->direction; params.addKeyMetadata = ixn->addKeyMetadata; params.shouldDedup = ixn->shouldDedup; - return std::make_unique<IndexScan>(opCtx, std::move(params), ws, ixn->filter.get()); + return std::make_unique<IndexScan>(expCtx, std::move(params), ws, ixn->filter.get()); } case STAGE_FETCH: { const FetchNode* fn = static_cast<const FetchNode*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, fn->children[0], ws); return std::make_unique<FetchStage>( - opCtx, ws, std::move(childStage), fn->filter.get(), collection); + expCtx, ws, std::move(childStage), fn->filter.get(), collection); } case STAGE_SORT_DEFAULT: { auto snDefault = static_cast<const SortNodeDefault*>(root); @@ -155,7 +156,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, auto returnKeyNode = static_cast<const ReturnKeyNode*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, returnKeyNode->children[0], ws); - return std::make_unique<ReturnKeyStage>(opCtx, + return std::make_unique<ReturnKeyStage>(expCtx, std::move(returnKeyNode->sortKeyMetaFields), ws, cq.getExpCtx()->sortKeyFormat, @@ -173,7 +174,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, case STAGE_PROJECTION_COVERED: { auto pn = static_cast<const ProjectionNodeCovered*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, pn->children[0], ws); - return std::make_unique<ProjectionStageCovered>(cq.getExpCtx(), + return std::make_unique<ProjectionStageCovered>(cq.getExpCtx().get(), cq.getQueryRequest().getProj(), cq.getProj(), ws, @@ -183,7 +184,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, case STAGE_PROJECTION_SIMPLE: { auto pn = static_cast<const ProjectionNodeSimple*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, pn->children[0], ws); - return std::make_unique<ProjectionStageSimple>(cq.getExpCtx(), + return std::make_unique<ProjectionStageSimple>(cq.getExpCtx().get(), cq.getQueryRequest().getProj(), cq.getProj(), ws, @@ -192,16 +193,16 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, case STAGE_LIMIT: { const LimitNode* ln = static_cast<const LimitNode*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, ln->children[0], ws); - return std::make_unique<LimitStage>(opCtx, ln->limit, ws, std::move(childStage)); + return std::make_unique<LimitStage>(expCtx, ln->limit, ws, std::move(childStage)); } case STAGE_SKIP: { const SkipNode* sn = static_cast<const SkipNode*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, sn->children[0], ws); - return std::make_unique<SkipStage>(opCtx, sn->skip, ws, std::move(childStage)); + return std::make_unique<SkipStage>(expCtx, sn->skip, ws, std::move(childStage)); } case STAGE_AND_HASH: { const AndHashNode* ahn = static_cast<const AndHashNode*>(root); - auto ret = std::make_unique<AndHashStage>(opCtx, ws); + auto ret = std::make_unique<AndHashStage>(expCtx, ws); for (size_t i = 0; i < ahn->children.size(); ++i) { auto childStage = buildStages(opCtx, collection, cq, qsol, ahn->children[i], ws); ret->addChild(std::move(childStage)); @@ -210,7 +211,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, } case STAGE_OR: { const OrNode* orn = static_cast<const OrNode*>(root); - auto ret = std::make_unique<OrStage>(opCtx, ws, orn->dedup, orn->filter.get()); + auto ret = std::make_unique<OrStage>(expCtx, ws, orn->dedup, orn->filter.get()); for (size_t i = 0; i < orn->children.size(); ++i) { auto childStage = buildStages(opCtx, collection, cq, qsol, orn->children[i], ws); ret->addChild(std::move(childStage)); @@ -219,7 +220,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, } case STAGE_AND_SORTED: { const AndSortedNode* asn = static_cast<const AndSortedNode*>(root); - auto ret = std::make_unique<AndSortedStage>(opCtx, ws); + auto ret = std::make_unique<AndSortedStage>(expCtx, ws); for (size_t i = 0; i < asn->children.size(); ++i) { auto childStage = buildStages(opCtx, collection, cq, qsol, asn->children[i], ws); ret->addChild(std::move(childStage)); @@ -232,7 +233,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, params.dedup = msn->dedup; params.pattern = msn->sort; params.collator = cq.getCollator(); - auto ret = std::make_unique<MergeSortStage>(opCtx, params, ws); + auto ret = std::make_unique<MergeSortStage>(expCtx, params, ws); for (size_t i = 0; i < msn->children.size(); ++i) { auto childStage = buildStages(opCtx, collection, cq, qsol, msn->children[i], ws); ret->addChild(std::move(childStage)); @@ -254,7 +255,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, opCtx, node->index.identifier.catalogName); invariant(twoDIndex); - return std::make_unique<GeoNear2DStage>(params, opCtx, ws, twoDIndex); + return std::make_unique<GeoNear2DStage>(params, expCtx, ws, twoDIndex); } case STAGE_GEO_NEAR_2DSPHERE: { const GeoNear2DSphereNode* node = static_cast<const GeoNear2DSphereNode*>(root); @@ -271,7 +272,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, opCtx, node->index.identifier.catalogName); invariant(s2Index); - return std::make_unique<GeoNear2DSphereStage>(params, opCtx, ws, s2Index); + return std::make_unique<GeoNear2DSphereStage>(params, expCtx, ws, s2Index); } case STAGE_TEXT: { const TextNode* node = static_cast<const TextNode*>(root); @@ -291,7 +292,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, // created by planning a query that contains "no-op" expressions. params.query = static_cast<FTSQueryImpl&>(*node->ftsQuery); params.wantTextScore = cq.metadataDeps()[DocumentMetadataFields::kTextScore]; - return std::make_unique<TextStage>(opCtx, params, ws, node->filter.get()); + return std::make_unique<TextStage>(expCtx, params, ws, node->filter.get()); } case STAGE_SHARDING_FILTER: { const ShardingFilterNode* fn = static_cast<const ShardingFilterNode*>(root); @@ -299,7 +300,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, auto css = CollectionShardingState::get(opCtx, collection->ns()); return std::make_unique<ShardFilterStage>( - opCtx, css->getOwnershipFilter(opCtx), ws, std::move(childStage)); + expCtx, css->getOwnershipFilter(opCtx), ws, std::move(childStage)); } case STAGE_DISTINCT_SCAN: { const DistinctNode* dn = static_cast<const DistinctNode*>(root); @@ -320,7 +321,7 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, params.scanDirection = dn->direction; params.bounds = dn->bounds; params.fieldNo = dn->fieldNo; - return std::make_unique<DistinctScan>(opCtx, std::move(params), ws); + return std::make_unique<DistinctScan>(expCtx, std::move(params), ws); } case STAGE_COUNT_SCAN: { const CountScanNode* csn = static_cast<const CountScanNode*>(root); @@ -342,13 +343,13 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, params.startKeyInclusive = csn->startKeyInclusive; params.endKey = csn->endKey; params.endKeyInclusive = csn->endKeyInclusive; - return std::make_unique<CountScan>(opCtx, std::move(params), ws); + return std::make_unique<CountScan>(expCtx, std::move(params), ws); } case STAGE_ENSURE_SORTED: { const EnsureSortedNode* esn = static_cast<const EnsureSortedNode*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, esn->children[0], ws); return std::make_unique<EnsureSortedStage>( - opCtx, esn->pattern, ws, std::move(childStage)); + expCtx, esn->pattern, ws, std::move(childStage)); } case STAGE_CACHED_PLAN: case STAGE_CHANGE_STREAM_PROXY: |