//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGOD_AQL_MODIFICATION_NODES_H #define ARANGOD_AQL_MODIFICATION_NODES_H 1 #include "Basics/Common.h" #include "Aql/Ast.h" #include "Aql/ExecutionNode.h" #include "Aql/ModificationOptions.h" #include "Aql/types.h" #include "Aql/Variable.h" #include "Basics/JsonHelper.h" #include "VocBase/voc-types.h" #include "VocBase/vocbase.h" namespace arangodb { namespace aql { struct Collection; class ExecutionBlock; class ExecutionPlan; //////////////////////////////////////////////////////////////////////////////// /// @brief abstract base class for modification operations //////////////////////////////////////////////////////////////////////////////// class ModificationNode : public ExecutionNode { friend class ExecutionBlock; friend class ModificationBlock; ////////////////////////////////////////////////////////////////////////////// /// @brief constructor with a vocbase and a collection and options ////////////////////////////////////////////////////////////////////////////// protected: ModificationNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase, Collection* collection, ModificationOptions const& options, Variable const* outVariableOld, Variable const* outVariableNew) : ExecutionNode(plan, id), _vocbase(vocbase), _collection(collection), _options(options), _outVariableOld(outVariableOld), _outVariableNew(outVariableNew) { TRI_ASSERT(_vocbase != nullptr); TRI_ASSERT(_collection != nullptr); } ModificationNode(ExecutionPlan*, arangodb::basics::Json const& json); ////////////////////////////////////////////////////////////////////////////// /// @brief export to VelocyPack ////////////////////////////////////////////////////////////////////////////// virtual void toVelocyPackHelper(arangodb::velocypack::Builder&, bool) const override; public: ////////////////////////////////////////////////////////////////////////////// /// @brief return the database ////////////////////////////////////////////////////////////////////////////// TRI_vocbase_t* vocbase() const { return _vocbase; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the collection ////////////////////////////////////////////////////////////////////////////// Collection const* collection() const { return _collection; } ////////////////////////////////////////////////////////////////////////////// /// @brief estimateCost /// Note that all the modifying nodes use this estimateCost method which is /// why we can make it final here. ////////////////////////////////////////////////////////////////////////////// double estimateCost(size_t&) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief getOptions ////////////////////////////////////////////////////////////////////////////// ModificationOptions const& getOptions() const { return _options; } ////////////////////////////////////////////////////////////////////////////// /// @brief getOptions ////////////////////////////////////////////////////////////////////////////// ModificationOptions& getOptions() { return _options; } ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesSetHere ////////////////////////////////////////////////////////////////////////////// std::vector getVariablesSetHere() const override final { std::vector v; if (_outVariableOld != nullptr) { v.emplace_back(_outVariableOld); } if (_outVariableNew != nullptr) { v.emplace_back(_outVariableNew); } return v; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the "$OLD" out variable ////////////////////////////////////////////////////////////////////////////// Variable const* getOutVariableOld() const { return _outVariableOld; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the "$NEW" out variable ////////////////////////////////////////////////////////////////////////////// Variable const* getOutVariableNew() const { return _outVariableNew; } ////////////////////////////////////////////////////////////////////////////// /// @brief clear the "$OLD" out variable ////////////////////////////////////////////////////////////////////////////// void clearOutVariableOld() { _outVariableOld = nullptr; } ////////////////////////////////////////////////////////////////////////////// /// @brief clear the "$NEW" out variable ////////////////////////////////////////////////////////////////////////////// void clearOutVariableNew() { _outVariableNew = nullptr; } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the node is a data modification node ////////////////////////////////////////////////////////////////////////////// bool isModificationNode() const override { return true; } protected: ////////////////////////////////////////////////////////////////////////////// /// @brief _vocbase, the database ////////////////////////////////////////////////////////////////////////////// TRI_vocbase_t* _vocbase; ////////////////////////////////////////////////////////////////////////////// /// @brief collection ////////////////////////////////////////////////////////////////////////////// Collection* _collection; ////////////////////////////////////////////////////////////////////////////// /// @brief modification operation options ////////////////////////////////////////////////////////////////////////////// ModificationOptions _options; ////////////////////////////////////////////////////////////////////////////// /// @brief output variable ($OLD) ////////////////////////////////////////////////////////////////////////////// Variable const* _outVariableOld; ////////////////////////////////////////////////////////////////////////////// /// @brief output variable ($NEW) ////////////////////////////////////////////////////////////////////////////// Variable const* _outVariableNew; }; //////////////////////////////////////////////////////////////////////////////// /// @brief class RemoveNode //////////////////////////////////////////////////////////////////////////////// class RemoveNode : public ModificationNode { friend class ExecutionNode; friend class ExecutionBlock; friend class RemoveBlock; public: RemoveNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase, Collection* collection, ModificationOptions const& options, Variable const* inVariable, Variable const* outVariableOld) : ModificationNode(plan, id, vocbase, collection, options, outVariableOld, nullptr), _inVariable(inVariable) { TRI_ASSERT(_inVariable != nullptr); } RemoveNode(ExecutionPlan*, arangodb::basics::Json const& base); ////////////////////////////////////////////////////////////////////////////// /// @brief return the type of the node ////////////////////////////////////////////////////////////////////////////// NodeType getType() const override final { return REMOVE; } ////////////////////////////////////////////////////////////////////////////// /// @brief export to VelocyPack ////////////////////////////////////////////////////////////////////////////// void toVelocyPackHelper(arangodb::velocypack::Builder&, bool) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief clone ExecutionNode recursively ////////////////////////////////////////////////////////////////////////////// ExecutionNode* clone(ExecutionPlan* plan, bool withDependencies, bool withProperties) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, returning a vector ////////////////////////////////////////////////////////////////////////////// std::vector getVariablesUsedHere() const override final { return std::vector{_inVariable}; } ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, modifying the set in-place ////////////////////////////////////////////////////////////////////////////// void getVariablesUsedHere( std::unordered_set& vars) const override final { vars.emplace(_inVariable); } private: ////////////////////////////////////////////////////////////////////////////// /// @brief input variable ////////////////////////////////////////////////////////////////////////////// Variable const* _inVariable; }; //////////////////////////////////////////////////////////////////////////////// /// @brief class InsertNode //////////////////////////////////////////////////////////////////////////////// class InsertNode : public ModificationNode { friend class ExecutionNode; friend class ExecutionBlock; friend class InsertBlock; public: InsertNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase, Collection* collection, ModificationOptions const& options, Variable const* inVariable, Variable const* outVariableNew) : ModificationNode(plan, id, vocbase, collection, options, nullptr, outVariableNew), _inVariable(inVariable) { TRI_ASSERT(_inVariable != nullptr); // _outVariable might be a nullptr } InsertNode(ExecutionPlan*, arangodb::basics::Json const& base); ////////////////////////////////////////////////////////////////////////////// /// @brief return the type of the node ////////////////////////////////////////////////////////////////////////////// NodeType getType() const override final { return INSERT; } ////////////////////////////////////////////////////////////////////////////// /// @brief export to VelocyPack ////////////////////////////////////////////////////////////////////////////// void toVelocyPackHelper(arangodb::velocypack::Builder&, bool) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief clone ExecutionNode recursively ////////////////////////////////////////////////////////////////////////////// ExecutionNode* clone(ExecutionPlan* plan, bool withDependencies, bool withProperties) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, returning a vector ////////////////////////////////////////////////////////////////////////////// std::vector getVariablesUsedHere() const override final { return std::vector{_inVariable}; } ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, modifying the set in-place ////////////////////////////////////////////////////////////////////////////// void getVariablesUsedHere( std::unordered_set& vars) const override final { vars.emplace(_inVariable); } private: ////////////////////////////////////////////////////////////////////////////// /// @brief input variable ////////////////////////////////////////////////////////////////////////////// Variable const* _inVariable; }; //////////////////////////////////////////////////////////////////////////////// /// @brief class UpdateNode //////////////////////////////////////////////////////////////////////////////// class UpdateNode : public ModificationNode { friend class ExecutionNode; friend class ExecutionBlock; friend class UpdateBlock; ////////////////////////////////////////////////////////////////////////////// /// @brief constructor with a vocbase and a collection name ////////////////////////////////////////////////////////////////////////////// public: UpdateNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase, Collection* collection, ModificationOptions const& options, Variable const* inDocVariable, Variable const* inKeyVariable, Variable const* outVariableOld, Variable const* outVariableNew) : ModificationNode(plan, id, vocbase, collection, options, outVariableOld, outVariableNew), _inDocVariable(inDocVariable), _inKeyVariable(inKeyVariable) { TRI_ASSERT(_inDocVariable != nullptr); // _inKeyVariable might be a nullptr } UpdateNode(ExecutionPlan*, arangodb::basics::Json const& base); ////////////////////////////////////////////////////////////////////////////// /// @brief return the type of the node ////////////////////////////////////////////////////////////////////////////// NodeType getType() const override final { return UPDATE; } ////////////////////////////////////////////////////////////////////////////// /// @brief export to VelocyPack ////////////////////////////////////////////////////////////////////////////// void toVelocyPackHelper(arangodb::velocypack::Builder&, bool) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief clone ExecutionNode recursively ////////////////////////////////////////////////////////////////////////////// ExecutionNode* clone(ExecutionPlan* plan, bool withDependencies, bool withProperties) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, returning a vector ////////////////////////////////////////////////////////////////////////////// std::vector getVariablesUsedHere() const override final { // Please do not change the order here without adjusting the // optimizer rule distributeInCluster as well! std::vector v{_inDocVariable}; if (_inKeyVariable != nullptr) { v.emplace_back(_inKeyVariable); } return v; } ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, modifying the set in-place ////////////////////////////////////////////////////////////////////////////// void getVariablesUsedHere( std::unordered_set& vars) const override final { vars.emplace(_inDocVariable); if (_inKeyVariable != nullptr) { vars.emplace(_inKeyVariable); } } private: ////////////////////////////////////////////////////////////////////////////// /// @brief input variable for documents ////////////////////////////////////////////////////////////////////////////// Variable const* _inDocVariable; ////////////////////////////////////////////////////////////////////////////// /// @brief input variable for keys ////////////////////////////////////////////////////////////////////////////// Variable const* _inKeyVariable; }; //////////////////////////////////////////////////////////////////////////////// /// @brief class ReplaceNode //////////////////////////////////////////////////////////////////////////////// class ReplaceNode : public ModificationNode { friend class ExecutionNode; friend class ExecutionBlock; friend class ReplaceBlock; ////////////////////////////////////////////////////////////////////////////// /// @brief constructor with a vocbase and a collection name ////////////////////////////////////////////////////////////////////////////// public: ReplaceNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase, Collection* collection, ModificationOptions const& options, Variable const* inDocVariable, Variable const* inKeyVariable, Variable const* outVariableOld, Variable const* outVariableNew) : ModificationNode(plan, id, vocbase, collection, options, outVariableOld, outVariableNew), _inDocVariable(inDocVariable), _inKeyVariable(inKeyVariable) { TRI_ASSERT(_inDocVariable != nullptr); // _inKeyVariable might be a nullptr } ReplaceNode(ExecutionPlan*, arangodb::basics::Json const& base); ////////////////////////////////////////////////////////////////////////////// /// @brief return the type of the node ////////////////////////////////////////////////////////////////////////////// NodeType getType() const override final { return REPLACE; } ////////////////////////////////////////////////////////////////////////////// /// @brief export to VelocyPack ////////////////////////////////////////////////////////////////////////////// void toVelocyPackHelper(arangodb::velocypack::Builder&, bool) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief clone ExecutionNode recursively ////////////////////////////////////////////////////////////////////////////// ExecutionNode* clone(ExecutionPlan* plan, bool withDependencies, bool withProperties) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, returning a vector ////////////////////////////////////////////////////////////////////////////// std::vector getVariablesUsedHere() const override final { // Please do not change the order here without adjusting the // optimizer rule distributeInCluster as well! std::vector v{_inDocVariable}; if (_inKeyVariable != nullptr) { v.emplace_back(_inKeyVariable); } return v; } ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, modifying the set in-place ////////////////////////////////////////////////////////////////////////////// void getVariablesUsedHere( std::unordered_set& vars) const override final { vars.emplace(_inDocVariable); if (_inKeyVariable != nullptr) { vars.emplace(_inKeyVariable); } } private: ////////////////////////////////////////////////////////////////////////////// /// @brief input variable for documents ////////////////////////////////////////////////////////////////////////////// Variable const* _inDocVariable; ////////////////////////////////////////////////////////////////////////////// /// @brief input variable for keys ////////////////////////////////////////////////////////////////////////////// Variable const* _inKeyVariable; }; //////////////////////////////////////////////////////////////////////////////// /// @brief class UpsertNode //////////////////////////////////////////////////////////////////////////////// class UpsertNode : public ModificationNode { friend class ExecutionNode; friend class ExecutionBlock; friend class UpsertBlock; ////////////////////////////////////////////////////////////////////////////// /// @brief constructor with a vocbase and a collection name ////////////////////////////////////////////////////////////////////////////// public: UpsertNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase, Collection* collection, ModificationOptions const& options, Variable const* inDocVariable, Variable const* insertVariable, Variable const* updateVariable, Variable const* outVariableNew, bool isReplace) : ModificationNode(plan, id, vocbase, collection, options, nullptr, outVariableNew), _inDocVariable(inDocVariable), _insertVariable(insertVariable), _updateVariable(updateVariable), _isReplace(isReplace) { TRI_ASSERT(_inDocVariable != nullptr); TRI_ASSERT(_insertVariable != nullptr); TRI_ASSERT(_updateVariable != nullptr); TRI_ASSERT(_outVariableOld == nullptr); } UpsertNode(ExecutionPlan*, arangodb::basics::Json const& base); ////////////////////////////////////////////////////////////////////////////// /// @brief return the type of the node ////////////////////////////////////////////////////////////////////////////// NodeType getType() const override final { return UPSERT; } ////////////////////////////////////////////////////////////////////////////// /// @brief export to VelocyPack ////////////////////////////////////////////////////////////////////////////// void toVelocyPackHelper(arangodb::velocypack::Builder&, bool) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief clone ExecutionNode recursively ////////////////////////////////////////////////////////////////////////////// ExecutionNode* clone(ExecutionPlan* plan, bool withDependencies, bool withProperties) const override final; ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, returning a vector ////////////////////////////////////////////////////////////////////////////// std::vector getVariablesUsedHere() const override final { // Please do not change the order here without adjusting the // optimizer rule distributeInCluster as well! return std::vector( {_inDocVariable, _insertVariable, _updateVariable}); } ////////////////////////////////////////////////////////////////////////////// /// @brief getVariablesUsedHere, modifying the set in-place ////////////////////////////////////////////////////////////////////////////// void getVariablesUsedHere( std::unordered_set& vars) const override final { vars.emplace(_inDocVariable); vars.emplace(_insertVariable); vars.emplace(_updateVariable); } private: ////////////////////////////////////////////////////////////////////////////// /// @brief input variable for the search document ////////////////////////////////////////////////////////////////////////////// Variable const* _inDocVariable; ////////////////////////////////////////////////////////////////////////////// /// @brief insert case expression ////////////////////////////////////////////////////////////////////////////// Variable const* _insertVariable; ////////////////////////////////////////////////////////////////////////////// /// @brief update case expression ////////////////////////////////////////////////////////////////////////////// Variable const* _updateVariable; ////////////////////////////////////////////////////////////////////////////// /// @brief whether to perform a REPLACE (or an UPDATE alternatively) ////////////////////////////////////////////////////////////////////////////// bool const _isReplace; }; } // namespace arangodb::aql } // namespace arangodb #endif