/** * Copyright (c) 2011 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #pragma once #include #include #include #include #include #include "mongo/bson/bsonobj.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" #include "mongo/db/pipeline/aggregation_request.h" #include "mongo/db/pipeline/document_comparator.h" #include "mongo/db/pipeline/mongo_process_interface.h" #include "mongo/db/pipeline/value_comparator.h" #include "mongo/db/pipeline/variables.h" #include "mongo/db/query/collation/collator_interface.h" #include "mongo/db/query/datetime/date_time_support.h" #include "mongo/db/query/explain_options.h" #include "mongo/db/query/tailable_mode.h" #include "mongo/util/intrusive_counter.h" #include "mongo/util/string_map.h" #include "mongo/util/uuid.h" namespace mongo { class ExpressionContext : public RefCountable { public: struct ResolvedNamespace { ResolvedNamespace() = default; ResolvedNamespace(NamespaceString ns, std::vector pipeline); NamespaceString ns; std::vector pipeline; }; /** * An RAII type that will temporarily change the ExpressionContext's collator. Resets the * collator to the previous value upon destruction. */ class CollatorStash { public: /** * Resets the collator on '_expCtx' to the original collator present at the time this * CollatorStash was constructed. */ ~CollatorStash(); private: /** * Temporarily changes the collator on 'expCtx' to be 'newCollator'. The collator will be * set back to the original value when this CollatorStash is deleted. * * This constructor is private, all CollatorStashes should be created by calling * ExpressionContext::temporarilyChangeCollator(). */ CollatorStash(const boost::intrusive_ptr& expCtx, std::unique_ptr newCollator); friend class ExpressionContext; boost::intrusive_ptr _expCtx; BSONObj _originalCollation; std::unique_ptr _originalCollatorOwned; const CollatorInterface* _originalCollatorUnowned{nullptr}; }; /** * Constructs an ExpressionContext to be used for Pipeline parsing and evaluation. * 'resolvedNamespaces' maps collection names (not full namespaces) to ResolvedNamespaces. */ ExpressionContext(OperationContext* opCtx, const AggregationRequest& request, std::unique_ptr collator, std::shared_ptr mongoProcessInterface, StringMap resolvedNamespaces); /** * Constructs an ExpressionContext to be used for MatchExpression parsing outside of the context * of aggregation. */ ExpressionContext(OperationContext* opCtx, const CollatorInterface* collator); /** * Used by a pipeline to check for interrupts so that killOp() works. Throws a UserAssertion if * this aggregation pipeline has been interrupted. */ void checkForInterrupt(); /** * Returns true if this is a collectionless aggregation on the specified database. */ bool isDBAggregation(StringData dbName) const { return ns.db() == dbName && ns.isCollectionlessAggregateNS(); } /** * Returns true if this is a collectionless aggregation on the 'admin' database. */ bool isClusterAggregation() const { return ns.isAdminDB() && ns.isCollectionlessAggregateNS(); } /** * Returns true if this aggregation is running on a single, specific namespace. */ bool isSingleNamespaceAggregation() const { return !ns.isCollectionlessAggregateNS(); } const CollatorInterface* getCollator() const { return _collator; } void setCollator(const CollatorInterface* collator); const DocumentComparator& getDocumentComparator() const { return _documentComparator; } const ValueComparator& getValueComparator() const { return _valueComparator; } /** * Temporarily resets the collator to be 'newCollator'. Returns a CollatorStash which will reset * the collator back to the old value upon destruction. */ std::unique_ptr temporarilyChangeCollator( std::unique_ptr newCollator); /** * Returns an ExpressionContext that is identical to 'this' that can be used to execute a * separate aggregation pipeline on 'ns' with the optional 'uuid'. */ boost::intrusive_ptr copyWith( NamespaceString ns, boost::optional uuid = boost::none, boost::optional> collator = boost::none) const; /** * Returns the ResolvedNamespace corresponding to 'nss'. It is an error to call this method on a * namespace not involved in the pipeline. */ const ResolvedNamespace& getResolvedNamespace(const NamespaceString& nss) const { auto it = _resolvedNamespaces.find(nss.coll()); invariant(it != _resolvedNamespaces.end()); return it->second; }; /** * Convenience call that returns true if the tailableMode indicates a tailable and awaitData * query. */ bool isTailableAwaitData() const { return tailableMode == TailableModeEnum::kTailableAndAwaitData; } // The explain verbosity requested by the user, or boost::none if no explain was requested. boost::optional explain; // The comment provided by the user, or the empty string if no comment was provided. std::string comment; bool fromMongos = false; bool needsMerge = false; bool inMongos = false; bool allowDiskUse = false; bool bypassDocumentValidation = false; bool inSnapshotReadOrMultiDocumentTransaction = false; NamespaceString ns; boost::optional uuid; std::string tempDir; // Defaults to empty to prevent external sorting in mongos. OperationContext* opCtx; // An interface for accessing information or performing operations that have different // implementations on mongod and mongos, or that only make sense on one of the two. // Additionally, putting some of this functionality behind an interface prevents aggregation // libraries from having large numbers of dependencies. This pointer is always non-null. std::shared_ptr mongoProcessInterface; const TimeZoneDatabase* timeZoneDatabase; // Collation requested by the user for this pipeline. Empty if the user did not request a // collation. BSONObj collation; Variables variables; VariablesParseState variablesParseState; TailableModeEnum tailableMode = TailableModeEnum::kNormal; // Tracks the depth of nested aggregation sub-pipelines. Used to enforce depth limits. size_t subPipelineDepth = 0; // If set, this will disallow use of features introduced in versions above the provided version. boost::optional maxFeatureCompatibilityVersion; protected: static const int kInterruptCheckPeriod = 128; ExpressionContext(NamespaceString nss, std::shared_ptr, const TimeZoneDatabase* tzDb); /** * Sets '_ownedCollator' and resets '_collator', 'documentComparator' and 'valueComparator'. * * Use with caution - '_ownedCollator' is used in the context of a Pipeline, and it is illegal * to change the collation once a Pipeline has been parsed with this ExpressionContext. */ void setCollator(std::unique_ptr collator) { _ownedCollator = std::move(collator); setCollator(_ownedCollator.get()); } friend class CollatorStash; // Collator used for comparisons. This is owned in the context of a Pipeline. // TODO SERVER-31294: Move ownership of an aggregation's collator elsewhere. std::unique_ptr _ownedCollator; // Collator used for comparisons. If '_ownedCollator' is non-null, then this must point to the // same collator object. const CollatorInterface* _collator = nullptr; // Used for all comparisons of Document/Value during execution of the aggregation operation. // Must not be changed after parsing a Pipeline with this ExpressionContext. DocumentComparator _documentComparator; ValueComparator _valueComparator; // A map from namespace to the resolved namespace, in case any views are involved. StringMap _resolvedNamespaces; int _interruptCounter = kInterruptCheckPeriod; }; } // namespace mongo