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