diff options
author | Arun Banala <arun.banala@mongodb.com> | 2020-01-27 17:14:37 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-01-29 00:23:05 +0000 |
commit | fe52d534b34f180077ab26bb22e140cb2750497b (patch) | |
tree | b291fa831d0a3a78612dbe19da31b4b6e8bb339b /src/mongo | |
parent | 681631228dbaa98e00d1ea6d98c00662ef293a2b (diff) | |
download | mongo-fe52d534b34f180077ab26bb22e140cb2750497b.tar.gz |
SERVER-45590 Allow building a LiteParsedPipeline without first building an AggregationRequest
Diffstat (limited to 'src/mongo')
29 files changed, 167 insertions, 165 deletions
diff --git a/src/mongo/db/auth/authorization_session_impl.cpp b/src/mongo/db/auth/authorization_session_impl.cpp index c8aa89175ae..941f3b84cf8 100644 --- a/src/mongo/db/auth/authorization_session_impl.cpp +++ b/src/mongo/db/auth/authorization_session_impl.cpp @@ -280,7 +280,7 @@ StatusWith<PrivilegeVector> AuthorizationSessionImpl::getPrivilegesForAggregate( // If the first stage of the pipeline is not an initial source, the pipeline is implicitly // reading documents from the underlying collection. The client must be authorized to do so. - auto liteParsedDocSource = LiteParsedDocumentSource::parse(aggRequest, pipeline[0]); + auto liteParsedDocSource = LiteParsedDocumentSource::parse(nss, pipeline[0]); if (!liteParsedDocSource->isInitialSource()) { Privilege currentPriv = Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find); @@ -289,8 +289,9 @@ StatusWith<PrivilegeVector> AuthorizationSessionImpl::getPrivilegesForAggregate( // Confirm privileges for the pipeline. for (auto&& pipelineStage : pipeline) { - liteParsedDocSource = LiteParsedDocumentSource::parse(aggRequest, pipelineStage); - PrivilegeVector currentPrivs = liteParsedDocSource->requiredPrivileges(isMongos); + liteParsedDocSource = LiteParsedDocumentSource::parse(nss, pipelineStage); + PrivilegeVector currentPrivs = liteParsedDocSource->requiredPrivileges( + isMongos, aggRequest.shouldBypassDocumentValidation()); Privilege::addPrivilegesToPrivilegeVector(&privileges, currentPrivs); } return privileges; diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp index be216023882..aceebd1a900 100644 --- a/src/mongo/db/commands/run_aggregate.cpp +++ b/src/mongo/db/commands/run_aggregate.cpp @@ -312,8 +312,8 @@ StatusWith<StringMap<ExpressionContext::ResolvedNamespace>> resolveInvolvedNames // We parse the pipeline corresponding to the resolved view in case we must resolve // other view namespaces that are also involved. - LiteParsedPipeline resolvedViewLitePipeline( - {resolvedView.getValue().getNamespace(), resolvedView.getValue().getPipeline()}); + LiteParsedPipeline resolvedViewLitePipeline(resolvedView.getValue().getNamespace(), + resolvedView.getValue().getPipeline()); const auto& resolvedViewInvolvedNamespaces = resolvedViewLitePipeline.getInvolvedNamespaces(); diff --git a/src/mongo/db/pipeline/document_source_change_stream.h b/src/mongo/db/pipeline/document_source_change_stream.h index 8f8ef6f6e79..9570f2e16e1 100644 --- a/src/mongo/db/pipeline/document_source_change_stream.h +++ b/src/mongo/db/pipeline/document_source_change_stream.h @@ -46,9 +46,9 @@ class DocumentSourceChangeStream final { public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec) { - return std::make_unique<LiteParsed>(request.getNamespaceString()); + return std::make_unique<LiteParsed>(nss); } explicit LiteParsed(NamespaceString nss) : _nss(std::move(nss)) {} @@ -66,7 +66,8 @@ public: } ActionSet actions{ActionType::changeStream, ActionType::find}; - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final { if (_nss.isAdminDB() && _nss.isCollectionlessAggregateNS()) { // Watching a whole cluster. return {Privilege(ResourcePattern::forAnyNormalResource(), actions)}; diff --git a/src/mongo/db/pipeline/document_source_coll_stats.h b/src/mongo/db/pipeline/document_source_coll_stats.h index 6aa1b27192a..5c20fdbc2dc 100644 --- a/src/mongo/db/pipeline/document_source_coll_stats.h +++ b/src/mongo/db/pipeline/document_source_coll_stats.h @@ -43,9 +43,9 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec) { - return std::make_unique<LiteParsed>(request.getNamespaceString()); + return std::make_unique<LiteParsed>(nss); } explicit LiteParsed(NamespaceString nss) : _nss(std::move(nss)) {} @@ -54,7 +54,8 @@ public: return true; } - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final { return {Privilege(ResourcePattern::forExactNamespace(_nss), ActionType::collStats)}; } diff --git a/src/mongo/db/pipeline/document_source_current_op.cpp b/src/mongo/db/pipeline/document_source_current_op.cpp index 20f67ef9175..85ca3cf8835 100644 --- a/src/mongo/db/pipeline/document_source_current_op.cpp +++ b/src/mongo/db/pipeline/document_source_current_op.cpp @@ -59,7 +59,7 @@ REGISTER_DOCUMENT_SOURCE(currentOp, constexpr StringData DocumentSourceCurrentOp::kStageName; std::unique_ptr<DocumentSourceCurrentOp::LiteParsed> DocumentSourceCurrentOp::LiteParsed::parse( - const AggregationRequest& request, const BSONElement& spec) { + const NamespaceString& nss, const BSONElement& spec) { // Need to check the value of allUsers; if true then inprog privilege is required. if (spec.type() != BSONType::Object) { uasserted(ErrorCodes::TypeMismatch, diff --git a/src/mongo/db/pipeline/document_source_current_op.h b/src/mongo/db/pipeline/document_source_current_op.h index f2e6470f370..eebd9e639de 100644 --- a/src/mongo/db/pipeline/document_source_current_op.h +++ b/src/mongo/db/pipeline/document_source_current_op.h @@ -47,7 +47,7 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec); LiteParsed(UserMode allUsers, LocalOpsMode localOps) @@ -57,7 +57,8 @@ public: return stdx::unordered_set<NamespaceString>(); } - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final { PrivilegeVector privileges; // In a sharded cluster, we always need the inprog privilege to run $currentOp on the diff --git a/src/mongo/db/pipeline/document_source_facet.cpp b/src/mongo/db/pipeline/document_source_facet.cpp index fe0f40913a8..20187eba611 100644 --- a/src/mongo/db/pipeline/document_source_facet.cpp +++ b/src/mongo/db/pipeline/document_source_facet.cpp @@ -120,26 +120,28 @@ StageConstraints::LookupRequirement computeLookupRequirement( } // namespace std::unique_ptr<DocumentSourceFacet::LiteParsed> DocumentSourceFacet::LiteParsed::parse( - const AggregationRequest& request, const BSONElement& spec) { + const NamespaceString& nss, const BSONElement& spec) { std::vector<LiteParsedPipeline> liteParsedPipelines; for (auto&& rawPipeline : extractRawPipelines(spec)) { - liteParsedPipelines.emplace_back( - AggregationRequest(request.getNamespaceString(), rawPipeline.second)); + liteParsedPipelines.emplace_back(LiteParsedPipeline(nss, rawPipeline.second)); } - PrivilegeVector requiredPrivileges; - for (auto&& pipeline : liteParsedPipelines) { + return std::make_unique<DocumentSourceFacet::LiteParsed>(std::move(liteParsedPipelines)); +} - // A correct isMongos flag is only required for DocumentSourceCurrentOp which is disallowed - // in $facet pipelines. +PrivilegeVector DocumentSourceFacet::LiteParsed::requiredPrivileges( + bool isMongos, bool bypassDocumentValidation) const { + PrivilegeVector requiredPrivileges; + for (auto&& pipeline : _liteParsedPipelines) { + // A correct isMongos flag is only required for DocumentSourceCurrentOp which is + // disallowed in $facet pipelines. const bool unusedIsMongosFlag = false; - Privilege::addPrivilegesToPrivilegeVector(&requiredPrivileges, - pipeline.requiredPrivileges(unusedIsMongosFlag)); + Privilege::addPrivilegesToPrivilegeVector( + &requiredPrivileges, + pipeline.requiredPrivileges(unusedIsMongosFlag, bypassDocumentValidation)); } - - return std::make_unique<DocumentSourceFacet::LiteParsed>(std::move(liteParsedPipelines), - std::move(requiredPrivileges)); + return requiredPrivileges; } stdx::unordered_set<NamespaceString> DocumentSourceFacet::LiteParsed::getInvolvedNamespaces() diff --git a/src/mongo/db/pipeline/document_source_facet.h b/src/mongo/db/pipeline/document_source_facet.h index 4a6e0aecc5a..6c555ee8c4f 100644 --- a/src/mongo/db/pipeline/document_source_facet.h +++ b/src/mongo/db/pipeline/document_source_facet.h @@ -69,16 +69,14 @@ public: class LiteParsed : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec); - LiteParsed(std::vector<LiteParsedPipeline> liteParsedPipelines, PrivilegeVector privileges) - : _liteParsedPipelines(std::move(liteParsedPipelines)), - _requiredPrivileges(std::move(privileges)) {} + LiteParsed(std::vector<LiteParsedPipeline> liteParsedPipelines) + : _liteParsedPipelines(std::move(liteParsedPipelines)) {} - PrivilegeVector requiredPrivileges(bool isMongos) const final { - return _requiredPrivileges; - } + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final; stdx::unordered_set<NamespaceString> getInvolvedNamespaces() const final; @@ -95,7 +93,6 @@ public: private: const std::vector<LiteParsedPipeline> _liteParsedPipelines; - const PrivilegeVector _requiredPrivileges; }; static boost::intrusive_ptr<DocumentSource> createFromBson( diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp index 3c95d5cf3a6..57acba28dbe 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp @@ -50,8 +50,8 @@ using boost::intrusive_ptr; namespace dps = ::mongo::dotted_path_support; -std::unique_ptr<DocumentSourceGraphLookUp::LiteParsed> DocumentSourceGraphLookUp::liteParse( - const AggregationRequest& request, const BSONElement& spec) { +std::unique_ptr<DocumentSourceGraphLookUp::LiteParsed> DocumentSourceGraphLookUp::LiteParsed::parse( + const NamespaceString& nss, const BSONElement& spec) { uassert(ErrorCodes::FailedToParse, str::stream() << "the $graphLookup stage specification must be an object, but found " << typeName(spec.type()), @@ -68,19 +68,15 @@ std::unique_ptr<DocumentSourceGraphLookUp::LiteParsed> DocumentSourceGraphLookUp << typeName(specObj["from"].type()), fromElement.type() == BSONType::String); - NamespaceString nss(request.getNamespaceString().db(), fromElement.valueStringData()); + NamespaceString fromNss(nss.db(), fromElement.valueStringData()); uassert(ErrorCodes::InvalidNamespace, - str::stream() << "invalid $graphLookup namespace: " << nss.ns(), - nss.isValid()); - - PrivilegeVector privileges{ - Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find)}; - - return std::make_unique<LiteParsed>(std::move(nss), std::move(privileges)); + str::stream() << "invalid $graphLookup namespace: " << fromNss.ns(), + fromNss.isValid()); + return std::make_unique<LiteParsed>(std::move(fromNss)); } REGISTER_DOCUMENT_SOURCE(graphLookup, - DocumentSourceGraphLookUp::liteParse, + DocumentSourceGraphLookUp::LiteParsed::parse, DocumentSourceGraphLookUp::createFromBson); const char* DocumentSourceGraphLookUp::getSourceName() const { diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.h b/src/mongo/db/pipeline/document_source_graph_lookup.h index 77512232c36..85afcb9cf69 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup.h +++ b/src/mongo/db/pipeline/document_source_graph_lookup.h @@ -41,18 +41,23 @@ class DocumentSourceGraphLookUp final : public DocumentSource { public: static constexpr StringData kStageName = "$graphLookup"_sd; - class LiteParsed : public LiteParsedDocumentSourceForeignCollections { + class LiteParsed : public LiteParsedDocumentSourceForeignCollection { public: - LiteParsed(NamespaceString foreignNss, PrivilegeVector privileges) - : LiteParsedDocumentSourceForeignCollections(std::move(foreignNss), - std::move(privileges)) {} + LiteParsed(NamespaceString foreignNss) + : LiteParsedDocumentSourceForeignCollection(std::move(foreignNss)) {} + + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, + const BSONElement& spec); + bool allowShardedForeignCollection(NamespaceString nss) const override { - return (_foreignNssSet.find(nss) == _foreignNssSet.end()); + return _foreignNss != nss; + } + + PrivilegeVector requiredPrivileges(bool isMongos, bool bypassDocumentValidation) const { + return {Privilege(ResourcePattern::forExactNamespace(_foreignNss), ActionType::find)}; } }; - static std::unique_ptr<LiteParsed> liteParse(const AggregationRequest& request, - const BSONElement& spec); const char* getSourceName() const final; diff --git a/src/mongo/db/pipeline/document_source_index_stats.h b/src/mongo/db/pipeline/document_source_index_stats.h index d750f691e55..2d262232407 100644 --- a/src/mongo/db/pipeline/document_source_index_stats.h +++ b/src/mongo/db/pipeline/document_source_index_stats.h @@ -44,9 +44,9 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec) { - return std::make_unique<LiteParsed>(request.getNamespaceString()); + return std::make_unique<LiteParsed>(nss); } explicit LiteParsed(NamespaceString nss) : _nss(std::move(nss)) {} @@ -55,7 +55,8 @@ public: return stdx::unordered_set<NamespaceString>(); } - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final { return {Privilege(ResourcePattern::forExactNamespace(_nss), ActionType::indexStats)}; } diff --git a/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h b/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h index fabc4e0cfd7..f49b9859fb5 100644 --- a/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h +++ b/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h @@ -47,7 +47,7 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec) { return std::make_unique<LiteParsed>(); } @@ -56,7 +56,8 @@ public: return stdx::unordered_set<NamespaceString>(); } - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final { return {Privilege(ResourcePattern::forAnyNormalResource(), ActionType::listCachedAndActiveUsers)}; } diff --git a/src/mongo/db/pipeline/document_source_list_local_sessions.h b/src/mongo/db/pipeline/document_source_list_local_sessions.h index 0b1738b4f53..426ab739c20 100644 --- a/src/mongo/db/pipeline/document_source_list_local_sessions.h +++ b/src/mongo/db/pipeline/document_source_list_local_sessions.h @@ -56,7 +56,7 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec) { return std::make_unique<LiteParsed>( @@ -69,7 +69,8 @@ public: return stdx::unordered_set<NamespaceString>(); } - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final { return listSessionsRequiredPrivileges(_spec); } diff --git a/src/mongo/db/pipeline/document_source_list_sessions.h b/src/mongo/db/pipeline/document_source_list_sessions.h index 75e5bfd7fee..fa280ad09f7 100644 --- a/src/mongo/db/pipeline/document_source_list_sessions.h +++ b/src/mongo/db/pipeline/document_source_list_sessions.h @@ -51,7 +51,7 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec) { return std::make_unique<LiteParsed>( listSessionsParseSpec(DocumentSourceListSessions::kStageName, spec)); @@ -63,7 +63,8 @@ public: return stdx::unordered_set<NamespaceString>(); } - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final { return listSessionsRequiredPrivileges(_spec); } diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp index c30c3a9d6c7..e730f3fd64f 100644 --- a/src/mongo/db/pipeline/document_source_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_lookup.cpp @@ -117,7 +117,7 @@ DocumentSourceLookUp::DocumentSourceLookUp(NamespaceString fromNs, } std::unique_ptr<DocumentSourceLookUp::LiteParsed> DocumentSourceLookUp::LiteParsed::parse( - const AggregationRequest& request, const BSONElement& spec) { + const NamespaceString& nss, const BSONElement& spec) { uassert(ErrorCodes::FailedToParse, str::stream() << "the $lookup stage specification must be an object, but found " << typeName(spec.type()), @@ -133,7 +133,7 @@ std::unique_ptr<DocumentSourceLookUp::LiteParsed> DocumentSourceLookUp::LitePars << typeName(specObj["from"].type()), fromElement.type() == BSONType::String); - NamespaceString fromNss(request.getNamespaceString().db(), fromElement.valueStringData()); + NamespaceString fromNss(nss.db(), fromElement.valueStringData()); uassert(ErrorCodes::InvalidNamespace, str::stream() << "invalid $lookup namespace: " << fromNss.ns(), fromNss.isValid()); @@ -145,8 +145,7 @@ std::unique_ptr<DocumentSourceLookUp::LiteParsed> DocumentSourceLookUp::LitePars boost::optional<LiteParsedPipeline> liteParsedPipeline; if (pipelineElem) { auto pipeline = uassertStatusOK(AggregationRequest::parsePipelineFromBSON(pipelineElem)); - AggregationRequest foreignAggReq(fromNss, std::move(pipeline)); - liteParsedPipeline = LiteParsedPipeline(foreignAggReq); + liteParsedPipeline = LiteParsedPipeline(fromNss, pipeline); auto pipelineInvolvedNamespaces = liteParsedPipeline->getInvolvedNamespaces(); foreignNssSet.insert(pipelineInvolvedNamespaces.begin(), pipelineInvolvedNamespaces.end()); diff --git a/src/mongo/db/pipeline/document_source_lookup.h b/src/mongo/db/pipeline/document_source_lookup.h index 6e72a8d7f44..7f1bb5b0608 100644 --- a/src/mongo/db/pipeline/document_source_lookup.h +++ b/src/mongo/db/pipeline/document_source_lookup.h @@ -62,7 +62,7 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec); LiteParsed(NamespaceString fromNss, @@ -76,7 +76,8 @@ public: return {_foreignNssSet}; } - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final { PrivilegeVector requiredPrivileges; Privilege::addPrivilegeToPrivilegeVector( &requiredPrivileges, @@ -84,9 +85,9 @@ public: if (_liteParsedPipeline) { Privilege::addPrivilegesToPrivilegeVector( - &requiredPrivileges, _liteParsedPipeline->requiredPrivileges(isMongos)); + &requiredPrivileges, + _liteParsedPipeline->requiredPrivileges(isMongos, bypassDocumentValidation)); } - return requiredPrivileges; } diff --git a/src/mongo/db/pipeline/document_source_lookup_test.cpp b/src/mongo/db/pipeline/document_source_lookup_test.cpp index 23db8ee91ae..a0edbed00e9 100644 --- a/src/mongo/db/pipeline/document_source_lookup_test.cpp +++ b/src/mongo/db/pipeline/document_source_lookup_test.cpp @@ -206,10 +206,7 @@ TEST_F(DocumentSourceLookUpTest, LiteParsedDocumentSourceLookupContainsExpectedN NamespaceString nss("test.test"); std::vector<BSONObj> pipeline; - AggregationRequest aggRequest(nss, pipeline); - auto liteParsedLookup = - DocumentSourceLookUp::LiteParsed::parse(aggRequest, stageSpec.firstElement()); - + auto liteParsedLookup = DocumentSourceLookUp::LiteParsed::parse(nss, stageSpec.firstElement()); auto namespaceSet = liteParsedLookup->getInvolvedNamespaces(); ASSERT_EQ(1ul, namespaceSet.count(NamespaceString("test.namespace1"))); diff --git a/src/mongo/db/pipeline/document_source_merge.cpp b/src/mongo/db/pipeline/document_source_merge.cpp index 835d5546db4..bc3239eb726 100644 --- a/src/mongo/db/pipeline/document_source_merge.cpp +++ b/src/mongo/db/pipeline/document_source_merge.cpp @@ -286,14 +286,13 @@ DocumentSourceMergeSpec parseMergeSpecAndResolveTargetNamespace(const BSONElemen } // namespace std::unique_ptr<DocumentSourceMerge::LiteParsed> DocumentSourceMerge::LiteParsed::parse( - const AggregationRequest& request, const BSONElement& spec) { + const NamespaceString& nss, const BSONElement& spec) { uassert(ErrorCodes::TypeMismatch, "{} requires a string or object argument, but found {}"_format(kStageName, typeName(spec.type())), spec.type() == BSONType::String || spec.type() == BSONType::Object); - auto mergeSpec = - parseMergeSpecAndResolveTargetNamespace(spec, request.getNamespaceString().db()); + auto mergeSpec = parseMergeSpecAndResolveTargetNamespace(spec, nss.db()); auto targetNss = mergeSpec.getTargetNss(); uassert(ErrorCodes::InvalidNamespace, @@ -311,15 +310,18 @@ std::unique_ptr<DocumentSourceMerge::LiteParsed> DocumentSourceMerge::LiteParsed MergeWhenNotMatchedMode_serializer(whenNotMatched)), isSupportedMergeMode(whenMatched, whenNotMatched)); - auto actions = ActionSet{getDescriptors().at({whenMatched, whenNotMatched}).actions}; - if (request.shouldBypassDocumentValidation()) { + return std::make_unique<DocumentSourceMerge::LiteParsed>( + std::move(targetNss), whenMatched, whenNotMatched); +} + +PrivilegeVector DocumentSourceMerge::LiteParsed::requiredPrivileges( + bool isMongos, bool bypassDocumentValidation) const { + auto actions = ActionSet{getDescriptors().at({_whenMatched, _whenNotMatched}).actions}; + if (bypassDocumentValidation) { actions.addAction(ActionType::bypassDocumentValidation); } - PrivilegeVector privileges{{ResourcePattern::forExactNamespace(targetNss), actions}}; - - return std::make_unique<DocumentSourceMerge::LiteParsed>(std::move(targetNss), - std::move(privileges)); + return {{ResourcePattern::forExactNamespace(_foreignNss), actions}}; } DocumentSourceMerge::DocumentSourceMerge(NamespaceString outputNs, diff --git a/src/mongo/db/pipeline/document_source_merge.h b/src/mongo/db/pipeline/document_source_merge.h index 5135b414334..fb93585112c 100644 --- a/src/mongo/db/pipeline/document_source_merge.h +++ b/src/mongo/db/pipeline/document_source_merge.h @@ -68,12 +68,18 @@ public: * collection is unsharded. This ensures that the unique index verification happens once on * mongos and can be bypassed on the shards. */ - class LiteParsed final : public LiteParsedDocumentSourceForeignCollections { + class LiteParsed final : public LiteParsedDocumentSourceForeignCollection { public: - using LiteParsedDocumentSourceForeignCollections:: - LiteParsedDocumentSourceForeignCollections; + LiteParsed(NamespaceString foreignNss, + MergeWhenMatchedModeEnum whenMatched, + MergeWhenNotMatchedModeEnum whenNotMatched) + : LiteParsedDocumentSourceForeignCollection(std::move(foreignNss)), + _whenMatched(whenMatched), + _whenNotMatched(whenNotMatched) {} - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + using LiteParsedDocumentSourceForeignCollection::LiteParsedDocumentSourceForeignCollection; + + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec); bool allowedToPassthroughFromMongos() const final { @@ -87,6 +93,13 @@ public: "{} cannot be used with a 'linearizable' read concern level"_format(kStageName)}}, Status::OK()}; } + + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const final; + + private: + MergeWhenMatchedModeEnum _whenMatched; + MergeWhenNotMatchedModeEnum _whenNotMatched; }; virtual ~DocumentSourceMerge() = default; diff --git a/src/mongo/db/pipeline/document_source_out.cpp b/src/mongo/db/pipeline/document_source_out.cpp index 356c5b5d110..67df77f760c 100644 --- a/src/mongo/db/pipeline/document_source_out.cpp +++ b/src/mongo/db/pipeline/document_source_out.cpp @@ -77,7 +77,7 @@ DocumentSourceOut::~DocumentSourceOut() { } std::unique_ptr<DocumentSourceOut::LiteParsed> DocumentSourceOut::LiteParsed::parseToDifferentDB( - const AggregationRequest& request, const BSONElement& spec) { + const NamespaceString& nss, const BSONElement& spec) { auto specObj = spec.Obj(); auto dbElem = specObj["db"]; @@ -90,38 +90,22 @@ std::unique_ptr<DocumentSourceOut::LiteParsed> DocumentSourceOut::LiteParsed::pa "Invalid {} target namespace, {}"_format(kStageName, targetNss.ns()), targetNss.isValid()); - ActionSet actions{ActionType::insert, ActionType::remove}; - if (request.shouldBypassDocumentValidation()) { - actions.addAction(ActionType::bypassDocumentValidation); - } - - PrivilegeVector privileges{Privilege(ResourcePattern::forExactNamespace(targetNss), actions)}; - - return std::make_unique<DocumentSourceOut::LiteParsed>(std::move(targetNss), - std::move(privileges)); + return std::make_unique<DocumentSourceOut::LiteParsed>(std::move(targetNss)); } std::unique_ptr<DocumentSourceOut::LiteParsed> DocumentSourceOut::LiteParsed::parse( - const AggregationRequest& request, const BSONElement& spec) { + const NamespaceString& nss, const BSONElement& spec) { uassert(16990, "{} only supports a string argument, but found {}"_format(kStageName, typeName(spec.type())), spec.type() == BSONType::String); - NamespaceString targetNss{request.getNamespaceString().db(), spec.valueStringData()}; + NamespaceString targetNss{nss.db(), spec.valueStringData()}; uassert(ErrorCodes::InvalidNamespace, "Invalid {} target namespace, {}"_format(kStageName, targetNss.ns()), targetNss.isValid()); - ActionSet actions{ActionType::insert, ActionType::remove}; - if (request.shouldBypassDocumentValidation()) { - actions.addAction(ActionType::bypassDocumentValidation); - } - - PrivilegeVector privileges{Privilege(ResourcePattern::forExactNamespace(targetNss), actions)}; - - return std::make_unique<DocumentSourceOut::LiteParsed>(std::move(targetNss), - std::move(privileges)); + return std::make_unique<DocumentSourceOut::LiteParsed>(std::move(targetNss)); } void DocumentSourceOut::initialize() { diff --git a/src/mongo/db/pipeline/document_source_out.h b/src/mongo/db/pipeline/document_source_out.h index a633c8ff026..bfbd4ebd2fd 100644 --- a/src/mongo/db/pipeline/document_source_out.h +++ b/src/mongo/db/pipeline/document_source_out.h @@ -44,25 +44,33 @@ public: * A "lite parsed" $out stage is similar to other stages involving foreign collections except in * some cases the foreign collection is allowed to be sharded. */ - class LiteParsed final : public LiteParsedDocumentSourceForeignCollections { + class LiteParsed final : public LiteParsedDocumentSourceForeignCollection { public: - using LiteParsedDocumentSourceForeignCollections:: - LiteParsedDocumentSourceForeignCollections; + using LiteParsedDocumentSourceForeignCollection::LiteParsedDocumentSourceForeignCollection; - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec); - static std::unique_ptr<LiteParsed> parseToDifferentDB(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parseToDifferentDB(const NamespaceString& nss, const BSONElement& spec); bool allowShardedForeignCollection(NamespaceString nss) const final { - return _foreignNssSet.find(nss) == _foreignNssSet.end(); + return _foreignNss != nss; } bool allowedToPassthroughFromMongos() const final { return false; } + PrivilegeVector requiredPrivileges(bool isMongos, bool bypassDocumentValidation) const { + ActionSet actions{ActionType::insert, ActionType::remove}; + if (bypassDocumentValidation) { + actions.addAction(ActionType::bypassDocumentValidation); + } + + return {Privilege(ResourcePattern::forExactNamespace(_foreignNss), actions)}; + } + ReadConcernSupportResult supportsReadConcern(repl::ReadConcernLevel level) const final { return { {level == repl::ReadConcernLevel::kLinearizableReadConcern, diff --git a/src/mongo/db/pipeline/document_source_plan_cache_stats.h b/src/mongo/db/pipeline/document_source_plan_cache_stats.h index 0e08a79348a..f091a24f1b3 100644 --- a/src/mongo/db/pipeline/document_source_plan_cache_stats.h +++ b/src/mongo/db/pipeline/document_source_plan_cache_stats.h @@ -40,9 +40,9 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec) { - return std::make_unique<LiteParsed>(request.getNamespaceString()); + return std::make_unique<LiteParsed>(nss); } explicit LiteParsed(NamespaceString nss) : _nss(std::move(nss)) {} @@ -52,7 +52,8 @@ public: return stdx::unordered_set<NamespaceString>(); } - PrivilegeVector requiredPrivileges(bool isMongos) const override { + PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const override { return {Privilege(ResourcePattern::forExactNamespace(_nss), ActionType::planCacheRead)}; } diff --git a/src/mongo/db/pipeline/document_source_union_with.cpp b/src/mongo/db/pipeline/document_source_union_with.cpp index 9413b8d3da6..f1b2532f771 100644 --- a/src/mongo/db/pipeline/document_source_union_with.cpp +++ b/src/mongo/db/pipeline/document_source_union_with.cpp @@ -38,7 +38,7 @@ REGISTER_TEST_DOCUMENT_SOURCE(unionWith, DocumentSourceUnionWith::createFromBson); std::unique_ptr<DocumentSourceUnionWith::LiteParsed> DocumentSourceUnionWith::LiteParsed::parse( - const AggregationRequest& request, const BSONElement& spec) { + const NamespaceString& nss, const BSONElement& spec) { uassert(ErrorCodes::FailedToParse, str::stream() << "the $unionWith stage specification must be an object or string, but found " @@ -49,16 +49,15 @@ std::unique_ptr<DocumentSourceUnionWith::LiteParsed> DocumentSourceUnionWith::Li stdx::unordered_set<NamespaceString> foreignNssSet; boost::optional<LiteParsedPipeline> liteParsedPipeline; if (spec.type() == BSONType::String) { - unionNss = NamespaceString(request.getNamespaceString().db(), spec.valueStringData()); + unionNss = NamespaceString(nss.db(), spec.valueStringData()); } else { auto unionWithSpec = UnionWithSpec::parse(IDLParserErrorContext(kStageName), spec.embeddedObject()); - unionNss = NamespaceString(request.getNamespaceString().db(), unionWithSpec.getColl()); + unionNss = NamespaceString(nss.db(), unionWithSpec.getColl()); // Recursively lite parse the nested pipeline, if one exists. if (unionWithSpec.getPipeline()) { - AggregationRequest foreignAggReq(unionNss, std::move(*unionWithSpec.getPipeline())); - liteParsedPipeline = LiteParsedPipeline(foreignAggReq); + liteParsedPipeline = LiteParsedPipeline(unionNss, *unionWithSpec.getPipeline()); foreignNssSet.merge(liteParsedPipeline->getInvolvedNamespaces()); } } diff --git a/src/mongo/db/pipeline/document_source_union_with.h b/src/mongo/db/pipeline/document_source_union_with.h index 7181a7d2ab7..52469a12ee3 100644 --- a/src/mongo/db/pipeline/document_source_union_with.h +++ b/src/mongo/db/pipeline/document_source_union_with.h @@ -45,7 +45,7 @@ public: class LiteParsed final : public LiteParsedDocumentSource { public: - static std::unique_ptr<LiteParsed> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss, const BSONElement& spec); LiteParsed(NamespaceString withNss, @@ -59,7 +59,7 @@ public: return {_foreignNssSet}; } - PrivilegeVector requiredPrivileges(bool) const final { + PrivilegeVector requiredPrivileges(bool, bool) const final { return {}; } diff --git a/src/mongo/db/pipeline/lite_parsed_document_source.cpp b/src/mongo/db/pipeline/lite_parsed_document_source.cpp index 28b5b133a65..06bec164f3d 100644 --- a/src/mongo/db/pipeline/lite_parsed_document_source.cpp +++ b/src/mongo/db/pipeline/lite_parsed_document_source.cpp @@ -46,7 +46,7 @@ void LiteParsedDocumentSource::registerParser(const std::string& name, Parser pa } std::unique_ptr<LiteParsedDocumentSource> LiteParsedDocumentSource::parse( - const AggregationRequest& request, const BSONObj& spec) { + const NamespaceString& nss, const BSONObj& spec) { uassert(40323, "A pipeline stage specification object must contain exactly one field.", spec.nFields() == 1); @@ -59,6 +59,6 @@ std::unique_ptr<LiteParsedDocumentSource> LiteParsedDocumentSource::parse( str::stream() << "Unrecognized pipeline stage name: '" << stageName << "'", it != parserMap.end()); - return it->second(request, specElem); + return it->second(nss, specElem); } } // namespace mongo diff --git a/src/mongo/db/pipeline/lite_parsed_document_source.h b/src/mongo/db/pipeline/lite_parsed_document_source.h index 82d9ce1b7f7..fd8ff192da9 100644 --- a/src/mongo/db/pipeline/lite_parsed_document_source.h +++ b/src/mongo/db/pipeline/lite_parsed_document_source.h @@ -36,7 +36,6 @@ #include "mongo/db/auth/privilege.h" #include "mongo/db/namespace_string.h" -#include "mongo/db/pipeline/aggregation_request.h" #include "mongo/db/read_concern_support_result.h" #include "mongo/db/repl/read_concern_args.h" #include "mongo/stdx/unordered_set.h" @@ -57,12 +56,12 @@ public: * This is the type of parser you should register using REGISTER_DOCUMENT_SOURCE. It need not * do any validation of options, only enough parsing to be able to implement the interface. * - * The AggregationRequest can be used to determine related information like the namespace on - * which this aggregation is being performed, and the BSONElement will be the element whose - * field name is the name of this stage (e.g. the first and only element in {$limit: 1}). + * The NamespaceString can be used to determine the namespace on which this aggregation is being + * performed, and the BSONElement will be the element whose field name is the name of this stage + * (e.g. the first and only element in {$limit: 1}). */ - using Parser = std::function<std::unique_ptr<LiteParsedDocumentSource>( - const AggregationRequest&, const BSONElement&)>; + using Parser = std::function<std::unique_ptr<LiteParsedDocumentSource>(const NamespaceString&, + const BSONElement&)>; /** * Registers a DocumentSource with a spec parsing function, so that when a stage with the given @@ -80,7 +79,7 @@ public: * Extracts the first field name from 'spec', and delegates to the parser that was registered * with that field name using registerParser() above. */ - static std::unique_ptr<LiteParsedDocumentSource> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsedDocumentSource> parse(const NamespaceString& nss, const BSONObj& spec); /** @@ -91,7 +90,8 @@ public: /** * Returns a list of the privileges required for this stage. */ - virtual PrivilegeVector requiredPrivileges(bool isMongos) const = 0; + virtual PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const = 0; /** * Returns true if this is a $collStats stage. @@ -182,7 +182,7 @@ public: * your stage doesn't need to communicate any special behavior before registering a * DocumentSource using this parser. */ - static std::unique_ptr<LiteParsedDocumentSourceDefault> parse(const AggregationRequest& request, + static std::unique_ptr<LiteParsedDocumentSourceDefault> parse(const NamespaceString& nss, const BSONElement& spec) { return std::make_unique<LiteParsedDocumentSourceDefault>(); } @@ -193,36 +193,27 @@ public: return stdx::unordered_set<NamespaceString>(); } - PrivilegeVector requiredPrivileges(bool isMongos) const final { + PrivilegeVector requiredPrivileges(bool isMongos, bool bypassDocumentValidation) const final { return {}; } }; /** - * Helper class for DocumentSources which reference one or more foreign collections. + * Helper class for DocumentSources which reference a foreign collection. */ -class LiteParsedDocumentSourceForeignCollections : public LiteParsedDocumentSource { +class LiteParsedDocumentSourceForeignCollection : public LiteParsedDocumentSource { public: - LiteParsedDocumentSourceForeignCollections(NamespaceString foreignNss, - PrivilegeVector privileges) - : _foreignNssSet{std::move(foreignNss)}, _requiredPrivileges(std::move(privileges)) {} - - LiteParsedDocumentSourceForeignCollections(stdx::unordered_set<NamespaceString> foreignNssSet, - PrivilegeVector privileges) - : _foreignNssSet(std::move(foreignNssSet)), _requiredPrivileges(std::move(privileges)) {} + LiteParsedDocumentSourceForeignCollection(NamespaceString foreignNss) + : _foreignNss(std::move(foreignNss)) {} stdx::unordered_set<NamespaceString> getInvolvedNamespaces() const final { - return {_foreignNssSet}; + return {_foreignNss}; } - PrivilegeVector requiredPrivileges(bool isMongos) const final { - return _requiredPrivileges; - } + virtual PrivilegeVector requiredPrivileges(bool isMongos, + bool bypassDocumentValidation) const = 0; protected: - stdx::unordered_set<NamespaceString> _foreignNssSet; - -private: - PrivilegeVector _requiredPrivileges; + NamespaceString _foreignNss; }; } // namespace mongo diff --git a/src/mongo/db/pipeline/lite_parsed_pipeline.h b/src/mongo/db/pipeline/lite_parsed_pipeline.h index 91404d25cbf..0c54e7a3d1e 100644 --- a/src/mongo/db/pipeline/lite_parsed_pipeline.h +++ b/src/mongo/db/pipeline/lite_parsed_pipeline.h @@ -53,11 +53,13 @@ public: * May throw a AssertionException if there is an invalid stage specification, although full * validation happens later, during Pipeline construction. */ - LiteParsedPipeline(const AggregationRequest& request) { - _stageSpecs.reserve(request.getPipeline().size()); + LiteParsedPipeline(const AggregationRequest& request) + : LiteParsedPipeline(request.getNamespaceString(), request.getPipeline()) {} - for (auto&& rawStage : request.getPipeline()) { - _stageSpecs.push_back(LiteParsedDocumentSource::parse(request, rawStage)); + LiteParsedPipeline(const NamespaceString& nss, const std::vector<BSONObj>& pipelineStages) { + _stageSpecs.reserve(pipelineStages.size()); + for (auto&& rawStage : pipelineStages) { + _stageSpecs.push_back(LiteParsedDocumentSource::parse(nss, rawStage)); } } @@ -77,11 +79,11 @@ public: /** * Returns a list of the priviliges required for this pipeline. */ - PrivilegeVector requiredPrivileges(bool isMongos) const { + PrivilegeVector requiredPrivileges(bool isMongos, bool bypassDocumentValidation) const { PrivilegeVector requiredPrivileges; for (auto&& spec : _stageSpecs) { - Privilege::addPrivilegesToPrivilegeVector(&requiredPrivileges, - spec->requiredPrivileges(isMongos)); + Privilege::addPrivilegesToPrivilegeVector( + &requiredPrivileges, spec->requiredPrivileges(isMongos, bypassDocumentValidation)); } return requiredPrivileges; diff --git a/src/mongo/db/update/pipeline_executor.cpp b/src/mongo/db/update/pipeline_executor.cpp index 542734e8a39..219f1ab6453 100644 --- a/src/mongo/db/update/pipeline_executor.cpp +++ b/src/mongo/db/update/pipeline_executor.cpp @@ -50,8 +50,7 @@ PipelineExecutor::PipelineExecutor(const boost::intrusive_ptr<ExpressionContext> // "Resolve" involved namespaces into a map. We have to populate this map so that any // $lookups, etc. will not fail instantiation. They will not be used for execution as these // stages are not allowed within an update context. - AggregationRequest aggRequest(NamespaceString("dummy.namespace"), pipeline); - LiteParsedPipeline liteParsedPipeline(aggRequest); + LiteParsedPipeline liteParsedPipeline(NamespaceString("dummy.namespace"), pipeline); StringMap<ExpressionContext::ResolvedNamespace> resolvedNamespaces; for (auto&& nss : liteParsedPipeline.getInvolvedNamespaces()) { resolvedNamespaces.try_emplace(nss.coll(), nss, std::vector<BSONObj>{}); diff --git a/src/mongo/db/views/view_catalog.cpp b/src/mongo/db/views/view_catalog.cpp index 5fce7a5119f..b09c3c00073 100644 --- a/src/mongo/db/views/view_catalog.cpp +++ b/src/mongo/db/views/view_catalog.cpp @@ -299,8 +299,7 @@ Status ViewCatalog::_upsertIntoGraph(WithLock lk, StatusWith<stdx::unordered_set<NamespaceString>> ViewCatalog::_validatePipeline( WithLock lk, OperationContext* opCtx, const ViewDefinition& viewDef) const { - AggregationRequest request(viewDef.viewOn(), viewDef.pipeline()); - const LiteParsedPipeline liteParsedPipeline(request); + const LiteParsedPipeline liteParsedPipeline(viewDef.viewOn(), viewDef.pipeline()); const auto involvedNamespaces = liteParsedPipeline.getInvolvedNamespaces(); // Verify that this is a legitimate pipeline specification by making sure it parses @@ -313,7 +312,7 @@ StatusWith<stdx::unordered_set<NamespaceString>> ViewCatalog::_validatePipeline( } boost::intrusive_ptr<ExpressionContext> expCtx = new ExpressionContext(opCtx, - request, + AggregationRequest(viewDef.viewOn(), viewDef.pipeline()), CollatorInterface::cloneCollator(viewDef.defaultCollator()), // We can use a stub MongoProcessInterface because we are only parsing // the Pipeline for validation here. We won't do anything with the @@ -507,7 +506,6 @@ std::shared_ptr<ViewDefinition> ViewCatalog::_lookup(WithLock lk, OperationContext* opCtx, StringData ns, ViewCatalogLookupBehavior lookupBehavior) { - ViewMap::const_iterator it = _viewMap.find(ns); if (it != _viewMap.end()) { return it->second; |