summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorAnton Korshunov <anton.korshunov@mongodb.com>2019-11-05 22:41:50 +0000
committerevergreen <evergreen@mongodb.com>2019-11-05 22:41:50 +0000
commit7c7bf229e2e1a911ad636e8d7827b2918215b357 (patch)
tree42f4a0a9b22c82ae8f73ca74462c0a0cd621a95e /src/mongo/db
parenta22581e85b43b826535b180afaddac2b6146b44f (diff)
downloadmongo-7c7bf229e2e1a911ad636e8d7827b2918215b357.tar.gz
SERVER-43877 Remove raw projection BSON from projection stages
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp16
-rw-r--r--src/mongo/db/commands/find_cmd.cpp16
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp14
-rw-r--r--src/mongo/db/exec/projection.cpp67
-rw-r--r--src/mongo/db/exec/projection.h29
-rw-r--r--src/mongo/db/ops/delete.cpp7
-rw-r--r--src/mongo/db/ops/update.cpp3
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp14
-rw-r--r--src/mongo/db/query/find.cpp16
-rw-r--r--src/mongo/db/query/get_executor.cpp24
-rw-r--r--src/mongo/db/query/get_executor.h18
-rw-r--r--src/mongo/db/query/stage_builder.cpp10
-rw-r--r--src/mongo/db/repl/storage_interface_impl.cpp8
13 files changed, 130 insertions, 112 deletions
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index fbe9235c19e..7a0c7f038e1 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -267,8 +267,8 @@ public:
css->checkShardVersionOrThrow(opCtx, autoColl.getCollection());
Collection* const collection = autoColl.getCollection();
- const auto exec =
- uassertStatusOK(getExecutorDelete(opCtx, opDebug, collection, &parsedDelete));
+ const auto exec = uassertStatusOK(
+ getExecutorDelete(opCtx, opDebug, collection, &parsedDelete, verbosity));
auto bodyBuilder = result->getBodyBuilder();
Explain::explainStages(exec.get(), collection, verbosity, BSONObj(), &bodyBuilder);
@@ -292,8 +292,8 @@ public:
css->checkShardVersionOrThrow(opCtx, autoColl.getCollection());
Collection* const collection = autoColl.getCollection();
- const auto exec =
- uassertStatusOK(getExecutorUpdate(opCtx, opDebug, collection, &parsedUpdate));
+ const auto exec = uassertStatusOK(
+ getExecutorUpdate(opCtx, opDebug, collection, &parsedUpdate, verbosity));
auto bodyBuilder = result->getBodyBuilder();
Explain::explainStages(exec.get(), collection, verbosity, BSONObj(), &bodyBuilder);
@@ -381,8 +381,8 @@ public:
Collection* const collection = autoColl.getCollection();
checkIfTransactionOnCappedColl(collection, inTransaction);
- const auto exec =
- uassertStatusOK(getExecutorDelete(opCtx, opDebug, collection, &parsedDelete));
+ const auto exec = uassertStatusOK(getExecutorDelete(
+ opCtx, opDebug, collection, &parsedDelete, boost::none /* verbosity */));
{
stdx::lock_guard<Client> lk(*opCtx->getClient());
@@ -487,8 +487,8 @@ public:
checkIfTransactionOnCappedColl(collection, inTransaction);
- const auto exec =
- uassertStatusOK(getExecutorUpdate(opCtx, opDebug, collection, &parsedUpdate));
+ const auto exec = uassertStatusOK(getExecutorUpdate(
+ opCtx, opDebug, collection, &parsedUpdate, boost::none /* verbosity */));
{
stdx::lock_guard<Client> lk(*opCtx->getClient());
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index 82f9dd07c96..56e65aad432 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -76,8 +76,10 @@ std::unique_ptr<QueryRequest> parseCmdObjectToQueryRequest(OperationContext* opC
return qr;
}
-boost::intrusive_ptr<ExpressionContext> makeExpressionContext(OperationContext* opCtx,
- const QueryRequest& queryRequest) {
+boost::intrusive_ptr<ExpressionContext> makeExpressionContext(
+ OperationContext* opCtx,
+ const QueryRequest& queryRequest,
+ boost::optional<ExplainOptions::Verbosity> verbosity) {
std::unique_ptr<CollatorInterface> collator;
if (!queryRequest.getCollation().isEmpty()) {
collator = uassertStatusOK(CollatorFactoryInterface::get(opCtx->getServiceContext())
@@ -100,9 +102,9 @@ boost::intrusive_ptr<ExpressionContext> makeExpressionContext(OperationContext*
// sense to start initializing these fields for find operations as well.
auto expCtx =
make_intrusive<ExpressionContext>(opCtx,
- boost::none, // explain
- false, // fromMongos
- false, // needsMerge
+ verbosity,
+ false, // fromMongos
+ false, // needsMerge
queryRequest.allowDiskUse(),
false, // bypassDocumentValidation
queryRequest.nss(),
@@ -227,7 +229,7 @@ public:
// Finish the parsing step by using the QueryRequest to create a CanonicalQuery.
const ExtensionsCallbackReal extensionsCallback(opCtx, &nss);
- auto expCtx = makeExpressionContext(opCtx, *qr);
+ auto expCtx = makeExpressionContext(opCtx, *qr, verbosity);
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(opCtx,
std::move(qr),
@@ -425,7 +427,7 @@ public:
// Finish the parsing step by using the QueryRequest to create a CanonicalQuery.
const ExtensionsCallbackReal extensionsCallback(opCtx, &nss);
- auto expCtx = makeExpressionContext(opCtx, *qr);
+ auto expCtx = makeExpressionContext(opCtx, *qr, boost::none /* verbosity */);
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(opCtx,
std::move(qr),
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index 8d7339d1d80..4c9671b9e34 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -377,8 +377,11 @@ private:
// info is more accurate.
AutoGetCollection collection(opCtx, _batch.getNamespace(), MODE_IX);
- auto exec = uassertStatusOK(getExecutorUpdate(
- opCtx, &CurOp::get(opCtx)->debug(), collection.getCollection(), &parsedUpdate));
+ auto exec = uassertStatusOK(getExecutorUpdate(opCtx,
+ &CurOp::get(opCtx)->debug(),
+ collection.getCollection(),
+ &parsedUpdate,
+ verbosity));
auto bodyBuilder = result->getBodyBuilder();
Explain::explainStages(
exec.get(), collection.getCollection(), verbosity, BSONObj(), &bodyBuilder);
@@ -451,8 +454,11 @@ private:
AutoGetCollection collection(opCtx, _batch.getNamespace(), MODE_IX);
// Explain the plan tree.
- auto exec = uassertStatusOK(getExecutorDelete(
- opCtx, &CurOp::get(opCtx)->debug(), collection.getCollection(), &parsedDelete));
+ auto exec = uassertStatusOK(getExecutorDelete(opCtx,
+ &CurOp::get(opCtx)->debug(),
+ collection.getCollection(),
+ &parsedDelete,
+ verbosity));
auto bodyBuilder = result->getBodyBuilder();
Explain::explainStages(
exec.get(), collection.getCollection(), verbosity, BSONObj(), &bodyBuilder);
diff --git a/src/mongo/db/exec/projection.cpp b/src/mongo/db/exec/projection.cpp
index d824df21a6c..514b90a78a4 100644
--- a/src/mongo/db/exec/projection.cpp
+++ b/src/mongo/db/exec/projection.cpp
@@ -45,9 +45,6 @@
#include "mongo/util/str.h"
namespace mongo {
-
-static const char* kIdField = "_id";
-
namespace {
void transitionMemberToOwnedObj(Document&& doc, WorkingSetMember* member) {
@@ -115,36 +112,14 @@ auto rehydrateIndexKey(const BSONObj& keyPattern, const BSONObj& dehydratedKey)
}
} // namespace
-ProjectionStage::ProjectionStage(OperationContext* opCtx,
+ProjectionStage::ProjectionStage(boost::intrusive_ptr<ExpressionContext> expCtx,
const BSONObj& projObj,
WorkingSet* ws,
std::unique_ptr<PlanStage> child,
const char* stageType)
- : PlanStage(opCtx, std::move(child), stageType), _projObj(projObj), _ws(*ws) {}
-
-// static
-void ProjectionStage::getSimpleInclusionFields(const BSONObj& projObj, FieldSet* includedFields) {
- // The _id is included by default.
- bool includeId = true;
-
- // Figure out what fields are in the projection. We could eventually do this using the
- // Projection AST.
- BSONObjIterator projObjIt(projObj);
- while (projObjIt.more()) {
- BSONElement elt = projObjIt.next();
- // Must deal with the _id case separately as there is an implicit _id: 1 in the
- // projection.
- if ((elt.fieldNameStringData() == kIdField) && !elt.trueValue()) {
- includeId = false;
- continue;
- }
- (*includedFields)[elt.fieldNameStringData()] = true;
- }
-
- if (includeId) {
- (*includedFields)[kIdField] = true;
- }
-}
+ : PlanStage{expCtx->opCtx, std::move(child), stageType},
+ _projObj{expCtx->explain ? boost::make_optional(projObj.getOwned()) : boost::none},
+ _ws{*ws} {}
bool ProjectionStage::isEOF() {
return child()->isEOF();
@@ -184,7 +159,7 @@ std::unique_ptr<PlanStageStats> ProjectionStage::getStats() {
auto ret = std::make_unique<PlanStageStats>(_commonStats, stageType());
auto projStats = std::make_unique<ProjectionStats>(_specificStats);
- projStats->projObj = _projObj;
+ projStats->projObj = _projObj.value_or(BSONObj{});
ret->specific = std::move(projStats);
ret->children.emplace_back(child()->getStats());
@@ -196,7 +171,7 @@ ProjectionStageDefault::ProjectionStageDefault(boost::intrusive_ptr<ExpressionCo
const projection_ast::Projection* projection,
WorkingSet* ws,
std::unique_ptr<PlanStage> child)
- : ProjectionStage{expCtx->opCtx, projObj, ws, std::move(child), "PROJECTION_DEFAULT"},
+ : ProjectionStage{expCtx, projObj, ws, std::move(child), "PROJECTION_DEFAULT"},
_wantRecordId{projection->metadataDeps()[DocumentMetadataFields::kRecordId]},
_projectType{projection->type()},
_executor{projection_executor::buildProjectionExecutor(expCtx, projection, {})} {}
@@ -241,16 +216,15 @@ Status ProjectionStageDefault::transform(WorkingSetMember* member) const {
return Status::OK();
}
-ProjectionStageCovered::ProjectionStageCovered(OperationContext* opCtx,
+ProjectionStageCovered::ProjectionStageCovered(boost::intrusive_ptr<ExpressionContext> expCtx,
const BSONObj& projObj,
+ const projection_ast::Projection* projection,
WorkingSet* ws,
std::unique_ptr<PlanStage> child,
const BSONObj& coveredKeyObj)
- : ProjectionStage(opCtx, projObj, ws, std::move(child), "PROJECTION_COVERED"),
- _coveredKeyObj(coveredKeyObj) {
- invariant(projObjHasOwnedData());
- // Figure out what fields are in the projection.
- getSimpleInclusionFields(_projObj, &_includedFields);
+ : ProjectionStage{expCtx, projObj, ws, std::move(child), "PROJECTION_COVERED"},
+ _coveredKeyObj{coveredKeyObj} {
+ invariant(projection->isSimple());
// If we're pulling data out of one index we can pre-compute the indices of the fields
// in the key that we pull data from and avoid looking up the field name each time.
@@ -258,6 +232,8 @@ ProjectionStageCovered::ProjectionStageCovered(OperationContext* opCtx,
// Sanity-check.
invariant(_coveredKeyObj.isOwned());
+ _includedFields = {projection->getRequiredFields().begin(),
+ projection->getRequiredFields().end()};
BSONObjIterator kpIt(_coveredKeyObj);
while (kpIt.more()) {
BSONElement elt = kpIt.next();
@@ -269,7 +245,7 @@ ProjectionStageCovered::ProjectionStageCovered(OperationContext* opCtx,
_includeKey.push_back(false);
} else {
// If we are including this key field store its field name.
- _keyFieldNames.push_back(fieldIt->first);
+ _keyFieldNames.push_back(*fieldIt);
_includeKey.push_back(true);
}
}
@@ -297,14 +273,15 @@ Status ProjectionStageCovered::transform(WorkingSetMember* member) const {
return Status::OK();
}
-ProjectionStageSimple::ProjectionStageSimple(OperationContext* opCtx,
+ProjectionStageSimple::ProjectionStageSimple(boost::intrusive_ptr<ExpressionContext> expCtx,
const BSONObj& projObj,
+ const projection_ast::Projection* projection,
WorkingSet* ws,
std::unique_ptr<PlanStage> child)
- : ProjectionStage(opCtx, projObj, ws, std::move(child), "PROJECTION_SIMPLE") {
- invariant(projObjHasOwnedData());
- // Figure out what fields are in the projection.
- getSimpleInclusionFields(_projObj, &_includedFields);
+ : ProjectionStage{expCtx, projObj, ws, std::move(child), "PROJECTION_SIMPLE"} {
+ invariant(projection->isSimple());
+ _includedFields = {projection->getRequiredFields().begin(),
+ projection->getRequiredFields().end()};
}
Status ProjectionStageSimple::transform(WorkingSetMember* member) const {
@@ -317,8 +294,8 @@ Status ProjectionStageSimple::transform(WorkingSetMember* member) const {
// Look at every field in the source document and see if we're including it.
auto objToProject = member->doc.value().toBson();
for (auto&& elt : objToProject) {
- auto fieldIt = _includedFields.find(elt.fieldNameStringData());
- if (_includedFields.end() != fieldIt) {
+ if (auto fieldIt = _includedFields.find(elt.fieldNameStringData());
+ _includedFields.end() != fieldIt) {
bob.append(elt);
}
}
diff --git a/src/mongo/db/exec/projection.h b/src/mongo/db/exec/projection.h
index 5b368750cad..0866dbdd150 100644
--- a/src/mongo/db/exec/projection.h
+++ b/src/mongo/db/exec/projection.h
@@ -43,7 +43,7 @@ namespace mongo {
*/
class ProjectionStage : public PlanStage {
protected:
- ProjectionStage(OperationContext* opCtx,
+ ProjectionStage(boost::intrusive_ptr<ExpressionContext> expCtx,
const BSONObj& projObj,
WorkingSet* ws,
std::unique_ptr<PlanStage> child,
@@ -60,22 +60,11 @@ public:
}
protected:
- using FieldSet = StringMap<bool>; // Value is unused.
+ using FieldSet = StringSet;
- /**
- * Given the projection spec for a simple inclusion projection,
- * 'projObj', populates 'includedFields' with the set of field
- * names to be included.
- */
- static void getSimpleInclusionFields(const BSONObj& projObj, FieldSet* includedFields);
-
- bool projObjHasOwnedData() {
- return _projObj.isOwned() && !_projObj.isEmpty();
- }
-
- // The projection object used by all projection implementations. We lack a ProjectionExpression
- // or similar so we use a BSONObj.
- BSONObj _projObj;
+ // The raw BSON projection used to populate projection stats. Optional, since it is required
+ // only in explain mode.
+ boost::optional<BSONObj> _projObj;
private:
/**
@@ -128,8 +117,9 @@ public:
/**
* ProjectionNodeCovered should obtain a fast-path object through this constructor.
*/
- ProjectionStageCovered(OperationContext* opCtx,
+ ProjectionStageCovered(boost::intrusive_ptr<ExpressionContext> expCtx,
const BSONObj& projObj,
+ const projection_ast::Projection* projection,
WorkingSet* ws,
std::unique_ptr<PlanStage> child,
const BSONObj& coveredKeyObj);
@@ -141,7 +131,7 @@ public:
private:
Status transform(WorkingSetMember* member) const final;
- // Has the field names present in the simple projection.
+ // Field names present in the simple projection.
FieldSet _includedFields;
// This is the key pattern we're extracting covered data from. It is maintained here since
@@ -166,8 +156,9 @@ public:
/**
* ProjectionNodeSimple should obtain a fast-path object through this constructor.
*/
- ProjectionStageSimple(OperationContext* opCtx,
+ ProjectionStageSimple(boost::intrusive_ptr<ExpressionContext> expCtx,
const BSONObj& projObj,
+ const projection_ast::Projection* projection,
WorkingSet* ws,
std::unique_ptr<PlanStage> child);
diff --git a/src/mongo/db/ops/delete.cpp b/src/mongo/db/ops/delete.cpp
index 3a95b360a47..85b06c4e7db 100644
--- a/src/mongo/db/ops/delete.cpp
+++ b/src/mongo/db/ops/delete.cpp
@@ -56,8 +56,11 @@ long long deleteObjects(OperationContext* opCtx,
ParsedDelete parsedDelete(opCtx, &request);
uassertStatusOK(parsedDelete.parseRequest());
- auto exec = uassertStatusOK(
- getExecutorDelete(opCtx, &CurOp::get(opCtx)->debug(), collection, &parsedDelete));
+ auto exec = uassertStatusOK(getExecutorDelete(opCtx,
+ &CurOp::get(opCtx)->debug(),
+ collection,
+ &parsedDelete,
+ boost::none /* verbosity */));
uassertStatusOK(exec->executePlan());
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index f6e0fcd3eaa..6f12b861cc4 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -97,7 +97,8 @@ UpdateResult update(OperationContext* opCtx, Database* db, const UpdateRequest&
uassertStatusOK(parsedUpdate.parseRequest());
OpDebug* const nullOpDebug = nullptr;
- auto exec = uassertStatusOK(getExecutorUpdate(opCtx, nullOpDebug, collection, &parsedUpdate));
+ auto exec = uassertStatusOK(getExecutorUpdate(
+ opCtx, nullOpDebug, collection, &parsedUpdate, boost::none /* verbosity */));
uassertStatusOK(exec->executePlan());
diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp
index d640bbf8113..3f22f0fd379 100644
--- a/src/mongo/db/ops/write_ops_exec.cpp
+++ b/src/mongo/db/ops/write_ops_exec.cpp
@@ -636,8 +636,11 @@ static SingleWriteResult performSingleUpdateOp(OperationContext* opCtx,
assertCanWrite_inlock(opCtx, ns, collection->getCollection());
- auto exec = uassertStatusOK(
- getExecutorUpdate(opCtx, &curOp.debug(), collection->getCollection(), &parsedUpdate));
+ auto exec = uassertStatusOK(getExecutorUpdate(opCtx,
+ &curOp.debug(),
+ collection->getCollection(),
+ &parsedUpdate,
+ boost::none /* verbosity */));
{
stdx::lock_guard<Client> lk(*opCtx->getClient());
@@ -865,8 +868,11 @@ static SingleWriteResult performSingleDeleteOp(OperationContext* opCtx,
CurOpFailpointHelpers::waitWhileFailPointEnabled(
&hangWithLockDuringBatchRemove, opCtx, "hangWithLockDuringBatchRemove");
- auto exec = uassertStatusOK(
- getExecutorDelete(opCtx, &curOp.debug(), collection.getCollection(), &parsedDelete));
+ auto exec = uassertStatusOK(getExecutorDelete(opCtx,
+ &curOp.debug(),
+ collection.getCollection(),
+ &parsedDelete,
+ boost::none /* verbosity */));
{
stdx::lock_guard<Client> lk(*opCtx->getClient());
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp
index 12b5f4073ee..0d903bd3086 100644
--- a/src/mongo/db/query/find.cpp
+++ b/src/mongo/db/query/find.cpp
@@ -591,7 +591,8 @@ std::string runQuery(OperationContext* opCtx,
beginQueryOp(opCtx, nss, upconvertedQuery, q.ntoreturn, q.ntoskip);
// Parse the qm into a CanonicalQuery.
- const boost::intrusive_ptr<ExpressionContext> expCtx;
+ const boost::intrusive_ptr<ExpressionContext> expCtx =
+ make_intrusive<ExpressionContext>(opCtx, nullptr /* collator */);
auto cq = uassertStatusOKWithContext(
CanonicalQuery::canonicalize(opCtx,
q,
@@ -607,10 +608,9 @@ std::string runQuery(OperationContext* opCtx,
// Parse, canonicalize, plan, transcribe, and get a plan executor.
AutoGetCollectionForReadCommand ctx(opCtx, nss, AutoGetCollection::ViewMode::kViewsForbidden);
Collection* const collection = ctx.getCollection();
+ const QueryRequest& qr = cq->getQueryRequest();
{
- const QueryRequest& qr = cq->getQueryRequest();
-
// Allow the query to run on secondaries if the read preference permits it. If no read
// preference was specified, allow the query to run iff slaveOk has been set.
const bool slaveOK = qr.hasReadPref()
@@ -622,10 +622,10 @@ std::string runQuery(OperationContext* opCtx,
}
// Get the execution plan for the query.
+ constexpr auto verbosity = ExplainOptions::Verbosity::kExecAllPlans;
+ expCtx->explain = qr.isExplain() ? boost::make_optional(verbosity) : boost::none;
auto exec = uassertStatusOK(getExecutorLegacyFind(opCtx, collection, std::move(cq)));
- const QueryRequest& qr = exec->getCanonicalQuery()->getQueryRequest();
-
// If it's actually an explain, do the explain and return rather than falling through
// to the normal query execution loop.
if (qr.isExplain()) {
@@ -633,11 +633,7 @@ std::string runQuery(OperationContext* opCtx,
bb.skip(sizeof(QueryResult::Value));
BSONObjBuilder explainBob;
- Explain::explainStages(exec.get(),
- collection,
- ExplainOptions::Verbosity::kExecAllPlans,
- BSONObj(),
- &explainBob);
+ Explain::explainStages(exec.get(), collection, verbosity, BSONObj(), &explainBob);
// Add the resulting object to the return buffer.
BSONObj explainObj = explainBob.obj();
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index 8f0623def21..b236de9e8ea 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -427,7 +427,11 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx,
std::move(root));
} else {
root = std::make_unique<ProjectionStageSimple>(
- opCtx, canonicalQuery->getQueryRequest().getProj(), ws, std::move(root));
+ canonicalQuery->getExpCtx(),
+ canonicalQuery->getQueryRequest().getProj(),
+ canonicalQuery->getProj(),
+ ws,
+ std::move(root));
}
}
@@ -686,7 +690,11 @@ StatusWith<unique_ptr<PlanStage>> applyProjection(OperationContext* opCtx,
//
StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete(
- OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedDelete* parsedDelete) {
+ OperationContext* opCtx,
+ OpDebug* opDebug,
+ Collection* collection,
+ ParsedDelete* parsedDelete,
+ boost::optional<ExplainOptions::Verbosity> verbosity) {
const DeleteRequest* request = parsedDelete->getRequest();
const NamespaceString& nss(request->getNamespaceString());
@@ -772,6 +780,9 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete(
// This is the regular path for when we have a CanonicalQuery.
unique_ptr<CanonicalQuery> cq(parsedDelete->releaseParsedQuery());
+ // Transfer the explain verbosity level into the expression context.
+ cq->getExpCtx()->explain = verbosity;
+
const size_t defaultPlannerOptions = 0;
StatusWith<PrepareExecutionResult> executionResult =
prepareExecution(opCtx, collection, ws.get(), std::move(cq), defaultPlannerOptions);
@@ -816,7 +827,11 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete(
//
StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate(
- OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedUpdate* parsedUpdate) {
+ OperationContext* opCtx,
+ OpDebug* opDebug,
+ Collection* collection,
+ ParsedUpdate* parsedUpdate,
+ boost::optional<ExplainOptions::Verbosity> verbosity) {
const UpdateRequest* request = parsedUpdate->getRequest();
UpdateDriver* driver = parsedUpdate->getDriver();
@@ -913,6 +928,9 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate(
// This is the regular path for when we have a CanonicalQuery.
unique_ptr<CanonicalQuery> cq(parsedUpdate->releaseParsedQuery());
+ // Transfer the explain verbosity level into the expression context.
+ cq->getExpCtx()->explain = verbosity;
+
const size_t defaultPlannerOptions = 0;
StatusWith<PrepareExecutionResult> executionResult =
prepareExecution(opCtx, collection, ws.get(), std::move(cq), defaultPlannerOptions);
diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h
index 51fd3b008af..99e1657c6a7 100644
--- a/src/mongo/db/query/get_executor.h
+++ b/src/mongo/db/query/get_executor.h
@@ -218,6 +218,9 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCoun
*
* 'opDebug' Optional argument. When not null, will be used to record operation statistics.
*
+ * If the delete operation is executed in explain mode, the 'verbosity' parameter should be
+ * set to the requested verbosity level, or boost::none otherwise.
+ *
* The returned PlanExecutor will used the YieldPolicy returned by parsedDelete->yieldPolicy().
*
* Does not take ownership of its arguments.
@@ -228,7 +231,11 @@ 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);
+ OperationContext* opCtx,
+ OpDebug* opDebug,
+ Collection* collection,
+ ParsedDelete* parsedDelete,
+ boost::optional<ExplainOptions::Verbosity> verbosity);
/**
* Get a PlanExecutor for an update operation. 'parsedUpdate' describes the query predicate
@@ -238,6 +245,9 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDele
*
* 'opDebug' Optional argument. When not null, will be used to record operation statistics.
*
+ * If the delete operation is executed in explain mode, the 'verbosity' parameter should be
+ * set to the requested verbosity level, or boost::none otherwise.
+ *
* The returned PlanExecutor will used the YieldPolicy returned by parsedUpdate->yieldPolicy().
*
* Does not take ownership of its arguments.
@@ -248,5 +258,9 @@ 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);
+ OperationContext* opCtx,
+ OpDebug* opDebug,
+ Collection* collection,
+ ParsedUpdate* parsedUpdate,
+ boost::optional<ExplainOptions::Verbosity> verbosity);
} // namespace mongo
diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp
index d7afdebefbb..76b00bfd6b1 100644
--- a/src/mongo/db/query/stage_builder.cpp
+++ b/src/mongo/db/query/stage_builder.cpp
@@ -154,8 +154,9 @@ 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>(opCtx,
+ return std::make_unique<ProjectionStageCovered>(cq.getExpCtx(),
cq.getQueryRequest().getProj(),
+ cq.getProj(),
ws,
std::move(childStage),
pn->coveredKeyObj);
@@ -163,8 +164,11 @@ 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>(
- opCtx, cq.getQueryRequest().getProj(), ws, std::move(childStage));
+ return std::make_unique<ProjectionStageSimple>(cq.getExpCtx(),
+ cq.getQueryRequest().getProj(),
+ cq.getProj(),
+ ws,
+ std::move(childStage));
}
case STAGE_LIMIT: {
const LimitNode* ln = static_cast<const LimitNode*>(root);
diff --git a/src/mongo/db/repl/storage_interface_impl.cpp b/src/mongo/db/repl/storage_interface_impl.cpp
index 79a05656b9d..0770b586e37 100644
--- a/src/mongo/db/repl/storage_interface_impl.cpp
+++ b/src/mongo/db/repl/storage_interface_impl.cpp
@@ -863,8 +863,8 @@ Status _updateWithQuery(OperationContext* opCtx,
uassertStatusOK(opCtx->recoveryUnit()->setTimestamp(ts));
}
- auto planExecutorResult =
- mongo::getExecutorUpdate(opCtx, nullptr, collection, &parsedUpdate);
+ auto planExecutorResult = mongo::getExecutorUpdate(
+ opCtx, nullptr, collection, &parsedUpdate, boost::none /* verbosity */);
if (!planExecutorResult.isOK()) {
return planExecutorResult.getStatus();
}
@@ -992,8 +992,8 @@ Status StorageInterfaceImpl::deleteByFilter(OperationContext* opCtx,
}
auto collection = collectionResult.getValue();
- auto planExecutorResult =
- mongo::getExecutorDelete(opCtx, nullptr, collection, &parsedDelete);
+ auto planExecutorResult = mongo::getExecutorDelete(
+ opCtx, nullptr, collection, &parsedDelete, boost::none /* verbosity */);
if (!planExecutorResult.isOK()) {
return planExecutorResult.getStatus();
}