1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <memory> 34 35 #include "mongo/bson/bsonelement.h" 36 #include "mongo/bson/mutable/element.h" 37 #include "mongo/db/field_ref_set.h" 38 #include "mongo/db/update/log_builder.h" 39 #include "mongo/db/update_index_data.h" 40 #include "mongo/util/assert_util.h" 41 42 namespace mongo { 43 44 class CollatorInterface; 45 class FieldRef; 46 47 /** 48 * Update modifier expressions are stored as a prefix tree of UpdateNodes, where two modifiers that 49 * share a field path prefix share a path prefix in the tree. The prefix tree is used to enforce 50 * that no update modifier's field path is a prefix of (or equal to) another update modifier's field 51 * path. The root of the UpdateNode tree is always an UpdateObjectNode. The leaves are always 52 * UpdateLeafNodes. 53 * 54 * Example: {$set: {'a.b': 5, c: 6}, $inc: {'a.c': 1}} 55 * 56 * UpdateObjectNode 57 * a / \ c 58 * UpdateObjectNode SetNode: _val = 6 59 * b / \ c 60 * SetNode: _val = 5 IncNode: _val = 1 61 */ 62 class UpdateNode { 63 public: 64 enum class Context { kAll, kInsertOnly }; 65 enum class Type { Object, Array, Leaf, Replacement }; 66 67 explicit UpdateNode(Type type, Context context = Context::kAll) context(context)68 : context(context), type(type) {} 69 virtual ~UpdateNode() = default; 70 71 virtual std::unique_ptr<UpdateNode> clone() const = 0; 72 73 /** 74 * Set the collation on the node and all descendants. This is a noop if no leaf nodes require a 75 * collator. If setCollator() is called, it is required that the current collator of all leaf 76 * nodes is the simple collator (nullptr). The collator must outlive the modifier interface. 77 * This is used to override the collation after obtaining a collection lock if the update did 78 * not specify a collation and the collection has a non-simple default collation. 79 */ 80 virtual void setCollator(const CollatorInterface* collator) = 0; 81 82 /** 83 * The parameters required by UpdateNode::apply. 84 */ 85 struct ApplyParams { ApplyParamsApplyParams86 ApplyParams(mutablebson::Element element, const FieldRefSet& immutablePaths) 87 : element(element), immutablePaths(immutablePaths) {} 88 89 // The element to update. 90 mutablebson::Element element; 91 92 // UpdateNode::apply uasserts if it modifies an immutable path. 93 const FieldRefSet& immutablePaths; 94 95 // The path taken through the UpdateNode tree beyond where the path existed in the document. 96 // For example, if the update is {$set: {'a.b.c': 5}}, and the document is {a: {}}, then at 97 // the leaf node, 'pathToCreate'="b.c". 98 std::shared_ptr<FieldRef> pathToCreate = std::make_shared<FieldRef>(); 99 100 // The path through the root document to 'element', ending with the field name of 'element'. 101 // For example, if the update is {$set: {'a.b.c': 5}}, and the document is {a: {}}, then at 102 // the leaf node, 'pathTaken'="a". 103 std::shared_ptr<FieldRef> pathTaken = std::make_shared<FieldRef>(); 104 105 // If there was a positional ($) element in the update expression, 'matchedField' is the 106 // index of the array element that caused the query to match the document. 107 StringData matchedField; 108 109 // True if the update is being applied to a document to be inserted. $setOnInsert behaves as 110 // a no-op when this flag is false. 111 bool insert = false; 112 113 // This is provided because some modifiers may ignore certain errors when the update is from 114 // replication. 115 bool fromOplogApplication = false; 116 117 // If true, UpdateNode::apply ensures that modified elements do not violate depth or DBRef 118 // constraints. 119 bool validateForStorage = true; 120 121 // Used to determine whether indexes are affected. 122 const UpdateIndexData* indexData = nullptr; 123 124 // If provided, UpdateNode::apply will log the update here. 125 LogBuilder* logBuilder = nullptr; 126 }; 127 128 /** 129 * The outputs of apply(). 130 */ 131 struct ApplyResult { noopResultApplyResult132 static ApplyResult noopResult() { 133 ApplyResult applyResult; 134 applyResult.indexesAffected = false; 135 applyResult.noop = true; 136 return applyResult; 137 } 138 139 bool indexesAffected = true; 140 bool noop = false; 141 }; 142 143 /** 144 * Applies the update node to 'applyParams.element', creating the fields in 145 * 'applyParams.pathToCreate' if required by the leaves (i.e. the leaves are not all $unset). 146 * Returns an ApplyResult specifying whether the operation was a no-op and whether indexes are 147 * affected. 148 */ 149 virtual ApplyResult apply(ApplyParams applyParams) const = 0; 150 151 /** 152 * Creates a new node by merging the contents of two input nodes. The semantics of the merge 153 * operation depend on the types of the input nodes. When the nodes have the same type, this 154 * function dispatches the merge to a createUpdateNodeByMerging implementation defined for that 155 * subtype. Throws AssertionException with a ConflictingUpdateOperators code when the types of 156 * the input nodes differ or when any of the child nodes fail to merge. 157 */ 158 static std::unique_ptr<UpdateNode> createUpdateNodeByMerging(const UpdateNode& leftNode, 159 const UpdateNode& rightNode, 160 FieldRef* pathTaken); 161 162 const Context context; 163 const Type type; 164 }; 165 166 } // namespace mongo 167