Status parseRolePossessionManipulationCommands(const BSONObj& cmdObj,
                                                   const StringData& cmdName,
                                                   const std::string& dbname,
                                                   std::string* parsedName,
                                                   vector<RoleName>* parsedRoleNames,
                                                   BSONObj* parsedWriteConcern) {
        unordered_set<std::string> validFieldNames;
        validFieldNames.insert(cmdName.toString());
        validFieldNames.insert("roles");
        validFieldNames.insert("writeConcern");

        Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames);
        if (!status.isOK()) {
            return status;
        }

        status = _extractWriteConcern(cmdObj, parsedWriteConcern);
        if (!status.isOK()) {
            return status;
        }

        status = bsonExtractStringField(cmdObj, cmdName, parsedName);
        if (!status.isOK()) {
            return status;
        }

        BSONElement rolesElement;
        status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement);
        if (!status.isOK()) {
            return status;
        }

        status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()),
                                             dbname,
                                             parsedRoleNames);
        if (!status.isOK()) {
            return status;
        }

        if (!parsedRoleNames->size()) {
            return Status(ErrorCodes::BadValue,
                          mongoutils::str::stream() << cmdName << " command requires a non-empty "
                                  "\"roles\" array");
        }
        return Status::OK();
    }
Beispiel #2
0
    void WriteResult::_mergeCommandResult(
        const std::vector<WriteOperation*>& ops,
        const BSONObj& result
    ) {
        int affected = _getIntOrDefault(result, "n");

        // Handle Write Batch
        switch (ops.front()->operationType()) {
            case dbWriteInsert:
                _nInserted += affected;
                break;

            case dbWriteDelete:
                _nRemoved += affected;
                break;

            case dbWriteUpdate:
                if (result.hasField("upserted")) {
                    int nUpserted = _createUpserts(result.getField("upserted"), ops);
                    _nUpserted += nUpserted;
                    _nMatched += (affected - nUpserted);
                } else {
                    _nMatched += affected;
                }

                _setModified(result);

                break;
        }

        // Handle Write Errors
        if (result.hasField("writeErrors")) {
            BSONElement writeErrors = result.getField("writeErrors");
            BSONObjIterator arrayIterator(writeErrors.Obj());
            BSONElement current;

            while (arrayIterator.more())
                _createWriteError(arrayIterator.next().Obj(), ops);
        }

        // Handle Write Concern Errors
        if (result.hasField("writeConcernError")) {
            BSONObj writeConcernError = result.getObjectField("writeConcernError");
            _createWriteConcernError(writeConcernError);
        }
    }
StatusWith<std::vector<BSONObj>> AggregationRequest::parsePipelineFromBSON(
    BSONElement pipelineElem) {
    std::vector<BSONObj> pipeline;
    if (pipelineElem.eoo() || pipelineElem.type() != BSONType::Array) {
        return {ErrorCodes::TypeMismatch, "'pipeline' option must be specified as an array"};
    }

    for (auto elem : pipelineElem.Obj()) {
        if (elem.type() != BSONType::Object) {
            return {ErrorCodes::TypeMismatch,
                    "Each element of the 'pipeline' array must be an object"};
        }
        pipeline.push_back(elem.embeddedObject().getOwned());
    }

    return std::move(pipeline);
}
Beispiel #4
0
    Status ExpressionParser::_parseTreeList( const BSONObj& arr, ListOfExpression* out ) {
        BSONObjIterator i( arr );
        while ( i.more() ) {
            BSONElement e = i.next();

            if ( e.type() != Object )
                return Status( ErrorCodes::BadValue,
                               "$or/$and/$nor entries need to be full objects" );

            StatusWithExpression sub = parse( e.Obj() );
            if ( !sub.isOK() )
                return sub.getStatus();

            out->add( sub.getValue() );
        }
        return Status::OK();
    }
Beispiel #5
0
StatusWith<ReadPreferenceSetting> ReadPreferenceSetting::fromBSON(const BSONObj& readPrefObj) {
    std::string modeStr;
    auto modeExtractStatus = bsonExtractStringField(readPrefObj, kModeFieldName, &modeStr);
    if (!modeExtractStatus.isOK()) {
        return modeExtractStatus;
    }

    ReadPreference mode;
    auto swReadPrefMode = parseReadPreferenceMode(modeStr);
    if (!swReadPrefMode.isOK()) {
        return swReadPrefMode.getStatus();
    }
    mode = std::move(swReadPrefMode.getValue());

    TagSet tags;
    BSONElement tagsElem;
    auto tagExtractStatus =
        bsonExtractTypedField(readPrefObj, kTagsFieldName, mongo::Array, &tagsElem);
    if (tagExtractStatus.isOK()) {
        tags = TagSet{BSONArray(tagsElem.Obj().getOwned())};

        // In accordance with the read preference spec, passing the default wildcard tagset
        // '[{}]' is the same as not passing a TagSet at all. Furthermore, passing an empty
        // TagSet with a non-primary ReadPreference is equivalent to passing the wildcard
        // ReadPreference.
        if (tags == TagSet() || tags == TagSet::primaryOnly()) {
            tags = defaultTagSetForMode(mode);
        }

        // If we are using a user supplied TagSet, check that it is compatible with
        // the readPreference mode.
        else if (ReadPreference::PrimaryOnly == mode && (tags != TagSet::primaryOnly())) {
            return Status(ErrorCodes::BadValue,
                          "Only empty tags are allowed with primary read preference");
        }
    }

    else if (ErrorCodes::NoSuchKey == tagExtractStatus) {
        tags = defaultTagSetForMode(mode);
    } else {
        return tagExtractStatus;
    }

    return ReadPreferenceSetting(mode, tags);
}
Beispiel #6
0
DeleteOp parseDeleteCommand(StringData dbName, const BSONObj& cmd) {
    BSONElement deletes;
    DeleteOp op;
    parseWriteCommand(dbName, cmd, "deletes", &deletes, &op);
    checkType(Array, deletes);
    for (auto doc : deletes.Obj()) {
        checkTypeInArray(Object, doc, deletes);
        op.deletes.emplace_back();
        auto& del = op.deletes.back();  // delete is a reserved word.
        bool haveQ = false;
        bool haveLimit = false;
        for (auto field : doc.Obj()) {
            const StringData fieldName = field.fieldNameStringData();
            if (fieldName == "q") {
                haveQ = true;
                checkType(Object, field);
                del.query = field.Obj();
            } else if (fieldName == "limit") {
                haveLimit = true;
                uassert(ErrorCodes::TypeMismatch,
                        str::stream()
                            << "The limit field in delete objects must be a number. Got a "
                            << typeName(field.type()),
                        field.isNumber());

                // Using a double to avoid throwing away illegal fractional portion. Don't want to
                // accept 0.5 here.
                const double limit = field.numberDouble();
                uassert(ErrorCodes::FailedToParse,
                        str::stream() << "The limit field in delete objects must be 0 or 1. Got "
                                      << limit,
                        limit == 0 || limit == 1);
                del.multi = (limit == 0);
            } else {
                uasserted(ErrorCodes::FailedToParse,
                          str::stream() << "Unrecognized field in delete operation: " << fieldName);
            }
        }
        uassert(ErrorCodes::FailedToParse, "The 'q' field is required for all deletes", haveQ);
        uassert(
            ErrorCodes::FailedToParse, "The 'limit' field is required for all deletes", haveLimit);
    }
    checkOpCountForCommand(op.deletes.size());
    return op;
}
// static
void ExpressionKeysPrivate::getHaystackKeys(const BSONObj& obj,
        const std::string& geoField,
        const std::vector<std::string>& otherFields,
        double bucketSize,
        BSONObjSet* keys) {

    BSONElement loc = obj.getFieldDotted(geoField);

    if (loc.eoo()) {
        return;
    }

    uassert(16775, "latlng not an array", loc.isABSONObj());
    string root;
    {
        BSONObjIterator i(loc.Obj());
        BSONElement x = i.next();
        BSONElement y = i.next();
        root = makeHaystackString(hashHaystackElement(x, bucketSize),
                                  hashHaystackElement(y, bucketSize));
    }

    verify(otherFields.size() == 1);

    BSONElementSet all;

    // This is getFieldsDotted (plural not singular) since the object we're indexing
    // may be an array.
    obj.getFieldsDotted(otherFields[0], all);

    if (all.size() == 0) {
        // We're indexing a document that doesn't have the secondary non-geo field present.
        // XXX: do we want to add this even if all.size() > 0?  result:empty search terms
        // match everything instead of only things w/empty search terms)
        addKey(root, BSONElement(), keys);
    } else {
        // Ex:If our secondary field is type: "foo" or type: {a:"foo", b:"bar"},
        // all.size()==1.  We can query on the complete field.
        // Ex: If our secondary field is type: ["A", "B"] all.size()==2 and all has values
        // "A" and "B".  The query looks for any of the fields in the array.
        for (BSONElementSet::iterator i = all.begin(); i != all.end(); ++i) {
            addKey(root, *i, keys);
        }
    }
}
    Status parseAndValidateRolePrivilegeManipulationCommands(const BSONObj& cmdObj,
                                                             const StringData& cmdName,
                                                             const std::string& dbname,
                                                             RoleName* parsedRoleName,
                                                             PrivilegeVector* parsedPrivileges,
                                                             BSONObj* parsedWriteConcern) {
        unordered_set<std::string> validFieldNames;
        validFieldNames.insert(cmdName.toString());
        validFieldNames.insert("privileges");
        validFieldNames.insert("writeConcern");

        Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames);
        if (!status.isOK()) {
            return status;
        }

        status = _extractWriteConcern(cmdObj, parsedWriteConcern);
        if (!status.isOK()) {
            return status;
        }

        BSONObjBuilder roleObjBuilder;

        // Parse role name
        std::string roleName;
        status = bsonExtractStringField(cmdObj, cmdName, &roleName);
        if (!status.isOK()) {
            return status;
        }
        *parsedRoleName = RoleName(roleName, dbname);

        // Parse privileges
        BSONElement privilegesElement;
        status = bsonExtractTypedField(cmdObj, "privileges", Array, &privilegesElement);
        if (!status.isOK()) {
            return status;
        }
        status = _parseAndValidatePrivilegeArray(BSONArray(privilegesElement.Obj()),
                                                 parsedPrivileges);
        if (!status.isOK()) {
            return status;
        }

        return Status::OK();
    }
Beispiel #9
0
    Status GeoExpression::parseQuery(const BSONObj &obj) {
        BSONObjIterator outerIt(obj);
        // "within" / "geoWithin" / "geoIntersects"
        BSONElement queryElt = outerIt.next();
        if (outerIt.more()) {
            return Status(ErrorCodes::BadValue,
                          str::stream() << "can't parse extra field: " << outerIt.next());
        }

        BSONObj::MatchType matchType = static_cast<BSONObj::MatchType>(queryElt.getGtLtOp());
        if (BSONObj::opGEO_INTERSECTS == matchType) {
            predicate = GeoExpression::INTERSECT;
        } else if (BSONObj::opWITHIN == matchType) {
            predicate = GeoExpression::WITHIN;
        } else {
            // eoo() or unknown query predicate.
            return Status(ErrorCodes::BadValue,
                          str::stream() << "invalid geo query predicate: " << obj);
        }

        // Parse geometry after predicates.
        if (Object != queryElt.type()) return Status(ErrorCodes::BadValue, "geometry must be an object");
        BSONObj geoObj = queryElt.Obj();

        BSONObjIterator geoIt(geoObj);

        while (geoIt.more()) {
            BSONElement elt = geoIt.next();
            if (str::equals(elt.fieldName(), "$uniqueDocs")) {
                // Deprecated "$uniqueDocs" field
                warning() << "deprecated $uniqueDocs option: " << obj.toString() << endl;
            } else {
                // The element must be a geo specifier. "$box", "$center", "$geometry", etc.
                geoContainer.reset(new GeometryContainer());
                Status status = geoContainer->parseFromQuery(elt);
                if (!status.isOK()) return status;
            }
        }

        if (geoContainer == NULL) {
            return Status(ErrorCodes::BadValue, "geo query doesn't have any geometry");
        }

        return Status::OK();
    }
Status bsonExtractOpTimeField(const BSONObj& object, StringData fieldName, repl::OpTime* out) {
    BSONElement element;
    Status status = bsonExtractTypedField(object, fieldName, Object, &element);
    if (!status.isOK())
        return status;

    BSONObj opTimeObj = element.Obj();
    Timestamp ts;
    status = bsonExtractTimestampField(opTimeObj, kTimestampFieldName, &ts);
    if (!status.isOK())
        return status;
    long long term;
    status = bsonExtractIntegerField(opTimeObj, kTermFieldName, &term);
    if (!status.isOK())
        return status;
    *out = repl::OpTime(ts, term);
    return Status::OK();
}
Beispiel #11
0
Status InMatchExpression::addEquality(const BSONElement& elt) {
    if (elt.type() == BSONType::RegEx) {
        return Status(ErrorCodes::BadValue, "InMatchExpression equality cannot be a regex");
    }
    if (elt.type() == BSONType::Undefined) {
        return Status(ErrorCodes::BadValue, "InMatchExpression equality cannot be undefined");
    }

    if (elt.type() == BSONType::jstNULL) {
        _hasNull = true;
    }
    if (elt.type() == BSONType::Array && elt.Obj().isEmpty()) {
        _hasEmptyArray = true;
    }
    _equalitySet.insert(elt);
    _originalEqualityVector.push_back(elt);
    return Status::OK();
}
Beispiel #12
0
bool LeafMatchExpression::_matchesElementExpandArray( const BSONElement& e ) const {
    if ( e.eoo() )
        return false;

    if ( matchesSingleElement( e ) )
        return true;

    if ( e.type() == Array ) {
        BSONObjIterator i( e.Obj() );
        while ( i.more() ) {
            BSONElement sub = i.next();
            if ( matchesSingleElement( sub ) )
                return true;
        }
    }

    return false;
}
void OperationShardingState::initializeShardVersion(NamespaceString nss,
                                                    const BSONElement& shardVersionElt) {
    invariant(!hasShardVersion());

    if (shardVersionElt.eoo() || shardVersionElt.type() != BSONType::Array) {
        return;
    }

    const BSONArray versionArr(shardVersionElt.Obj());
    bool hasVersion = false;
    ChunkVersion newVersion = ChunkVersion::fromBSON(versionArr, &hasVersion);

    if (!hasVersion) {
        return;
    }

    setShardVersion(std::move(nss), std::move(newVersion));
}
Beispiel #14
0
Status ArrayFilterEntries::addEquality(const BSONElement& e) {
    if (e.type() == RegEx)
        return Status(ErrorCodes::BadValue, "ArrayFilterEntries equality cannot be a regex");

    if (e.type() == Undefined) {
        return Status(ErrorCodes::BadValue, "ArrayFilterEntries equality cannot be undefined");
    }

    if (e.type() == jstNULL) {
        _hasNull = true;
    }

    if (e.type() == Array && e.Obj().isEmpty())
        _hasEmptyArray = true;

    _equalities.insert(e);
    return Status::OK();
}
Beispiel #15
0
    bool MatchExpressionParser::_isExpressionDocument( const BSONElement& e ) {
        if ( e.type() != Object )
            return false;

        BSONObj o = e.Obj();
        if ( o.isEmpty() )
            return false;

        const char* name = o.firstElement().fieldName();
        if ( name[0] != '$' )
            return false;

        if ( _isDBRefDocument( o ) ) {
            return false;
        }

        return true;
    }
Beispiel #16
0
        /**
         * Returns true if 'e' contains a valid operation.
         */
        bool _checkOperation(const BSONElement& e, string& errmsg) {
            if (e.type() != Object) {
                errmsg = str::stream() << "op not an object: " << e.fieldName();
                return false;
            }
            BSONObj obj = e.Obj();
            // op - operation type
            BSONElement opElement = obj.getField("op");
            if (opElement.eoo()) {
                errmsg = str::stream() << "op does not contain required \"op\" field: "
                                       << e.fieldName();
                return false;
            }
            if (opElement.type() != mongo::String) {
                errmsg = str::stream() << "\"op\" field is not a string: " << e.fieldName();
                return false;
            }
            // operation type -- see logOp() comments for types
            const char *opType = opElement.valuestrsafe();
            if (*opType == '\0') {
                errmsg = str::stream() << "\"op\" field value cannot be empty: " << e.fieldName();
                return false;
            }

            // ns - namespace
            // Only operations of type 'n' are allowed to have an empty namespace.
            BSONElement nsElement = obj.getField("ns");
            if (nsElement.eoo()) {
                errmsg = str::stream() << "op does not contain required \"ns\" field: "
                                       << e.fieldName();
                return false;
            }
            if (nsElement.type() != mongo::String) {
                errmsg = str::stream() << "\"ns\" field is not a string: " << e.fieldName();
                return false;
            }
            if (*opType != 'n' && nsElement.String().empty()) {
                errmsg = str::stream()
                    << "\"ns\" field value cannot be empty when op type is not 'n': "
                    << e.fieldName();
                return false;
            }
            return true;
        }
intrusive_ptr<DocumentSource> DocumentSourceGroup::createFromBson(
    BSONElement elem, const intrusive_ptr<ExpressionContext>& pExpCtx) {
    uassert(15947, "a group's fields must be specified in an object", elem.type() == Object);

    intrusive_ptr<DocumentSourceGroup> pGroup(DocumentSourceGroup::create(pExpCtx));

    BSONObj groupObj(elem.Obj());
    BSONObjIterator groupIterator(groupObj);
    VariablesIdGenerator idGenerator;
    VariablesParseState vps(&idGenerator);
    while (groupIterator.more()) {
        BSONElement groupField(groupIterator.next());
        const char* pFieldName = groupField.fieldName();

        if (str::equals(pFieldName, "_id")) {
            uassert(
                15948, "a group's _id may only be specified once", pGroup->_idExpressions.empty());
            pGroup->parseIdExpression(groupField, vps);
            invariant(!pGroup->_idExpressions.empty());
        } else if (str::equals(pFieldName, "$doingMerge")) {
            massert(17030, "$doingMerge should be true if present", groupField.Bool());

            pGroup->setDoingMerge(true);
        } else {
            /*
              Treat as a projection field with the additional ability to
              add aggregation operators.
            */
            auto parsedAccumulator = Accumulator::parseAccumulator(groupField, vps);
            auto fieldName = parsedAccumulator.first.toString();
            auto accExpression = parsedAccumulator.second;
            auto factory =
                Accumulator::getFactory(groupField.embeddedObject().firstElementFieldName());

            pGroup->addAccumulator(fieldName, factory, accExpression);
        }
    }

    uassert(15955, "a group specification must include an _id", !pGroup->_idExpressions.empty());

    pGroup->_variables.reset(new Variables(idGenerator.getIdCount()));

    return pGroup;
}
intrusive_ptr<DocumentSource> DocumentSourceCollStats::createFromBson(
    BSONElement specElem, const intrusive_ptr<ExpressionContext>& pExpCtx) {
    uassert(40166,
            str::stream() << "$collStats must take a nested object but found: " << specElem,
            specElem.type() == BSONType::Object);
    intrusive_ptr<DocumentSourceCollStats> collStats(new DocumentSourceCollStats(pExpCtx));

    for (const auto& elem : specElem.embeddedObject()) {
        StringData fieldName = elem.fieldNameStringData();

        if ("latencyStats" == fieldName) {
            uassert(40167,
                    str::stream() << "latencyStats argument must be an object, but got " << elem
                                  << " of type "
                                  << typeName(elem.type()),
                    elem.type() == BSONType::Object);
            if (!elem["histograms"].eoo()) {
                uassert(40305,
                        str::stream() << "histograms option to latencyStats must be bool, got "
                                      << elem
                                      << "of type "
                                      << typeName(elem.type()),
                        elem["histograms"].isBoolean());
            }
        } else if ("storageStats" == fieldName) {
            uassert(40279,
                    str::stream() << "storageStats argument must be an object, but got " << elem
                                  << " of type "
                                  << typeName(elem.type()),
                    elem.type() == BSONType::Object);
        } else if ("count" == fieldName) {
            uassert(40480,
                    str::stream() << "count argument must be an object, but got " << elem
                                  << " of type "
                                  << typeName(elem.type()),
                    elem.type() == BSONType::Object);
        } else {
            uasserted(40168, str::stream() << "unrecognized option to $collStats: " << fieldName);
        }
    }

    collStats->_collStatsSpec = specElem.Obj().getOwned();
    return collStats;
}
Beispiel #19
0
    void WriteResult::_createUpsert(const BSONElement& upsert, const std::vector<WriteOperation*>& ops) {
        int batchIndex = 0;
        BSONElement id;

        if (upsert.isABSONObj()) {
            // Upsert result came from MongoDB 2.6+
            batchIndex = _getIntOrDefault(upsert.Obj(), "index");
            id = upsert["_id"];
        } else {
            // Upsert result came from MongoDB <2.6
            id = upsert;
        }

        BSONObjBuilder bob;
        bob.append("index", static_cast<long long>(ops[batchIndex]->getBulkIndex()));
        bob.appendAs(id, "_id");

        _upserted.push_back(bob.obj());
    }
/*
 * Recurses over all fields of an obj (document in collection)
 *    and fills term,score map term_freqs
 * @param tokenizer, tokenizer to tokenize a string into terms
 * @param obj, object being parsed
 * term_freqs, map <term,score> to be filled up
 */
void FTSSpec::_scoreRecurseV1(const Tools& tools,
                              const BSONObj& obj,
                              TermFrequencyMap* term_freqs) const {
    BSONObjIterator j(obj);
    while (j.more()) {
        BSONElement x = j.next();

        if (languageOverrideField() == x.fieldName())
            continue;

        if (x.type() == String) {
            double w = 1;
            _weightV1(x.fieldName(), &w);
            _scoreStringV1(tools, x.valuestr(), term_freqs, w);
        } else if (x.isABSONObj()) {
            _scoreRecurseV1(tools, x.Obj(), term_freqs);
        }
    }
}
Beispiel #21
0
StatusWith<WriteConcernOptions> extractWriteConcern(const BSONObj& cmdObj,
                                                    const std::string& dbName) {
    // The default write concern if empty is w : 1
    // Specifying w : 0 is/was allowed, but is interpreted identically to w : 1
    WriteConcernOptions writeConcern =
        repl::getGlobalReplicationCoordinator()->getGetLastErrorDefault();
    if (writeConcern.wNumNodes == 0 && writeConcern.wMode.empty()) {
        writeConcern.wNumNodes = 1;
    }
    // Upgrade default write concern if necessary.
    addJournalSyncForWMajority(&writeConcern);

    BSONElement writeConcernElement;
    Status wcStatus = bsonExtractTypedField(cmdObj, "writeConcern", Object, &writeConcernElement);
    if (!wcStatus.isOK()) {
        if (wcStatus == ErrorCodes::NoSuchKey) {
            // Return default write concern if no write concern is given.
            return writeConcern;
        }
        return wcStatus;
    }

    BSONObj writeConcernObj = writeConcernElement.Obj();
    // Empty write concern is interpreted to default.
    if (writeConcernObj.isEmpty()) {
        return writeConcern;
    }

    wcStatus = writeConcern.parse(writeConcernObj);
    if (!wcStatus.isOK()) {
        return wcStatus;
    }

    wcStatus = validateWriteConcern(writeConcern, dbName);
    if (!wcStatus.isOK()) {
        return wcStatus;
    }

    // Upgrade parsed write concern if necessary.
    addJournalSyncForWMajority(&writeConcern);

    return writeConcern;
}
Status ReadAfterOpTimeArgs::initialize(const BSONObj& cmdObj) {
    auto afterElem = cmdObj[ReadAfterOpTimeArgs::kRootFieldName];

    if (afterElem.eoo()) {
        return Status::OK();
    }

    if (!afterElem.isABSONObj()) {
        return Status(ErrorCodes::FailedToParse, "'after' field should be an object");
    }

    BSONObj readAfterObj = afterElem.Obj();
    BSONElement opTimeElem;
    auto opTimeStatus = bsonExtractTypedField(
        readAfterObj, ReadAfterOpTimeArgs::kOpTimeFieldName, Object, &opTimeElem);

    if (!opTimeStatus.isOK()) {
        return opTimeStatus;
    }

    BSONObj opTimeObj = opTimeElem.Obj();
    BSONElement timestampElem;

    Timestamp timestamp;
    auto timestampStatus = bsonExtractTimestampField(
        opTimeObj, ReadAfterOpTimeArgs::kOpTimestampFieldName, &timestamp);

    if (!timestampStatus.isOK()) {
        return timestampStatus;
    }

    long long termNumber;
    auto termStatus =
        bsonExtractIntegerField(opTimeObj, ReadAfterOpTimeArgs::kOpTermFieldName, &termNumber);

    if (!termStatus.isOK()) {
        return termStatus;
    }

    _opTime = OpTime(timestamp, termNumber);

    return Status::OK();
}
Status V2UserDocumentParser::initializeUserPrivilegesFromUserDocument(const BSONObj& doc,
                                                                      User* user) const {
    BSONElement privilegesElement = doc[PRIVILEGES_FIELD_NAME];
    if (privilegesElement.eoo())
        return Status::OK();
    if (privilegesElement.type() != Array) {
        return Status(ErrorCodes::UnsupportedFormat,
                      "User document 'inheritedPrivileges' element must be Array if present.");
    }
    PrivilegeVector privileges;
    std::string errmsg;
    for (BSONObjIterator it(privilegesElement.Obj()); it.more(); it.next()) {
        if ((*it).type() != Object) {
            warning() << "Wrong type of element in inheritedPrivileges array for "
                      << user->getName() << ": " << *it;
            continue;
        }
        Privilege privilege;
        ParsedPrivilege pp;
        if (!pp.parseBSON((*it).Obj(), &errmsg)) {
            warning() << "Could not parse privilege element in user document for "
                      << user->getName() << ": " << errmsg;
            continue;
        }
        std::vector<std::string> unrecognizedActions;
        Status status =
            ParsedPrivilege::parsedPrivilegeToPrivilege(pp, &privilege, &unrecognizedActions);
        if (!status.isOK()) {
            warning() << "Could not parse privilege element in user document for "
                      << user->getName() << causedBy(status);
            continue;
        }
        if (unrecognizedActions.size()) {
            std::string unrecognizedActionsString;
            joinStringDelim(unrecognizedActions, &unrecognizedActionsString, ',');
            warning() << "Encountered unrecognized actions \" " << unrecognizedActionsString
                      << "\" while parsing user document for " << user->getName();
        }
        privileges.push_back(privilege);
    }
    user->setPrivileges(privileges);
    return Status::OK();
}
Beispiel #24
0
StatusWith<ChunkVersion> ChunkVersion::parseFromBSONWithFieldForCommands(const BSONObj& obj,
                                                                         StringData field) {
    BSONElement versionElem;
    Status status = bsonExtractField(obj, field, &versionElem);
    if (!status.isOK())
        return status;

    if (versionElem.type() != Array) {
        return {ErrorCodes::TypeMismatch,
                str::stream() << "Invalid type " << versionElem.type()
                              << " for shardVersion element. Expected an array"};
    }

    BSONObjIterator it(versionElem.Obj());
    if (!it.more())
        return {ErrorCodes::BadValue, "Unexpected empty version"};

    ChunkVersion version;

    // Expect the timestamp
    {
        BSONElement tsPart = it.next();
        if (tsPart.type() != bsonTimestamp)
            return {ErrorCodes::TypeMismatch,
                    str::stream() << "Invalid type " << tsPart.type()
                                  << " for version timestamp part."};

        version._combined = tsPart.timestamp().asULL();
    }

    // Expect the epoch OID
    {
        BSONElement epochPart = it.next();
        if (epochPart.type() != jstOID)
            return {ErrorCodes::TypeMismatch,
                    str::stream() << "Invalid type " << epochPart.type()
                                  << " for version epoch part."};

        version._epoch = epochPart.OID();
    }

    return version;
}
Beispiel #25
0
    static void fixQuery( BSONObjBuilder& b  , const BSONObj& obj ) {
        BSONObjIterator i( obj );
        while ( i.more() ) {
            BSONElement e = i.next();
            
            if ( e.type() != Object ) {
                b.append( e );
                continue;
            }

            BSONObj sub = e.Obj();
            if ( sub.firstElement().fieldName()[0] != '#' ) {
                b.append( e );
                continue;
            }
            
            _fixField( b , e );
        }
    }
Status CurrentDateNode::init(BSONElement modExpr,
                             const boost::intrusive_ptr<ExpressionContext>& expCtx) {
    invariant(modExpr.ok());

    if (modExpr.type() == BSONType::Bool) {
        _typeIsDate = true;
    } else if (modExpr.type() == BSONType::Object) {
        auto foundValidType = false;
        for (auto&& elem : modExpr.Obj()) {
            if (elem.fieldNameStringData() == kType) {
                if (elem.type() == BSONType::String) {
                    if (elem.valueStringData() == kDate) {
                        _typeIsDate = true;
                        foundValidType = true;
                    } else if (elem.valueStringData() == kTimestamp) {
                        _typeIsDate = false;
                        foundValidType = true;
                    }
                }
            } else {
                return Status(ErrorCodes::BadValue,
                              str::stream() << "Unrecognized $currentDate option: "
                                            << elem.fieldNameStringData());
            }
        }

        if (!foundValidType) {
            return Status(ErrorCodes::BadValue,
                          "The '$type' string field is required "
                          "to be 'date' or 'timestamp': "
                          "{$currentDate: {field : {$type: 'date'}}}");
        }
    } else {
        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();
}
    /**
     * Takes a BSONArray of name,source pair documents, parses that array and returns (via the
     * output param parsedRoleNames) a list of the role names in the input array.
     * Also validates the input array and returns a non-OK status if there is anything wrong.
     */
    Status _extractRoleNamesFromBSONArray(const BSONArray rolesArray,
                                         const std::string& dbname,
                                         AuthorizationManager* authzManager,
                                         std::vector<RoleName>* parsedRoleNames) {
        for (BSONObjIterator it(rolesArray); it.more(); it.next()) {
            BSONElement element = *it;
            if (element.type() == String) {
                RoleName roleName(element.String(), dbname);
                if (!authzManager->roleExists(roleName)) {
                    return Status(ErrorCodes::RoleNotFound,
                                  mongoutils::str::stream() << roleName.getFullName() <<
                                          " does not name an existing role");
                }
                parsedRoleNames->push_back(roleName);
            } else if (element.type() == Object) {
                BSONObj roleObj = element.Obj();

                std::string roleNameString;
                std::string roleSource;
                Status status = bsonExtractStringField(roleObj, "name", &roleNameString);
                if (!status.isOK()) {
                    return status;
                }
                status = bsonExtractStringField(roleObj, "source", &roleSource);
                if (!status.isOK()) {
                    return status;
                }

                RoleName roleName(roleNameString, roleSource);
                if (!authzManager->roleExists(roleName)) {
                    return Status(ErrorCodes::RoleNotFound,
                                  mongoutils::str::stream() << roleName.getFullName() <<
                                          " does not name an existing role");
                }
                parsedRoleNames->push_back(roleName);
            } else {
                return Status(ErrorCodes::UnsupportedFormat,
                              "Values in 'roles' array must be sub-documents or strings");
            }
        }
        return Status::OK();
    }
Status parseAndValidateRolePrivilegeManipulationCommands(const BSONObj& cmdObj,
                                                         StringData cmdName,
                                                         const std::string& dbname,
                                                         RoleName* parsedRoleName,
                                                         PrivilegeVector* parsedPrivileges) {
    unordered_set<std::string> validFieldNames;
    validFieldNames.insert(cmdName.toString());
    validFieldNames.insert("privileges");

    Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames);
    if (!status.isOK()) {
        return status;
    }

    BSONObjBuilder roleObjBuilder;

    // Parse role name
    std::string roleName;
    status = bsonExtractStringField(cmdObj, cmdName, &roleName);
    if (!status.isOK()) {
        return status;
    }
    *parsedRoleName = RoleName(roleName, dbname);

    // Parse privileges
    BSONElement privilegesElement;
    status = bsonExtractTypedField(cmdObj, "privileges", Array, &privilegesElement);
    if (!status.isOK()) {
        return status;
    }
    status = parseAndValidatePrivilegeArray(BSONArray(privilegesElement.Obj()), parsedPrivileges);
    if (!status.isOK()) {
        return status;
    }
    if (!parsedPrivileges->size()) {
        return Status(ErrorCodes::BadValue,
                      mongoutils::str::stream() << cmdName << " command requires a non-empty "
                                                              "\"privileges\" array");
    }

    return Status::OK();
}
Beispiel #29
0
Status ReadConcernArgs::initialize(const BSONElement& readConcernElem) {
    if (readConcernElem.eoo()) {
        return Status::OK();
    }

    dassert(readConcernElem.fieldNameStringData() == kReadConcernFieldName);

    if (!readConcernElem.isABSONObj()) {
        return Status(ErrorCodes::FailedToParse,
                      str::stream() << kReadConcernFieldName << " field should be an object");
    }

    BSONObj readConcernObj = readConcernElem.Obj();

    if (readConcernObj.hasField(kAfterOpTimeFieldName)) {
        OpTime opTime;
        auto opTimeStatus = bsonExtractOpTimeField(readConcernObj, kAfterOpTimeFieldName, &opTime);
        if (!opTimeStatus.isOK()) {
            return opTimeStatus;
        }
        _opTime = opTime;
    }

    std::string levelString;
    auto readCommittedStatus =
        bsonExtractStringField(readConcernObj, kLevelFieldName, &levelString);
    if (readCommittedStatus.isOK()) {
        if (levelString == kLocalReadConcernStr) {
            _level = ReadConcernLevel::kLocalReadConcern;
        } else if (levelString == kMajorityReadConcernStr) {
            _level = ReadConcernLevel::kMajorityReadConcern;
        } else {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << kReadConcernFieldName << '.' << kLevelFieldName
                                        << " must be either \"local\" or \"majority\"");
        }
    } else if (readCommittedStatus != ErrorCodes::NoSuchKey) {
        return readCommittedStatus;
    }

    return Status::OK();
}
Beispiel #30
0
Status ModifierSet::init(const BSONElement& modExpr) {

    //
    // field name analysis
    //

    // Break down the field name into its 'dotted' components (aka parts) and check that
    // the field is fit for updates
    _fieldRef.parse(modExpr.fieldName());
    Status status = fieldchecker::isUpdatable(_fieldRef);
    if (! status.isOK()) {
        return status;
    }

    // If a $-positional operator was used, get the index in which it occurred.
    fieldchecker::isPositional(_fieldRef, &_posDollar);

    //
    // value analysis
    //

    // Is the target set value safe?
    switch (modExpr.type()) {

    case EOO:
        return Status(ErrorCodes::BadValue, "cannot $set an empty value");

    case Object:
    case Array:
        if (! modExpr.Obj().okForStorage()) {
            return Status(ErrorCodes::BadValue, "cannot use '$' as values");
        }
        break;

    default:
        break;
    }

    _val = modExpr;

    return Status::OK();
}