summaryrefslogtreecommitdiff
path: root/src/mongo/db/query
diff options
context:
space:
mode:
authorIan Boros <ian.boros@mongodb.com>2020-01-30 13:10:55 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-02-28 22:16:41 +0000
commitcfa5c05fa1855fb1a04cb3a6e2eb10a7e82bf726 (patch)
tree7ab1e1ce8e2edd6837952c131fe14d43a0633235 /src/mongo/db/query
parent793ae32c597f197b6445750aa9bfdaabc206132d (diff)
downloadmongo-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.cpp25
-rw-r--r--src/mongo/db/query/canonical_query.h5
-rw-r--r--src/mongo/db/query/get_executor.cpp108
-rw-r--r--src/mongo/db/query/get_executor.h20
-rw-r--r--src/mongo/db/query/internal_plans.cpp74
-rw-r--r--src/mongo/db/query/internal_plans.h28
-rw-r--r--src/mongo/db/query/plan_cache_indexability_test.cpp37
-rw-r--r--src/mongo/db/query/projection_test.cpp6
-rw-r--r--src/mongo/db/query/query_planner_partialidx_test.cpp24
-rw-r--r--src/mongo/db/query/query_planner_test_fixture.cpp18
-rw-r--r--src/mongo/db/query/query_planner_test_fixture.h13
-rw-r--r--src/mongo/db/query/query_planner_test_lib.cpp5
-rw-r--r--src/mongo/db/query/query_solution_test.cpp5
-rw-r--r--src/mongo/db/query/stage_builder.cpp39
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: