summaryrefslogtreecommitdiff
path: root/src/mongo/db/update/update_object_node.cpp
diff options
context:
space:
mode:
authorTess Avitabile <tess.avitabile@mongodb.com>2017-11-09 15:42:32 -0500
committerTess Avitabile <tess.avitabile@mongodb.com>2017-11-15 09:29:21 -0500
commit50521fcdcb57dad03b68d8ef070b970f227329cf (patch)
treefeaddf8b8e9e65ee2a361cdcde4b23a50f94d211 /src/mongo/db/update/update_object_node.cpp
parente7f03f979c98ea7cc90151839d6d91276f5d32ed (diff)
downloadmongo-50521fcdcb57dad03b68d8ef070b970f227329cf.tar.gz
SERVER-31894 Update system should not use mutablebson::Element operator[](StringData name) for arrays
Diffstat (limited to 'src/mongo/db/update/update_object_node.cpp')
-rw-r--r--src/mongo/db/update/update_object_node.cpp40
1 files changed, 24 insertions, 16 deletions
diff --git a/src/mongo/db/update/update_object_node.cpp b/src/mongo/db/update/update_object_node.cpp
index 542ed8cd201..ebf0b6cf8a1 100644
--- a/src/mongo/db/update/update_object_node.cpp
+++ b/src/mongo/db/update/update_object_node.cpp
@@ -81,6 +81,21 @@ StatusWith<std::string> parseArrayFilterIdentifier(
}
/**
+ * Gets the child of 'element' named 'field', if it exists. Otherwise returns a non-ok element.
+ */
+mutablebson::Element getChild(mutablebson::Element element, StringData field) {
+ if (element.getType() == BSONType::Object) {
+ return element[field];
+ } else if (element.getType() == BSONType::Array) {
+ auto indexFromField = parseUnsignedBase10Integer(field);
+ if (indexFromField) {
+ return element.findNthChild(*indexFromField);
+ }
+ }
+ return element.getDocument().end();
+}
+
+/**
* Applies 'child' to the child of 'applyParams->element' named 'field' (which will create it, if it
* does not exist). If 'applyParams->pathToCreate' is created, then 'applyParams->pathToCreate' is
* moved to the end of 'applyParams->pathTaken', and 'applyParams->element' is advanced to the end
@@ -101,18 +116,8 @@ void applyChild(const UpdateNode& child,
if (!applyParams->pathToCreate->empty()) {
// We're already traversing a path with elements that don't exist yet, so we will definitely
// need to append.
- } else if (applyParams->element.getType() == BSONType::Object) {
- childElement = applyParams->element[field];
- } else if (applyParams->element.getType() == BSONType::Array) {
- boost::optional<size_t> indexFromField = parseUnsignedBase10Integer(field);
- if (indexFromField) {
- childElement = applyParams->element.findNthChild(*indexFromField);
- } else {
- // We're trying to traverse an array element, but the path specifies a name instead of
- // an index. We append the name to 'pathToCreate' for now, even though we know we won't
- // be able to create it. If the update eventually needs to create the path,
- // pathsupport::createPathAt() will provide a sensible PathNotViable UserError.
- }
+ } else {
+ childElement = getChild(applyParams->element, field);
}
if (childElement.ok()) {
@@ -124,7 +129,8 @@ void applyChild(const UpdateNode& child,
// We are traversing path components that do not exist in our document. Any update modifier
// that creates new path components (i.e., any modifiers that return true for
// allowCreation()) will need to create this component, so we append it to the
- // 'pathToCreate' FieldRef.
+ // 'pathToCreate' FieldRef. If the component cannot be created, pathsupport::createPathAt()
+ // will provide a sensible PathNotViable UserError.
childElement = applyParams->element;
applyParams->pathToCreate->appendPart(field);
}
@@ -147,7 +153,8 @@ void applyChild(const UpdateNode& child,
// to the end of 'pathTaken'. We should advance 'element' to the end of 'pathTaken'.
if (applyParams->pathTaken->numParts() > pathTakenSizeBefore) {
for (auto i = pathTakenSizeBefore; i < applyParams->pathTaken->numParts(); ++i) {
- applyParams->element = applyParams->element[applyParams->pathTaken->getPart(i)];
+ applyParams->element =
+ getChild(applyParams->element, applyParams->pathTaken->getPart(i));
invariant(applyParams->element.ok());
}
} else if (!applyParams->pathToCreate->empty()) {
@@ -155,14 +162,15 @@ void applyChild(const UpdateNode& child,
// If the child is a leaf node, it may have created 'pathToCreate' without moving
// 'pathToCreate' to the end of 'pathTaken'. We should move 'pathToCreate' to the end of
// 'pathTaken' and advance 'element' to the end of 'pathTaken'.
- childElement = applyParams->element[applyParams->pathToCreate->getPart(0)];
+ childElement = getChild(applyParams->element, applyParams->pathToCreate->getPart(0));
if (childElement.ok()) {
applyParams->element = childElement;
applyParams->pathTaken->appendPart(applyParams->pathToCreate->getPart(0));
// Either the path was fully created or not created at all.
for (size_t i = 1; i < applyParams->pathToCreate->numParts(); ++i) {
- applyParams->element = applyParams->element[applyParams->pathToCreate->getPart(i)];
+ applyParams->element =
+ getChild(applyParams->element, applyParams->pathToCreate->getPart(i));
invariant(applyParams->element.ok());
applyParams->pathTaken->appendPart(applyParams->pathToCreate->getPart(i));
}