const CHAR* _omAgentNodeMgr::_getSvcNameFromArg( const CHAR * arg ) { const CHAR *pSvcName = NULL ; try { BSONObj objArg1( arg ) ; BSONElement e = objArg1.getField( PMD_OPTION_SVCNAME ) ; if ( e.type() != String ) { PD_LOG( PDERROR, "Param[%s] type[%s] error: %s", PMD_OPTION_SVCNAME, e.type(), e.toString().c_str() ) ; goto error ; } pSvcName = e.valuestrsafe() ; } catch( std::exception &e ) { PD_LOG( PDERROR, "Ocuur exception: %s", e.what() ) ; goto error ; } done: return pSvcName ; error: goto done ; }
int64_t WiredTigerUtil::getIdentSize(WT_SESSION* s, const std::string& uri ) { BSONObjBuilder b; Status status = WiredTigerUtil::exportTableToBSON(s, "statistics:" + uri, "statistics=(fast)", &b); if ( !status.isOK() ) { if ( status.code() == ErrorCodes::CursorNotFound ) { // ident gone, so its 0 return 0; } uassertStatusOK( status ); } BSONObj obj = b.obj(); BSONObj sub = obj["block-manager"].Obj(); BSONElement e = sub["file size in bytes"]; invariant( e.type() ); if ( e.isNumber() ) return e.safeNumberLong(); return strtoull( e.valuestrsafe(), NULL, 10 ); }
void CollectionShardingState::onDeleteOp(OperationContext* txn, const CollectionShardingState::DeleteState& deleteState) { dassert(txn->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_IX)); if (txn->writesAreReplicated() && serverGlobalParams.clusterRole == ClusterRole::ShardServer && _nss == NamespaceString::kConfigCollectionNamespace) { if (auto idElem = deleteState.idDoc["_id"]) { uassert(40070, "cannot delete shardIdentity document while in --shardsvr mode", idElem.str() != ShardIdentityType::IdName); } } // For backwards compatibility, cancel a pending asynchronous addShard task created on the // primary config as a result of a 3.2 mongos doing addShard for the shard with id // deletedDocId. if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer && _nss == ShardType::ConfigNS) { BSONElement idElement = deleteState.idDoc["_id"]; invariant(!idElement.eoo()); auto shardIdStr = idElement.valuestrsafe(); txn->recoveryUnit()->registerChange( new RemoveShardLogOpHandler(txn, ShardId(std::move(shardIdStr)))); } checkShardVersionOrThrow(txn); if (_sourceMgr && deleteState.isMigrating) { _sourceMgr->getCloner()->onDeleteOp(txn, deleteState.idDoc); } }
void run() { OperationContextImpl txn; Client::WriteContext ctx(&txn, _ns); int numFinishedIndexesStart = _catalog->numIndexesReady(&txn); Helpers::ensureIndex(&txn, _coll, BSON("x" << 1), false, "_x_0"); Helpers::ensureIndex(&txn, _coll, BSON("y" << 1), false, "_y_0"); ASSERT_TRUE(_catalog->numIndexesReady(&txn) == numFinishedIndexesStart+2); IndexCatalog::IndexIterator ii = _catalog->getIndexIterator(&txn,false); int indexesIterated = 0; bool foundIndex = false; while (ii.more()) { IndexDescriptor* indexDesc = ii.next(); indexesIterated++; BSONObjIterator boit(indexDesc->infoObj()); while (boit.more() && !foundIndex) { BSONElement e = boit.next(); if (str::equals(e.fieldName(), "name") && str::equals(e.valuestrsafe(), "_y_0")) { foundIndex = true; break; } } } ctx.commit(); ASSERT_TRUE(indexesIterated == _catalog->numIndexesReady(&txn)); ASSERT_TRUE(foundIndex); }
virtual Status set( const BSONElement& newValueElement ) { if (!theReplSet) { return Status( ErrorCodes::BadValue, "replication is not enabled" ); } std::string prefetch = newValueElement.valuestrsafe(); return setFromString( prefetch ); }
string FTSSpec::getLanguageToUse( const BSONObj& userDoc ) const { BSONElement e = userDoc[_languageOverrideField]; if ( e.type() == String ) { const char * x = e.valuestrsafe(); if ( strlen( x ) > 0 ) return x; } return _defaultLanguage; }
virtual Status set(const BSONElement& newValueElement) { if (getGlobalReplicationCoordinator()->getReplicationMode() != ReplicationCoordinator::modeReplSet) { return Status(ErrorCodes::BadValue, "replication is not enabled"); } std::string prefetch = newValueElement.valuestrsafe(); return setFromString(prefetch); }
const FTSLanguage& FTSSpec::_getLanguageToUseV1(const BSONObj& userDoc) const { BSONElement e = userDoc[_languageOverrideField]; if (e.type() == String) { const char* x = e.valuestrsafe(); if (strlen(x) > 0) { StatusWithFTSLanguage swl = FTSLanguage::make(x, TEXT_INDEX_VERSION_1); dassert(swl.isOK()); // make() w/ TEXT_INDEX_VERSION_1 guaranteed to not fail. return *swl.getValue(); } } return *_defaultLanguage; }
StatusWith<ParsedDistinct> ParsedDistinct::parse(OperationContext* txn, const NamespaceString& nss, const BSONObj& cmdObj, const ExtensionsCallback& extensionsCallback, bool isExplain) { // Extract the key field. BSONElement keyElt; auto statusKey = bsonExtractTypedField(cmdObj, kKeyField, BSONType::String, &keyElt); if (!statusKey.isOK()) { return {statusKey}; } auto key = keyElt.valuestrsafe(); auto qr = stdx::make_unique<QueryRequest>(nss); // Extract the query field. If the query field is nonexistent, an empty query is used. if (BSONElement queryElt = cmdObj[kQueryField]) { if (queryElt.type() == BSONType::Object) { qr->setFilter(queryElt.embeddedObject()); } else if (queryElt.type() != BSONType::jstNULL) { return Status(ErrorCodes::TypeMismatch, str::stream() << "\"" << kQueryField << "\" had the wrong type. Expected " << typeName(BSONType::Object) << " or " << typeName(BSONType::jstNULL) << ", found " << typeName(queryElt.type())); } } // Extract the collation field, if it exists. if (BSONElement collationElt = cmdObj[kCollationField]) { if (collationElt.type() != BSONType::Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "\"" << kCollationField << "\" had the wrong type. Expected " << typeName(BSONType::Object) << ", found " << typeName(collationElt.type())); } qr->setCollation(collationElt.embeddedObject()); } qr->setExplain(isExplain); auto cq = CanonicalQuery::canonicalize(txn, std::move(qr), extensionsCallback); if (!cq.isOK()) { return cq.getStatus(); } return ParsedDistinct(std::move(cq.getValue()), std::move(key)); }
/** * Used by explain() and run() to get the PlanExecutor for the query. */ StatusWith<unique_ptr<PlanExecutor>> getPlanExecutor(OperationContext* txn, Collection* collection, const string& ns, const BSONObj& cmdObj, bool isExplain) const { // Extract the key field. BSONElement keyElt; auto statusKey = bsonExtractTypedField(cmdObj, kKeyField, BSONType::String, &keyElt); if (!statusKey.isOK()) { return {statusKey}; } string key = keyElt.valuestrsafe(); // Extract the query field. If the query field is nonexistent, an empty query is used. BSONObj query; if (BSONElement queryElt = cmdObj[kQueryField]) { if (queryElt.type() == BSONType::Object) { query = queryElt.embeddedObject(); } else if (queryElt.type() != BSONType::jstNULL) { return Status(ErrorCodes::TypeMismatch, str::stream() << "\"" << kQueryField << "\" had the wrong type. Expected " << typeName(BSONType::Object) << " or " << typeName(BSONType::jstNULL) << ", found " << typeName(queryElt.type())); } } // Extract the collation field, if it exists. // TODO SERVER-23473: Pass this collation spec object down so that it can be converted into // a CollatorInterface. BSONObj collation; if (BSONElement collationElt = cmdObj[kCollationField]) { if (collationElt.type() != BSONType::Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "\"" << kCollationField << "\" had the wrong type. Expected " << typeName(BSONType::Object) << ", found " << typeName(collationElt.type())); } collation = collationElt.embeddedObject(); } auto executor = getExecutorDistinct( txn, collection, ns, query, key, isExplain, PlanExecutor::YIELD_AUTO); if (!executor.isOK()) { return executor.getStatus(); } return std::move(executor.getValue()); }
BSONObj removeFile(const BSONObj& args, void* data) { BSONElement e = singleArg(args); bool found = false; boost::filesystem::path root(e.valuestrsafe()); if (boost::filesystem::exists(root)) { found = true; boost::filesystem::remove_all(root); } BSONObjBuilder b; b.appendBool("removed", found); return b.obj(); }
/** * 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() != mongol::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() != mongol::String) { errmsg = str::stream() << "\"ns\" field is not a string: " << e.fieldName(); return false; } if (nsElement.String().find('\0') != std::string::npos) { errmsg = str::stream() << "namespaces cannot have embedded null characters"; 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; }
Status WriteConcernOptions::parse(const BSONObj& obj) { reset(); if (obj.isEmpty()) { return Status(ErrorCodes::FailedToParse, "write concern object cannot be empty"); } BSONElement jEl = obj["j"]; if (!jEl.eoo() && !jEl.isNumber() && jEl.type() != Bool) { return Status(ErrorCodes::FailedToParse, "j must be numeric or a boolean value"); } const bool j = jEl.trueValue(); BSONElement fsyncEl = obj["fsync"]; if (!fsyncEl.eoo() && !fsyncEl.isNumber() && fsyncEl.type() != Bool) { return Status(ErrorCodes::FailedToParse, "fsync must be numeric or a boolean value"); } const bool fsync = fsyncEl.trueValue(); if (j && fsync) return Status(ErrorCodes::FailedToParse, "fsync and j options cannot be used together"); if (j) { syncMode = SyncMode::JOURNAL; } else if (fsync) { syncMode = SyncMode::FSYNC; } else if (!jEl.eoo()) { syncMode = SyncMode::NONE; } BSONElement e = obj["w"]; if (e.isNumber()) { wNumNodes = e.numberInt(); } else if (e.type() == String) { wMode = e.valuestrsafe(); } else if (e.eoo() || e.type() == jstNULL || e.type() == Undefined) { wNumNodes = 1; } else { return Status(ErrorCodes::FailedToParse, "w has to be a number or a string"); } wTimeout = obj["wtimeout"].numberInt(); return Status::OK(); }
BSONObj cat(const BSONObj& args){ BSONElement e = oneArg(args); stringstream ss; ifstream f(e.valuestrsafe()); uassert(CANT_OPEN_FILE, "couldn't open file", f.is_open() ); streamsize sz = 0; while( 1 ) { char ch = 0; // slow...maybe change one day f.get(ch); if( ch == 0 ) break; ss << ch; sz += 1; uassert(13301, "cat() : file to big to load as a variable", sz < 1024 * 1024 * 16); } return BSON( "" << ss.str() ); }
BSONObj md5sumFile(const BSONObj& args){ BSONElement e = oneArg(args); stringstream ss; FILE* f = fopen(e.valuestrsafe(), "rb"); uassert(CANT_OPEN_FILE, "couldn't open file", f ); md5digest d; md5_state_t st; md5_init(&st); enum {BUFLEN = 4*1024}; char buffer[BUFLEN]; int bytes_read; while( (bytes_read = fread(buffer, 1, BUFLEN, f)) ) { md5_append( &st , (const md5_byte_t*)(buffer) , bytes_read ); } md5_finish(&st, d); return BSON( "" << digestToString( d ) ); }
void run() { Client::WriteContext ctx(_ns); int numFinishedIndexesStart = _catalog->numIndexesReady(); BSONObjBuilder b1; b1.append("key", BSON("x" << 1)); b1.append("ns", _ns); b1.append("name", "_x_0"); _catalog->createIndex(b1.obj(), true); BSONObjBuilder b2; b2.append("key", BSON("y" << 1)); b2.append("ns", _ns); b2.append("name", "_y_0"); _catalog->createIndex(b2.obj(), true); ASSERT_TRUE(_catalog->numIndexesReady() == numFinishedIndexesStart+2); IndexCatalog::IndexIterator ii = _catalog->getIndexIterator(false); int indexesIterated = 0; bool foundIndex = false; while (ii.more()) { IndexDescriptor* indexDesc = ii.next(); indexesIterated++; BSONObjIterator boit(indexDesc->infoObj()); while (boit.more() && !foundIndex) { BSONElement e = boit.next(); if (str::equals(e.fieldName(), "name") && str::equals(e.valuestrsafe(), "_y_0")) { foundIndex = true; break; } } } ASSERT_TRUE(indexesIterated == _catalog->numIndexesReady()); ASSERT_TRUE(foundIndex); }
Status WriteConcernOptions::parse( const BSONObj& obj ) { if ( obj.isEmpty() ) { return Status( ErrorCodes::BadValue, "write concern object cannot be empty" ); } bool j = obj["j"].trueValue(); bool fsync = obj["fsync"].trueValue(); if ( j & fsync ) return Status( ErrorCodes::BadValue, "fsync and j options cannot be used together" ); if ( j ) { syncMode = JOURNAL; } if ( fsync ) { syncMode = FSYNC; } BSONElement e = obj["w"]; if ( e.isNumber() ) { wNumNodes = e.numberInt(); } else if ( e.type() == String ) { wMode = e.valuestrsafe(); } else if ( e.eoo() || e.type() == jstNULL || e.type() == Undefined ) { wNumNodes = 1; } else { return Status( ErrorCodes::BadValue, "w has to be a number or a string" ); } wTimeout = obj["wtimeout"].numberInt(); return Status::OK(); }
// static void IndexBoundsBuilder::translate(const MatchExpression* expr, const BSONElement& elt, OrderedIntervalList* oilOut, bool* exactOut) { int direction = (elt.numberInt() >= 0) ? 1 : -1; Interval interval; bool exact = false; oilOut->name = elt.fieldName(); bool isHashed = false; if (mongoutils::str::equals("hashed", elt.valuestrsafe())) { isHashed = true; } if (isHashed) { verify(MatchExpression::EQ == expr->matchType() || MatchExpression::MATCH_IN == expr->matchType()); } if (MatchExpression::EQ == expr->matchType()) { const EqualityMatchExpression* node = static_cast<const EqualityMatchExpression*>(expr); // We have to copy the data out of the parse tree and stuff it into the index // bounds. BSONValue will be useful here. BSONObj dataObj; if (isHashed) { dataObj = ExpressionMapping::hash(node->getData()); } else { dataObj = objFromElement(node->getData()); } // UNITTEST 11738048 if (Array == dataObj.firstElement().type()) { // XXX: build better bounds warning() << "building lazy bounds for " << expr->toString() << endl; interval = allValues(); exact = false; } else { verify(dataObj.isOwned()); interval = makePointInterval(dataObj); // XXX: it's exact if the index isn't sparse if (dataObj.firstElement().isNull()) { exact = false; } else if (isHashed) { exact = false; } else { exact = true; } } } else if (MatchExpression::LTE == expr->matchType()) { const LTEMatchExpression* node = static_cast<const LTEMatchExpression*>(expr); BSONElement dataElt = node->getData(); BSONObjBuilder bob; bob.appendMinForType("", dataElt.type()); bob.append(dataElt); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); interval = makeRangeInterval(dataObj, true, true); // XXX: only exact if not (null or array) exact = true; } else if (MatchExpression::LT == expr->matchType()) { const LTMatchExpression* node = static_cast<const LTMatchExpression*>(expr); BSONElement dataElt = node->getData(); BSONObjBuilder bob; bob.appendMinForType("", dataElt.type()); bob.append(dataElt); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); interval = makeRangeInterval(dataObj, true, false); // XXX: only exact if not (null or array) exact = true; } else if (MatchExpression::GT == expr->matchType()) { const GTMatchExpression* node = static_cast<const GTMatchExpression*>(expr); BSONElement dataElt = node->getData(); BSONObjBuilder bob; bob.append(node->getData()); bob.appendMaxForType("", dataElt.type()); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); interval = makeRangeInterval(dataObj, false, true); // XXX: only exact if not (null or array) exact = true; } else if (MatchExpression::GTE == expr->matchType()) { const GTEMatchExpression* node = static_cast<const GTEMatchExpression*>(expr); BSONElement dataElt = node->getData(); BSONObjBuilder bob; bob.append(dataElt); bob.appendMaxForType("", dataElt.type()); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); interval = makeRangeInterval(dataObj, true, true); // XXX: only exact if not (null or array) exact = true; } else if (MatchExpression::REGEX == expr->matchType()) { warning() << "building lazy bounds for " << expr->toString() << endl; interval = allValues(); exact = false; } else if (MatchExpression::MOD == expr->matchType()) { BSONObjBuilder bob; bob.appendMinForType("", NumberDouble); bob.appendMaxForType("", NumberDouble); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); interval = makeRangeInterval(dataObj, true, true); exact = false; } else if (MatchExpression::MATCH_IN == expr->matchType()) { warning() << "building lazy bounds for " << expr->toString() << endl; interval = allValues(); exact = false; } else if (MatchExpression::TYPE_OPERATOR == expr->matchType()) { const TypeMatchExpression* tme = static_cast<const TypeMatchExpression*>(expr); BSONObjBuilder bob; bob.appendMinForType("", tme->getData()); bob.appendMaxForType("", tme->getData()); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); interval = makeRangeInterval(dataObj, true, true); exact = false; } else if (MatchExpression::MATCH_IN == expr->matchType()) { warning() << "building lazy bounds for " << expr->toString() << endl; interval = allValues(); exact = false; } else if (MatchExpression::GEO == expr->matchType()) { const GeoMatchExpression* gme = static_cast<const GeoMatchExpression*>(expr); // Can only do this for 2dsphere. if (!mongoutils::str::equals("2dsphere", elt.valuestrsafe())) { warning() << "Planner error trying to build geo bounds for " << elt.toString() << " index element."; verify(0); } const S2Region& region = gme->getGeoQuery().getRegion(); ExpressionMapping::cover2dsphere(region, oilOut); *exactOut = false; // XXX: restructure this method return; } else { warning() << "Planner error, trying to build bounds for expr " << expr->toString() << endl; verify(0); } if (-1 == direction) { reverseInterval(&interval); } oilOut->intervals.push_back(interval); *exactOut = exact; }
Status WriteConcernOptions::parse(const BSONObj& obj) { reset(); if (obj.isEmpty()) { return Status(ErrorCodes::FailedToParse, "write concern object cannot be empty"); } BSONElement jEl; BSONElement fsyncEl; BSONElement wEl; for (auto e : obj) { const auto fieldName = e.fieldNameStringData(); if (fieldName == kJFieldName) { jEl = e; if (!jEl.isNumber() && jEl.type() != Bool) { return Status(ErrorCodes::FailedToParse, "j must be numeric or a boolean value"); } } else if (fieldName == kFSyncFieldName) { fsyncEl = e; if (!fsyncEl.isNumber() && fsyncEl.type() != Bool) { return Status(ErrorCodes::FailedToParse, "fsync must be numeric or a boolean value"); } } else if (fieldName == kWFieldName) { wEl = e; } else if (fieldName == kWTimeoutFieldName) { wTimeout = e.numberInt(); } else if (fieldName == kWElectionIdFieldName) { // Ignore. } else if (fieldName == kWOpTimeFieldName) { // Ignore. } else if (fieldName.equalCaseInsensitive(kGetLastErrorFieldName)) { // Ignore GLE field. } else { return Status(ErrorCodes::FailedToParse, str::stream() << "unrecognized write concern field: " << fieldName); } } const bool j = jEl.trueValue(); const bool fsync = fsyncEl.trueValue(); if (j && fsync) return Status(ErrorCodes::FailedToParse, "fsync and j options cannot be used together"); if (j) { syncMode = SyncMode::JOURNAL; } else if (fsync) { syncMode = SyncMode::FSYNC; } else if (!jEl.eoo()) { syncMode = SyncMode::NONE; } if (wEl.isNumber()) { wNumNodes = wEl.numberInt(); } else if (wEl.type() == String) { wMode = wEl.valuestrsafe(); } else if (wEl.eoo() || wEl.type() == jstNULL || wEl.type() == Undefined) { wNumNodes = 1; } else { return Status(ErrorCodes::FailedToParse, "w has to be a number or a string"); } return Status::OK(); }
// static void IndexBoundsBuilder::translate(const MatchExpression* expr, const BSONElement& elt, OrderedIntervalList* oilOut, bool* exactOut) { oilOut->name = elt.fieldName(); bool isHashed = false; if (mongoutils::str::equals("hashed", elt.valuestrsafe())) { isHashed = true; } if (isHashed) { verify(MatchExpression::EQ == expr->matchType() || MatchExpression::MATCH_IN == expr->matchType()); } if (MatchExpression::ELEM_MATCH_VALUE == expr->matchType()) { OrderedIntervalList acc; bool exact; translate(expr->getChild(0), elt, &acc, &exact); if (!exact) { *exactOut = false; } for (size_t i = 1; i < expr->numChildren(); ++i) { OrderedIntervalList next; translate(expr->getChild(i), elt, &next, &exact); if (!exact) { *exactOut = false; } intersectize(next, &acc); } for (size_t i = 0; i < acc.intervals.size(); ++i) { oilOut->intervals.push_back(acc.intervals[i]); } if (!oilOut->intervals.empty()) { std::sort(oilOut->intervals.begin(), oilOut->intervals.end(), IntervalComparison); } } else if (MatchExpression::EQ == expr->matchType()) { const EqualityMatchExpression* node = static_cast<const EqualityMatchExpression*>(expr); translateEquality(node->getData(), isHashed, oilOut, exactOut); } else if (MatchExpression::LTE == expr->matchType()) { const LTEMatchExpression* node = static_cast<const LTEMatchExpression*>(expr); BSONElement dataElt = node->getData(); // Everything is <= MaxKey. if (MaxKey == dataElt.type()) { oilOut->intervals.push_back(allValues()); *exactOut = true; return; } BSONObjBuilder bob; bob.appendMinForType("", dataElt.type()); bob.appendAs(dataElt, ""); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); oilOut->intervals.push_back(makeRangeInterval(dataObj, true, true)); // XXX: only exact if not (null or array) *exactOut = true; } else if (MatchExpression::LT == expr->matchType()) { const LTMatchExpression* node = static_cast<const LTMatchExpression*>(expr); BSONElement dataElt = node->getData(); // Everything is <= MaxKey. if (MaxKey == dataElt.type()) { oilOut->intervals.push_back(allValues()); *exactOut = true; return; } BSONObjBuilder bob; bob.appendMinForType("", dataElt.type()); bob.appendAs(dataElt, ""); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); QLOG() << "data obj is " << dataObj.toString() << endl; oilOut->intervals.push_back(makeRangeInterval(dataObj, true, false)); // XXX: only exact if not (null or array) *exactOut = true; } else if (MatchExpression::GT == expr->matchType()) { const GTMatchExpression* node = static_cast<const GTMatchExpression*>(expr); BSONElement dataElt = node->getData(); // Everything is > MinKey. if (MinKey == dataElt.type()) { oilOut->intervals.push_back(allValues()); *exactOut = true; return; } BSONObjBuilder bob; bob.appendAs(node->getData(), ""); bob.appendMaxForType("", dataElt.type()); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); oilOut->intervals.push_back(makeRangeInterval(dataObj, false, true)); // XXX: only exact if not (null or array) *exactOut = true; } else if (MatchExpression::GTE == expr->matchType()) { const GTEMatchExpression* node = static_cast<const GTEMatchExpression*>(expr); BSONElement dataElt = node->getData(); // Everything is >= MinKey. if (MinKey == dataElt.type()) { oilOut->intervals.push_back(allValues()); *exactOut = true; return; } BSONObjBuilder bob; bob.appendAs(dataElt, ""); bob.appendMaxForType("", dataElt.type()); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); oilOut->intervals.push_back(makeRangeInterval(dataObj, true, true)); // XXX: only exact if not (null or array) *exactOut = true; } else if (MatchExpression::REGEX == expr->matchType()) { const RegexMatchExpression* rme = static_cast<const RegexMatchExpression*>(expr); translateRegex(rme, oilOut, exactOut); } else if (MatchExpression::MOD == expr->matchType()) { BSONObjBuilder bob; bob.appendMinForType("", NumberDouble); bob.appendMaxForType("", NumberDouble); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); oilOut->intervals.push_back(makeRangeInterval(dataObj, true, true)); *exactOut = false; } else if (MatchExpression::TYPE_OPERATOR == expr->matchType()) { const TypeMatchExpression* tme = static_cast<const TypeMatchExpression*>(expr); BSONObjBuilder bob; bob.appendMinForType("", tme->getData()); bob.appendMaxForType("", tme->getData()); BSONObj dataObj = bob.obj(); verify(dataObj.isOwned()); oilOut->intervals.push_back(makeRangeInterval(dataObj, true, true)); *exactOut = false; } else if (MatchExpression::MATCH_IN == expr->matchType()) { const InMatchExpression* ime = static_cast<const InMatchExpression*>(expr); const ArrayFilterEntries& afr = ime->getData(); *exactOut = true; // Create our various intervals. bool thisBoundExact = false; for (BSONElementSet::iterator it = afr.equalities().begin(); it != afr.equalities().end(); ++it) { translateEquality(*it, isHashed, oilOut, &thisBoundExact); if (!thisBoundExact) { *exactOut = false; } } for (size_t i = 0; i < afr.numRegexes(); ++i) { translateRegex(afr.regex(i), oilOut, &thisBoundExact); if (!thisBoundExact) { *exactOut = false; } } // XXX: what happens here? if (afr.hasNull()) { } // XXX: what happens here as well? if (afr.hasEmptyArray()) { } unionize(oilOut); } else if (MatchExpression::GEO == expr->matchType()) { const GeoMatchExpression* gme = static_cast<const GeoMatchExpression*>(expr); // Can only do this for 2dsphere. if (!mongoutils::str::equals("2dsphere", elt.valuestrsafe())) { warning() << "Planner error trying to build geo bounds for " << elt.toString() << " index element."; verify(0); } const S2Region& region = gme->getGeoQuery().getRegion(); ExpressionMapping::cover2dsphere(region, oilOut); *exactOut = false; } else { warning() << "Planner error, trying to build bounds for expr " << expr->toString() << endl; verify(0); } }
Status validateKeyPattern(const BSONObj& key) { const ErrorCodes::Error code = ErrorCodes::CannotCreateIndex; if ( key.objsize() > 2048 ) return Status(code, "Index key pattern too large."); if ( key.isEmpty() ) return Status(code, "Index keys cannot be empty."); string pluginName = IndexNames::findPluginName( key ); if ( pluginName.size() ) { if ( !IndexNames::isKnownName( pluginName ) ) return Status(code, mongoutils::str::stream() << "Unknown index plugin '" << pluginName << '\''); } BSONObjIterator it( key ); while ( it.more() ) { BSONElement keyElement = it.next(); if ( !keyElement.isNumber() && keyElement.type() != String ) { return Status(code, "Index keys must have numeric type or string type."); } if ( keyElement.type() == String && pluginName != keyElement.str() ) { return Status(code, "Can't use more than one index plugin for a single index."); } // Ensure that the fields on which we are building the index are valid: a field must not // begin with a '$' unless it is part of a DBRef or text index, and a field path cannot // contain an empty field. If a field cannot be created or updated, it should not be // indexable. FieldRef keyField( keyElement.fieldName() ); const size_t numParts = keyField.numParts(); if ( numParts == 0 ) { return Status(code, "Index keys cannot be an empty field."); } // "$**" is acceptable for a text index. if ( mongoutils::str::equals( keyElement.fieldName(), "$**" ) && keyElement.valuestrsafe() == IndexNames::TEXT ) continue; for ( size_t i = 0; i != numParts; ++i ) { const StringData part = keyField.getPart(i); // Check if the index key path contains an empty field. if ( part.empty() ) { return Status(code, "Index keys cannot contain an empty field."); } if ( part[0] != '$' ) continue; // Check if the '$'-prefixed field is part of a DBRef: since we don't have the // necessary context to validate whether this is a proper DBRef, we allow index // creation on '$'-prefixed names that match those used in a DBRef. const bool mightBePartOfDbRef = (i != 0) && (part == "$db" || part == "$id" || part == "$ref"); if ( !mightBePartOfDbRef ) { return Status(code, "Index key contains an illegal field name: " "field name starts with '$'."); } } } return Status::OK(); }
INT32 _omAgentNodeMgr::rmANode( const CHAR *arg1, const CHAR *arg2, const CHAR *roleStr, string *omsvc ) { INT32 rc = SDB_OK ; const CHAR *pSvcName = _getSvcNameFromArg( arg1 ) ; BOOLEAN backupDialog = FALSE ; CHAR cfgPath[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ; CHAR cfgFile[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ; pmdOptionsCB nodeOptions ; BOOLEAN hasLock = FALSE ; if ( !pSvcName ) { PD_LOG( PDERROR, "Failed to get svc name from arg" ) ; rc = SDB_INVALIDARG ; goto error ; } if ( arg2 ) { try { BSONObj objArg2( arg2 ) ; if ( !objArg2.isEmpty() ) { backupDialog = TRUE ; } } catch( std::exception &e ) { PD_LOG( PDERROR, "Ocuur exception: %s", e.what() ) ; rc = SDB_INVALIDARG ; 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 = 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 ; } lockBucket( pSvcName ) ; hasLock = TRUE ; rc = nodeOptions.initFromFile( cfgFile, FALSE ) ; if ( rc ) { if ( SDB_FNE == rc ) { rc = SDBCM_NODE_NOTEXISTED ; } else { PD_LOG( PDERROR, "Extract node[%s] config failed, rc: %d", pSvcName, rc ) ; } goto error ; } if ( omsvc ) { *omsvc = nodeOptions.getOMService() ; } if ( roleStr && 0 != *roleStr && 0 != ossStrcmp( nodeOptions.dbroleStr(), roleStr ) ) { PD_LOG( PDERROR, "Role[%s] is not expect[%s]", nodeOptions.dbroleStr(), roleStr ) ; rc = SDB_PERM ; goto error ; } try { BSONObj configObj( arg1 ) ; BSONObjIterator itr( configObj ) ; while ( itr.more() ) { BSONElement e = itr.next() ; if ( 0 != ossStrcmp( e.fieldName(), PMD_OPTION_CLUSTER_NAME ) && 0 != ossStrcmp( e.fieldName(), PMD_OPTION_BUSINESS_NAME ) && 0 != ossStrcmp( e.fieldName(), PMD_OPTION_USERTAG ) ) { continue ; } string name ; nodeOptions.getFieldStr( e.fieldName(), name, "" ) ; if ( 0 != ossStrcmp( e.valuestrsafe(), name.c_str() ) ) { rc = SDBCM_NODE_NOTEXISTED ; goto error ; } } } catch( std::exception &e ) { PD_LOG( PDERROR, "Extrace config obj occur exception: %s", e.what() ) ; rc = SDB_INVALIDARG ; goto error ; } stopANode( pSvcName, NODE_START_CLIENT, FALSE ) ; if ( backupDialog ) { CHAR bakPath[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ; ossStrncpy( bakPath, nodeOptions.getDbPath(), OSS_MAX_PATHSIZE ) ; ossStrncat( bakPath, "_bak", OSS_MAX_PATHSIZE ) ; if ( SDB_OK == ossAccess( bakPath ) ) { ossDelete( bakPath ) ; } if ( SDB_OK == ( rc = ossRenamePath( nodeOptions.getDiagLogPath(), bakPath ) ) ) { PD_LOG( PDEVENT, "Move node[%s] dialog[%s] to path[%s]", pSvcName, nodeOptions.getDiagLogPath(), bakPath ) ; } else { PD_LOG( PDERROR, "Move node[%s] dialog[%s] to path[%s] failed, " "rc: %d", pSvcName, nodeOptions.getDiagLogPath(), bakPath, rc ) ; } } { pmdStartup startupFile ; if ( SDB_OK == startupFile.init( nodeOptions.getDbPath(), FALSE ) ) { startupFile.final() ; rc = nodeOptions.removeAllDir() ; if ( rc ) { PD_LOG( PDERROR, "Remove node[%s] directorys failed, rc: %d", pSvcName, rc ) ; goto error ; } } }
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 ; }
StatusWith<BSONObj> FTSSpec::fixSpec(const BSONObj& spec) { if (spec["textIndexVersion"].numberInt() == TEXT_INDEX_VERSION_1) { return _fixSpecV1(spec); } map<string, int> m; BSONObj keyPattern; { BSONObjBuilder b; // Populate m and keyPattern. { bool addedFtsStuff = false; BSONObjIterator i(spec["key"].Obj()); while (i.more()) { BSONElement e = i.next(); if (e.fieldNameStringData() == "_fts") { if (INDEX_NAME != e.valuestrsafe()) { return {ErrorCodes::CannotCreateIndex, "expecting _fts:\"text\""}; } addedFtsStuff = true; b.append(e); } else if (e.fieldNameStringData() == "_ftsx") { if (e.numberInt() != 1) { return {ErrorCodes::CannotCreateIndex, "expecting _ftsx:1"}; } b.append(e); } else if (e.type() == String && INDEX_NAME == e.valuestr()) { if (!addedFtsStuff) { _addFTSStuff(&b); addedFtsStuff = true; } m[e.fieldName()] = 1; } else { if (e.numberInt() != 1 && e.numberInt() != -1) { return {ErrorCodes::CannotCreateIndex, "expected value 1 or -1 for non-text key in compound index"}; } b.append(e); } } verify(addedFtsStuff); } keyPattern = b.obj(); // Verify that index key is in the correct format: extraBefore fields, then text // fields, then extraAfter fields. { BSONObjIterator i(spec["key"].Obj()); verify(i.more()); BSONElement e = i.next(); // extraBefore fields while (String != e.type()) { Status notReservedStatus = verifyFieldNameNotReserved(e.fieldNameStringData()); if (!notReservedStatus.isOK()) { return notReservedStatus; } if (!i.more()) { return {ErrorCodes::CannotCreateIndex, "expected additional fields in text index key pattern"}; } e = i.next(); } // text fields bool alreadyFixed = (e.fieldNameStringData() == "_fts"); if (alreadyFixed) { if (!i.more()) { return {ErrorCodes::CannotCreateIndex, "expected _ftsx after _fts"}; } e = i.next(); if (e.fieldNameStringData() != "_ftsx") { return {ErrorCodes::CannotCreateIndex, "expected _ftsx after _fts"}; } e = i.next(); } else { do { Status notReservedStatus = verifyFieldNameNotReserved(e.fieldNameStringData()); if (!notReservedStatus.isOK()) { return notReservedStatus; } e = i.next(); } while (!e.eoo() && e.type() == String); } // extraAfterFields while (!e.eoo()) { if (e.type() == BSONType::String) { return {ErrorCodes::CannotCreateIndex, "'text' fields in index must all be adjacent"}; } Status notReservedStatus = verifyFieldNameNotReserved(e.fieldNameStringData()); if (!notReservedStatus.isOK()) { return notReservedStatus; } e = i.next(); } } } if (spec["weights"].type() == Object) { BSONObjIterator i(spec["weights"].Obj()); while (i.more()) { BSONElement e = i.next(); if (!e.isNumber()) { return {ErrorCodes::CannotCreateIndex, "weight for text index needs numeric type"}; } m[e.fieldName()] = e.numberInt(); } } else if (spec["weights"].str() == WILDCARD) { m[WILDCARD] = 1; } else if (!spec["weights"].eoo()) { return {ErrorCodes::CannotCreateIndex, "text index option 'weights' must be an object"}; } if (m.empty()) { return {ErrorCodes::CannotCreateIndex, "text index option 'weights' must specify fields or the wildcard"}; } BSONObj weights; { BSONObjBuilder b; for (map<string, int>::iterator i = m.begin(); i != m.end(); ++i) { if (i->second <= 0 || i->second >= MAX_WORD_WEIGHT) { return {ErrorCodes::CannotCreateIndex, str::stream() << "text index weight must be in the exclusive interval (0," << MAX_WORD_WEIGHT << ") but found: " << i->second}; } // Verify weight refers to a valid field. if (i->first != "$**") { FieldRef keyField(i->first); if (keyField.numParts() == 0) { return {ErrorCodes::CannotCreateIndex, "weight cannot be on an empty field"}; } for (size_t partNum = 0; partNum < keyField.numParts(); partNum++) { StringData part = keyField.getPart(partNum); if (part.empty()) { return {ErrorCodes::CannotCreateIndex, "weight cannot have empty path component"}; } if (part.startsWith("$")) { return {ErrorCodes::CannotCreateIndex, "weight cannot have path component with $ prefix"}; } } } b.append(i->first, i->second); } weights = b.obj(); } BSONElement default_language_elt = spec["default_language"]; string default_language(default_language_elt.str()); if (default_language_elt.eoo()) { default_language = moduleDefaultLanguage; } else if (default_language_elt.type() != BSONType::String) { return {ErrorCodes::CannotCreateIndex, "default_language needs a string type"}; } if (!FTSLanguage::make(default_language, TEXT_INDEX_VERSION_3).getStatus().isOK()) { return {ErrorCodes::CannotCreateIndex, "default_language is not valid"}; } BSONElement language_override_elt = spec["language_override"]; string language_override(language_override_elt.str()); if (language_override_elt.eoo()) { language_override = "language"; } else if (language_override_elt.type() != BSONType::String) { return {ErrorCodes::CannotCreateIndex, "language_override must be a string"}; } else if (!validateOverride(language_override)) { return {ErrorCodes::CannotCreateIndex, "language_override is not valid"}; } int version = -1; int textIndexVersion = TEXT_INDEX_VERSION_3; // default text index version BSONObjBuilder b; BSONObjIterator i(spec); while (i.more()) { BSONElement e = i.next(); StringData fieldName = e.fieldNameStringData(); if (fieldName == "key") { b.append("key", keyPattern); } else if (fieldName == "weights") { b.append("weights", weights); weights = BSONObj(); } else if (fieldName == "default_language") { b.append("default_language", default_language); default_language = ""; } else if (fieldName == "language_override") { b.append("language_override", language_override); language_override = ""; } else if (fieldName == "v") { version = e.numberInt(); } else if (fieldName == "textIndexVersion") { if (!e.isNumber()) { return {ErrorCodes::CannotCreateIndex, "text index option 'textIndexVersion' must be a number"}; } textIndexVersion = e.numberInt(); if (textIndexVersion != TEXT_INDEX_VERSION_2 && textIndexVersion != TEXT_INDEX_VERSION_3) { return {ErrorCodes::CannotCreateIndex, str::stream() << "bad textIndexVersion: " << textIndexVersion}; } } else { b.append(e); } } if (!weights.isEmpty()) { b.append("weights", weights); } if (!default_language.empty()) { b.append("default_language", default_language); } if (!language_override.empty()) { b.append("language_override", language_override); } if (version >= 0) { b.append("v", version); } b.append("textIndexVersion", textIndexVersion); return b.obj(); }
Status validateKeyPattern(const BSONObj& key, IndexDescriptor::IndexVersion indexVersion) { const ErrorCodes::Error code = ErrorCodes::CannotCreateIndex; if (key.objsize() > 2048) return Status(code, "Index key pattern too large."); if (key.isEmpty()) return Status(code, "Index keys cannot be empty."); string pluginName = IndexNames::findPluginName(key); if (pluginName.size()) { if (!IndexNames::isKnownName(pluginName)) return Status( code, mongoutils::str::stream() << "Unknown index plugin '" << pluginName << '\''); } BSONObjIterator it(key); while (it.more()) { BSONElement keyElement = it.next(); switch (indexVersion) { case IndexVersion::kV0: case IndexVersion::kV1: { if (keyElement.type() == BSONType::Object || keyElement.type() == BSONType::Array) { return {code, str::stream() << "Values in index key pattern cannot be of type " << typeName(keyElement.type()) << " for index version v:" << static_cast<int>(indexVersion)}; } if (pluginName == IndexNames::ALLPATHS) { return {code, str::stream() << "'" << pluginName << "' index plugin is not allowed with index version v:" << static_cast<int>(indexVersion)}; } break; } case IndexVersion::kV2: { if (keyElement.isNumber()) { double value = keyElement.number(); if (std::isnan(value)) { return {code, "Values in the index key pattern cannot be NaN."}; } else if (value == 0.0) { return {code, "Values in the index key pattern cannot be 0."}; } } else if (keyElement.type() != BSONType::String) { return {code, str::stream() << "Values in v:2 index key pattern cannot be of type " << typeName(keyElement.type()) << ". Only numbers > 0, numbers < 0, and strings are allowed."}; } break; } default: MONGO_UNREACHABLE; } if (keyElement.type() == String && pluginName != keyElement.str()) { return Status(code, "Can't use more than one index plugin for a single index."); } // Check if the all paths index is compounded. If it is the key is invalid because // compounded all paths indexes are disallowed. if (pluginName == IndexNames::ALLPATHS && key.nFields() != 1) { return Status(code, "all paths indexes do not allow compounding"); } // Ensure that the fields on which we are building the index are valid: a field must not // begin with a '$' unless it is part of an allPaths, DBRef or text index, and a field path // cannot contain an empty field. If a field cannot be created or updated, it should not be // indexable. FieldRef keyField(keyElement.fieldName()); const size_t numParts = keyField.numParts(); if (numParts == 0) { return Status(code, "Index keys cannot be an empty field."); } // "$**" is acceptable for a text index or all paths index. if (mongoutils::str::equals(keyElement.fieldName(), "$**") && ((keyElement.isNumber()) || (keyElement.valuestrsafe() == IndexNames::TEXT))) continue; if (mongoutils::str::equals(keyElement.fieldName(), "_fts") && keyElement.valuestrsafe() != IndexNames::TEXT) { return Status(code, "Index key contains an illegal field name: '_fts'"); } for (size_t i = 0; i != numParts; ++i) { const StringData part = keyField.getPart(i); // Check if the index key path contains an empty field. if (part.empty()) { return Status(code, "Index keys cannot contain an empty field."); } if (part[0] != '$') continue; // Check if the '$'-prefixed field is part of a DBRef: since we don't have the // necessary context to validate whether this is a proper DBRef, we allow index // creation on '$'-prefixed names that match those used in a DBRef. const bool mightBePartOfDbRef = (i != 0) && (part == "$db" || part == "$id" || part == "$ref"); const bool isPartOfAllPaths = (i == numParts - 1) && (part == "$**") && (pluginName == IndexNames::ALLPATHS); if (!mightBePartOfDbRef && !isPartOfAllPaths) { return Status(code, "Index key contains an illegal field name: " "field name starts with '$'."); } } } return Status::OK(); }
INT32 _fmpController::_handleOneLoop( const BSONObj &obj, INT32 step ) { INT32 rc = SDB_OK ; BSONObj res ; if ( FMP_CONTROL_STEP_BEGIN == step ) { UINT32 seqID = 1 ; BSONElement beSeq = obj.getField( FMP_SEQ_ID ) ; if ( beSeq.isNumber() ) { seqID = (UINT32)beSeq.numberInt() ; } BSONElement diag = obj.getField( FMP_DIAG_PATH ) ; if ( !diag.eoo() && String == diag.type() ) { CHAR diaglogShort[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ; ossSnprintf( diaglogShort, OSS_MAX_PATHSIZE, "%s_%u.%s", PD_FMP_DIAGLOG_PREFIX, seqID, PD_FMP_DIAGLOG_SUBFIX ) ; CHAR diaglog[ OSS_MAX_PATHSIZE + 1 ] = {0} ; engine::utilBuildFullPath( diag.valuestrsafe(), diaglogShort, OSS_MAX_PATHSIZE, diaglog ) ; sdbEnablePD( diaglog ) ; } BSONElement localService = obj.getField( FMP_LOCAL_SERVICE ) ; if ( !localService.eoo() && String == localService.type() && 0 == ossStrlen(FMP_COORD_SERVICE) ) { ossMemcpy( FMP_COORD_SERVICE, localService.valuestrsafe(), ossStrlen( localService.valuestrsafe() ) + 1 ) ; } BSONElement localUser = obj.getField( FMP_LOCAL_USERNAME ) ; if ( String == localUser.type() ) { ossStrncpy( g_UserName, localUser.valuestrsafe(), OSS_MAX_PATHSIZE ) ; } BSONElement localPass = obj.getField( FMP_LOCAL_PASSWORD ) ; if ( String == localPass.type() ) { ossStrncpy( g_Password, localPass.valuestrsafe(), OSS_MAX_PATHSIZE ) ; } BSONElement fType = obj.getField( FMP_FUNC_TYPE ) ; if ( fType.eoo() ) { rc = _createVM( FMP_FUNC_TYPE_JS ) ; if ( SDB_OK != rc ) { PD_LOG(PDERROR, "failed to create vm:%d", rc ) ; res = BSON( FMP_ERR_MSG << "failed to create vm" << FMP_RES_CODE << rc ) ; goto error ; } rc = _vm->init( obj ) ; if ( SDB_OK != rc ) { PD_LOG(PDERROR, "failed to init vm:%d", rc ) ; res = BSON( FMP_ERR_MSG << "failed to init vm" << FMP_RES_CODE << rc ) ; goto error ; } } else if ( NumberInt != fType.type() ) { PD_LOG( PDERROR, "invalid type of func type:%s", fType.toString().c_str() ) ; rc = SDB_SYS ; res = BSON( FMP_ERR_MSG << "invalid type of func type" << FMP_RES_CODE << SDB_SYS ) ; goto error ; } else { rc = _createVM( fType.Int() ) ; if ( SDB_OK != rc ) { PD_LOG(PDERROR, "failed to create vm:%d", rc ) ; res = BSON( FMP_ERR_MSG << "failed to create vm" << FMP_RES_CODE << rc ) ; goto error ; } rc = _vm->init( obj ) ; if ( SDB_OK != rc ) { PD_LOG(PDERROR, "failed to init vm:%d", rc ) ; res = BSON( FMP_ERR_MSG << "failed to init vm" << FMP_RES_CODE << rc ) ; goto error ; } } } else if ( FMP_CONTROL_STEP_DOWNLOAD == step ) { SDB_ASSERT( NULL != _vm, "impossible" ) ; rc = _vm->eval( obj, res ) ; if ( SDB_OK != rc ) { PD_LOG( PDERROR, "failed to pre eval func:%s, rc:%d", obj.toString(FALSE, TRUE).c_str(), rc ) ; if ( res.isEmpty() ) { res = BSON( FMP_ERR_MSG << "failed to pre eval func" << FMP_RES_CODE << rc ) ; } goto error ; } } else if ( FMP_CONTROL_STEP_EVAL == step ) { rc = _vm->initGlobalDB( res ) ; if ( rc ) { PD_LOG( PDWARNING, "Failed to init global db: %s", res.toString( FALSE, TRUE ).c_str() ) ; } rc = _vm->eval( obj, res ) ; if ( SDB_OK != rc ) { PD_LOG( PDERROR, "failed to eval func:%s, rc:%d", obj.toString(FALSE, TRUE).c_str(), rc ) ; if ( res.isEmpty() ) { res = BSON( FMP_ERR_MSG << "failed to eval func" << FMP_RES_CODE << rc ) ; } goto error ; } } else if ( FMP_CONTROL_STEP_FETCH == step ) { BSONObj next ; rc = _vm->fetch( next ) ; if ( !next.isEmpty() ) { res = next ; } else { PD_LOG( PDERROR, "a empty obj was fetched out" ) ; rc = SDB_SYS ; res = BSON( FMP_ERR_MSG << "a empty obj was fetched out" << FMP_RES_CODE << rc ) ; goto error ; } if ( SDB_DMS_EOC == rc ) { _clear() ; } else if ( SDB_OK != rc ) { goto error ; } } else { SDB_ASSERT( FALSE, "impossible" ) ; } done: { INT32 rrc = SDB_OK ; if ( !res.isEmpty() ) { rrc = _writeMsg( res ) ; } else { rrc = _writeMsg( BSON( FMP_RES_CODE << rc ) ) ; } if ( SDB_OK != rrc ) { rc = rrc ; PD_LOG( PDERROR, "failed to write msg:%d", rc ) ; } } return rc ; error: goto done ; }
BSONObj FTSSpec::fixSpec( const BSONObj& spec ) { if ( spec["textIndexVersion"].numberInt() == TEXT_INDEX_VERSION_1 ) { return _fixSpecV1( spec ); } map<string,int> m; BSONObj keyPattern; { BSONObjBuilder b; // Populate m and keyPattern. { bool addedFtsStuff = false; BSONObjIterator i( spec["key"].Obj() ); while ( i.more() ) { BSONElement e = i.next(); if ( str::equals( e.fieldName(), "_fts" ) ) { uassert( 17271, "expecting _fts:\"text\"", INDEX_NAME == e.valuestrsafe() ); addedFtsStuff = true; b.append( e ); } else if ( str::equals( e.fieldName(), "_ftsx" ) ) { uassert( 17272, "expecting _ftsx:1", e.numberInt() == 1 ); b.append( e ); } else if ( e.type() == String && INDEX_NAME == e.valuestr() ) { if ( !addedFtsStuff ) { _addFTSStuff( &b ); addedFtsStuff = true; } m[e.fieldName()] = 1; } else { uassert( 17273, "expected value 1 or -1 for non-text key in compound index", e.numberInt() == 1 || e.numberInt() == -1 ); b.append( e ); } } verify( addedFtsStuff ); } keyPattern = b.obj(); // Verify that index key is in the correct format: extraBefore fields, then text // fields, then extraAfter fields. { BSONObjIterator i( spec["key"].Obj() ); BSONElement e; // extraBefore fields do { verify( i.more() ); e = i.next(); } while ( INDEX_NAME != e.valuestrsafe() ); // text fields bool alreadyFixed = str::equals( e.fieldName(), "_fts" ); if ( alreadyFixed ) { uassert( 17288, "expected _ftsx after _fts", i.more() ); e = i.next(); uassert( 17274, "expected _ftsx after _fts", str::equals( e.fieldName(), "_ftsx" ) ); e = i.next(); } else { do { uassert( 17289, "text index with reserved fields _fts/ftsx not allowed", !str::equals( e.fieldName(), "_fts" ) && !str::equals( e.fieldName(), "_ftsx" ) ); e = i.next(); } while ( !e.eoo() && INDEX_NAME == e.valuestrsafe() ); } // extraAfterFields while ( !e.eoo() ) { uassert( 17290, "compound text index key suffix fields must have value 1", e.numberInt() == 1 && !str::equals( "_ftsx", e.fieldName() ) ); e = i.next(); } } } if ( spec["weights"].type() == Object ) { BSONObjIterator i( spec["weights"].Obj() ); while ( i.more() ) { BSONElement e = i.next(); uassert( 17283, "weight for text index needs numeric type", e.isNumber() ); m[e.fieldName()] = e.numberInt(); // Verify weight refers to a valid field. if ( str::equals( e.fieldName(), "$**" ) ) { continue; } FieldRef keyField( e.fieldName() ); uassert( 17294, "weight cannot be on an empty field", keyField.numParts() != 0 ); for ( size_t i = 0; i < keyField.numParts(); i++ ) { StringData part = keyField.getPart(i); uassert( 17291, "weight cannot have empty path component", !part.empty() ); uassert( 17292, "weight cannot have path component with $ prefix", !part.startsWith( "$" ) ); } } } else if ( spec["weights"].str() == WILDCARD ) { m[WILDCARD] = 1; } else if ( !spec["weights"].eoo() ) { uasserted( 17284, "text index option 'weights' must be an object" ); } BSONObj weights; { BSONObjBuilder b; for ( map<string,int>::iterator i = m.begin(); i != m.end(); ++i ) { uassert( 16674, "score for word too high", i->second > 0 && i->second < MAX_WORD_WEIGHT ); b.append( i->first, i->second ); } weights = b.obj(); } BSONElement default_language_elt = spec["default_language"]; string default_language( default_language_elt.str() ); if ( default_language_elt.eoo() ) { default_language = moduleDefaultLanguage; } else { uassert( 17263, "default_language needs a string type", default_language_elt.type() == String ); } uassert( 17264, "default_language is not valid", FTSLanguage::make( default_language, TEXT_INDEX_VERSION_2 ).getStatus().isOK() ); BSONElement language_override_elt = spec["language_override"]; string language_override( language_override_elt.str() ); if ( language_override_elt.eoo() ) { language_override = "language"; } else { uassert( 17136, "language_override is not valid", language_override_elt.type() == String && validateOverride( language_override ) ); } int version = -1; int textIndexVersion = TEXT_INDEX_VERSION_2; BSONObjBuilder b; BSONObjIterator i( spec ); while ( i.more() ) { BSONElement e = i.next(); if ( str::equals( e.fieldName(), "key" ) ) { b.append( "key", keyPattern ); } else if ( str::equals( e.fieldName(), "weights" ) ) { b.append( "weights", weights ); weights = BSONObj(); } else if ( str::equals( e.fieldName(), "default_language" ) ) { b.append( "default_language", default_language); default_language = ""; } else if ( str::equals( e.fieldName(), "language_override" ) ) { b.append( "language_override", language_override); language_override = ""; } else if ( str::equals( e.fieldName(), "v" ) ) { version = e.numberInt(); } else if ( str::equals( e.fieldName(), "textIndexVersion" ) ) { uassert( 17293, "text index option 'textIndexVersion' must be a number", e.isNumber() ); textIndexVersion = e.numberInt(); uassert( 16730, str::stream() << "bad textIndexVersion: " << textIndexVersion, textIndexVersion == TEXT_INDEX_VERSION_2 ); } else { b.append( e ); } } if ( !weights.isEmpty() ) b.append( "weights", weights ); if ( !default_language.empty() ) b.append( "default_language", default_language); if ( !language_override.empty() ) b.append( "language_override", language_override); if ( version >= 0 ) b.append( "v", version ); b.append( "textIndexVersion", textIndexVersion ); return b.obj(); }