BSONObj UpdateStage::applyUpdateOpsForInsert(OperationContext* opCtx, const CanonicalQuery* cq, const BSONObj& query, UpdateDriver* driver, mutablebson::Document* doc, bool isInternalRequest, const NamespaceString& ns, bool enforceOkForStorage, UpdateStats* stats) { // Since this is an insert (no docs found and upsert:true), we will be logging it // as an insert in the oplog. We don't need the driver's help to build the // oplog record, then. We also set the context of the update driver to the INSERT_CONTEXT. // Some mods may only work in that context (e.g. $setOnInsert). driver->setLogOp(false); driver->setInsert(true); FieldRefSet immutablePaths; if (!isInternalRequest) { auto immutablePathsVector = getImmutableFields(opCtx, ns); if (immutablePathsVector) { immutablePaths.fillFrom( transitional_tools_do_not_use::unspool_vector(*immutablePathsVector)); } } immutablePaths.keepShortest(&idFieldRef); if (cq) { uassertStatusOK(driver->populateDocumentWithQueryFields(*cq, immutablePaths, *doc)); if (driver->isDocReplacement()) stats->fastmodinsert = true; } else { fassert(17354, CanonicalQuery::isSimpleIdQuery(query)); BSONElement idElt = query[idFieldName]; fassert(17352, doc->root().appendElement(idElt)); } // Apply the update modifications here. Do not validate for storage, since we will validate the // entire document after the update. However, we ensure that no immutable fields are updated. const bool validateForStorage = false; if (isInternalRequest) { immutablePaths.clear(); } Status updateStatus = driver->update(StringData(), doc, validateForStorage, immutablePaths); if (!updateStatus.isOK()) { uasserted(16836, updateStatus.reason()); } // Ensure _id exists and is first auto idAndFirstStatus = ensureIdFieldIsFirst(doc); if (idAndFirstStatus.code() == ErrorCodes::InvalidIdField) { // _id field is missing addObjectIDIdField(doc); } else { uassertStatusOK(idAndFirstStatus); } // Validate that the object replacement or modifiers resulted in a document // that contains all the immutable keys and can be stored if it isn't coming // from a migration or via replication. if (!isInternalRequest) { if (enforceOkForStorage) { storage_validation::storageValid(*doc); } checkImmutablePathsPresent(*doc, immutablePaths); } BSONObj newObj = doc->getObject(); if (newObj.objsize() > BSONObjMaxUserSize) { uasserted(17420, str::stream() << "Document to upsert is larger than " << BSONObjMaxUserSize); } return newObj; }