summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/optimizer/utils/utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/query/optimizer/utils/utils.cpp')
-rw-r--r--src/mongo/db/query/optimizer/utils/utils.cpp192
1 files changed, 96 insertions, 96 deletions
diff --git a/src/mongo/db/query/optimizer/utils/utils.cpp b/src/mongo/db/query/optimizer/utils/utils.cpp
index 322ae174570..da4be863228 100644
--- a/src/mongo/db/query/optimizer/utils/utils.cpp
+++ b/src/mongo/db/query/optimizer/utils/utils.cpp
@@ -62,9 +62,12 @@ std::vector<ABT::reference_type> collectComposed(const ABT& n) {
return {n.ref()};
}
-FieldNameType getSimpleField(const ABT& node) {
- const PathGet* pathGet = node.cast<PathGet>();
- return pathGet != nullptr ? pathGet->name() : "";
+bool isSimplePath(const ABT& node) {
+ if (auto getPtr = node.cast<PathGet>();
+ getPtr != nullptr && getPtr->getPath().is<PathIdentity>()) {
+ return true;
+ }
+ return false;
}
std::string PrefixId::getNextId(const std::string& key) {
@@ -337,18 +340,8 @@ VariableNameSetType collectVariableReferences(const ABT& n) {
return NodeVariableTracker::collect(n);
}
-PartialSchemaReqConversion::PartialSchemaReqConversion()
- : _success(false),
- _bound(),
- _reqMap(),
- _hasIntersected(false),
- _hasTraversed(false),
- _hasEmptyInterval(false),
- _retainPredicate(false) {}
-
PartialSchemaReqConversion::PartialSchemaReqConversion(PartialSchemaRequirements reqMap)
- : _success(true),
- _bound(),
+ : _bound(),
_reqMap(std::move(reqMap)),
_hasIntersected(false),
_hasTraversed(false),
@@ -356,8 +349,7 @@ PartialSchemaReqConversion::PartialSchemaReqConversion(PartialSchemaRequirements
_retainPredicate(false) {}
PartialSchemaReqConversion::PartialSchemaReqConversion(ABT bound)
- : _success(true),
- _bound(std::move(bound)),
+ : _bound(std::move(bound)),
_reqMap(),
_hasIntersected(false),
_hasTraversed(false),
@@ -369,23 +361,24 @@ PartialSchemaReqConversion::PartialSchemaReqConversion(ABT bound)
*/
class PartialSchemaReqConverter {
public:
- PartialSchemaReqConverter() = default;
+ using ResultType = boost::optional<PartialSchemaReqConversion>;
+
+ PartialSchemaReqConverter(const bool isFilterContext) : _isFilterContext(isFilterContext) {}
- PartialSchemaReqConversion handleEvalPathAndEvalFilter(PartialSchemaReqConversion pathResult,
- PartialSchemaReqConversion inputResult) {
- if (!pathResult._success || !inputResult._success) {
+ ResultType handleEvalPathAndEvalFilter(ResultType pathResult, ResultType inputResult) {
+ if (!pathResult || !inputResult) {
return {};
}
- if (pathResult._bound.has_value() || !inputResult._bound.has_value() ||
- !inputResult._reqMap.empty()) {
+ if (pathResult->_bound.has_value() || !inputResult->_bound.has_value() ||
+ !inputResult->_reqMap.empty()) {
return {};
}
- if (auto boundPtr = inputResult._bound->cast<Variable>(); boundPtr != nullptr) {
+ if (auto boundPtr = inputResult->_bound->cast<Variable>(); boundPtr != nullptr) {
const ProjectionName& boundVarName = boundPtr->name();
PartialSchemaRequirements newMap;
- for (auto& [key, req] : pathResult._reqMap) {
+ for (auto& [key, req] : pathResult->_reqMap) {
if (!key._projectionName.empty()) {
return {};
}
@@ -393,40 +386,40 @@ public:
}
PartialSchemaReqConversion result{std::move(newMap)};
- result._hasEmptyInterval = pathResult._hasEmptyInterval;
- result._retainPredicate = pathResult._retainPredicate;
+ result._hasEmptyInterval = pathResult->_hasEmptyInterval;
+ result._retainPredicate = pathResult->_retainPredicate;
return result;
}
return {};
}
- PartialSchemaReqConversion transport(const ABT& n,
- const EvalPath& evalPath,
- PartialSchemaReqConversion pathResult,
- PartialSchemaReqConversion inputResult) {
+ ResultType transport(const ABT& n,
+ const EvalPath& evalPath,
+ ResultType pathResult,
+ ResultType inputResult) {
return handleEvalPathAndEvalFilter(std::move(pathResult), std::move(inputResult));
}
- PartialSchemaReqConversion transport(const ABT& n,
- const EvalFilter& evalFilter,
- PartialSchemaReqConversion pathResult,
- PartialSchemaReqConversion inputResult) {
+ ResultType transport(const ABT& n,
+ const EvalFilter& evalFilter,
+ ResultType pathResult,
+ ResultType inputResult) {
return handleEvalPathAndEvalFilter(std::move(pathResult), std::move(inputResult));
}
- static PartialSchemaReqConversion handleComposition(const bool isMultiplicative,
- PartialSchemaReqConversion leftResult,
- PartialSchemaReqConversion rightResult) {
- if (!leftResult._success || !rightResult._success) {
+ static ResultType handleComposition(const bool isMultiplicative,
+ ResultType leftResult,
+ ResultType rightResult) {
+ if (!leftResult || !rightResult) {
return {};
}
- if (leftResult._bound.has_value() || rightResult._bound.has_value()) {
+ if (leftResult->_bound.has_value() || rightResult->_bound.has_value()) {
return {};
}
- auto& leftReqMap = leftResult._reqMap;
- auto& rightReqMap = rightResult._reqMap;
+ auto& leftReqMap = leftResult->_reqMap;
+ auto& rightReqMap = rightResult->_reqMap;
if (isMultiplicative) {
{
ProjectionRenames projectionRenames;
@@ -438,7 +431,7 @@ public:
}
}
- if (!leftResult._hasTraversed && !rightResult._hasTraversed) {
+ if (!leftResult->_hasTraversed && !rightResult->_hasTraversed) {
// Intersect intervals only if we have not traversed. E.g. (-inf, 90) ^ (70, +inf)
// becomes (70, 90).
for (auto& [key, req] : leftReqMap) {
@@ -446,7 +439,7 @@ public:
if (newIntervals) {
req.getIntervals() = std::move(newIntervals.get());
} else {
- leftResult._hasEmptyInterval = true;
+ leftResult->_hasEmptyInterval = true;
break;
}
}
@@ -455,7 +448,7 @@ public:
return {};
}
- leftResult._hasIntersected = true;
+ leftResult->_hasIntersected = true;
return leftResult;
}
@@ -534,32 +527,40 @@ public:
rightPath.is<PathIdentity>()) {
// leftPath = Id, rightPath = Traverse Id.
combineIntervalsDNF(false /*intersect*/, leftIntervals, newInterval);
- leftResult._retainPredicate = true;
+ leftResult->_retainPredicate = true;
return leftResult;
} else if (const auto rightTraversePtr = rightPath.cast<PathTraverse>();
rightTraversePtr != nullptr && rightTraversePtr->getPath().is<PathIdentity>() &&
leftPath.is<PathIdentity>()) {
// leftPath = Traverse Id, rightPath = Id.
combineIntervalsDNF(false /*intersect*/, rightIntervals, newInterval);
- rightResult._retainPredicate = true;
+ rightResult->_retainPredicate = true;
return rightResult;
}
return {};
}
- PartialSchemaReqConversion transport(const ABT& n,
- const PathComposeM& pathComposeM,
- PartialSchemaReqConversion leftResult,
- PartialSchemaReqConversion rightResult) {
+ ResultType transport(const ABT& n,
+ const PathComposeM& pathComposeM,
+ ResultType leftResult,
+ ResultType rightResult) {
+ if (!_isFilterContext) {
+ return {};
+ }
+
return handleComposition(
true /*isMultiplicative*/, std::move(leftResult), std::move(rightResult));
}
- PartialSchemaReqConversion transport(const ABT& n,
- const PathComposeA& pathComposeA,
- PartialSchemaReqConversion leftResult,
- PartialSchemaReqConversion rightResult) {
+ ResultType transport(const ABT& n,
+ const PathComposeA& pathComposeA,
+ ResultType leftResult,
+ ResultType rightResult) {
+ if (!_isFilterContext) {
+ return {};
+ }
+
const auto& path1 = pathComposeA.getPath1();
const auto& path2 = pathComposeA.getPath2();
const auto& eqNull = make<PathCompare>(Operations::Eq, Constant::null());
@@ -571,9 +572,9 @@ public:
auto intervalExpr = IntervalReqExpr::makeSingularDNF(IntervalRequirement{
{true /*inclusive*/, Constant::null()}, {true /*inclusive*/, Constant::null()}});
- return {PartialSchemaRequirements{
+ return {{PartialSchemaRequirements{
{PartialSchemaKey{},
- PartialSchemaRequirement{"" /*boundProjectionName*/, std::move(intervalExpr)}}}};
+ PartialSchemaRequirement{"" /*boundProjectionName*/, std::move(intervalExpr)}}}}};
}
return handleComposition(
@@ -581,19 +582,18 @@ public:
}
template <class T>
- static PartialSchemaReqConversion handleGetAndTraverse(const ABT& n,
- PartialSchemaReqConversion inputResult) {
- if (!inputResult._success) {
+ static ResultType handleGetAndTraverse(const ABT& n, ResultType inputResult) {
+ if (!inputResult) {
return {};
}
- if (inputResult._bound.has_value()) {
+ if (inputResult->_bound.has_value()) {
return {};
}
// New map has keys with appended paths.
PartialSchemaRequirements newMap;
- for (auto& entry : inputResult._reqMap) {
+ for (auto& entry : inputResult->_reqMap) {
if (!entry.first._projectionName.empty()) {
return {};
}
@@ -608,41 +608,39 @@ public:
newMap.emplace(PartialSchemaKey{"", std::move(path)}, std::move(entry.second));
}
- inputResult._reqMap = std::move(newMap);
+ inputResult->_reqMap = std::move(newMap);
return inputResult;
}
- PartialSchemaReqConversion transport(const ABT& n,
- const PathGet& pathGet,
- PartialSchemaReqConversion inputResult) {
+ ResultType transport(const ABT& n, const PathGet& pathGet, ResultType inputResult) {
return handleGetAndTraverse<PathGet>(n, std::move(inputResult));
}
- PartialSchemaReqConversion transport(const ABT& n,
- const PathTraverse& pathTraverse,
- PartialSchemaReqConversion inputResult) {
- if (inputResult._reqMap.size() > 1) {
+ ResultType transport(const ABT& n, const PathTraverse& pathTraverse, ResultType inputResult) {
+ if (!inputResult) {
+ return {};
+ }
+ if (inputResult->_reqMap.size() > 1) {
// Cannot append traverse if we have more than one requirement.
return {};
}
- PartialSchemaReqConversion result =
- handleGetAndTraverse<PathTraverse>(n, std::move(inputResult));
- result._hasTraversed = true;
+ auto result = handleGetAndTraverse<PathTraverse>(n, std::move(inputResult));
+ if (result) {
+ result->_hasTraversed = true;
+ }
return result;
}
- PartialSchemaReqConversion transport(const ABT& n,
- const PathCompare& pathCompare,
- PartialSchemaReqConversion inputResult) {
- if (!inputResult._success) {
+ ResultType transport(const ABT& n, const PathCompare& pathCompare, ResultType inputResult) {
+ if (!inputResult) {
return {};
}
- if (!inputResult._bound.has_value() || !inputResult._reqMap.empty()) {
+ if (!inputResult->_bound.has_value() || !inputResult->_reqMap.empty()) {
return {};
}
- const auto& bound = inputResult._bound;
+ const auto& bound = inputResult->_bound;
bool lowBoundInclusive = false;
boost::optional<ABT> lowBound;
bool highBoundInclusive = false;
@@ -678,51 +676,53 @@ public:
auto intervalExpr = IntervalReqExpr::makeSingularDNF(IntervalRequirement{
{lowBoundInclusive, std::move(lowBound)}, {highBoundInclusive, std::move(highBound)}});
- return {PartialSchemaRequirements{
+ return {{PartialSchemaRequirements{
{PartialSchemaKey{},
- PartialSchemaRequirement{"" /*boundProjectionName*/, std::move(intervalExpr)}}}};
+ PartialSchemaRequirement{"" /*boundProjectionName*/, std::move(intervalExpr)}}}}};
}
- PartialSchemaReqConversion transport(const ABT& n, const PathIdentity& pathIdentity) {
- return {PartialSchemaRequirements{{{}, {}}}};
+ ResultType transport(const ABT& n, const PathIdentity& pathIdentity) {
+ return {{PartialSchemaRequirements{{{}, {}}}}};
}
- PartialSchemaReqConversion transport(const ABT& n, const Constant& c) {
+ ResultType transport(const ABT& n, const Constant& c) {
if (c.isNull()) {
// Cannot create bounds with just NULL.
return {};
}
- return {n};
+ return {{n}};
}
template <typename T, typename... Ts>
- PartialSchemaReqConversion transport(const ABT& n, const T& node, Ts&&...) {
+ ResultType transport(const ABT& n, const T& node, Ts&&...) {
if constexpr (std::is_base_of_v<ExpressionSyntaxSort, T>) {
// We allow expressions to participate in bounds.
- return {n};
+ return {{n}};
}
// General case. Reject conversion.
return {};
}
- PartialSchemaReqConversion convert(const ABT& input) {
+ ResultType convert(const ABT& input) {
return algebra::transport<true>(input, *this);
}
+
+private:
+ const bool _isFilterContext;
};
-PartialSchemaReqConversion convertExprToPartialSchemaReq(const ABT& expr) {
- PartialSchemaReqConverter converter;
- PartialSchemaReqConversion result = converter.convert(expr);
- if (result._reqMap.empty()) {
- result._success = false;
- return result;
+boost::optional<PartialSchemaReqConversion> convertExprToPartialSchemaReq(
+ const ABT& expr, const bool isFilterContext) {
+ PartialSchemaReqConverter converter(isFilterContext);
+ auto result = converter.convert(expr);
+ if (!result || result->_reqMap.empty()) {
+ return {};
}
- for (const auto& entry : result._reqMap) {
+ for (const auto& entry : result->_reqMap) {
if (entry.first.emptyPath() && isIntervalReqFullyOpenDNF(entry.second.getIntervals())) {
// We need to determine either path or interval (or both).
- result._success = false;
- return result;
+ return {};
}
}
return result;