Esempio n. 1
0
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);
    }
}
Esempio n. 2
0
        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;
        }
Esempio n. 3
0
        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();
        }
Esempio n. 4
0
 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);
}
Esempio n. 6
0
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());
        }
    }
}
Esempio n. 7
0
        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());
        }
Esempio n. 8
0
// 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;
}
Esempio n. 9
0
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;
    }
Esempio n. 11
0
    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;
    }
Esempio n. 12
0
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();
}
Esempio n. 13
0
        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;
        }
Esempio n. 14
0
        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;
        }
Esempio n. 15
0
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);
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
 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));
 }
Esempio n. 19
0
   // 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 ;
   }
Esempio n. 20
0
   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 ;
   }
Esempio n. 21
0
    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" );
        }

    }
Esempio n. 22
0
    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();
    }
Esempio n. 23
0
 static double fieldWithDefault(const BSONObj& infoObj, const string& name, double def) {
     BSONElement e = infoObj[name];
     if (e.isNumber()) { return e.numberDouble(); }
     return def;
 }
Esempio n. 24
0
    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() );
    }
Esempio n. 25
0
    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();
    }
Esempio n. 26
0
    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;
        }
    }
}
Esempio n. 28
0
 static double configValueWithDefault(const IndexDescriptor *desc, const string& name, double def) {
     BSONElement e = desc->getInfoElement(name);
     if (e.isNumber()) { return e.numberDouble(); }
     return def;
 }
Esempio n. 29
0
   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 ;
   }
Esempio n. 30
0
 int hash( const BSONElement& e ) const {
     uassert( 13322 , "not a number" , e.isNumber() );
     return hash( e.numberDouble() );
 }