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(); }
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); }
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(); }
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); }
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(); }
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(); }
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(); }
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)); }
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(); }
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; }
/** * 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; }
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); } } }
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, ×tamp); 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(); }
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; }
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(); }
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(); }
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(); }