diff options
-rw-r--r-- | src/mongo/db/matcher/expression_visitor.h | 143 | ||||
-rw-r--r-- | src/mongo/db/query/bind_input_params.cpp | 84 | ||||
-rw-r--r-- | src/mongo/db/query/bind_input_params.h | 11 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_stage_builder.cpp | 89 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_utils.cpp | 210 | ||||
-rw-r--r-- | src/mongo/db/query/sbe_utils.h | 13 |
6 files changed, 378 insertions, 172 deletions
diff --git a/src/mongo/db/matcher/expression_visitor.h b/src/mongo/db/matcher/expression_visitor.h index 78ba0ce3df3..f31e604f518 100644 --- a/src/mongo/db/matcher/expression_visitor.h +++ b/src/mongo/db/matcher/expression_visitor.h @@ -101,90 +101,67 @@ class WhereNoOpMatchExpression; template <bool IsConst = false> class MatchExpressionVisitor { public: + template <typename T> + using MaybeConstPtr = tree_walker::MaybeConstPtr<IsConst, T>; + virtual ~MatchExpressionVisitor() = default; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, AlwaysFalseMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, AlwaysTrueMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, AndMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, BitsAllClearMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, BitsAllSetMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, BitsAnyClearMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, BitsAnySetMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, ElemMatchObjectMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, ElemMatchValueMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, EqualityMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, ExistsMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, ExprMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, GTEMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, GTMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, GeoMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, GeoNearMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, InMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalBucketGeoWithinMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, InternalExprEqMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, InternalExprGTMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalExprGTEMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, InternalExprLTMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalExprLTEMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaAllElemMatchFromIndexMatchExpression> - expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaAllowedPropertiesMatchExpression> - expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaBinDataEncryptedTypeExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaBinDataFLE2EncryptedTypeExpression> - expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaBinDataSubTypeExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaCondMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaEqMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaFmodMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaMatchArrayIndexMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaMaxItemsMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaMaxLengthMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaMaxPropertiesMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaMinItemsMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaMinLengthMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaMinPropertiesMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaObjectMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaRootDocEqMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, InternalSchemaTypeExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaUniqueItemsMatchExpression> expr) = 0; - virtual void visit( - tree_walker::MaybeConstPtr<IsConst, InternalSchemaXorMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, LTEMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, LTMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, ModMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, NorMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, NotMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, OrMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, RegexMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, SizeMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, TextMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, TextNoOpMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, TwoDPtInAnnulusExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, TypeMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, WhereMatchExpression> expr) = 0; - virtual void visit(tree_walker::MaybeConstPtr<IsConst, WhereNoOpMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<AlwaysFalseMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<AlwaysTrueMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<AndMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<BitsAllClearMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<BitsAllSetMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<BitsAnyClearMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<BitsAnySetMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<ElemMatchObjectMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<ElemMatchValueMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<EqualityMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<ExistsMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<ExprMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<GTEMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<GTMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<GeoMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<GeoNearMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalBucketGeoWithinMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalExprEqMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalExprGTMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalExprGTEMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalExprLTMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalExprLTEMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaAllElemMatchFromIndexMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaAllowedPropertiesMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaBinDataEncryptedTypeExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaBinDataFLE2EncryptedTypeExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaBinDataSubTypeExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaCondMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaEqMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaFmodMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaMatchArrayIndexMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaMaxItemsMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaMaxLengthMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaMaxPropertiesMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaMinItemsMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaMinLengthMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaMinPropertiesMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaObjectMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaRootDocEqMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaTypeExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaUniqueItemsMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<InternalSchemaXorMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<LTEMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<LTMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<ModMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<NorMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<NotMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<OrMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<RegexMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<SizeMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<TextMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<TextNoOpMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<TwoDPtInAnnulusExpression> expr) = 0; + virtual void visit(MaybeConstPtr<TypeMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<WhereMatchExpression> expr) = 0; + virtual void visit(MaybeConstPtr<WhereNoOpMatchExpression> expr) = 0; }; using MatchExpressionMutableVisitor = MatchExpressionVisitor<false>; diff --git a/src/mongo/db/query/bind_input_params.cpp b/src/mongo/db/query/bind_input_params.cpp index c6276a5d60b..d0396fcf723 100644 --- a/src/mongo/db/query/bind_input_params.cpp +++ b/src/mongo/db/query/bind_input_params.cpp @@ -33,7 +33,9 @@ #include "mongo/db/exec/sbe/values/value.h" #include "mongo/db/matcher/expression_array.h" #include "mongo/db/matcher/expression_where.h" +#include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/sbe_stage_builder_filter.h" +#include "mongo/db/query/sbe_stage_builder_index_scan.h" namespace mongo::input_params { namespace { @@ -290,9 +292,6 @@ private: guard->reset(); } accessor->reset(owned, typeTag, value); - } else { - // TODO SERVER-65361: add tassert here if the slotId is missing from - // _inputParamToSlotMap but not from IETs. } } @@ -318,6 +317,38 @@ public: private: MatchExpressionParameterBindingVisitor* const _visitor; }; + +/** + * Evaluates IndexBounds from the given IntervalEvaluationTrees for the given query. + * 'indexBoundsInfo' contains the interval evaluation trees. + * + * Returns the built index bounds. + */ +std::unique_ptr<IndexBounds> makeIndexBounds( + const stage_builder::IndexBoundsEvaluationInfo& indexBoundsInfo, const CanonicalQuery& cq) { + auto bounds = std::make_unique<IndexBounds>(); + bounds->fields.reserve(indexBoundsInfo.iets.size()); + + tassert(6335200, + "IET list size must be equal to the number of fields in the key pattern", + static_cast<size_t>(indexBoundsInfo.index.keyPattern.nFields()) == + indexBoundsInfo.iets.size()); + + BSONObjIterator it{indexBoundsInfo.index.keyPattern}; + BSONElement keyElt = it.next(); + for (auto&& iet : indexBoundsInfo.iets) { + auto oil = interval_evaluation_tree::evaluateIntervals( + iet, cq.getInputParamIdToMatchExpressionMap(), keyElt, indexBoundsInfo.index); + bounds->fields.emplace_back(std::move(oil)); + keyElt = it.next(); + } + + IndexBoundsBuilder::alignBounds(bounds.get(), + indexBoundsInfo.index.keyPattern, + indexBoundsInfo.index.collator != nullptr, + indexBoundsInfo.direction); + return bounds; +} } // namespace void bind(const CanonicalQuery& canonicalQuery, @@ -327,4 +358,51 @@ void bind(const CanonicalQuery& canonicalQuery, MatchExpressionParameterBindingWalker walker{&visitor}; tree_walker::walk<true, MatchExpression>(canonicalQuery.root(), &walker); } + +void bindIndexBounds(const CanonicalQuery& cq, + const stage_builder::IndexBoundsEvaluationInfo& indexBoundsInfo, + sbe::RuntimeEnvironment* runtimeEnvironment) { + auto bounds = makeIndexBounds(indexBoundsInfo, cq); + auto intervals = stage_builder::makeIntervalsFromIndexBounds(*bounds, + indexBoundsInfo.direction == 1, + indexBoundsInfo.keyStringVersion, + indexBoundsInfo.ordering); + const bool isGenericScan = intervals.empty(); + runtimeEnvironment->resetSlot(indexBoundsInfo.slots.isGenericScan, + sbe::value::TypeTags::Boolean, + sbe::value::bitcastFrom<bool>(isGenericScan), + /*owned*/ true); + if (isGenericScan) { + IndexBoundsChecker checker{ + bounds.get(), indexBoundsInfo.index.keyPattern, indexBoundsInfo.direction}; + IndexSeekPoint seekPoint; + if (checker.getStartSeekPoint(&seekPoint)) { + auto startKey = std::make_unique<KeyString::Value>( + IndexEntryComparison::makeKeyStringFromSeekPointForSeek( + seekPoint, + indexBoundsInfo.keyStringVersion, + indexBoundsInfo.ordering, + indexBoundsInfo.direction == 1)); + runtimeEnvironment->resetSlot( + indexBoundsInfo.slots.initialStartKey, + sbe::value::TypeTags::ksValue, + sbe::value::bitcastFrom<KeyString::Value*>(startKey.release()), + /*owned*/ true); + runtimeEnvironment->resetSlot(indexBoundsInfo.slots.indexBounds, + sbe::value::TypeTags::indexBounds, + sbe::value::bitcastFrom<IndexBounds*>(bounds.release()), + /*owned*/ true); + } else { + runtimeEnvironment->resetSlot(indexBoundsInfo.slots.initialStartKey, + sbe::value::TypeTags::Nothing, + 0, + /*owned*/ true); + } + } else { + auto [boundsTag, boundsVal] = + stage_builder::packIndexIntervalsInSbeArray(std::move(intervals)); + runtimeEnvironment->resetSlot( + indexBoundsInfo.slots.lowHighKeyIntervals, boundsTag, boundsVal, /*owned*/ true); + } +} } // namespace mongo::input_params diff --git a/src/mongo/db/query/bind_input_params.h b/src/mongo/db/query/bind_input_params.h index 82092c1ab6f..910ce991878 100644 --- a/src/mongo/db/query/bind_input_params.h +++ b/src/mongo/db/query/bind_input_params.h @@ -44,4 +44,15 @@ namespace mongo::input_params { void bind(const CanonicalQuery&, const stage_builder::InputParamToSlotMap&, sbe::RuntimeEnvironment*); + +/** + * Binds index bounds evaluated from IETs to index bounds slots for the given query. + * + * - 'cq' is the query + * - 'indexBoundsInfo' contains the IETs and the slots + * - runtimeEnvironment SBE runtime environment + */ +void bindIndexBounds(const CanonicalQuery& cq, + const stage_builder::IndexBoundsEvaluationInfo& indexBoundsInfo, + sbe::RuntimeEnvironment* runtimeEnvironment); } // namespace mongo::input_params diff --git a/src/mongo/db/query/sbe_stage_builder.cpp b/src/mongo/db/query/sbe_stage_builder.cpp index ac891dd5253..919a7ce6dc8 100644 --- a/src/mongo/db/query/sbe_stage_builder.cpp +++ b/src/mongo/db/query/sbe_stage_builder.cpp @@ -73,6 +73,7 @@ #include "mongo/db/query/sbe_stage_builder_filter.h" #include "mongo/db/query/sbe_stage_builder_index_scan.h" #include "mongo/db/query/sbe_stage_builder_projection.h" +#include "mongo/db/query/sbe_utils.h" #include "mongo/db/query/shard_filterer_factory_impl.h" #include "mongo/db/query/util/make_data_structure.h" #include "mongo/db/s/collection_sharding_state.h" @@ -354,91 +355,6 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateEofPlan( return {std::move(stage), std::move(outputs)}; } - -/** - * Evaluates IndexBounds from the given IntervalEvaluationTrees for the given query. - * 'indexBoundsInfo' contains the interval evaluation trees. - * - * Returns the built index bounds. - */ -std::unique_ptr<IndexBounds> makeIndexBounds(const IndexBoundsEvaluationInfo& indexBoundsInfo, - const CanonicalQuery& cq) { - auto bounds = std::make_unique<IndexBounds>(); - bounds->fields.reserve(indexBoundsInfo.iets.size()); - - tassert(6335200, - "IET list size must be equal to the number of fields in the key pattern", - static_cast<size_t>(indexBoundsInfo.index.keyPattern.nFields()) == - indexBoundsInfo.iets.size()); - - BSONObjIterator it{indexBoundsInfo.index.keyPattern}; - BSONElement keyElt = it.next(); - for (auto&& iet : indexBoundsInfo.iets) { - auto oil = interval_evaluation_tree::evaluateIntervals( - iet, cq.getInputParamIdToMatchExpressionMap(), keyElt, indexBoundsInfo.index); - bounds->fields.emplace_back(std::move(oil)); - keyElt = it.next(); - } - - IndexBoundsBuilder::alignBounds(bounds.get(), - indexBoundsInfo.index.keyPattern, - indexBoundsInfo.index.collator != nullptr, - indexBoundsInfo.direction); - return bounds; -} - -/** - * Binds index bounds evaluated from IETs to index bounds slots for the given query. - * - * - 'cq' is the query - * - 'indexBoundsInfo' contains the IETs and the slots - * - runtimeEnvironment SBE runtime environment - */ -void bindIndexBoundsParams(const CanonicalQuery& cq, - const IndexBoundsEvaluationInfo& indexBoundsInfo, - sbe::RuntimeEnvironment* runtimeEnvironment) { - auto bounds = makeIndexBounds(indexBoundsInfo, cq); - auto intervals = makeIntervalsFromIndexBounds(*bounds, - indexBoundsInfo.direction == 1, - indexBoundsInfo.keyStringVersion, - indexBoundsInfo.ordering); - const bool isGenericScan = intervals.empty(); - runtimeEnvironment->resetSlot(indexBoundsInfo.slots.isGenericScan, - sbe::value::TypeTags::Boolean, - sbe::value::bitcastFrom<bool>(isGenericScan), - /*owned*/ true); - if (isGenericScan) { - IndexBoundsChecker checker{ - bounds.get(), indexBoundsInfo.index.keyPattern, indexBoundsInfo.direction}; - IndexSeekPoint seekPoint; - if (checker.getStartSeekPoint(&seekPoint)) { - auto startKey = std::make_unique<KeyString::Value>( - IndexEntryComparison::makeKeyStringFromSeekPointForSeek( - seekPoint, - indexBoundsInfo.keyStringVersion, - indexBoundsInfo.ordering, - indexBoundsInfo.direction == 1)); - runtimeEnvironment->resetSlot( - indexBoundsInfo.slots.initialStartKey, - sbe::value::TypeTags::ksValue, - sbe::value::bitcastFrom<KeyString::Value*>(startKey.release()), - /*owned*/ true); - runtimeEnvironment->resetSlot(indexBoundsInfo.slots.indexBounds, - sbe::value::TypeTags::indexBounds, - sbe::value::bitcastFrom<IndexBounds*>(bounds.release()), - /*owned*/ true); - } else { - runtimeEnvironment->resetSlot(indexBoundsInfo.slots.initialStartKey, - sbe::value::TypeTags::Nothing, - 0, - /*owned*/ true); - } - } else { - auto [boundsTag, boundsVal] = packIndexIntervalsInSbeArray(std::move(intervals)); - runtimeEnvironment->resetSlot( - indexBoundsInfo.slots.lowHighKeyIntervals, boundsTag, boundsVal, /*owned*/ true); - } -} } // namespace std::unique_ptr<sbe::RuntimeEnvironment> makeRuntimeEnvironment( @@ -543,12 +459,13 @@ void prepareSlotBasedExecutableTree(OperationContext* opCtx, } } + // TODO SERVER-66039: Add dassert on sbe::validateInputParamsBindings(). // If the cached plan is parameterized, bind new values for the parameters into the runtime // environment. input_params::bind(cq, data->inputParamToSlotMap, env); for (auto&& indexBoundsInfo : data->indexBoundsEvaluationInfos) { - bindIndexBoundsParams(cq, indexBoundsInfo, env); + input_params::bindIndexBounds(cq, indexBoundsInfo, env); } } diff --git a/src/mongo/db/query/sbe_utils.cpp b/src/mongo/db/query/sbe_utils.cpp index 427fdf9d7e0..19bf5c77bbe 100644 --- a/src/mongo/db/query/sbe_utils.cpp +++ b/src/mongo/db/query/sbe_utils.cpp @@ -27,11 +27,205 @@ * it in the license file. */ +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kQuery + #include "mongo/db/query/sbe_utils.h" +#include "mongo/db/matcher/expression_array.h" +#include "mongo/db/matcher/expression_where.h" +#include "mongo/db/matcher/match_expression_walker.h" #include "mongo/db/query/query_planner_params.h" +#include "mongo/db/query/sbe_stage_builder.h" +#include "mongo/logv2/log.h" namespace mongo::sbe { +namespace { +/** + * Helper class that collects InputParamIds from IET EvalNodes. + */ +class InputParamIdsCollector { +public: + InputParamIdsCollector(stdx::unordered_set<MatchExpression::InputParamId>& inputParamIds) + : _inputParamIds{inputParamIds} {} + + template <typename... Args> + void transport(Args...) {} + + void transport(const interval_evaluation_tree::EvalNode& node) { + _inputParamIds.insert(node.inputParamId()); + } + +private: + stdx::unordered_set<MatchExpression::InputParamId>& _inputParamIds; +}; + +/** + * Collect InputParamsIds from IETs of the given 'indexBoundsEvaluationInfos' for debugging + * purposes. + */ +stdx::unordered_set<MatchExpression::InputParamId> collectInputParamIdsFromIETs( + const std::vector<stage_builder::IndexBoundsEvaluationInfo>& indexBoundsEvaluationInfos) { + stdx::unordered_set<MatchExpression::InputParamId> inputParamIds; + InputParamIdsCollector transporter{inputParamIds}; + for (const auto& indexBoundsInfo : indexBoundsEvaluationInfos) { + for (const auto& iet : indexBoundsInfo.iets) { + optimizer::algebra::transport(iet, transporter); + } + } + return inputParamIds; +} + +struct MatchExpressionInputParamIdsValidatorVisitorContext { + size_t numberOfIncorrectlyMissingInputParamIds{0}; +}; + +class MatchExpressionInputParamIdsValidatorVisitor final : public MatchExpressionConstVisitor { +public: + MatchExpressionInputParamIdsValidatorVisitor( + MatchExpressionInputParamIdsValidatorVisitorContext* context, + const stdx::unordered_set<MatchExpression::InputParamId>& paramIdsFromIETs, + const stage_builder::InputParamToSlotMap& inputParamToSlotMap) + : _context{context}, + _paramIdsFromIETs{paramIdsFromIETs}, + _inputParamToSlotMap{inputParamToSlotMap} { + invariant(_context); + } + + void visit(const BitsAllClearMatchExpression* expr) final { + visitBitTestExpr(expr); + } + + void visit(const BitsAllSetMatchExpression* expr) final { + visitBitTestExpr(expr); + } + + void visit(const BitsAnyClearMatchExpression* expr) final { + visitBitTestExpr(expr); + } + + void visit(const BitsAnySetMatchExpression* expr) final { + visitBitTestExpr(expr); + } + + void visit(const EqualityMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const GTEMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const GTMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const InMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const LTEMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const LTMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const ModMatchExpression* expr) final { + validate(expr->getDivisorInputParamId(), expr); + validate(expr->getRemainderInputParamId(), expr); + } + + void visit(const RegexMatchExpression* expr) final { + validate(expr->getCompiledRegexInputParamId(), expr); + validate(expr->getSourceRegexInputParamId(), expr); + } + + void visit(const SizeMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const TypeMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const WhereMatchExpression* expr) final { + visitExpr(expr); + } + + void visit(const AlwaysFalseMatchExpression* expr) final {} + void visit(const AlwaysTrueMatchExpression* expr) final {} + void visit(const AndMatchExpression* expr) final {} + void visit(const ElemMatchObjectMatchExpression* matchExpr) final {} + void visit(const ElemMatchValueMatchExpression* matchExpr) final {} + void visit(const ExistsMatchExpression* expr) final {} + void visit(const ExprMatchExpression* expr) final {} + void visit(const GeoMatchExpression* expr) final {} + void visit(const GeoNearMatchExpression* expr) final {} + void visit(const InternalBucketGeoWithinMatchExpression* expr) final {} + void visit(const InternalExprEqMatchExpression* expr) final {} + void visit(const InternalExprGTMatchExpression* expr) final {} + void visit(const InternalExprGTEMatchExpression* expr) final {} + void visit(const InternalExprLTMatchExpression* expr) final {} + void visit(const InternalExprLTEMatchExpression* expr) final {} + void visit(const InternalSchemaAllElemMatchFromIndexMatchExpression* expr) final {} + void visit(const InternalSchemaAllowedPropertiesMatchExpression* expr) final {} + void visit(const InternalSchemaBinDataEncryptedTypeExpression* expr) final {} + void visit(const InternalSchemaBinDataFLE2EncryptedTypeExpression* expr) final {} + void visit(const InternalSchemaBinDataSubTypeExpression* expr) final {} + void visit(const InternalSchemaCondMatchExpression* expr) final {} + void visit(const InternalSchemaEqMatchExpression* expr) final {} + void visit(const InternalSchemaFmodMatchExpression* expr) final {} + void visit(const InternalSchemaMatchArrayIndexMatchExpression* expr) final {} + void visit(const InternalSchemaMaxItemsMatchExpression* expr) final {} + void visit(const InternalSchemaMaxLengthMatchExpression* expr) final {} + void visit(const InternalSchemaMaxPropertiesMatchExpression* expr) final {} + void visit(const InternalSchemaMinItemsMatchExpression* expr) final {} + void visit(const InternalSchemaMinLengthMatchExpression* expr) final {} + void visit(const InternalSchemaMinPropertiesMatchExpression* expr) final {} + void visit(const InternalSchemaObjectMatchExpression* expr) final {} + void visit(const InternalSchemaRootDocEqMatchExpression* expr) final {} + void visit(const InternalSchemaTypeExpression* expr) final {} + void visit(const InternalSchemaUniqueItemsMatchExpression* expr) final {} + void visit(const InternalSchemaXorMatchExpression* expr) final {} + void visit(const NorMatchExpression* expr) final {} + void visit(const NotMatchExpression* expr) final {} + void visit(const OrMatchExpression* expr) final {} + void visit(const TextMatchExpression* expr) final {} + void visit(const TextNoOpMatchExpression* expr) final {} + void visit(const TwoDPtInAnnulusExpression* expr) final {} + void visit(const WhereNoOpMatchExpression* expr) final {} + +private: + void visitBitTestExpr(const BitTestMatchExpression* expr) { + validate(expr->getBitPositionsParamId(), expr); + validate(expr->getBitMaskParamId(), expr); + } + + template <typename T> + void visitExpr(const T* expr) { + validate(expr->getInputParamId(), expr); + } + + void validate(const boost::optional<MatchExpression::InputParamId>& inputParamId, + const MatchExpression* expr) { + if (inputParamId && !_inputParamToSlotMap.contains(*inputParamId) && + !_paramIdsFromIETs.contains(*inputParamId)) { + ++_context->numberOfIncorrectlyMissingInputParamIds; + LOGV2_WARNING(6536100, + "Found mismatched input param", + "inputParamID"_attr = *inputParamId, + "expr"_attr = expr->debugString()); + } + } + + MatchExpressionInputParamIdsValidatorVisitorContext* _context; + + const stdx::unordered_set<MatchExpression::InputParamId>& _paramIdsFromIETs; + const stage_builder::InputParamToSlotMap& _inputParamToSlotMap; +}; +} // namespace + bool isQuerySbeCompatible(const CollectionPtr* collection, const CanonicalQuery* cq, size_t plannerOptions) { @@ -61,4 +255,20 @@ bool isQuerySbeCompatible(const CollectionPtr* collection, isQueryNotAgainstTimeseriesCollection && isQueryNotAgainstClusteredCollection && doesNotSortOnMetaOrPathWithNumericComponents && isNotOplog; } + +bool validateInputParamsBindings( + const MatchExpression* root, + const std::vector<stage_builder::IndexBoundsEvaluationInfo>& indexBoundsEvaluationInfos, + const stage_builder::InputParamToSlotMap& inputParamToSlotMap) { + auto inputParamIdsFromIETs = collectInputParamIdsFromIETs(indexBoundsEvaluationInfos); + MatchExpressionInputParamIdsValidatorVisitorContext context{}; + MatchExpressionInputParamIdsValidatorVisitor visitor{ + &context, inputParamIdsFromIETs, inputParamToSlotMap}; + MatchExpressionWalker walker{&visitor, nullptr, nullptr}; + tree_walker::walk<true, MatchExpression>(root, &walker); + if (context.numberOfIncorrectlyMissingInputParamIds != 0) { + LOGV2_WARNING(6536101, "Found mismatched input params", "expr"_attr = root->debugString()); + } + return context.numberOfIncorrectlyMissingInputParamIds == 0; +} } // namespace mongo::sbe diff --git a/src/mongo/db/query/sbe_utils.h b/src/mongo/db/query/sbe_utils.h index 7de483b6f5a..5dce1500213 100644 --- a/src/mongo/db/query/sbe_utils.h +++ b/src/mongo/db/query/sbe_utils.h @@ -31,6 +31,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/query/canonical_query.h" +#include "mongo/db/query/sbe_stage_builder.h" namespace mongo::sbe { /** @@ -39,4 +40,16 @@ namespace mongo::sbe { bool isQuerySbeCompatible(const CollectionPtr* collection, const CanonicalQuery* cq, size_t plannerOptions); + +/** + * Some of InputParamIds assigned in the MatchExpression tree (parameter 'root') might be missing + * from 'inputParamToSlotMap' due to later optimizations on index bound evaluation step. This + * function validates that in this case the missing parameters are indeed missing due to the + * optimizations mentioned above and, as such, are not represented in Interval Evaluation Tree built + * during index bound evaluation and stored in 'inputParamToSlotMap'. + */ +bool validateInputParamsBindings( + const MatchExpression* root, + const std::vector<stage_builder::IndexBoundsEvaluationInfo>& indexBoundsEvaluationInfos, + const stage_builder::InputParamToSlotMap& inputParamToSlotMap); } // namespace mongo::sbe |