// testcount is a wrapper around runCount that
    //  - sets up a countStage
    //  - runs it
    //  - asserts count is not trivial
    //  - asserts nCounted is equal to expected_n
    //  - asserts nSkipped is correct
    void testCount(const CountRequest& request, int expected_n = kDocuments, bool indexed = false) {
        setup();
        getLocs();

        unique_ptr<WorkingSet> ws(new WorkingSet);

        StatusWithMatchExpression statusWithMatcher =
            MatchExpressionParser::parse(request.getQuery());
        ASSERT(statusWithMatcher.isOK());
        unique_ptr<MatchExpression> expression = std::move(statusWithMatcher.getValue());

        PlanStage* scan;
        if (indexed) {
            scan = createIndexScan(expression.get(), ws.get());
        } else {
            scan = createCollScan(expression.get(), ws.get());
        }

        CountStage countStage(&_txn, _coll, request, ws.get(), scan);

        const CountStats* stats = runCount(countStage);

        ASSERT_FALSE(stats->trivialCount);
        ASSERT_EQUALS(stats->nCounted, expected_n);
        ASSERT_EQUALS(stats->nSkipped, request.getSkip());
    }
Example #2
0
Status ModifierPull::init(const BSONElement& modExpr, const Options& opts, bool* positional) {
    // Perform standard field name and updateable checks.
    _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()
                                    << "'");
    }

    _exprElt = modExpr;

    _collator = opts.collator;

    // If the element in the mod is actually an object or a regular expression, we need to
    // build a matcher, instead of just doing an equality comparision.
    if ((_exprElt.type() == mongo::Object) || (_exprElt.type() == mongo::RegEx)) {
        if (_exprElt.type() == Object) {
            _exprObj = _exprElt.embeddedObject();

            // If not is not a query operator, then it is a primitive.
            _matcherOnPrimitive = (MatchExpressionParser::parsePathAcceptingKeyword(
                                       _exprObj.firstElement(), PathAcceptingKeyword::EQUALITY) !=
                                   PathAcceptingKeyword::EQUALITY);

            // If the object is primitive then wrap it up into an object.
            if (_matcherOnPrimitive)
                _exprObj = BSON("" << _exprObj);
        } else {
            // For a regex, we also need to wrap and treat like a primitive.
            _matcherOnPrimitive = true;
            _exprObj = _exprElt.wrap("");
        }

        // Build the matcher around the object we built above. Currently, we do not allow $pull
        // operations to contain $text/$where clauses, so preserving this behaviour.
        StatusWithMatchExpression parseResult = MatchExpressionParser::parse(
            _exprObj, ExtensionsCallbackDisallowExtensions(), _collator);
        if (!parseResult.isOK()) {
            return parseResult.getStatus();
        }

        _matchExpr = std::move(parseResult.getValue());
    }

    return Status::OK();
}
    void run() {
        ScopedTransaction transaction(&_txn, MODE_IX);
        Lock::DBLock lk(_txn.lockState(), nsToDatabaseSubstring(ns()), MODE_X);
        OldClientContext ctx(&_txn, ns());
        Database* db = ctx.db();
        Collection* coll = db->getCollection(ns());
        if (!coll) {
            WriteUnitOfWork wuow(&_txn);
            coll = db->createCollection(&_txn, ns());
            wuow.commit();
        }

        WorkingSet ws;

        // Add an object to the DB.
        insert(BSON("foo" << 5));
        set<RecordId> recordIds;
        getRecordIds(&recordIds, coll);
        ASSERT_EQUALS(size_t(1), recordIds.size());

        // Create a mock stage that returns the WSM.
        auto mockStage = make_unique<QueuedDataStage>(&_txn, &ws);

        // Mock data.
        {
            WorkingSetID id = ws.allocate();
            WorkingSetMember* mockMember = ws.get(id);
            mockMember->recordId = *recordIds.begin();
            ws.transitionToRecordIdAndIdx(id);

            // State is RecordId and index, shouldn't be able to get the foo data inside.
            BSONElement elt;
            ASSERT_FALSE(mockMember->getFieldDotted("foo", &elt));
            mockStage->pushBack(id);
        }

        // Make the filter.
        BSONObj filterObj = BSON("foo" << 6);
        const CollatorInterface* collator = nullptr;
        StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(
            filterObj, ExtensionsCallbackDisallowExtensions(), collator);
        verify(statusWithMatcher.isOK());
        unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue());

        // Matcher requires that foo==6 but we only have data with foo==5.
        unique_ptr<FetchStage> fetchStage(
            new FetchStage(&_txn, &ws, mockStage.release(), filterExpr.get(), coll));

        // First call should return a fetch request as it's not in memory.
        WorkingSetID id = WorkingSet::INVALID_ID;
        PlanStage::StageState state;

        // Normally we'd return the object but we have a filter that prevents it.
        state = fetchStage->work(&id);
        ASSERT_EQUALS(PlanStage::NEED_TIME, state);

        // No more data to fetch, so, EOF.
        state = fetchStage->work(&id);
        ASSERT_EQUALS(PlanStage::IS_EOF, state);
    }
    Status CanonicalQuery::init(LiteParsedQuery* lpq) {
        _pq.reset(lpq);

        // Build a parse tree from the BSONObj in the parsed query.
        StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter());
        if (!swme.isOK()) { return swme.getStatus(); }

        MatchExpression* root = swme.getValue();
        root = normalizeTree(root);
        Status validStatus = isValid(root);
        if (!validStatus.isOK()) {
            return validStatus;
        }

        _root.reset(root);

        if (!_pq->getProj().isEmpty()) {
            LiteProjection* liteProj = NULL;
            Status liteProjStatus = LiteProjection::make(_pq->getFilter(), _pq->getProj(), &liteProj);
            if (!liteProjStatus.isOK()) {
                return liteProjStatus;
            }
            _liteProj.reset(liteProj);
        }

        return Status::OK();
    }
Example #5
0
void IndexCatalogEntry::init(OperationContext* txn, IndexAccessMethod* accessMethod) {
    verify(_accessMethod == NULL);
    _accessMethod = accessMethod;

    _isReady = _catalogIsReady(txn);
    _head = _catalogHead(txn);
    _isMultikey = _catalogIsMultikey(txn);

    if (BSONElement filterElement = _descriptor->getInfoElement("partialFilterExpression")) {
        invariant(filterElement.isABSONObj());
        BSONObj filter = filterElement.Obj();
        // TODO SERVER-23618: pass the appropriate CollatorInterface* instead of nullptr.
        StatusWithMatchExpression statusWithMatcher =
            MatchExpressionParser::parse(filter, ExtensionsCallbackDisallowExtensions(), nullptr);
        // this should be checked in create, so can blow up here
        invariantOK(statusWithMatcher.getStatus());
        _filterExpression = std::move(statusWithMatcher.getValue());
        LOG(2) << "have filter expression for " << _ns << " " << _descriptor->indexName() << " "
               << filter;
    }

    if (BSONElement collationElement = _descriptor->getInfoElement("collation")) {
        invariant(collationElement.isABSONObj());
        BSONObj collation = collationElement.Obj();
        auto statusWithCollator =
            CollatorFactoryInterface::get(txn->getServiceContext())->makeFromBSON(collation);
        invariantOK(statusWithCollator.getStatus());
        _collator = std::move(statusWithCollator.getValue());
    }
}
Status AuthzManagerExternalStateMock::_queryVector(
    OperationContext* opCtx,
    const NamespaceString& collectionName,
    const BSONObj& query,
    std::vector<BSONObjCollection::iterator>* result) {
    const CollatorInterface* collator = nullptr;
    boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContext(opCtx, collator));
    StatusWithMatchExpression parseResult = MatchExpressionParser::parse(query, std::move(expCtx));
    if (!parseResult.isOK()) {
        return parseResult.getStatus();
    }
    const std::unique_ptr<MatchExpression> matcher = std::move(parseResult.getValue());

    NamespaceDocumentMap::iterator mapIt = _documents.find(collectionName);
    if (mapIt == _documents.end())
        return Status::OK();

    for (BSONObjCollection::iterator vecIt = mapIt->second.begin(); vecIt != mapIt->second.end();
         ++vecIt) {
        if (matcher->matchesBSON(*vecIt)) {
            result->push_back(vecIt);
        }
    }
    return Status::OK();
}
    Status AuthzManagerExternalStateMock::_queryVector(
            const NamespaceString& collectionName,
            const BSONObj& query,
            std::vector<BSONObjCollection::iterator>* result) {

        StatusWithMatchExpression parseResult = MatchExpressionParser::parse(query);
        if (!parseResult.isOK()) {
            return parseResult.getStatus();
        }
        MatchExpression* matcher = parseResult.getValue();

        NamespaceDocumentMap::iterator mapIt = _documents.find(collectionName);
        if (mapIt == _documents.end())
            return Status(ErrorCodes::NoMatchingDocument,
                          "No collection named " + collectionName.ns());

        for (BSONObjCollection::iterator vecIt = mapIt->second.begin();
             vecIt != mapIt->second.end();
             ++vecIt) {

            if (matcher->matchesBSON(*vecIt)) {
                result->push_back(vecIt);
            }
        }
        return Status::OK();
    }
Example #8
0
    int countResults(CollectionScanParams::Direction direction, const BSONObj& filterObj) {
        AutoGetCollectionForRead ctx(&_txn, ns());

        // Configure the scan.
        CollectionScanParams params;
        params.collection = ctx.getCollection();
        params.direction = direction;
        params.tailable = false;

        // Make the filter.
        StatusWithMatchExpression swme = MatchExpressionParser::parse(filterObj);
        verify(swme.isOK());
        unique_ptr<MatchExpression> filterExpr(swme.getValue());

        // Make a scan and have the runner own it.
        unique_ptr<WorkingSet> ws = make_unique<WorkingSet>();
        unique_ptr<PlanStage> ps =
            make_unique<CollectionScan>(&_txn, params, ws.get(), filterExpr.get());

        auto statusWithPlanExecutor = PlanExecutor::make(
            &_txn, std::move(ws), std::move(ps), params.collection, PlanExecutor::YIELD_MANUAL);
        ASSERT_OK(statusWithPlanExecutor.getStatus());
        unique_ptr<PlanExecutor> exec = std::move(statusWithPlanExecutor.getValue());

        // Use the runner to count the number of objects scanned.
        int count = 0;
        for (BSONObj obj; PlanExecutor::ADVANCED == exec->getNext(&obj, NULL);) {
            ++count;
        }
        return count;
    }
    int countResults(const IndexScanParams& params, BSONObj filterObj = BSONObj()) {
        AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(ns()));

        const CollatorInterface* collator = nullptr;
        const boost::intrusive_ptr<ExpressionContext> expCtx(
            new ExpressionContext(&_opCtx, collator));
        StatusWithMatchExpression statusWithMatcher =
            MatchExpressionParser::parse(filterObj, expCtx);
        verify(statusWithMatcher.isOK());
        unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue());

        unique_ptr<WorkingSet> ws = stdx::make_unique<WorkingSet>();
        unique_ptr<IndexScan> ix =
            stdx::make_unique<IndexScan>(&_opCtx, params, ws.get(), filterExpr.get());

        auto statusWithPlanExecutor = PlanExecutor::make(
            &_opCtx, std::move(ws), std::move(ix), ctx.getCollection(), PlanExecutor::NO_YIELD);
        ASSERT_OK(statusWithPlanExecutor.getStatus());
        auto exec = std::move(statusWithPlanExecutor.getValue());

        int count = 0;
        PlanExecutor::ExecState state;
        for (RecordId dl; PlanExecutor::ADVANCED == (state = exec->getNext(NULL, &dl));) {
            ++count;
        }
        ASSERT_EQUALS(PlanExecutor::IS_EOF, state);

        return count;
    }
    Status AuthzManagerExternalStateMock::_queryVector(
            const NamespaceString& collectionName,
            const BSONObj& query,
            std::vector<BSONObjCollection::iterator>* result) {

        StatusWithMatchExpression parseResult = 
                MatchExpressionParser::parse(query, MatchExpressionParser::WhereCallback());
        if (!parseResult.isOK()) {
            return parseResult.getStatus();
        }
        const boost::scoped_ptr<MatchExpression> matcher(parseResult.getValue());

        NamespaceDocumentMap::iterator mapIt = _documents.find(collectionName);
        if (mapIt == _documents.end())
            return Status::OK();

        for (BSONObjCollection::iterator vecIt = mapIt->second.begin();
             vecIt != mapIt->second.end();
             ++vecIt) {

            if (matcher->matchesBSON(*vecIt)) {
                result->push_back(vecIt);
            }
        }
        return Status::OK();
    }
Example #11
0
        int countResults(CollectionScanParams::Direction direction, const BSONObj& filterObj) {
            AutoGetCollectionForRead ctx(&_txn, ns());

            // Configure the scan.
            CollectionScanParams params;
            params.collection = ctx.getCollection();
            params.direction = direction;
            params.tailable = false;

            // Make the filter.
            StatusWithMatchExpression swme = MatchExpressionParser::parse(filterObj);
            verify(swme.isOK());
            auto_ptr<MatchExpression> filterExpr(swme.getValue());

            // Make a scan and have the runner own it.
            WorkingSet* ws = new WorkingSet();
            PlanStage* ps = new CollectionScan(&_txn, params, ws, filterExpr.get());

            PlanExecutor* rawExec;
            Status status = PlanExecutor::make(&_txn, ws, ps, params.collection,
                                               PlanExecutor::YIELD_MANUAL, &rawExec);
            ASSERT_OK(status);
            boost::scoped_ptr<PlanExecutor> exec(rawExec);

            // Use the runner to count the number of objects scanned.
            int count = 0;
            for (BSONObj obj; PlanExecutor::ADVANCED == exec->getNext(&obj, NULL); ) { ++count; }
            return count;
        }
        /**
         * Given a match expression, represented as the BSON object 'filterObj',
         * create a SingleSolutionRunner capable of executing a simple collection
         * scan.
         *
         * The caller takes ownership of the returned SingleSolutionRunner*.
         */
        SingleSolutionRunner* makeCollScanRunner(Client::Context& ctx,
                                                 BSONObj& filterObj) {
            CollectionScanParams csparams;
            csparams.collection = ctx.db()->getCollection( &_txn, ns() );
            csparams.direction = CollectionScanParams::FORWARD;
            auto_ptr<WorkingSet> ws(new WorkingSet());
            // Parse the filter.
            StatusWithMatchExpression swme = MatchExpressionParser::parse(filterObj);
            verify(swme.isOK());
            auto_ptr<MatchExpression> filter(swme.getValue());
            // Make the stage.
            auto_ptr<PlanStage> root(new CollectionScan(csparams, ws.get(), filter.release()));

            CanonicalQuery* cq;
            verify(CanonicalQuery::canonicalize(ns(), filterObj, &cq).isOK());
            verify(NULL != cq);

            // Hand the plan off to the single solution runner.
            SingleSolutionRunner* ssr = new SingleSolutionRunner(ctx.db()->getCollection(&_txn, ns()),
                                                                 cq,
                                                                 new QuerySolution(),
                                                                 root.release(),
                                                                 ws.release());
            return ssr;
        }
Example #13
0
        void run() {
            Client::WriteContext ctx(ns());

            for (int i = 0; i < 50; ++i) {
                insert(BSON("foo" << 1 << "bar" << 1));
            }

            addIndex(BSON("foo" << 1));
            addIndex(BSON("bar" << 1));

            WorkingSet ws;
            BSONObj filterObj = BSON("foo" << BSON("$ne" << 1));
            StatusWithMatchExpression swme = MatchExpressionParser::parse(filterObj);
            verify(swme.isOK());
            auto_ptr<MatchExpression> filterExpr(swme.getValue());
            scoped_ptr<AndSortedStage> ah(new AndSortedStage(&ws, filterExpr.get()));

            // Scan over foo == 1
            IndexScanParams params;
            params.descriptor = getIndex(BSON("foo" << 1));
            params.bounds.isSimpleRange = true;
            params.bounds.startKey = BSON("" << 1);
            params.bounds.endKey = BSON("" << 1);
            params.bounds.endKeyInclusive = true;
            params.direction = 1;
            ah->addChild(new IndexScan(params, &ws, NULL));

            // bar == 1
            params.descriptor = getIndex(BSON("bar" << 1));
            ah->addChild(new IndexScan(params, &ws, NULL));

            // Filter drops everything.
            ASSERT_EQUALS(0, countResults(ah.get()));
        }
    // $near must be the only field in the expression object.
    TEST( MatchExpressionParserGeoNear, ParseNearExtraField ) {
        BSONObj query = fromjson("{loc:{$near:{$maxDistance:100, "
                                 "$geometry:{type:\"Point\", coordinates:[0,0]}}, foo: 1}}");

        StatusWithMatchExpression result = MatchExpressionParser::parse( query );
        ASSERT_FALSE( result.isOK() );
    }
TEST(MatchExpressionParserGeoNear, ParseInvalidNearSphere) {
    {
        BSONObj query = fromjson("{loc: {$maxDistance: 100, $nearSphere: [0,0]}}");
        StatusWithMatchExpression result =
            MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions());
        ASSERT_FALSE(result.isOK());
    }
    {
        BSONObj query = fromjson("{loc: {$minDistance: 100, $nearSphere: [0,0]}}");
        StatusWithMatchExpression result =
            MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions());
        ASSERT_FALSE(result.isOK());
    }
    {
        BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $maxDistance: {}}}");
        ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()),
                      UserException);
    }
    {
        BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $minDistance: {}}}");
        ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()),
                      UserException);
    }
    {
        BSONObj query = fromjson("{loc: {$nearSphere: [0,0], $eq: 1}}");
        ASSERT_THROWS(MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions()),
                      UserException);
    }
}
Example #16
0
Status CanonicalQuery::init(LiteParsedQuery* lpq) {
    _pq.reset(lpq);

    // Build a parse tree from the BSONObj in the parsed query.
    StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter());
    if (!swme.isOK()) {
        return swme.getStatus();
    }

    MatchExpression* root = swme.getValue();
    root = normalizeTree(root);
    Status validStatus = isValid(root);
    if (!validStatus.isOK()) {
        return validStatus;
    }

    _root.reset(root);

    // Validate the projection if there is one.
    if (!_pq->getProj().isEmpty()) {
        ParsedProjection* pp;
        Status projStatus = ParsedProjection::make(_pq->getProj(), root, &pp);
        if (!projStatus.isOK()) {
            return projStatus;
        }
        _proj.reset(pp);
    }

    return Status::OK();
}
Example #17
0
    int countResults(const IndexScanParams& params, BSONObj filterObj = BSONObj()) {
        AutoGetCollectionForRead ctx(&_txn, NamespaceString(ns()));

        const CollatorInterface* collator = nullptr;
        StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(
            filterObj, ExtensionsCallbackDisallowExtensions(), collator);
        verify(statusWithMatcher.isOK());
        unique_ptr<MatchExpression> filterExpr = std::move(statusWithMatcher.getValue());

        unique_ptr<WorkingSet> ws = stdx::make_unique<WorkingSet>();
        unique_ptr<IndexScan> ix =
            stdx::make_unique<IndexScan>(&_txn, params, ws.get(), filterExpr.get());

        auto statusWithPlanExecutor = PlanExecutor::make(
            &_txn, std::move(ws), std::move(ix), ctx.getCollection(), PlanExecutor::YIELD_MANUAL);
        ASSERT_OK(statusWithPlanExecutor.getStatus());
        unique_ptr<PlanExecutor> exec = std::move(statusWithPlanExecutor.getValue());

        int count = 0;
        PlanExecutor::ExecState state;
        for (RecordId dl; PlanExecutor::ADVANCED == (state = exec->getNext(NULL, &dl));) {
            ++count;
        }
        ASSERT_EQUALS(PlanExecutor::IS_EOF, state);

        return count;
    }
Example #18
0
        bool run(OperationContext* txn,
                 const string& dbname,
                 BSONObj& jsobj,
                 int,
                 string& errmsg,
                 BSONObjBuilder& result,
                 bool /*fromRepl*/) {

            AutoGetDb autoDb(txn, dbname, MODE_S);

            const Database* d = autoDb.getDb();
            const DatabaseCatalogEntry* dbEntry = NULL;

            list<string> names;
            if ( d ) {
                dbEntry = d->getDatabaseCatalogEntry();
                dbEntry->getCollectionNamespaces( &names );
                names.sort();
            }

            scoped_ptr<MatchExpression> matcher;
            if ( jsobj["filter"].isABSONObj() ) {
                StatusWithMatchExpression parsed =
                    MatchExpressionParser::parse( jsobj["filter"].Obj() );
                if ( !parsed.isOK() ) {
                    return appendCommandStatus( result, parsed.getStatus() );
                }
                matcher.reset( parsed.getValue() );
            }

            BSONArrayBuilder arr;

            for ( list<string>::const_iterator i = names.begin(); i != names.end(); ++i ) {
                string ns = *i;

                StringData collection = nsToCollectionSubstring( ns );
                if ( collection == "system.namespaces" ) {
                    continue;
                }

                BSONObjBuilder b;
                b.append( "name", collection );

                CollectionOptions options =
                    dbEntry->getCollectionCatalogEntry( txn, ns )->getCollectionOptions(txn);
                b.append( "options", options.toBSON() );

                BSONObj maybe = b.obj();
                if ( matcher && !matcher->matchesBSON( maybe ) ) {
                    continue;
                }

                arr.append( maybe );
            }

            result.append( "collections", arr.arr() );

            return true;
        }
    TEST( MatchExpressionParserTest, SimpleEQ1 ) {
        BSONObj query = BSON( "x" << 2 );
        StatusWithMatchExpression result = MatchExpressionParser::parse( query );
        ASSERT_TRUE( result.isOK() );

        ASSERT( result.getValue()->matchesBSON( BSON( "x" << 2 ) ) );
        ASSERT( !result.getValue()->matchesBSON( BSON( "x" << 3 ) ) );
    }
    TEST( MatchExpressionParserTreeTest, NOT1 ) {
        BSONObj query = BSON( "x" << BSON( "$not" << BSON( "$gt" << 5 ) ) );
        StatusWithMatchExpression result = MatchExpressionParser::parse( query );
        ASSERT_TRUE( result.isOK() );

        ASSERT( result.getValue()->matchesBSON( BSON( "x" << 2 ) ) );
        ASSERT( !result.getValue()->matchesBSON( BSON( "x" << 8 ) ) );
    }
TEST(MatchExpressionParserTest, SimpleEQ1) {
    BSONObj query = BSON("x" << 2);
    const CollatorInterface* collator = nullptr;
    StatusWithMatchExpression result = MatchExpressionParser::parse(query, collator);
    ASSERT_TRUE(result.isOK());

    ASSERT(result.getValue()->matchesBSON(BSON("x" << 2)));
    ASSERT(!result.getValue()->matchesBSON(BSON("x" << 3)));
}
Example #22
0
        void run() {
            ScopedTransaction transaction(&_txn, MODE_IX);
            Lock::DBLock lk(_txn.lockState(), nsToDatabaseSubstring(ns()), MODE_X);
            Client::Context ctx(&_txn, ns());
            Database* db = ctx.db();
            Collection* coll = db->getCollection(&_txn, ns());
            if (!coll) {
                WriteUnitOfWork wuow(&_txn);
                coll = db->createCollection(&_txn, ns());
                wuow.commit();
            }

            WorkingSet ws;

            // Add an object to the DB.
            insert(BSON("foo" << 5));
            set<DiskLoc> locs;
            getLocs(&locs, coll);
            ASSERT_EQUALS(size_t(1), locs.size());

            // Create a mock stage that returns the WSM.
            auto_ptr<MockStage> mockStage(new MockStage(&ws));

            // Mock data.
            {
                WorkingSetMember mockMember;
                mockMember.state = WorkingSetMember::LOC_AND_IDX;
                mockMember.loc = *locs.begin();

                // State is loc and index, shouldn't be able to get the foo data inside.
                BSONElement elt;
                ASSERT_FALSE(mockMember.getFieldDotted("foo", &elt));
                mockStage->pushBack(mockMember);
            }

            // Make the filter.
            BSONObj filterObj = BSON("foo" << 6);
            StatusWithMatchExpression swme = MatchExpressionParser::parse(filterObj);
            verify(swme.isOK());
            auto_ptr<MatchExpression> filterExpr(swme.getValue());

            // Matcher requires that foo==6 but we only have data with foo==5.
            auto_ptr<FetchStage> fetchStage(
                     new FetchStage(&_txn, &ws, mockStage.release(), filterExpr.get(), coll));

            // First call should return a fetch request as it's not in memory.
            WorkingSetID id = WorkingSet::INVALID_ID;
            PlanStage::StageState state;

            // Normally we'd return the object but we have a filter that prevents it.
            state = fetchStage->work(&id);
            ASSERT_EQUALS(PlanStage::NEED_TIME, state);

            // No more data to fetch, so, EOF.
            state = fetchStage->work(&id);
            ASSERT_EQUALS(PlanStage::IS_EOF, state);
        }
TEST(MatchExpressionParserTreeTest, NOT1) {
    BSONObj query = BSON("x" << BSON("$not" << BSON("$gt" << 5)));
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    StatusWithMatchExpression result = MatchExpressionParser::parse(query, expCtx);
    ASSERT_TRUE(result.isOK());

    ASSERT(result.getValue()->matchesBSON(BSON("x" << 2)));
    ASSERT(!result.getValue()->matchesBSON(BSON("x" << 8)));
}
std::unique_ptr<MatchExpression> QueryPlannerTest::parseMatchExpression(const BSONObj& obj) {
    StatusWithMatchExpression status =
        MatchExpressionParser::parse(obj, ExtensionsCallbackDisallowExtensions());
    if (!status.isOK()) {
        FAIL(str::stream() << "failed to parse query: " << obj.toString()
                           << ". Reason: " << status.getStatus().toString());
    }
    return std::move(status.getValue());
}
TEST(MatchExpressionParserTreeTest, NOT1) {
    BSONObj query = BSON("x" << BSON("$not" << BSON("$gt" << 5)));
    const CollatorInterface* collator = nullptr;
    StatusWithMatchExpression result =
        MatchExpressionParser::parse(query, ExtensionsCallbackDisallowExtensions(), collator);
    ASSERT_TRUE(result.isOK());

    ASSERT(result.getValue()->matchesBSON(BSON("x" << 2)));
    ASSERT(!result.getValue()->matchesBSON(BSON("x" << 8)));
}
Example #26
0
    Status CanonicalQuery::init(LiteParsedQuery* lpq) {
        _pq.reset(lpq);

        // Build a parse tree from the BSONObj in the parsed query.
        StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter());
        if (!swme.isOK()) { return swme.getStatus(); }

        _root.reset(swme.getValue());
        return Status::OK();
    }
std::unique_ptr<MatchExpression> QueryPlannerTest::parseMatchExpression(
    const BSONObj& obj, const CollatorInterface* collator) {
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    expCtx->setCollator(collator);
    StatusWithMatchExpression status = MatchExpressionParser::parse(obj, std::move(expCtx));
    if (!status.isOK()) {
        FAIL(str::stream() << "failed to parse query: " << obj.toString() << ". Reason: "
                           << status.getStatus().toString());
    }
    return std::move(status.getValue());
}
    TEST( MatchExpressionParserTreeTest, NOREmbedded ) {
        BSONObj query = BSON( "$nor" << BSON_ARRAY( BSON( "x" << 1 ) <<
                                                    BSON( "y" << 2 ) ) );
        StatusWithMatchExpression result = MatchExpressionParser::parse( query );
        ASSERT_TRUE( result.isOK() );

        ASSERT( !result.getValue()->matchesBSON( BSON( "x" << 1 ) ) );
        ASSERT( !result.getValue()->matchesBSON( BSON( "y" << 2 ) ) );
        ASSERT( result.getValue()->matchesBSON( BSON( "x" << 3 ) ) );
        ASSERT( result.getValue()->matchesBSON( BSON( "y" << 1 ) ) );
    }
    TEST( MatchExpressionParserLeafTest, NotRegex1 ) {
        BSONObjBuilder b;
        b.appendRegex( "$not", "abc", "i" );
        BSONObj query = BSON( "x" << b.obj() );
        StatusWithMatchExpression result = MatchExpressionParser::parse( query );
        ASSERT_TRUE( result.isOK() );

        ASSERT( !result.getValue()->matchesBSON( BSON( "x" << "abc" ) ) );
        ASSERT( !result.getValue()->matchesBSON( BSON( "x" << "ABC" ) ) );
        ASSERT( result.getValue()->matchesBSON( BSON( "x" << "AC" ) ) );
    }
Example #30
0
    StatusWithMatchExpression MatchExpressionParser::_parseAll( const char* name,
                                                      const BSONElement& e ) {
        if ( e.type() != Array )
            return StatusWithMatchExpression( ErrorCodes::BadValue, "$all needs an array" );

        BSONObj arr = e.Obj();
        if ( arr.firstElement().type() == Object &&
             mongoutils::str::equals( "$elemMatch",
                                      arr.firstElement().Obj().firstElement().fieldName() ) ) {
            // $all : [ { $elemMatch : {} } ... ]

            std::auto_ptr<AllElemMatchOp> temp( new AllElemMatchOp() );
            Status s = temp->init( name );
            if ( !s.isOK() )
                return StatusWithMatchExpression( s );

            BSONObjIterator i( arr );
            while ( i.more() ) {
                BSONElement hopefullyElemMatchElemennt = i.next();

                if ( hopefullyElemMatchElemennt.type() != Object ) {
                    // $all : [ { $elemMatch : ... }, 5 ]
                    return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                 "$all/$elemMatch has to be consistent" );
                }

                BSONObj hopefullyElemMatchObj = hopefullyElemMatchElemennt.Obj();
                if ( !mongoutils::str::equals( "$elemMatch",
                                               hopefullyElemMatchObj.firstElement().fieldName() ) ) {
                    // $all : [ { $elemMatch : ... }, { x : 5 } ]
                    return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                 "$all/$elemMatch has to be consistent" );
                }

                StatusWithMatchExpression inner = _parseElemMatch( "", hopefullyElemMatchObj.firstElement() );
                if ( !inner.isOK() )
                    return inner;
                temp->add( static_cast<ArrayMatchingMatchExpression*>( inner.getValue() ) );
            }

            return StatusWithMatchExpression( temp.release() );
        }

        std::auto_ptr<AllMatchExpression> temp( new AllMatchExpression() );
        Status s = temp->init( name );
        if ( !s.isOK() )
            return StatusWithMatchExpression( s );

        s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), arr );
        if ( !s.isOK() )
            return StatusWithMatchExpression( s );

        return StatusWithMatchExpression( temp.release() );
    }