bool ComparisonMatchExpression::matchesSingleElement(const BSONElement& e) const { if (e.canonicalType() != _rhs.canonicalType()) { // some special cases // jstNULL and undefined are treated the same if (e.canonicalType() + _rhs.canonicalType() == 5) { return matchType() == EQ || matchType() == LTE || matchType() == GTE; } if (_rhs.type() == MaxKey || _rhs.type() == MinKey) { return matchType() != EQ; } return false; } // Special case handling for NaN. NaN is equal to NaN but // otherwise always compares to false. if (std::isnan(e.numberDouble()) || std::isnan(_rhs.numberDouble())) { bool bothNaN = std::isnan(e.numberDouble()) && std::isnan(_rhs.numberDouble()); switch (matchType()) { case LT: return false; case LTE: return bothNaN; case EQ: return bothNaN; case GT: return false; case GTE: return bothNaN; default: // This is a comparison match expression, so it must be either // a $lt, $lte, $gt, $gte, or equality expression. fassertFailed(17448); } } int x = compareElementValues(e, _rhs, _collator); switch (matchType()) { case LT: return x < 0; case LTE: return x <= 0; case EQ: return x == 0; case GT: return x > 0; case GTE: return x >= 0; default: // This is a comparison match expression, so it must be either // a $lt, $lte, $gt, $gte, or equality expression. fassertFailed(16828); } }
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = dbname + "." + cmdObj.firstElement().valuestr(); NamespaceDetails *nsd = nsdetails(ns); if (NULL == nsd) { errmsg = "can't find ns"; return false; } vector<int> idxs; nsd->findIndexByType(GEOSEARCHNAME, idxs); if (idxs.size() == 0) { errmsg = "no geoSearch index"; return false; } if (idxs.size() > 1) { errmsg = "more than 1 geosearch index"; return false; } BSONElement nearElt = cmdObj["near"]; BSONElement maxDistance = cmdObj["maxDistance"]; BSONElement search = cmdObj["search"]; uassert(13318, "near needs to be an array", nearElt.isABSONObj()); uassert(13319, "maxDistance needs a number", maxDistance.isNumber()); uassert(13320, "search needs to be an object", search.type() == Object); unsigned limit = 50; if (cmdObj["limit"].isNumber()) limit = static_cast<unsigned>(cmdObj["limit"].numberInt()); int idxNum = idxs[0]; IndexDetails& id = nsd->idx(idxNum); if (CatalogHack::testIndexMigration()) { auto_ptr<IndexDescriptor> desc(CatalogHack::getDescriptor(nsd, idxNum)); auto_ptr<HaystackAccessMethod> ham(new HaystackAccessMethod(desc.get())); ham->searchCommand(nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), &result, limit); } else { GeoHaystackSearchIndex *si = static_cast<GeoHaystackSearchIndex*>(id.getSpec().getType()); verify(&id == si->getDetails()); si->searchCommand(nsd, nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), result, limit); } return 1; }
GeoHaystackSearchIndex( const IndexPlugin* plugin , const IndexSpec* spec ) : IndexType( plugin , spec ) { BSONElement e = spec->info["bucketSize"]; uassert( 13321 , "need bucketSize" , e.isNumber() ); _bucketSize = e.numberDouble(); BSONObjBuilder orderBuilder; BSONObjIterator i( spec->keyPattern ); while ( i.more() ) { BSONElement e = i.next(); if ( e.type() == String && GEOSEARCHNAME == e.valuestr() ) { uassert( 13314 , "can't have 2 geo fields" , _geo.size() == 0 ); uassert( 13315 , "2d has to be first in index" , _other.size() == 0 ); _geo = e.fieldName(); } else { _other.push_back( e.fieldName() ); } orderBuilder.append( "" , 1 ); } uassert( 13316 , "no geo field specified" , _geo.size() ); uassert( 13317 , "no other fields specified" , _other.size() ); uassert( 13326 , "quadrant search can only have 1 other field for now" , _other.size() == 1 ); _order = orderBuilder.obj(); }
virtual Status set(const BSONElement& newValueElement) { long long newValue; if (!newValueElement.isNumber()) { StringBuilder sb; sb << "Expected number type for journalCommitInterval via setParameter command: " << newValueElement; return Status(ErrorCodes::BadValue, sb.str()); } if (newValueElement.type() == NumberDouble && (newValueElement.numberDouble() - newValueElement.numberLong()) > 0) { StringBuilder sb; sb << "journalCommitInterval must be a whole number: " << newValueElement; return Status(ErrorCodes::BadValue, sb.str()); } newValue = newValueElement.numberLong(); if (newValue <= 1 || newValue >= 500) { StringBuilder sb; sb << "journalCommitInterval must be between 1 and 500, but attempted to set to: " << newValue; return Status(ErrorCodes::BadValue, sb.str()); } storageGlobalParams.journalCommitInterval = static_cast<unsigned>(newValue); return Status::OK(); }
// static int ExpressionKeysPrivate::hashHaystackElement(const BSONElement& e, double bucketSize) { uassert(16776, "geo field is not a number", e.isNumber()); double d = e.numberDouble(); d += 180; d /= bucketSize; return static_cast<int>(d); }
void ExpressionParams::parseHaystackParams(const BSONObj& infoObj, std::string* geoFieldOut, std::vector<std::string>* otherFieldsOut, double* bucketSizeOut) { BSONElement e = infoObj["bucketSize"]; uassert(16777, "need bucketSize", e.isNumber()); *bucketSizeOut = e.numberDouble(); uassert(16769, "bucketSize cannot be zero", *bucketSizeOut != 0.0); // Example: // db.foo.ensureIndex({ pos : "geoHaystack", type : 1 }, { bucketSize : 1 }) BSONObjIterator i(infoObj.getObjectField("key")); while (i.more()) { BSONElement e = i.next(); if (e.type() == String && IndexNames::GEO_HAYSTACK == e.valuestr()) { uassert(16770, "can't have more than one geo field", geoFieldOut->size() == 0); uassert(16771, "the geo field has to be first in index", otherFieldsOut->size() == 0); *geoFieldOut = e.fieldName(); } else { uassert(16772, "geoSearch can only have 1 non-geo field for now", otherFieldsOut->size() == 0); otherFieldsOut->push_back(e.fieldName()); } } }
GeoHaystackSearchIndex(const IndexPlugin* plugin, const IndexSpec* spec) : IndexType(plugin, spec) { BSONElement e = spec->info["bucketSize"]; uassert(13321, "need bucketSize", e.isNumber()); _bucketSize = e.numberDouble(); uassert(16455, "bucketSize cannot be zero", _bucketSize != 0.0); // Example: // db.foo.ensureIndex({ pos : "geoHaystack", type : 1 }, { bucketSize : 1 }) BSONObjIterator i(spec->keyPattern); while (i.more()) { BSONElement e = i.next(); if (e.type() == String && GEOSEARCHNAME == e.valuestr()) { uassert(13314, "can't have more than one geo field", _geoField.size() == 0); uassert(13315, "the geo field has to be first in index", _otherFields.size() == 0); _geoField = e.fieldName(); } else { // TODO(hk): Do we want to do any checking on e.type and e.valuestr? uassert(13326, "geoSearch can only have 1 non-geo field for now", _otherFields.size() == 0); _otherFields.push_back(e.fieldName()); } } uassert(13316, "no geo field specified", _geoField.size()); // XXX: Fix documentation that says the other field is optional; code says it's mandatory. uassert(13317, "no non-geo fields specified", _otherFields.size()); }
// static StatusWith<BSONObj> S2AccessMethod::fixSpec(const BSONObj& specObj) { // If the spec object has the field "2dsphereIndexVersion", validate it. If it doesn't, add // {2dsphereIndexVersion: 3}, which is the default for newly-built indexes. BSONElement indexVersionElt = specObj[kIndexVersionFieldName]; if (indexVersionElt.eoo()) { BSONObjBuilder bob; bob.appendElements(specObj); bob.append(kIndexVersionFieldName, S2_INDEX_VERSION_3); return bob.obj(); } if (!indexVersionElt.isNumber()) { return {ErrorCodes::CannotCreateIndex, str::stream() << "Invalid type for geo index version { " << kIndexVersionFieldName << " : " << indexVersionElt << " }, only versions: [" << S2_INDEX_VERSION_1 << "," << S2_INDEX_VERSION_2 << "," << S2_INDEX_VERSION_3 << "] are supported"}; } if (indexVersionElt.type() == BSONType::NumberDouble && !std::isnormal(indexVersionElt.numberDouble())) { return {ErrorCodes::CannotCreateIndex, str::stream() << "Invalid value for geo index version { " << kIndexVersionFieldName << " : " << indexVersionElt << " }, only versions: [" << S2_INDEX_VERSION_1 << "," << S2_INDEX_VERSION_2 << "," << S2_INDEX_VERSION_3 << "] are supported"}; } const auto indexVersion = indexVersionElt.numberLong(); if (indexVersion != S2_INDEX_VERSION_1 && indexVersion != S2_INDEX_VERSION_2 && indexVersion != S2_INDEX_VERSION_3) { return {ErrorCodes::CannotCreateIndex, str::stream() << "unsupported geo index version { " << kIndexVersionFieldName << " : " << indexVersionElt << " }, only versions: [" << S2_INDEX_VERSION_1 << "," << S2_INDEX_VERSION_2 << "," << S2_INDEX_VERSION_3 << "] are supported"}; } return specObj; }
bool readMultiDeleteProperty(const BSONElement& limitElement) { // Using a double to avoid throwing away illegal fractional portion. Don't want to accept 0.5 // here const double limit = limitElement.numberDouble(); uassert(ErrorCodes::FailedToParse, str::stream() << "The limit field in delete objects must be 0 or 1. Got " << limit, limit == 0 || limit == 1); return limit == 0; }
bool errmsgRun(OperationContext* opCtx, const string& dbname, const BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result) { const NamespaceString nss = CommandHelpers::parseNsCollectionRequired(dbname, cmdObj); AutoGetCollectionForReadCommand ctx(opCtx, nss); // Check whether we are allowed to read from this node after acquiring our locks. auto replCoord = repl::ReplicationCoordinator::get(opCtx); uassertStatusOK(replCoord->checkCanServeReadsFor( opCtx, nss, ReadPreferenceSetting::get(opCtx).canRunOnSecondary())); Collection* collection = ctx.getCollection(); if (!collection) { errmsg = "can't find ns"; return false; } vector<IndexDescriptor*> idxs; collection->getIndexCatalog()->findIndexByType(opCtx, IndexNames::GEO_HAYSTACK, idxs); if (idxs.size() == 0) { errmsg = "no geoSearch index"; return false; } if (idxs.size() > 1) { errmsg = "more than 1 geosearch index"; return false; } BSONElement nearElt = cmdObj["near"]; BSONElement maxDistance = cmdObj["maxDistance"]; BSONElement search = cmdObj["search"]; uassert(13318, "near needs to be an array", nearElt.isABSONObj()); uassert(13319, "maxDistance needs a number", maxDistance.isNumber()); uassert(13320, "search needs to be an object", search.type() == Object); unsigned limit = 50; if (cmdObj["limit"].isNumber()) limit = static_cast<unsigned>(cmdObj["limit"].numberInt()); IndexDescriptor* desc = idxs[0]; HaystackAccessMethod* ham = static_cast<HaystackAccessMethod*>(collection->getIndexCatalog()->getIndex(desc)); ham->searchCommand(opCtx, collection, nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), &result, limit); return 1; }
bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result) { const std::string ns = parseNsCollectionRequired(dbname, cmdObj); AutoGetCollectionForRead ctx(txn, ns); Collection* collection = ctx.getCollection(); if (!collection) { errmsg = "can't find ns"; return false; } vector<IndexDescriptor*> idxs; collection->getIndexCatalog()->findIndexByType(txn, IndexNames::GEO_HAYSTACK, idxs); if (idxs.size() == 0) { errmsg = "no geoSearch index"; return false; } if (idxs.size() > 1) { errmsg = "more than 1 geosearch index"; return false; } BSONElement nearElt = cmdObj["near"]; BSONElement maxDistance = cmdObj["maxDistance"]; BSONElement search = cmdObj["search"]; uassert(13318, "near needs to be an array", nearElt.isABSONObj()); uassert(13319, "maxDistance needs a number", maxDistance.isNumber()); uassert(13320, "search needs to be an object", search.type() == Object); unsigned limit = 50; if (cmdObj["limit"].isNumber()) limit = static_cast<unsigned>(cmdObj["limit"].numberInt()); IndexDescriptor* desc = idxs[0]; HaystackAccessMethod* ham = static_cast<HaystackAccessMethod*>(collection->getIndexCatalog()->getIndex(desc)); ham->searchCommand(txn, collection, nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), &result, limit); return 1; }
Status bsonExtractDoubleField(const BSONObj& object, StringData fieldName, double* out) { BSONElement value; Status status = bsonExtractField(object, fieldName, &value); if (!status.isOK()) return status; if (!value.isNumber()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "Expected field \"" << fieldName << "\" to have numeric type, but found " << typeName(value.type())); } *out = value.numberDouble(); return Status::OK(); }
bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { const string ns = dbname + "." + cmdObj.firstElement().valuestr(); Client::ReadContext ctx(ns); Database* db = ctx.ctx().db(); if ( !db ) { errmsg = "can't find ns"; return false; } Collection* collection = db->getCollection( ns ); if ( !collection ) { errmsg = "can't find ns"; return false; } vector<IndexDescriptor*> idxs; collection->getIndexCatalog()->findIndexByType(IndexNames::GEO_HAYSTACK, idxs); if (idxs.size() == 0) { errmsg = "no geoSearch index"; return false; } if (idxs.size() > 1) { errmsg = "more than 1 geosearch index"; return false; } BSONElement nearElt = cmdObj["near"]; BSONElement maxDistance = cmdObj["maxDistance"]; BSONElement search = cmdObj["search"]; uassert(13318, "near needs to be an array", nearElt.isABSONObj()); uassert(13319, "maxDistance needs a number", maxDistance.isNumber()); uassert(13320, "search needs to be an object", search.type() == Object); unsigned limit = 50; if (cmdObj["limit"].isNumber()) limit = static_cast<unsigned>(cmdObj["limit"].numberInt()); IndexDescriptor* desc = idxs[0]; HaystackAccessMethod* ham = static_cast<HaystackAccessMethod*>( collection->getIndexCatalog()->getIndex(desc) ); ham->searchCommand(nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), &result, limit); return 1; }
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = dbname + "." + cmdObj.firstElement().valuestr(); NamespaceDetails * d = nsdetails( ns.c_str() ); if ( ! d ) { errmsg = "can't find ns"; return false; } vector<int> idxs; d->findIndexByType( GEOSEARCHNAME , idxs ); if ( idxs.size() == 0 ) { errmsg = "no geoSearch index"; return false; } if ( idxs.size() > 1 ) { errmsg = "more than 1 geosearch index"; return false; } int idxNum = idxs[0]; IndexDetails& id = d->idx( idxNum ); GeoHaystackSearchIndex * si = (GeoHaystackSearchIndex*)id.getSpec().getType(); verify( &id == si->getDetails() ); BSONElement n = cmdObj["near"]; BSONElement maxDistance = cmdObj["maxDistance"]; BSONElement search = cmdObj["search"]; uassert( 13318 , "near needs to be an array" , n.isABSONObj() ); uassert( 13319 , "maxDistance needs a number" , maxDistance.isNumber() ); uassert( 13320 , "search needs to be an object" , search.type() == Object ); unsigned limit = 50; if ( cmdObj["limit"].isNumber() ) limit = (unsigned)cmdObj["limit"].numberInt(); si->searchCommand( d , idxNum , n.Obj() , maxDistance.numberDouble() , search.Obj() , result , limit ); return 1; }
bool BitTestMatchExpression::matchesSingleElement(const BSONElement& e, MatchDetails* details) const { // Validate 'e' is a number or a BinData. if (!e.isNumber() && e.type() != BSONType::BinData) { return false; } if (e.type() == BSONType::BinData) { int eBinaryLen; // Length of eBinary (in bytes). const char* eBinary = e.binData(eBinaryLen); return performBitTest(eBinary, eBinaryLen); } invariant(e.isNumber()); if (e.type() == BSONType::NumberDouble) { double eDouble = e.numberDouble(); // NaN doubles are rejected. if (std::isnan(eDouble)) { return false; } // Integral doubles that are too large or small to be represented as a 64-bit signed // integer are treated as 0. We use 'kLongLongMaxAsDouble' because if we just did // eDouble > 2^63-1, it would be compared against 2^63. eDouble=2^63 would not get caught // that way. if (eDouble >= BSONElement::kLongLongMaxPlusOneAsDouble || eDouble < std::numeric_limits<long long>::min()) { return false; } // This checks if e is an integral double. if (eDouble != static_cast<double>(static_cast<long long>(eDouble))) { return false; } } long long eValue = e.numberLong(); return performBitTest(eValue); }
FieldParser::FieldState FieldParser::extractNumber(BSONElement elem, const BSONField<double>& field, double* out, string* errMsg) { if (elem.eoo()) { if (field.hasDefault()) { *out = field.getDefault(); return FIELD_DEFAULT; } else { return FIELD_NONE; } } if (elem.isNumber()) { *out = elem.numberDouble(); return FIELD_SET; } _genFieldErrMsg(elem, field, "number", errMsg); return FIELD_INVALID; }
Status bsonExtractIntegerField(const BSONObj& object, const StringData& fieldName, long long* out) { BSONElement value; Status status = bsonExtractField(object, fieldName, &value); if (!status.isOK()) return status; if (!value.isNumber()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "Expected field \"" << fieldName << "\" to have numeric type, but found " << typeName(value.type())); } long long result = value.safeNumberLong(); if (result != value.numberDouble()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Expected field \"" << fieldName << "\" to have a value " "exactly representable as a 64-bit integer, but found " << value); } *out = result; return Status::OK(); }
// static StatusWith<int> LiteParsedQuery::parseMaxTimeMS(const BSONElement& maxTimeMSElt) { if (!maxTimeMSElt.eoo() && !maxTimeMSElt.isNumber()) { return StatusWith<int>(ErrorCodes::BadValue, (StringBuilder() << maxTimeMSElt.fieldNameStringData() << " must be a number").str()); } long long maxTimeMSLongLong = maxTimeMSElt.safeNumberLong(); // returns 0 on EOO if (maxTimeMSLongLong < 0 || maxTimeMSLongLong > INT_MAX) { return StatusWith<int>(ErrorCodes::BadValue, (StringBuilder() << maxTimeMSElt.fieldNameStringData() << " is out of range").str()); } double maxTimeMSDouble = maxTimeMSElt.numberDouble(); if (maxTimeMSElt.type() == mongo::NumberDouble && floor(maxTimeMSDouble) != maxTimeMSDouble) { return StatusWith<int>(ErrorCodes::BadValue, (StringBuilder() << maxTimeMSElt.fieldNameStringData() << " has non-integral value").str()); } return StatusWith<int>(static_cast<int>(maxTimeMSLongLong)); }
// PD_TRACE_DECLARE_FUNCTION ( SDB__CLSSPLIT_INIT, "_rtnSplit::init" ) INT32 _rtnSplit::init ( INT32 flags, INT64 numToSkip, INT64 numToReturn, const CHAR * pMatcherBuff, const CHAR * pSelectBuff, const CHAR * pOrderByBuff, const CHAR * pHintBuff ) { INT32 rc = SDB_OK ; PD_TRACE_ENTRY ( SDB__CLSSPLIT_INIT ) ; const CHAR *pCollectionName = NULL ; const CHAR *pTargetName = NULL ; const CHAR *pSourceName = NULL ; try { BSONObj boRequest ( pMatcherBuff ) ; BSONElement beName = boRequest.getField ( CAT_COLLECTION_NAME ) ; BSONElement beTarget = boRequest.getField ( CAT_TARGET_NAME ) ; BSONElement beSplitKey = boRequest.getField ( CAT_SPLITVALUE_NAME ) ; BSONElement beSource = boRequest.getField ( CAT_SOURCE_NAME ) ; BSONElement bePercent = boRequest.getField ( CAT_SPLITPERCENT_NAME ) ; // validate collection name and read PD_CHECK ( !beName.eoo() && beName.type() == String, SDB_INVALIDARG, error, PDERROR, "Invalid collection name: %s", beName.toString().c_str() ) ; pCollectionName = beName.valuestr() ; PD_CHECK ( ossStrlen ( pCollectionName ) < DMS_COLLECTION_SPACE_NAME_SZ + DMS_COLLECTION_NAME_SZ + 1, SDB_INVALIDARG, error, PDERROR, "Collection name is too long: %s", pCollectionName ) ; ossStrncpy ( _szCollection, pCollectionName, DMS_COLLECTION_SPACE_NAME_SZ + DMS_COLLECTION_NAME_SZ + 1 ) ; // validate target name and read PD_CHECK ( !beTarget.eoo() && beTarget.type() == String, SDB_INVALIDARG, error, PDERROR, "Invalid target group name: %s", beTarget.toString().c_str() ) ; pTargetName = beTarget.valuestr() ; PD_CHECK ( ossStrlen ( pTargetName ) < OP_MAXNAMELENGTH, SDB_INVALIDARG, error, PDERROR, "target group name is too long: %s", pTargetName ) ; ossStrncpy ( _szTargetName, pTargetName, OP_MAXNAMELENGTH ) ; // validate source name and read PD_CHECK ( !beSource.eoo() && beSource.type() == String, SDB_INVALIDARG, error, PDERROR, "Invalid source group name: %s", beSource.toString().c_str() ) ; pSourceName = beSource.valuestr() ; PD_CHECK ( ossStrlen ( pSourceName ) < OP_MAXNAMELENGTH, SDB_INVALIDARG, error, PDERROR, "source group name is too long: %s", pSourceName ) ; ossStrncpy ( _szSourceName, pSourceName, OP_MAXNAMELENGTH ) ; // read split key PD_CHECK ( !beSplitKey.eoo() && beSplitKey.type() == Object, SDB_INVALIDARG, error, PDERROR, "Invalid split key: %s", beSplitKey.toString().c_str() ) ; _splitKey = beSplitKey.embeddedObject () ; // percent _percent = bePercent.numberDouble() ; } catch ( std::exception &e ) { PD_RC_CHECK ( SDB_SYS, PDERROR, "Exception handled when parsing split request: %s", e.what() ) ; } PD_TRACE4 ( SDB__CLSSPLIT_INIT, PD_PACK_STRING ( pCollectionName ), PD_PACK_STRING ( pTargetName ), PD_PACK_STRING ( pSourceName ), PD_PACK_STRING ( _splitKey.toString().c_str() ) ) ; done: PD_TRACE_EXITRC ( SDB__CLSSPLIT_INIT, rc ) ; return rc ; error: goto done ; }
INT32 _omAgentNodeMgr::_addANode( const CHAR *arg1, const CHAR *arg2, BOOLEAN needLock, BOOLEAN isModify, string *omsvc ) { INT32 rc = SDB_OK ; const CHAR *pSvcName = NULL ; const CHAR *pDBPath = NULL ; string otherCfg ; CHAR dbPath[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ; CHAR cfgPath[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ; CHAR cfgFile[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ; BOOLEAN createDBPath = FALSE ; BOOLEAN createCfgPath = FALSE ; BOOLEAN createCfgFile = FALSE ; BOOLEAN hasLock = FALSE ; try { stringstream ss ; BSONObj objArg1( arg1 ) ; BSONObjIterator it ( objArg1 ) ; while ( it.more() ) { BSONElement e = it.next() ; if ( 0 == ossStrcmp( e.fieldName(), PMD_OPTION_SVCNAME ) ) { if ( e.type() != String ) { PD_LOG( PDERROR, "Param[%s] type[%d] is not string", PMD_OPTION_SVCNAME, e.type() ) ; rc = SDB_INVALIDARG ; goto error ; } pSvcName = e.valuestrsafe() ; } else if ( 0 == ossStrcmp( e.fieldName(), PMD_OPTION_DBPATH ) ) { if ( e.type() != String ) { PD_LOG( PDERROR, "Param[%s] type[%d] is not string", PMD_OPTION_DBPATH, e.type() ) ; rc = SDB_INVALIDARG ; goto error ; } pDBPath = e.valuestrsafe() ; } else { ss << e.fieldName() << "=" ; switch( e.type() ) { case NumberDouble : ss << e.numberDouble () ; break ; case NumberInt : ss << e.numberLong () ; break ; case NumberLong : ss << e.numberInt () ; break ; case String : ss << e.valuestrsafe () ; break ; case Bool : ss << ( e.boolean() ? "TRUE" : "FALSE" ) ; break ; default : PD_LOG ( PDERROR, "Unexpected type[%d] for %s", e.type(), e.toString().c_str() ) ; rc = SDB_INVALIDARG ; goto error ; } ss << endl ; } } otherCfg = ss.str() ; } catch( std::exception &e ) { PD_LOG( PDERROR, "Occur exception: %s", e.what() ) ; rc = SDB_INVALIDARG ; goto error ; } if ( !pSvcName || !pDBPath ) { PD_LOG( PDERROR, "Param [%s] or [%s] is not config", PMD_OPTION_SVCNAME, PMD_OPTION_DBPATH ) ; rc = SDB_INVALIDARG ; goto error ; } if ( !ossGetRealPath( pDBPath, dbPath, OSS_MAX_PATHSIZE ) ) { PD_LOG( PDERROR, "Invalid db path: %s", pDBPath ) ; rc = SDB_INVALIDARG ; goto error ; } if ( needLock ) { lockBucket( pSvcName ) ; hasLock = TRUE ; } if ( isModify && !getNodeProcessInfo( pSvcName ) ) { rc = SDBCM_NODE_NOTEXISTED ; goto error ; } rc = ossAccess( dbPath, W_OK ) ; if ( SDB_PERM == rc ) { PD_LOG ( PDERROR, "Permission error for path: %s", dbPath ) ; goto error ; } else if ( SDB_FNE == rc ) { rc = ossMkdir ( dbPath, OSS_CREATE|OSS_READWRITE ) ; if ( rc ) { PD_LOG ( PDERROR, "Failed to create config file in path: %s, " "rc: %d", dbPath, rc ) ; goto error ; } createDBPath = TRUE ; } else if ( rc ) { PD_LOG ( PDERROR, "System error for access path: %s, rc: %d", dbPath, rc ) ; goto error ; } rc = utilBuildFullPath( sdbGetOMAgentOptions()->getLocalCfgPath(), pSvcName, OSS_MAX_PATHSIZE, cfgPath ) ; if ( rc ) { PD_LOG( PDERROR, "Build config path for service[%s] failed, rc: %d", pSvcName, rc ) ; goto error ; } rc = ossAccess( cfgPath, W_OK ) ; if ( SDB_PERM == rc ) { PD_LOG ( PDERROR, "Permission error for path[%s]", cfgPath ) ; goto error ; } else if ( SDB_FNE == rc ) { rc = ossMkdir ( cfgPath, OSS_CREATE|OSS_READWRITE ) ; if ( rc ) { PD_LOG ( PDERROR, "Failed to create directory: %s, rc: %d", cfgPath, rc ) ; goto error ; } createCfgPath = TRUE ; } else if ( rc ) { PD_LOG ( PDERROR, "System error for access path: %s, rc: %d", cfgPath, rc ) ; goto error ; } else if ( !isModify ) { PD_LOG ( PDERROR, "service[%s] node existed", pSvcName ) ; rc = SDBCM_NODE_EXISTED ; goto error ; } rc = utilBuildFullPath( cfgPath, PMD_DFT_CONF, OSS_MAX_PATHSIZE, cfgFile ) ; if ( rc ) { PD_LOG ( PDERROR, "Build config file for service[%s] failed, rc: %d", pSvcName, rc ) ; goto error ; } { pmdOptionsCB nodeOptions ; stringstream ss ; ss << PMD_OPTION_SVCNAME << "=" << pSvcName << endl ; ss << PMD_OPTION_DBPATH << "=" << dbPath << endl ; ss << otherCfg ; rc = utilWriteConfigFile( cfgFile, ss.str().c_str(), isModify ? FALSE : TRUE ) ; if ( rc ) { PD_LOG( PDERROR, "Write config file[%s] failed, rc: %d", cfgFile, rc ) ; goto error ; } createCfgFile = TRUE ; rc = nodeOptions.initFromFile( cfgFile, FALSE ) ; if ( rc ) { PD_LOG( PDERROR, "Extract node[%s] config failed, rc: %d", pSvcName, rc ) ; goto error ; } if ( omsvc ) { *omsvc = nodeOptions.getOMService() ; } } if ( isModify || !arg2 ) { goto done ; } try { CHAR cataCfgFile[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ; BSONObj objArg2( arg2 ) ; stringstream ss ; if ( objArg2.isEmpty() ) { goto done ; } rc = utilBuildFullPath( cfgPath, PMD_DFT_CAT, OSS_MAX_PATHSIZE, cataCfgFile ) ; if ( rc ) { PD_LOG( PDERROR, "Build cat config file failed in service[%s], " "rc: %d", pSvcName, rc ) ; goto error ; } ss << objArg2 << endl ; rc = utilWriteConfigFile( cataCfgFile, ss.str().c_str(), TRUE ) ; if ( rc ) { PD_LOG( PDERROR, "Write cat file[%s] failed in service[%s], rc: %d", cataCfgFile, pSvcName, rc ) ; goto error ; } } catch( std::exception &e ) { PD_LOG( PDERROR, "Occur exeption for extract the second args for " "service[%s]: %s", pSvcName, e.what() ) ; rc = SDB_INVALIDARG ; goto error ; } done: if ( SDB_OK == rc ) { if ( !isModify ) { addNodeProcessInfo( pSvcName ) ; PD_LOG( PDEVENT, "Add node[%s] succeed", pSvcName ) ; } else { PD_LOG( PDEVENT, "Modify node[%s] succeed", pSvcName ) ; } } if ( hasLock ) { releaseBucket( pSvcName ) ; } return rc ; error: if ( createCfgFile ) { ossDelete( cfgFile ) ; } if ( createCfgPath ) { ossDelete( cfgPath ) ; } if ( createDBPath ) { ossDelete( dbPath ) ; } goto done ; }
StatusWithMatchExpression MatchExpressionParser::_parseSubField( const BSONObj& context, const char* name, const BSONElement& e, int position, bool* stop ) { *stop = false; // TODO: these should move to getGtLtOp, or its replacement if ( mongoutils::str::equals( "$eq", e.fieldName() ) ) return _parseComparison( name, new EqualityMatchExpression(), e ); if ( mongoutils::str::equals( "$not", e.fieldName() ) ) { return _parseNot( name, e ); } int x = e.getGtLtOp(-1); switch ( x ) { case -1: return StatusWithMatchExpression( ErrorCodes::BadValue, mongoutils::str::stream() << "unknown operator: " << e.fieldName() ); case BSONObj::LT: return _parseComparison( name, new LTMatchExpression(), e ); case BSONObj::LTE: return _parseComparison( name, new LTEMatchExpression(), e ); case BSONObj::GT: return _parseComparison( name, new GTMatchExpression(), e ); case BSONObj::GTE: return _parseComparison( name, new GTEMatchExpression(), e ); case BSONObj::NE: return _parseComparison( name, new NEMatchExpression(), e ); case BSONObj::Equality: return _parseComparison( name, new EqualityMatchExpression(), e ); case BSONObj::opIN: { if ( e.type() != Array ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$in needs an array" ); std::auto_ptr<InMatchExpression> temp( new InMatchExpression() ); temp->init( name ); Status s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), e.Obj() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp.release() ); } case BSONObj::NIN: { if ( e.type() != Array ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$nin needs an array" ); std::auto_ptr<NinMatchExpression> temp( new NinMatchExpression() ); temp->init( name ); Status s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), e.Obj() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp.release() ); } case BSONObj::opSIZE: { int size = 0; if ( e.type() == String ) { // matching old odd semantics size = 0; } else if ( e.type() == NumberInt || e.type() == NumberLong ) { size = e.numberInt(); } else if ( e.type() == NumberDouble ) { if ( e.numberInt() == e.numberDouble() ) { size = e.numberInt(); } else { // old semantcs require exact numeric match // so [1,2] != 1 or 2 size = -1; } } else { return StatusWithMatchExpression( ErrorCodes::BadValue, "$size needs a number" ); } std::auto_ptr<SizeMatchExpression> temp( new SizeMatchExpression() ); Status s = temp->init( name, size ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp.release() ); } case BSONObj::opEXISTS: { if ( e.eoo() ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$exists can't be eoo" ); std::auto_ptr<ExistsMatchExpression> temp( new ExistsMatchExpression() ); Status s = temp->init( name, e.trueValue() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp.release() ); } case BSONObj::opTYPE: { if ( !e.isNumber() ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$type has to be a number" ); int type = e.numberInt(); if ( e.type() != NumberInt && type != e.number() ) type = -1; std::auto_ptr<TypeMatchExpression> temp( new TypeMatchExpression() ); Status s = temp->init( name, type ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp.release() ); } case BSONObj::opMOD: return _parseMOD( name, e ); case BSONObj::opOPTIONS: return StatusWithMatchExpression( ErrorCodes::BadValue, "$options has to be after a $regex" ); case BSONObj::opREGEX: { if ( position != 0 ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$regex has to be first" ); *stop = true; return _parseRegexDocument( name, context ); } case BSONObj::opELEM_MATCH: return _parseElemMatch( name, e ); case BSONObj::opALL: return _parseAll( name, e ); case BSONObj::opWITHIN: return expressionParserGeoCallback( name, context ); default: return StatusWithMatchExpression( ErrorCodes::BadValue, "not done" ); } }
Status ModifierPush::init(const BSONElement& modExpr, const Options& opts, bool* positional) { // // 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 // and ensure only one occurrence. size_t foundCount; bool foundDollar = fieldchecker::isPositional(_fieldRef, &_posDollar, &foundCount); if (positional) *positional = foundDollar; if (foundDollar && foundCount > 1) { return Status(ErrorCodes::BadValue, str::stream() << "Too many positional (i.e. '$') elements found in path '" << _fieldRef.dottedField() << "'"); } // // value analysis // // Are the target push values safe to store? BSONElement sliceElem; BSONElement sortElem; BSONElement positionElem; switch (modExpr.type()) { case Array: if (_pushMode == PUSH_ALL) { _eachMode = true; Status status = parseEachMode(PUSH_ALL, modExpr, &_eachElem, &sliceElem, &sortElem, &positionElem); if (!status.isOK()) { return status; } } else { _val = modExpr; } break; case Object: if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, str::stream() << "$pushAll requires an array of values " "but was given an embedded document."); } // If any known clause ($each, $slice, or $sort) is present, we'd assume // we're using the $each variation of push and would parse accodingly. _eachMode = inEachMode(modExpr); if (_eachMode) { Status status = parseEachMode(PUSH_NORMAL, modExpr, &_eachElem, &sliceElem, &sortElem, &positionElem); if (!status.isOK()) { return status; } } else { _val = modExpr; } break; default: if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, str::stream() << "$pushAll requires an array of values " "but was given an " << typeName(modExpr.type())); } _val = modExpr; break; } // Is slice present and correct? if (sliceElem.type() != EOO) { if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, "cannot use $slice in $pushAll"); } if (!sliceElem.isNumber()) { return Status(ErrorCodes::BadValue, str::stream() << "The value for $slice must " "be a numeric value not a " << typeName(sliceElem.type())); } // TODO: Cleanup and unify numbers wrt getting int32/64 bson values (from doubles) // If the value of slice is not fraction, even if it's a double, we allow it. The // reason here is that the shell will use doubles by default unless told otherwise. const double doubleVal = sliceElem.numberDouble(); if (doubleVal - static_cast<int64_t>(doubleVal) != 0) { return Status(ErrorCodes::BadValue, "The $slice value in $push cannot be fractional"); } _slice = sliceElem.numberLong(); _slicePresent = true; } // Is position present and correct? if (positionElem.type() != EOO) { if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, "cannot use $position in $pushAll"); } if (!positionElem.isNumber()) { return Status(ErrorCodes::BadValue, str::stream() << "The value for $position must " "be a positive numeric value not a " << typeName(positionElem.type())); } // TODO: Cleanup and unify numbers wrt getting int32/64 bson values (from doubles) // If the value of position is not fraction, even if it's a double, we allow it. The // reason here is that the shell will use doubles by default unless told otherwise. const double doubleVal = positionElem.numberDouble(); if (doubleVal - static_cast<int64_t>(doubleVal) != 0) { return Status(ErrorCodes::BadValue, "The $position value in $push cannot be fractional"); } if (static_cast<double>(numeric_limits<int64_t>::max()) < doubleVal) { return Status(ErrorCodes::BadValue, "The $position value in $push is too large a number."); } if (static_cast<double>(numeric_limits<int64_t>::min()) > doubleVal) { return Status(ErrorCodes::BadValue, "The $position value in $push is too small a number."); } const int64_t tempVal = positionElem.numberLong(); if (tempVal < 0) return Status(ErrorCodes::BadValue, "The $position value in $push must be positive."); _startPosition = size_t(tempVal); } // Is sort present and correct? if (sortElem.type() != EOO) { if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, "cannot use $sort in $pushAll"); } if (sortElem.type() != Object && !sortElem.isNumber()) { return Status(ErrorCodes::BadValue, "The $sort is invalid: use 1/-1 to sort the whole element, " "or {field:1/-1} to sort embedded fields"); } if (sortElem.isABSONObj()) { BSONObj sortObj = sortElem.embeddedObject(); if (sortObj.isEmpty()) { return Status(ErrorCodes::BadValue, "The $sort pattern is empty when it should be a set of fields."); } // Check if the sort pattern is sound. BSONObjIterator sortIter(sortObj); while (sortIter.more()) { BSONElement sortPatternElem = sortIter.next(); // We require either <field>: 1 or -1 for asc and desc. if (!isPatternElement(sortPatternElem)) { return Status(ErrorCodes::BadValue, "The $sort element value must be either 1 or -1"); } // All fields parts must be valid. FieldRef sortField(sortPatternElem.fieldName()); if (sortField.numParts() == 0) { return Status(ErrorCodes::BadValue, "The $sort field cannot be empty"); } for (size_t i = 0; i < sortField.numParts(); i++) { if (sortField.getPart(i).size() == 0) { return Status(ErrorCodes::BadValue, str::stream() << "The $sort field is a dotted field " "but has an empty part: " << sortField.dottedField()); } } } _sort = PatternElementCmp(sortElem.embeddedObject()); } else { // Ensure the sortElem number is valid. if (!isPatternElement(sortElem)) { return Status(ErrorCodes::BadValue, "The $sort element value must be either 1 or -1"); } _sort = PatternElementCmp(BSON("" << sortElem.number())); } _sortPresent = true; } return Status::OK(); }
static double fieldWithDefault(const BSONObj& infoObj, const string& name, double def) { BSONElement e = infoObj[name]; if (e.isNumber()) { return e.numberDouble(); } return def; }
StatusWithMatchExpression MatchExpressionParser::_parseSubField( const BSONObj& context, const AndMatchExpression* andSoFar, const char* name, const BSONElement& e ) { // TODO: these should move to getGtLtOp, or its replacement if ( mongoutils::str::equals( "$eq", e.fieldName() ) ) return _parseComparison( name, new EqualityMatchExpression(), e ); if ( mongoutils::str::equals( "$not", e.fieldName() ) ) { return _parseNot( name, e ); } int x = e.getGtLtOp(-1); switch ( x ) { case -1: return StatusWithMatchExpression( ErrorCodes::BadValue, mongoutils::str::stream() << "unknown operator: " << e.fieldName() ); case BSONObj::LT: return _parseComparison( name, new LTMatchExpression(), e ); case BSONObj::LTE: return _parseComparison( name, new LTEMatchExpression(), e ); case BSONObj::GT: return _parseComparison( name, new GTMatchExpression(), e ); case BSONObj::GTE: return _parseComparison( name, new GTEMatchExpression(), e ); case BSONObj::NE: { StatusWithMatchExpression s = _parseComparison( name, new EqualityMatchExpression(), e ); if ( !s.isOK() ) return s; std::auto_ptr<NotMatchExpression> n( new NotMatchExpression() ); Status s2 = n->init( s.getValue() ); if ( !s2.isOK() ) return StatusWithMatchExpression( s2 ); return StatusWithMatchExpression( n.release() ); } case BSONObj::Equality: return _parseComparison( name, new EqualityMatchExpression(), e ); case BSONObj::opIN: { if ( e.type() != Array ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$in needs an array" ); std::auto_ptr<InMatchExpression> temp( new InMatchExpression() ); Status s = temp->init( name ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), e.Obj() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp.release() ); } case BSONObj::NIN: { if ( e.type() != Array ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$nin needs an array" ); std::auto_ptr<InMatchExpression> temp( new InMatchExpression() ); Status s = temp->init( name ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), e.Obj() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); std::auto_ptr<NotMatchExpression> temp2( new NotMatchExpression() ); s = temp2->init( temp.release() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp2.release() ); } case BSONObj::opSIZE: { int size = 0; if ( e.type() == String ) { // matching old odd semantics size = 0; } else if ( e.type() == NumberInt || e.type() == NumberLong ) { if (e.numberLong() < 0) { // SERVER-11952. Setting 'size' to -1 means that no documents // should match this $size expression. size = -1; } else { size = e.numberInt(); } } else if ( e.type() == NumberDouble ) { if ( e.numberInt() == e.numberDouble() ) { size = e.numberInt(); } else { // old semantcs require exact numeric match // so [1,2] != 1 or 2 size = -1; } } else { return StatusWithMatchExpression( ErrorCodes::BadValue, "$size needs a number" ); } std::auto_ptr<SizeMatchExpression> temp( new SizeMatchExpression() ); Status s = temp->init( name, size ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp.release() ); } case BSONObj::opEXISTS: { if ( e.eoo() ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$exists can't be eoo" ); std::auto_ptr<ExistsMatchExpression> temp( new ExistsMatchExpression() ); Status s = temp->init( name ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); if ( e.trueValue() ) return StatusWithMatchExpression( temp.release() ); std::auto_ptr<NotMatchExpression> temp2( new NotMatchExpression() ); s = temp2->init( temp.release() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp2.release() ); } case BSONObj::opTYPE: { if ( !e.isNumber() ) return StatusWithMatchExpression( ErrorCodes::BadValue, "$type has to be a number" ); int type = e.numberInt(); if ( e.type() != NumberInt && type != e.number() ) type = -1; std::auto_ptr<TypeMatchExpression> temp( new TypeMatchExpression() ); Status s = temp->init( name, type ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( temp.release() ); } case BSONObj::opMOD: return _parseMOD( name, e ); case BSONObj::opOPTIONS: { // TODO: try to optimize this // we have to do this since $options can be before or after a $regex // but we validate here BSONObjIterator i( context ); while ( i.more() ) { BSONElement temp = i.next(); if ( temp.getGtLtOp( -1 ) == BSONObj::opREGEX ) return StatusWithMatchExpression( NULL ); } return StatusWithMatchExpression( ErrorCodes::BadValue, "$options needs a $regex" ); } case BSONObj::opREGEX: { return _parseRegexDocument( name, context ); } case BSONObj::opELEM_MATCH: return _parseElemMatch( name, e ); case BSONObj::opALL: return _parseAll( name, e ); case BSONObj::opWITHIN: case BSONObj::opGEO_INTERSECTS: return expressionParserGeoCallback( name, x, context ); } return StatusWithMatchExpression( ErrorCodes::BadValue, mongoutils::str::stream() << "not handled: " << e.fieldName() ); }
Status MemberConfig::initialize(const BSONObj& mcfg, ReplicaSetTagConfig* tagConfig) { Status status = bsonCheckOnlyHasFields( "replica set member configuration", mcfg, kLegalMemberConfigFieldNames); if (!status.isOK()) return status; // // Parse _id field. // BSONElement idElement = mcfg[kIdFieldName]; if (idElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << kIdFieldName << " field is missing"); } if (!idElement.isNumber()) { return Status(ErrorCodes::TypeMismatch, str::stream() << kIdFieldName << " field has non-numeric type " << typeName(idElement.type())); } _id = idElement.numberInt(); // // Parse h field. // std::string hostAndPortString; status = bsonExtractStringField(mcfg, kHostFieldName, &hostAndPortString); if (!status.isOK()) return status; boost::trim(hostAndPortString); status = _host.initialize(hostAndPortString); if (!status.isOK()) return status; if (!_host.hasPort()) { // make port explicit even if default. _host = HostAndPort(_host.host(), _host.port()); } // // Parse votes field. // BSONElement votesElement = mcfg[kVotesFieldName]; int votes; if (votesElement.eoo()) { votes = kVotesFieldDefault; } else if (votesElement.isNumber()) { votes = votesElement.numberInt(); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << kVotesFieldName << " field value has non-numeric type " << typeName(votesElement.type())); } if (votes != 0 && votes != 1) { return Status(ErrorCodes::BadValue, str::stream() << kVotesFieldName << " field value is " << votesElement.numberInt() << " but must be 0 or 1"); } _isVoter = bool(votes); // // Parse priority field. // BSONElement priorityElement = mcfg[kPriorityFieldName]; if (priorityElement.eoo()) { _priority = kPriorityFieldDefault; } else if (priorityElement.isNumber()) { _priority = priorityElement.numberDouble(); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << kPriorityFieldName << " field has non-numeric type " << typeName(priorityElement.type())); } // // Parse arbiterOnly field. // status = bsonExtractBooleanFieldWithDefault(mcfg, kArbiterOnlyFieldName, kArbiterOnlyFieldDefault, &_arbiterOnly); if (!status.isOK()) return status; // // Parse slaveDelay field. // BSONElement slaveDelayElement = mcfg[kSlaveDelayFieldName]; if (slaveDelayElement.eoo()) { _slaveDelay = kSlaveDelayFieldDefault; } else if (slaveDelayElement.isNumber()) { _slaveDelay = Seconds(slaveDelayElement.numberInt()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << kSlaveDelayFieldName << " field value has non-numeric type " << typeName(slaveDelayElement.type())); } // // Parse hidden field. // status = bsonExtractBooleanFieldWithDefault(mcfg, kHiddenFieldName, kHiddenFieldDefault, &_hidden); if (!status.isOK()) return status; // // Parse buildIndexes field. // status = bsonExtractBooleanFieldWithDefault(mcfg, kBuildIndexesFieldName, kBuildIndexesFieldDefault, &_buildIndexes); if (!status.isOK()) return status; // // Parse "tags" field. // _tags.clear(); BSONElement tagsElement; status = bsonExtractTypedField(mcfg, kTagsFieldName, Object, &tagsElement); if (status.isOK()) { for (BSONObj::iterator tagIter(tagsElement.Obj()); tagIter.more();) { const BSONElement& tag = tagIter.next(); if (tag.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "tags." << tag.fieldName() << " field has non-string value of type " << typeName(tag.type())); } _tags.push_back(tagConfig->makeTag(tag.fieldNameStringData(), tag.valueStringData())); } } else if (ErrorCodes::NoSuchKey != status) { return status; } return Status::OK(); }
Status ModifierPush::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 // and ensure only one occurrence. size_t foundCount; bool foundDollar = fieldchecker::isPositional(_fieldRef, &_posDollar, &foundCount); if (foundDollar && foundCount > 1) { return Status(ErrorCodes::BadValue, "too many positional($) elements found."); } // // value analysis // // Are the target push values safe to store? BSONElement sliceElem; BSONElement sortElem; switch (modExpr.type()) { case Array: if (! modExpr.Obj().okForStorage()) { return Status(ErrorCodes::BadValue, "cannot use '$' or '.' as values"); } if (_pushMode == PUSH_ALL) { _eachMode = true; Status status = parseEachMode(PUSH_ALL, modExpr, &_eachElem, &sliceElem, &sortElem); if (!status.isOK()) { return status; } } else { _val = modExpr; } break; case Object: if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, "$pushAll requires an array of values"); } // If any known clause ($each, $slice, or $sort) is present, we'd assume // we're using the $each variation of push and would parse accodingly. _eachMode = inEachMode(modExpr); if (_eachMode) { Status status = parseEachMode(PUSH_NORMAL, modExpr, &_eachElem, &sliceElem, &sortElem); if (!status.isOK()) { return status; } } else { if (! modExpr.Obj().okForStorage()) { return Status(ErrorCodes::BadValue, "cannot use '$' as values"); } _val = modExpr; } break; default: if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, "$pushAll requires an array of values"); } _val = modExpr; break; } // Is slice present and correct? if (sliceElem.type() != EOO) { if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, "cannot use $slice in $pushAll"); } if (!sliceElem.isNumber()) { return Status(ErrorCodes::BadValue, "$slice must be a numeric value"); } // If the value of slice is not fraction, even if it's a double, we allow it. The // reason here is that the shell will use doubles by default unless told otherwise. double fractional = sliceElem.numberDouble(); if (fractional - static_cast<int64_t>(fractional) != 0) { return Status(ErrorCodes::BadValue, "$slice in $push cannot be fractional"); } _slice = sliceElem.numberLong(); if (_slice > 0) { return Status(ErrorCodes::BadValue, "$slice in $push must be zero or negative"); } _slicePresent = true; } // Is sort present and correct? if (sortElem.type() != EOO) { if (_pushMode == PUSH_ALL) { return Status(ErrorCodes::BadValue, "cannot use $sort in $pushAll"); } if (!_slicePresent) { return Status(ErrorCodes::BadValue, "$sort requires $slice to be present"); } else if (sortElem.type() != Object) { return Status(ErrorCodes::BadValue, "invalid $sort clause"); } BSONObj sortObj = sortElem.embeddedObject(); if (sortObj.isEmpty()) { return Status(ErrorCodes::BadValue, "sort parttern is empty"); } // Check if the sort pattern is sound. BSONObjIterator sortIter(sortObj); while (sortIter.more()) { BSONElement sortPatternElem = sortIter.next(); // We require either <field>: 1 or -1 for asc and desc. if (!isPatternElement(sortPatternElem)) { return Status(ErrorCodes::BadValue, "$sort elements' must be either 1 or -1"); } // All fields parts must be valid. FieldRef sortField; sortField.parse(sortPatternElem.fieldName()); if (sortField.numParts() == 0) { return Status(ErrorCodes::BadValue, "$sort field cannot be empty"); } for (size_t i = 0; i < sortField.numParts(); i++) { if (sortField.getPart(i).size() == 0) { return Status(ErrorCodes::BadValue, "empty field in dotted sort pattern"); } } } _sort = PatternElementCmp(sortElem.embeddedObject()); _sortPresent = true; } return Status::OK(); }
void BSONComparatorInterfaceBase<T>::hashCombineBSONElement( size_t& hash, BSONElement elemToHash, bool considerFieldName, const StringData::ComparatorInterface* stringComparator) { boost::hash_combine(hash, elemToHash.canonicalType()); const StringData fieldName = elemToHash.fieldNameStringData(); if (considerFieldName && !fieldName.empty()) { SimpleStringDataComparator::kInstance.hash_combine(hash, fieldName); } switch (elemToHash.type()) { // Order of types is the same as in compareElementValues(). case mongo::EOO: case mongo::Undefined: case mongo::jstNULL: case mongo::MaxKey: case mongo::MinKey: // These are valueless types break; case mongo::Bool: boost::hash_combine(hash, elemToHash.boolean()); break; case mongo::bsonTimestamp: boost::hash_combine(hash, elemToHash.timestamp().asULL()); break; case mongo::Date: boost::hash_combine(hash, elemToHash.date().asInt64()); break; case mongo::NumberDecimal: { const Decimal128 dcml = elemToHash.numberDecimal(); if (dcml.toAbs().isGreater(Decimal128(std::numeric_limits<double>::max(), Decimal128::kRoundTo34Digits, Decimal128::kRoundTowardZero)) && !dcml.isInfinite() && !dcml.isNaN()) { // Normalize our decimal to force equivalent decimals // in the same cohort to hash to the same value Decimal128 dcmlNorm(dcml.normalize()); boost::hash_combine(hash, dcmlNorm.getValue().low64); boost::hash_combine(hash, dcmlNorm.getValue().high64); break; } // Else, fall through and convert the decimal to a double and hash. // At this point the decimal fits into the range of doubles, is infinity, or is NaN, // which doubles have a cheaper representation for. } case mongo::NumberDouble: case mongo::NumberLong: case mongo::NumberInt: { // This converts all numbers to doubles, which ignores the low-order bits of // NumberLongs > 2**53 and precise decimal numbers without double representations, // but that is ok since the hash will still be the same for equal numbers and is // still likely to be different for different numbers. (Note: this issue only // applies for decimals when they are outside of the valid double range. See // the above case.) // SERVER-16851 const double dbl = elemToHash.numberDouble(); if (std::isnan(dbl)) { boost::hash_combine(hash, std::numeric_limits<double>::quiet_NaN()); } else { boost::hash_combine(hash, dbl); } break; } case mongo::jstOID: elemToHash.__oid().hash_combine(hash); break; case mongo::String: { if (stringComparator) { stringComparator->hash_combine(hash, elemToHash.valueStringData()); } else { SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.valueStringData()); } break; } case mongo::Code: case mongo::Symbol: SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.valueStringData()); break; case mongo::Object: case mongo::Array: hashCombineBSONObj(hash, elemToHash.embeddedObject(), true, // considerFieldName stringComparator); break; case mongo::DBRef: case mongo::BinData: // All bytes of the value are required to be identical. SimpleStringDataComparator::kInstance.hash_combine( hash, StringData(elemToHash.value(), elemToHash.valuesize())); break; case mongo::RegEx: SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.regex()); SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.regexFlags()); break; case mongo::CodeWScope: { SimpleStringDataComparator::kInstance.hash_combine( hash, StringData(elemToHash.codeWScopeCode(), elemToHash.codeWScopeCodeLen())); hashCombineBSONObj(hash, elemToHash.codeWScopeObject(), true, // considerFieldName &SimpleStringDataComparator::kInstance); break; } } }
static double configValueWithDefault(const IndexDescriptor *desc, const string& name, double def) { BSONElement e = desc->getInfoElement(name); if (e.isNumber()) { return e.numberDouble(); } return def; }
void _sptInvoker::_reportError( JSContext *cx, INT32 rc, const bson::BSONObj &detail ) { sdbSetErrno( rc ) ; if ( SDB_OK != rc ) { stringstream ss ; BSONObjIterator itr( detail) ; INT32 fieldNum = detail.nFields() ; INT32 count = 0 ; while ( itr.more() ) { if ( count > 0 ) { ss << ", " ; } BSONElement e = itr.next() ; if ( fieldNum > 1 || 0 != ossStrcmp( SPT_ERR, e.fieldName() ) ) { ss << e.fieldName() << ": " ; } if ( String == e.type() ) { ss << e.valuestr() ; } else if ( NumberInt == e.type() ) { ss << e.numberInt() ; } else if ( NumberLong == e.type() ) { ss << e.numberLong() ; } else if ( NumberDouble == e.type() ) { ss << e.numberDouble() ; } else if ( Bool == e.type() ) { ss << ( e.boolean() ? "true" : "false" ) ; } else { ss << e.toString( false, false ) ; } ++count ; } sdbSetErrMsg( ss.str().c_str() ) ; if ( sdbIsErrMsgEmpty() ) { sdbSetErrMsg( getErrDesp( rc ) ) ; } JS_SetPendingException( cx , INT_TO_JSVAL( rc ) ) ; } else { sdbSetErrMsg( NULL ) ; } return ; }
int hash( const BSONElement& e ) const { uassert( 13322 , "not a number" , e.isNumber() ); return hash( e.numberDouble() ); }