summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/query_planner_common.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/query/query_planner_common.cpp')
-rw-r--r--src/mongo/db/query/query_planner_common.cpp41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/mongo/db/query/query_planner_common.cpp b/src/mongo/db/query/query_planner_common.cpp
index 013c2b88378..b6c3253fd28 100644
--- a/src/mongo/db/query/query_planner_common.cpp
+++ b/src/mongo/db/query/query_planner_common.cpp
@@ -33,7 +33,10 @@
#include "mongo/base/exact_cast.h"
#include "mongo/db/query/projection_ast_path_tracking_visitor.h"
#include "mongo/db/query/query_planner_common.h"
+#include "mongo/db/query/query_solution.h"
+#include "mongo/db/query/stage_types.h"
#include "mongo/db/query/tree_walker.h"
+#include "mongo/logv2/log.h"
#include "mongo/logv2/redaction.h"
#include "mongo/util/assert_util.h"
@@ -42,7 +45,38 @@
namespace mongo {
-void QueryPlannerCommon::reverseScans(QuerySolutionNode* node) {
+bool QueryPlannerCommon::scanDirectionsEqual(QuerySolutionNode* node, int direction) {
+ StageType type = node->getType();
+
+ boost::optional<int> scanDir;
+ if (STAGE_IXSCAN == type) {
+ IndexScanNode* isn = static_cast<IndexScanNode*>(node);
+ scanDir = isn->direction;
+ } else if (STAGE_DISTINCT_SCAN == type) {
+ DistinctNode* dn = static_cast<DistinctNode*>(node);
+ scanDir = dn->direction;
+ } else if (STAGE_COLLSCAN == type) {
+ CollectionScanNode* collScan = static_cast<CollectionScanNode*>(node);
+ scanDir = collScan->direction;
+ } else {
+ // We shouldn't encounter a sort stage.
+ invariant(!isSortStageType(type));
+ }
+
+ // If we found something with a direction, and the direction doesn't match, we return false.
+ if (scanDir && scanDir != direction) {
+ return false;
+ }
+
+ for (size_t i = 0; i < node->children.size(); ++i) {
+ if (!scanDirectionsEqual(node->children[i].get(), direction)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void QueryPlannerCommon::reverseScans(QuerySolutionNode* node, bool reverseCollScans) {
StageType type = node->getType();
if (STAGE_IXSCAN == type) {
@@ -72,6 +106,9 @@ void QueryPlannerCommon::reverseScans(QuerySolutionNode* node) {
// reverse direction of comparison for merge
MergeSortNode* msn = static_cast<MergeSortNode*>(node);
msn->sort = reverseSortObj(msn->sort);
+ } else if (reverseCollScans && STAGE_COLLSCAN == type) {
+ CollectionScanNode* collScan = static_cast<CollectionScanNode*>(node);
+ collScan->direction *= -1;
} else {
// Reversing scans is done in order to determine whether or not we need to add an explicit
// SORT stage. There shouldn't already be one present in the plan.
@@ -79,7 +116,7 @@ void QueryPlannerCommon::reverseScans(QuerySolutionNode* node) {
}
for (size_t i = 0; i < node->children.size(); ++i) {
- reverseScans(node->children[i].get());
+ reverseScans(node->children[i].get(), reverseCollScans);
}
}