summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops/modifier_current_date.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/ops/modifier_current_date.cpp')
-rw-r--r--src/mongo/db/ops/modifier_current_date.cpp358
1 files changed, 167 insertions, 191 deletions
diff --git a/src/mongo/db/ops/modifier_current_date.cpp b/src/mongo/db/ops/modifier_current_date.cpp
index f38cc4e4441..75d0be014e3 100644
--- a/src/mongo/db/ops/modifier_current_date.cpp
+++ b/src/mongo/db/ops/modifier_current_date.cpp
@@ -38,239 +38,215 @@
namespace mongo {
- namespace str = mongoutils::str;
+namespace str = mongoutils::str;
- namespace {
- const char kType[] = "$type";
- const char kDate[] = "date";
- const char kTimestamp[] = "timestamp";
- }
+namespace {
+const char kType[] = "$type";
+const char kDate[] = "date";
+const char kTimestamp[] = "timestamp";
+}
- struct ModifierCurrentDate::PreparedState {
+struct ModifierCurrentDate::PreparedState {
+ PreparedState(mutablebson::Document& doc) : doc(doc), elemFound(doc.end()), idxFound(0) {}
- PreparedState(mutablebson::Document& doc)
- : doc(doc)
- , elemFound(doc.end())
- , idxFound(0) {
- }
+ // Document that is going to be changed.
+ mutablebson::Document& doc;
- // Document that is going to be changed.
- mutablebson::Document& doc;
+ // Element corresponding to _fieldRef[0.._idxFound].
+ mutablebson::Element elemFound;
- // Element corresponding to _fieldRef[0.._idxFound].
- mutablebson::Element elemFound;
+ // 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;
- };
+ModifierCurrentDate::ModifierCurrentDate() : _pathReplacementPosition(0), _typeIsDate(true) {}
- ModifierCurrentDate::ModifierCurrentDate()
- : _pathReplacementPosition(0)
- , _typeIsDate(true) {
- }
+ModifierCurrentDate::~ModifierCurrentDate() {}
- ModifierCurrentDate::~ModifierCurrentDate() {
+Status ModifierCurrentDate::init(const BSONElement& modExpr,
+ const Options& opts,
+ bool* positional) {
+ _updatePath.parse(modExpr.fieldName());
+ Status status = fieldchecker::isUpdatable(_updatePath);
+ if (!status.isOK()) {
+ return status;
}
- Status ModifierCurrentDate::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 (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 (foundDollar && foundCount > 1) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Too many positional (i.e. '$') elements found in path '"
+ << _updatePath.dottedField() << "'");
+ }
- // Validate and store the type to produce
- switch (modExpr.type()) {
- case Bool:
- _typeIsDate = true;
- break;
- case Object: {
- const BSONObj argObj = modExpr.embeddedObject();
- const BSONElement typeElem = argObj.getField(kType);
- bool badInput = typeElem.eoo() || !(typeElem.type() == String);
+ // Validate and store the type to produce
+ switch (modExpr.type()) {
+ case Bool:
+ _typeIsDate = true;
+ break;
+ case Object: {
+ const BSONObj argObj = modExpr.embeddedObject();
+ const BSONElement typeElem = argObj.getField(kType);
+ bool badInput = typeElem.eoo() || !(typeElem.type() == String);
+
+ if (!badInput) {
+ std::string typeVal = typeElem.String();
+ badInput = !(typeElem.String() == kDate || typeElem.String() == kTimestamp);
+ if (!badInput)
+ _typeIsDate = (typeVal == kDate);
if (!badInput) {
- std::string typeVal = typeElem.String();
- badInput = !(typeElem.String() == kDate || typeElem.String() == kTimestamp);
- if (!badInput)
- _typeIsDate = (typeVal == kDate);
-
- if (!badInput) {
- // Check to make sure only the $type field was given as an arg
- BSONObjIterator i( argObj );
- const bool onlyHasTypeField = ((i.next().fieldNameStringData() == kType)
- && i.next().eoo());
- if (!onlyHasTypeField) {
- return Status(ErrorCodes::BadValue,
- str::stream() <<
- "The only valid field of the option is '$type': "
- "{$currentDate: {field : {$type: 'date/timestamp'}}}; "
+ // Check to make sure only the $type field was given as an arg
+ BSONObjIterator i(argObj);
+ const bool onlyHasTypeField =
+ ((i.next().fieldNameStringData() == kType) && i.next().eoo());
+ if (!onlyHasTypeField) {
+ return Status(ErrorCodes::BadValue,
+ str::stream()
+ << "The only valid field of the option is '$type': "
+ "{$currentDate: {field : {$type: 'date/timestamp'}}}; "
<< "arg: " << argObj);
- }
-
}
-
- }
-
- if (badInput) {
- return Status(ErrorCodes::BadValue,
- "The '$type' string field is required "
- "to be 'date' or 'timestamp': "
- "{$currentDate: {field : {$type: 'date'}}}");
}
- break;
}
- default:
- return Status(ErrorCodes::BadValue,
- str::stream() << typeName(modExpr.type())
- << " is not valid type for $currentDate."
- " Please use a boolean ('true')"
- " or a $type expression ({$type: 'timestamp/date'}).");
- }
-
- return Status::OK();
- }
-
- Status ModifierCurrentDate::prepare(mutablebson::Element root,
- StringData matchedField,
- ExecInfo* execInfo) {
-
- _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()) {
+ if (badInput) {
return Status(ErrorCodes::BadValue,
- str::stream() << "The positional operator did not find the match "
- "needed from the query. Unexpanded update: "
- << _updatePath.dottedField());
+ "The '$type' string field is required "
+ "to be 'date' or 'timestamp': "
+ "{$currentDate: {field : {$type: 'date'}}}");
}
- _updatePath.setPart(_pathReplacementPosition, matchedField);
+ break;
}
+ default:
+ return Status(ErrorCodes::BadValue,
+ str::stream() << typeName(modExpr.type())
+ << " is not valid type for $currentDate."
+ " Please use a boolean ('true')"
+ " or a $type expression ({$type: 'timestamp/date'}).");
+ }
- // 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;
- }
+ return Status::OK();
+}
- // 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;
+Status ModifierCurrentDate::prepare(mutablebson::Element root,
+ StringData matchedField,
+ ExecInfo* execInfo) {
+ _preparedState.reset(new PreparedState(root.getDocument()));
- return Status::OK();
+ // 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);
}
- Status ModifierCurrentDate::apply() const {
+ // 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;
+ }
- const bool destExists = (_preparedState->elemFound.ok() &&
- _preparedState->idxFound == (_updatePath.numParts() - 1));
+ // 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;
- 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 = destExists ?
- _preparedState->elemFound:
- doc.end() ;
+ return Status::OK();
+}
- if (!destExists) {
- // Creates the final element that's going to be $set in 'doc'.
- // fills in the value with place-holder/empty
+Status ModifierCurrentDate::apply() const {
+ const bool destExists = (_preparedState->elemFound.ok() &&
+ _preparedState->idxFound == (_updatePath.numParts() - 1));
- elemToSet = _typeIsDate ?
- doc.makeElementDate(lastPart, Date_t()) :
- doc.makeElementTimestamp(lastPart, Timestamp());
+ 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 = destExists ? _preparedState->elemFound : doc.end();
- if (!elemToSet.ok()) {
- return Status(ErrorCodes::InternalError, "can't create new element");
- }
+ if (!destExists) {
+ // Creates the final element that's going to be $set in 'doc'.
+ // fills in the value with place-holder/empty
- // 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++;
- }
+ elemToSet = _typeIsDate ? doc.makeElementDate(lastPart, Date_t())
+ : doc.makeElementTimestamp(lastPart, Timestamp());
- // createPathAt() will complete the path and attach 'elemToSet' at the end of it.
- Status s = pathsupport::createPathAt(_updatePath,
- _preparedState->idxFound,
- _preparedState->elemFound,
- elemToSet);
- if (!s.isOK())
- return s;
+ if (!elemToSet.ok()) {
+ return Status(ErrorCodes::InternalError, "can't create new element");
}
- dassert(elemToSet.ok());
-
- // By the time we are here the element is in place and we just need to update the value
- if (_typeIsDate) {
- const mongo::Date_t now = mongo::jsTime();
- Status s = elemToSet.setValueDate(now);
- if (!s.isOK())
- return s;
- }
- else {
- Status s = elemToSet.setValueTimestamp(getNextGlobalTimestamp());
- if (!s.isOK())
- return s;
+ // 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++;
}
- // Set the elemFound, idxFound to the changed element for oplog logging.
- _preparedState->elemFound = elemToSet;
- _preparedState->idxFound = (_updatePath.numParts() - 1);
+ // createPathAt() will complete the path and attach 'elemToSet' at the end of it.
+ Status s = pathsupport::createPathAt(
+ _updatePath, _preparedState->idxFound, _preparedState->elemFound, elemToSet);
+ if (!s.isOK())
+ return s;
+ }
- return Status::OK();
+ dassert(elemToSet.ok());
+
+ // By the time we are here the element is in place and we just need to update the value
+ if (_typeIsDate) {
+ const mongo::Date_t now = mongo::jsTime();
+ Status s = elemToSet.setValueDate(now);
+ if (!s.isOK())
+ return s;
+ } else {
+ Status s = elemToSet.setValueTimestamp(getNextGlobalTimestamp());
+ if (!s.isOK())
+ return s;
}
- Status ModifierCurrentDate::log(LogBuilder* logBuilder) const {
- // TODO: None of this checks should be needed unless someone calls if we are a noOp
- // When we cleanup we should build in testing that no-one calls in the noOp case
- const bool destExists = (_preparedState->elemFound.ok() &&
- _preparedState->idxFound == (_updatePath.numParts() - 1));
+ // Set the elemFound, idxFound to the changed element for oplog logging.
+ _preparedState->elemFound = elemToSet;
+ _preparedState->idxFound = (_updatePath.numParts() - 1);
- // If the destination doesn't exist then we have nothing to log.
- // This would only happen if apply isn't called or fails when it had to create an element
- if (!destExists)
- return Status::OK();
+ return Status::OK();
+}
- return logBuilder->addToSetsWithNewFieldName(_updatePath.dottedField(),
- _preparedState->elemFound);
- }
+Status ModifierCurrentDate::log(LogBuilder* logBuilder) const {
+ // TODO: None of this checks should be needed unless someone calls if we are a noOp
+ // When we cleanup we should build in testing that no-one calls in the noOp case
+ const bool destExists = (_preparedState->elemFound.ok() &&
+ _preparedState->idxFound == (_updatePath.numParts() - 1));
+
+ // If the destination doesn't exist then we have nothing to log.
+ // This would only happen if apply isn't called or fails when it had to create an element
+ if (!destExists)
+ return Status::OK();
+
+ return logBuilder->addToSetsWithNewFieldName(_updatePath.dottedField(),
+ _preparedState->elemFound);
+}
-} // namespace mongo
+} // namespace mongo