Example #1
0
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;
}