summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/pipeline_d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/pipeline/pipeline_d.cpp')
-rw-r--r--src/mongo/db/pipeline/pipeline_d.cpp85
1 files changed, 55 insertions, 30 deletions
diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp
index 4a4f4b7ea14..69540a8b8bd 100644
--- a/src/mongo/db/pipeline/pipeline_d.cpp
+++ b/src/mongo/db/pipeline/pipeline_d.cpp
@@ -96,6 +96,39 @@ using std::unique_ptr;
using write_ops::Insert;
namespace {
+
+/**
+ * Return whether the given sort spec can be used in a find() sort.
+ */
+bool canSortBePushedDown(const BSONObj& sortSpec) {
+ // Return whether or not a sort stage can be pushed into the query layer.
+ for (auto&& elem : sortSpec) {
+ if (BSONType::Object != elem.type()) {
+ continue;
+ }
+
+ BSONObj subObj = elem.embeddedObject();
+ if (subObj.nFields() != 1) {
+ continue;
+ }
+
+ BSONElement firstElem = subObj.firstElement();
+ if (firstElem.fieldNameStringData() == "$meta" && firstElem.type() == BSONType::String) {
+ // Indeed it's a $meta.
+
+ // Technically sorting by {$meta: "textScore"} can be done in find() but requires a
+ // corresponding projection, so for simplicity we don't support it.
+ if (firstElem.valueStringData() == "textScore" ||
+ firstElem.valueStringData() == "randVal") {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
/**
* Returns a PlanExecutor which uses a random cursor to sample documents if successful. Returns {}
* if the storage engine doesn't support random cursors, or if 'sampleSize' is a large enough
@@ -233,7 +266,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> attemptToGetExe
return distinctExecutor.getStatus().withContext(
"Unable to use distinct scan to optimize $group stage");
} else if (!distinctExecutor.getValue()) {
- return {ErrorCodes::OperationFailed,
+ return {ErrorCodes::NoQueryExecutionPlans,
"Unable to use distinct scan to optimize $group stage"};
} else {
return distinctExecutor;
@@ -680,17 +713,16 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep
pipeline->addInitialSource(groupTransform);
return swExecutorGrouped;
- } else if (swExecutorGrouped == ErrorCodes::QueryPlanKilled) {
- return {ErrorCodes::OperationFailed,
- str::stream() << "Failed to determine whether query system can provide a "
- "DISTINCT_SCAN grouping: "
- << swExecutorGrouped.getStatus().toString()};
+ } else if (swExecutorGrouped != ErrorCodes::NoQueryExecutionPlans) {
+ return swExecutorGrouped.getStatus().withContext(
+ "Failed to determine whether query system can provide a "
+ "DISTINCT_SCAN grouping");
}
}
const BSONObj emptyProjection;
- const BSONObj metaSortProjection = BSON("$meta"
- << "sortKey");
+ const BSONObj metaSortProjection = BSON("$sortKey" << BSON("$meta"
+ << "sortKey"));
// The only way to get meta information (e.g. the text score) is to let the query system handle
// the projection. In all other cases, unless the query system can do an index-covered
@@ -700,7 +732,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep
plannerOpts |= QueryPlannerParams::NO_UNCOVERED_PROJECTIONS;
}
- if (sortStage) {
+ if (sortStage && canSortBePushedDown(*sortObj)) {
// See if the query system can provide a non-blocking sort.
auto swExecutorSort =
attemptToGetExecutor(opCtx,
@@ -736,11 +768,11 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep
if (swExecutorSortAndProj.isOK()) {
// Success! We have a non-blocking sort and a covered projection.
exec = std::move(swExecutorSortAndProj.getValue());
- } else if (swExecutorSortAndProj == ErrorCodes::QueryPlanKilled) {
- return {ErrorCodes::OperationFailed,
- str::stream() << "Failed to determine whether query system can provide a "
- "covered projection in addition to a non-blocking sort: "
- << swExecutorSortAndProj.getStatus().toString()};
+ } else if (swExecutorSortAndProj != ErrorCodes::NoQueryExecutionPlans) {
+
+ return swExecutorSortAndProj.getStatus().withContext(
+ "Failed to determine whether query system can provide a "
+ "covered projection in addition to a non-blocking sort");
} else {
// The query system couldn't cover the projection.
*projectionObj = BSONObj();
@@ -755,20 +787,15 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep
pipeline->_sources.push_front(sortStage->getLimitSrc());
}
return std::move(exec);
- } else if (swExecutorSort == ErrorCodes::QueryPlanKilled) {
- return {
- ErrorCodes::OperationFailed,
- str::stream()
- << "Failed to determine whether query system can provide a non-blocking sort: "
- << swExecutorSort.getStatus().toString()};
+ } else if (swExecutorSort != ErrorCodes::NoQueryExecutionPlans) {
+ return swExecutorSort.getStatus().withContext(
+ "Failed to determine whether query system can provide a non-blocking sort");
}
- // The query system can't provide a non-blocking sort.
- *sortObj = BSONObj();
}
- // Either there was no $sort stage, or the query system could not provide a non-blocking
- // sort.
- dassert(sortObj->isEmpty());
+ // Either there's no sort or the query system can't provide a non-blocking sort.
+ *sortObj = BSONObj();
+
*projectionObj = removeSortKeyMetaProjection(*projectionObj);
const auto metadataRequired = deps.getAllRequiredMetadataTypes();
if (metadataRequired.size() == 1 &&
@@ -796,11 +823,9 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep
if (swExecutorProj.isOK()) {
// Success! We have a covered projection.
return std::move(swExecutorProj.getValue());
- } else if (swExecutorProj == ErrorCodes::QueryPlanKilled) {
- return {ErrorCodes::OperationFailed,
- str::stream()
- << "Failed to determine whether query system can provide a covered projection: "
- << swExecutorProj.getStatus().toString()};
+ } else if (swExecutorProj != ErrorCodes::NoQueryExecutionPlans) {
+ return swExecutorProj.getStatus().withContext(
+ "Failed to determine whether query system can provide a covered projection");
}
// The query system couldn't provide a covered or simple uncovered projection.