Status ModifierInc::log(mutablebson::Element logRoot) const {

        // We'd like to create an entry such as {$set: {<fieldname>: <value>}} under 'logRoot'.
        // We start by creating the {$set: ...} Element.
        mutablebson::Document& doc = logRoot.getDocument();
        mutablebson::Element setElement = doc.makeElementObject("$set");
        if (!setElement.ok()) {
            return Status(ErrorCodes::InternalError, "cannot append log entry for $set mod");
        }

        // Then we create the {<fieldname>: <value>} Element.
        mutablebson::Element logElement = doc.makeElementSafeNum(
            _fieldRef.dottedField(),
            _preparedState->newValue);

        if (!logElement.ok()) {
            return Status(ErrorCodes::InternalError, "cannot append details for $set mod");
        }

        // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} one.
        Status status = setElement.pushBack(logElement);
        if (!status.isOK()) {
            return status;
        }

        // And attach the result under the 'logRoot' Element provided.
        return logRoot.pushBack(setElement);
    }
Ejemplo n.º 2
0
Status ModifierSet::log(mutablebson::Element logRoot) const {

    // We'd like to create an entry such as {$set: {<fieldname>: <value>}} under 'logRoot'.
    // We start by creating the {$set: ...} Element.
    mutablebson::Document& doc = logRoot.getDocument();
    mutablebson::Element setElement = doc.makeElementObject("$set");
    if (!setElement.ok()) {
        return Status(ErrorCodes::InternalError, "cannot create log entry for $set mod");
    }

    // Then we create the {<fieldname>: <value>} Element. Note that we log the mod with a
    // dotted field, if it was applied over a dotted field. The rationale is that the
    // secondary may be in a different state than the primary and thus make different
    // decisions about creating the intermediate path in _fieldRef or not.
    mutablebson::Element logElement = doc.makeElementWithNewFieldName(_fieldRef.dottedField(),
                                      _val);
    if (!logElement.ok()) {
        return Status(ErrorCodes::InternalError, "cannot create details for $set mod");
    }

    // Now, we attach the {<fieldname>: <value>} Element under the {$set: ...} one.
    Status status = setElement.pushBack(logElement);
    if (!status.isOK()) {
        return status;
    }

    // And attach the result under the 'logRoot' Element provided.
    return logRoot.pushBack(setElement);
}
Ejemplo n.º 3
0
    Status ModifierUnset::log(mutablebson::Element logRoot) const {

        // We'd like to create an entry such as {$unset: {<fieldname>: 1}} under 'logRoot'.
        // We start by creating the {$unset: ...} Element.
        mutablebson::Document& doc = logRoot.getDocument();
        mutablebson::Element unsetElement = doc.makeElementObject("$unset");
        if (!unsetElement.ok()) {
            return Status(ErrorCodes::InternalError, "cannot create log entry for $unset mod");
        }

        // Then we create the {<fieldname>: <value>} Element. Note that <fieldname> must be a
        // dotted field, and not only the last part of that field. The rationale here is that
        // somoene picking up this log entry -- e.g., a secondary -- must be capable of doing
        // the same path find/creation that was done in the previous calls here.
        mutablebson::Element logElement = doc.makeElementInt(_fieldRef.dottedField(), 1);
        if (!logElement.ok()) {
            return Status(ErrorCodes::InternalError, "cannot create log details for $unset mod");
        }

        // Now, we attach the {<fieldname>: `} Element under the {$unset: ...} one.
        Status status = unsetElement.pushBack(logElement);
        if (!status.isOK()) {
            return status;
        }

        // And attach the result under the 'logRoot' Element provided.
        return logRoot.pushBack(unsetElement);
    }
    Status ModifierAddToSet::log(mb::Element logRoot) const {

        // TODO: This is copied more or less identically from $push. As a result, it copies the
        // behavior in $push that relies on 'apply' having been called unless this is a no-op.

        // TODO We can log just a positional set in several cases. For now, let's just log the
        // full resulting array.

        // We'd like to create an entry such as {$set: {<fieldname>: [<resulting aray>]}} under
        // 'logRoot'.  We start by creating the {$set: ...} Element.
        mb::Document& doc = logRoot.getDocument();
        mb::Element setElement = doc.makeElementObject("$set");
        if (!setElement.ok()) {
            return Status(ErrorCodes::InternalError, "cannot create log entry for $addToSet mod");
        }

        // Then we create the {<fieldname>:[]} Element, that is, an empty array.
        mb::Element logElement = doc.makeElementArray(_fieldRef.dottedField());
        if (!logElement.ok()) {
            return Status(ErrorCodes::InternalError, "cannot create details for $addToSet mod");
        }

        // Fill up the empty array.
        mb::Element curr = _preparedState->elemFound.leftChild();
        while (curr.ok()) {

            dassert(curr.hasValue());

            // We need to copy each array entry from the resulting document to the log
            // document.
            mb::Element currCopy = doc.makeElementWithNewFieldName(
                StringData(),
                curr.getValue());
            if (!currCopy.ok()) {
                return Status(ErrorCodes::InternalError, "could create copy element");
            }
            Status status = logElement.pushBack(currCopy);
            if (!status.isOK()) {
                return Status(ErrorCodes::BadValue, "could not append entry for $addToSet log");
            }
            curr = curr.rightSibling();
        }

        // Now, we attach the {<fieldname>: [<filled array>]} Element under the {$set: ...}
        // one.
        Status status = setElement.pushBack(logElement);
        if (!status.isOK()) {
            return status;
        }

        // And attach the result under the 'logRoot' Element provided.
        return logRoot.pushBack(setElement);
    }
Ejemplo n.º 5
0
    Status AuthorizationManager::getBSONForRole(RoleGraph* graph,
                                                const RoleName& roleName,
                                                mutablebson::Element result) {
        if (!graph->roleExists(roleName)) {
            return Status(ErrorCodes::RoleNotFound,
                          mongoutils::str::stream() << roleName.getFullName() <<
                                  "does not name an existing role");
        }
        std::string id = mongoutils::str::stream() << roleName.getDB() << "." << roleName.getRole();
        result.appendString("_id", id);
        result.appendString(ROLE_NAME_FIELD_NAME, roleName.getRole());
        result.appendString(ROLE_SOURCE_FIELD_NAME, roleName.getDB());

        // Build privileges array
        mutablebson::Element privilegesArrayElement =
                result.getDocument().makeElementArray("privileges");
        result.pushBack(privilegesArrayElement);
        const PrivilegeVector& privileges = graph->getDirectPrivileges(roleName);
        Status status = getBSONForPrivileges(privileges, privilegesArrayElement);
        if (!status.isOK()) {
            return status;
        }

        // Build roles array
        mutablebson::Element rolesArrayElement = result.getDocument().makeElementArray("roles");
        result.pushBack(rolesArrayElement);
        for (RoleNameIterator roles = graph->getDirectSubordinates(roleName);
             roles.more();
             roles.next()) {

            const RoleName& subRole = roles.get();
            mutablebson::Element roleObj = result.getDocument().makeElementObject("");
            roleObj.appendString(ROLE_NAME_FIELD_NAME, subRole.getRole());
            roleObj.appendString(ROLE_SOURCE_FIELD_NAME, subRole.getDB());
            rolesArrayElement.pushBack(roleObj);
        }

        return Status::OK();
    }
Ejemplo n.º 6
0
Status createPathAt(const FieldRef& prefix,
                    size_t idxFound,
                    mutablebson::Element elemFound,
                    mutablebson::Element newElem) {
    Status status = Status::OK();

    // Sanity check that 'idxField' is an actual part.
    const size_t size = prefix.numParts();
    if (idxFound >= size) {
        return Status(ErrorCodes::BadValue, "index larger than path size");
    }

    mutablebson::Document& doc = elemFound.getDocument();

    // If we are creating children under an array and a numeric index is next, then perhaps
    // we need padding.
    size_t i = idxFound;
    bool inArray = false;
    if (elemFound.getType() == mongol::Array) {
        size_t newIdx = 0;
        if (!isNumeric(prefix.getPart(idxFound), &newIdx)) {
            return Status(ErrorCodes::InvalidPath, "Array require numeric fields");
        }

        status = maybePadTo(&elemFound, newIdx);
        if (!status.isOK()) {
            return status;
        }

        // If there is a next field, that would be an array element. We'd like to mark that
        // field because we create array elements differently than we do regular objects.
        if (++i < size) {
            inArray = true;
        }
    }

    // Create all the remaining parts but the last one.
    for (; i < size - 1; i++) {
        mutablebson::Element elem = doc.makeElementObject(prefix.getPart(i));
        if (!elem.ok()) {
            return Status(ErrorCodes::InternalError, "cannot create path");
        }

        // If this field is an array element, we wrap it in an object (because array
        // elements are wraped in { "N": <element> } objects.
        if (inArray) {
            // TODO pass empty StringData to makeElementObject, when that's supported.
            mutablebson::Element arrayObj = doc.makeElementObject("" /* it's an array */);
            if (!arrayObj.ok()) {
                return Status(ErrorCodes::InternalError, "cannot create item on array");
            }
            status = arrayObj.pushBack(elem);
            if (!status.isOK()) {
                return status;
            }
            status = elemFound.pushBack(arrayObj);
            if (!status.isOK()) {
                return status;
            }
            inArray = false;
        } else {
            status = elemFound.pushBack(elem);
            if (!status.isOK()) {
                return status;
            }
        }

        elemFound = elem;
    }

    // Attach the last element. Here again, if we're in a field that is an array element,
    // we wrap it in an object first.
    if (inArray) {
        // TODO pass empty StringData to makeElementObject, when that's supported.
        mutablebson::Element arrayObj = doc.makeElementObject("" /* it's an array */);
        if (!arrayObj.ok()) {
            return Status(ErrorCodes::InternalError, "cannot create item on array");
        }

        status = arrayObj.pushBack(newElem);
        if (!status.isOK()) {
            return status;
        }

        status = elemFound.pushBack(arrayObj);
        if (!status.isOK()) {
            return status;
        }

    } else {
        status = elemFound.pushBack(newElem);
        if (!status.isOK()) {
            return status;
        }
    }

    return Status::OK();
}
    Status ModifierPull::log(mb::Element logRoot) const {

        mb::Document& doc = logRoot.getDocument();

        mb::Element opElement = doc.end();
        mb::Element logElement = doc.end();

        if (!_preparedState->elemFound.ok() ||
            _preparedState->idxFound < static_cast<int32_t>(_fieldRef.numParts() - 1)) {

            // If we didn't find the element that we wanted to pull from, we log an unset for
            // that element.

            opElement = doc.makeElementObject("$unset");
            if (!opElement.ok()) {
                return Status(ErrorCodes::InternalError, "cannot create log entry for $pull mod");
            }

            logElement = doc.makeElementInt(_fieldRef.dottedField(), 1);

        } else {

            // TODO: This is copied more or less identically from $push. As a result, it copies the
            // behavior in $push that relies on 'apply' having been called unless this is a no-op.

            // TODO We can log just a positional unset in several cases. For now, let's just log
            // the full resulting array.

            // We'd like to create an entry such as {$set: {<fieldname>: [<resulting aray>]}} under
            // 'logRoot'.  We start by creating the {$set: ...} Element.

            opElement = doc.makeElementObject("$set");
            if (!opElement.ok()) {
                return Status(ErrorCodes::InternalError, "cannot create log entry for $pull mod");
            }

            // Then we create the {<fieldname>:[]} Element, that is, an empty array.
            logElement = doc.makeElementArray(_fieldRef.dottedField());
            if (!logElement.ok()) {
                return Status(ErrorCodes::InternalError, "cannot create details for $pull mod");
            }

            mb::Element curr = _preparedState->elemFound.leftChild();
            while (curr.ok()) {

                dassert(curr.hasValue());

                // We need to copy each array entry from the resulting document to the log
                // document.
                mb::Element currCopy = doc.makeElementWithNewFieldName(
                    StringData(),
                    curr.getValue());
                if (!currCopy.ok()) {
                    return Status(ErrorCodes::InternalError, "could create copy element");
                }
                Status status = logElement.pushBack(currCopy);
                if (!status.isOK()) {
                    return Status(ErrorCodes::BadValue, "could not append entry for $pull log");
                }
                curr = curr.rightSibling();
            }

        }

        // Now, we attach log element under the op element.
        Status status = opElement.pushBack(logElement);
        if (!status.isOK()) {
            return status;
        }

        // And attach the result under the 'logRoot' Element provided by the caller.
        return logRoot.pushBack(opElement);
    }