summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/optimizer/rewrites/path.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/query/optimizer/rewrites/path.cpp')
-rw-r--r--src/mongo/db/query/optimizer/rewrites/path.cpp50
1 files changed, 35 insertions, 15 deletions
diff --git a/src/mongo/db/query/optimizer/rewrites/path.cpp b/src/mongo/db/query/optimizer/rewrites/path.cpp
index 2752b72c752..58c5b34a68b 100644
--- a/src/mongo/db/query/optimizer/rewrites/path.cpp
+++ b/src/mongo/db/query/optimizer/rewrites/path.cpp
@@ -44,13 +44,8 @@ ABT::reference_type PathFusion::follow(ABT::reference_type n) {
bool PathFusion::fuse(ABT& lhs, const ABT& rhs) {
if (auto rhsComposeM = rhs.cast<PathComposeM>(); rhsComposeM != nullptr) {
- // Try to fuse first with right path, then left.
- if (_info[rhsComposeM->getPath2().cast<PathSyntaxSort>()]._isConst) {
- if (fuse(lhs, rhsComposeM->getPath2())) {
- return true;
- }
- if (_info[rhsComposeM->getPath1().cast<PathSyntaxSort>()]._isConst &&
- fuse(lhs, rhsComposeM->getPath1())) {
+ for (const auto& branch : collectComposed(rhs)) {
+ if (_info[branch.cast<PathSyntaxSort>()]._isConst && fuse(lhs, branch)) {
return true;
}
}
@@ -307,7 +302,7 @@ void PathFusion::transport(ABT& n, const PathComposeM& path, ABT& p1, ABT& p2) {
}
}
-void PathFusion::tryFuseComposition(ABT& n, const ABT& input) {
+void PathFusion::tryFuseComposition(ABT& n, ABT& input) {
// Check to see if our flattened composition consists of constant branches containing only
// Field and Keep elements. If we have duplicate Field branches then retain only the
// latest one. For example:
@@ -327,6 +322,7 @@ void PathFusion::tryFuseComposition(ABT& n, const ABT& input) {
}
bool updated = false;
+ bool hasDefault = false;
for (const auto& branch : collectComposed(n)) {
auto info = _info.find(branch.cast<PathSyntaxSort>());
if (info == _info.cend()) {
@@ -369,19 +365,43 @@ void PathFusion::tryFuseComposition(ABT& n, const ABT& input) {
}
}
toKeep = std::move(newKeepSet);
- } else if (auto defaultPtr = branch.cast<PathDefault>(); defaultPtr != nullptr &&
- defaultPtr->getDefault().is<Constant>() &&
- defaultPtr->getDefault().cast<Constant>()->isObject() &&
- inputType == Type::object) {
- // Skip over PathDefault with an empty object since our input is already an object.
- updated = true;
+ } else if (auto defaultPtr = branch.cast<PathDefault>(); defaultPtr != nullptr) {
+ if (auto constPtr = defaultPtr->getDefault().cast<Constant>();
+ constPtr != nullptr && constPtr->isObject() && inputType == Type::object) {
+ // Skip over PathDefault with an empty object since our input is already an object.
+ updated = true;
+ } else {
+ // Skip over other PathDefaults but remember we had one.
+ hasDefault = true;
+ }
} else {
return;
- };
+ }
+ }
+
+ if (toKeep && input != Constant::emptyObject()) {
+ // Check if we assign to every field we keep. If so, drop dependence on input.
+ bool assignToAllKeptFields = true;
+ for (const auto& fieldName : *toKeep) {
+ if (fieldMap.count(fieldName) == 0) {
+ assignToAllKeptFields = false;
+ break;
+ }
+ }
+ if (assignToAllKeptFields) {
+ // Do not need the input, do not keep fields, and ignore defaults.
+ input = Constant::emptyObject();
+ toKeep = boost::none;
+ updated = true;
+ hasDefault = false;
+ }
}
if (!updated) {
return;
}
+ if (hasDefault) {
+ return;
+ }
ABT result = make<PathIdentity>();
if (toKeep) {