summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops/modifier_compare.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/ops/modifier_compare.cpp')
-rw-r--r--src/mongo/db/ops/modifier_compare.cpp233
1 files changed, 107 insertions, 126 deletions
diff --git a/src/mongo/db/ops/modifier_compare.cpp b/src/mongo/db/ops/modifier_compare.cpp
index 6d37e4b2797..36f800202e4 100644
--- a/src/mongo/db/ops/modifier_compare.cpp
+++ b/src/mongo/db/ops/modifier_compare.cpp
@@ -37,156 +37,137 @@
namespace mongo {
- namespace str = mongoutils::str;
+namespace str = mongoutils::str;
- struct ModifierCompare::PreparedState {
+struct ModifierCompare::PreparedState {
+ PreparedState(mutablebson::Document& targetDoc)
+ : doc(targetDoc), idxFound(0), elemFound(doc.end()) {}
- PreparedState(mutablebson::Document& targetDoc)
- : doc(targetDoc)
- , idxFound(0)
- , elemFound(doc.end()) {
- }
+ // Document that is going to be changed.
+ mutablebson::Document& doc;
- // Document that is going to be changed.
- mutablebson::Document& doc;
+ // Index in _fieldRef for which an Element exist in the document.
+ size_t idxFound;
- // Index in _fieldRef for which an Element exist in the document.
- size_t idxFound;
+ // Element corresponding to _fieldRef[0.._idxFound].
+ mutablebson::Element elemFound;
+};
- // Element corresponding to _fieldRef[0.._idxFound].
- mutablebson::Element elemFound;
- };
+ModifierCompare::ModifierCompare(ModifierCompare::ModifierCompareMode mode)
+ : _mode(mode), _pathReplacementPosition(0) {}
- ModifierCompare::ModifierCompare(ModifierCompare::ModifierCompareMode mode)
- : _mode(mode)
- , _pathReplacementPosition(0) {
- }
+ModifierCompare::~ModifierCompare() {}
- ModifierCompare::~ModifierCompare() {
+Status ModifierCompare::init(const BSONElement& modExpr, const Options& opts, bool* positional) {
+ _updatePath.parse(modExpr.fieldName());
+ Status status = fieldchecker::isUpdatable(_updatePath);
+ if (!status.isOK()) {
+ return status;
}
- Status ModifierCompare::init(const BSONElement& modExpr, const Options& opts,
- bool* positional) {
-
- _updatePath.parse(modExpr.fieldName());
- Status status = fieldchecker::isUpdatable(_updatePath);
- if (!status.isOK()) {
- return status;
- }
+ // If a $-positional operator was used, get the index in which it occurred
+ // and ensure only one occurrence.
+ size_t foundCount;
+ bool foundDollar =
+ fieldchecker::isPositional(_updatePath, &_pathReplacementPosition, &foundCount);
- // If a $-positional operator was used, get the index in which it occurred
- // and ensure only one occurrence.
- size_t foundCount;
- bool foundDollar = fieldchecker::isPositional(
- _updatePath, &_pathReplacementPosition, &foundCount);
-
- if (positional)
- *positional = foundDollar;
-
- if (foundDollar && foundCount > 1) {
- return Status(ErrorCodes::BadValue,
- str::stream() << "Too many positional (i.e. '$') elements found in path '"
- << _updatePath.dottedField() << "'");
- }
+ if (positional)
+ *positional = foundDollar;
- // Store value for later.
- _val = modExpr;
- return Status::OK();
+ if (foundDollar && foundCount > 1) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Too many positional (i.e. '$') elements found in path '"
+ << _updatePath.dottedField() << "'");
}
- Status ModifierCompare::prepare(mutablebson::Element root,
+ // Store value for later.
+ _val = modExpr;
+ return Status::OK();
+}
+
+Status ModifierCompare::prepare(mutablebson::Element root,
StringData matchedField,
ExecInfo* execInfo) {
+ _preparedState.reset(new PreparedState(root.getDocument()));
- _preparedState.reset(new PreparedState(root.getDocument()));
-
- // If we have a $-positional field, it is time to bind it to an actual field part.
- if (_pathReplacementPosition) {
- if (matchedField.empty()) {
- return Status(ErrorCodes::BadValue,
- str::stream() << "The positional operator did not find the match "
- "needed from the query. Unexpanded update: "
- << _updatePath.dottedField());
- }
- _updatePath.setPart(_pathReplacementPosition, matchedField);
- }
-
- // Locate the field name in 'root'. Note that we may not have all the parts in the path
- // in the doc -- which is fine. Our goal now is merely to reason about whether this mod
- // apply is a noOp or whether is can be in place. The remaining path, if missing, will
- // be created during the apply.
- Status status = pathsupport::findLongestPrefix(_updatePath,
- root,
- &_preparedState->idxFound,
- &_preparedState->elemFound);
-
- // FindLongestPrefix may say the path does not exist at all, which is fine here, or
- // that the path was not viable or otherwise wrong, in which case, the mod cannot
- // proceed.
- if (status.code() == ErrorCodes::NonExistentPath) {
- _preparedState->elemFound = root.getDocument().end();
- }
- else if (!status.isOK()) {
- return status;
- }
-
- // We register interest in the field name. The driver needs this info to sort out if
- // there is any conflict among mods.
- execInfo->fieldRef[0] = &_updatePath;
-
- const bool destExists = (_preparedState->elemFound.ok() &&
- _preparedState->idxFound == (_updatePath.numParts() - 1));
- if (!destExists) {
- execInfo->noOp = false;
- }
- else {
- const int compareVal = _preparedState->elemFound.compareWithBSONElement(_val, false);
- execInfo->noOp = (compareVal == 0) ||
- ((_mode == ModifierCompare::MAX) ?
- (compareVal > 0) : (compareVal < 0));
+ // If we have a $-positional field, it is time to bind it to an actual field part.
+ if (_pathReplacementPosition) {
+ if (matchedField.empty()) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "The positional operator did not find the match "
+ "needed from the query. Unexpanded update: "
+ << _updatePath.dottedField());
}
+ _updatePath.setPart(_pathReplacementPosition, matchedField);
+ }
- return Status::OK();
+ // Locate the field name in 'root'. Note that we may not have all the parts in the path
+ // in the doc -- which is fine. Our goal now is merely to reason about whether this mod
+ // apply is a noOp or whether is can be in place. The remaining path, if missing, will
+ // be created during the apply.
+ Status status = pathsupport::findLongestPrefix(
+ _updatePath, root, &_preparedState->idxFound, &_preparedState->elemFound);
+
+ // FindLongestPrefix may say the path does not exist at all, which is fine here, or
+ // that the path was not viable or otherwise wrong, in which case, the mod cannot
+ // proceed.
+ if (status.code() == ErrorCodes::NonExistentPath) {
+ _preparedState->elemFound = root.getDocument().end();
+ } else if (!status.isOK()) {
+ return status;
}
- Status ModifierCompare::apply() const {
+ // We register interest in the field name. The driver needs this info to sort out if
+ // there is any conflict among mods.
+ execInfo->fieldRef[0] = &_updatePath;
+
+ const bool destExists = (_preparedState->elemFound.ok() &&
+ _preparedState->idxFound == (_updatePath.numParts() - 1));
+ if (!destExists) {
+ execInfo->noOp = false;
+ } else {
+ const int compareVal = _preparedState->elemFound.compareWithBSONElement(_val, false);
+ execInfo->noOp = (compareVal == 0) ||
+ ((_mode == ModifierCompare::MAX) ? (compareVal > 0) : (compareVal < 0));
+ }
- const bool destExists = (_preparedState->elemFound.ok() &&
- _preparedState->idxFound == (_updatePath.numParts() - 1));
- // If there's no need to create any further field part, the $set is simply a value
- // assignment.
- if (destExists) {
- return _preparedState->elemFound.setValueBSONElement(_val);
- }
+ return Status::OK();
+}
- mutablebson::Document& doc = _preparedState->doc;
- StringData lastPart = _updatePath.getPart(_updatePath.numParts() - 1);
- // If the element exists and is the same type, then that is what we want to work with
- mutablebson::Element elemToSet = doc.makeElementWithNewFieldName(lastPart, _val);
- if (!elemToSet.ok()) {
- return Status(ErrorCodes::InternalError, "can't create new element");
- }
-
- // Now, we can be in two cases here, as far as attaching the element being set goes:
- // (a) none of the parts in the element's path exist, or (b) some parts of the path
- // exist but not all.
- if (!_preparedState->elemFound.ok()) {
- _preparedState->elemFound = doc.root();
- _preparedState->idxFound = 0;
- }
- else {
- _preparedState->idxFound++;
- }
+Status ModifierCompare::apply() const {
+ const bool destExists = (_preparedState->elemFound.ok() &&
+ _preparedState->idxFound == (_updatePath.numParts() - 1));
+ // If there's no need to create any further field part, the $set is simply a value
+ // assignment.
+ if (destExists) {
+ return _preparedState->elemFound.setValueBSONElement(_val);
+ }
- // createPathAt() will complete the path and attach 'elemToSet' at the end of it.
- return pathsupport::createPathAt(_updatePath,
- _preparedState->idxFound,
- _preparedState->elemFound,
- elemToSet);
+ mutablebson::Document& doc = _preparedState->doc;
+ StringData lastPart = _updatePath.getPart(_updatePath.numParts() - 1);
+ // If the element exists and is the same type, then that is what we want to work with
+ mutablebson::Element elemToSet = doc.makeElementWithNewFieldName(lastPart, _val);
+ if (!elemToSet.ok()) {
+ return Status(ErrorCodes::InternalError, "can't create new element");
}
- Status ModifierCompare::log(LogBuilder* logBuilder) const {
- return logBuilder->addToSetsWithNewFieldName(_updatePath.dottedField(), _val);
+ // Now, we can be in two cases here, as far as attaching the element being set goes:
+ // (a) none of the parts in the element's path exist, or (b) some parts of the path
+ // exist but not all.
+ if (!_preparedState->elemFound.ok()) {
+ _preparedState->elemFound = doc.root();
+ _preparedState->idxFound = 0;
+ } else {
+ _preparedState->idxFound++;
}
-} // namespace mongo
+ // createPathAt() will complete the path and attach 'elemToSet' at the end of it.
+ return pathsupport::createPathAt(
+ _updatePath, _preparedState->idxFound, _preparedState->elemFound, elemToSet);
+}
+
+Status ModifierCompare::log(LogBuilder* logBuilder) const {
+ return logBuilder->addToSetsWithNewFieldName(_updatePath.dottedField(), _val);
+}
+
+} // namespace mongo