Пример #1
0
    void run() {
        // Rewrite (AND (OR a b) e) => (OR (AND a e) (AND b e))
        {
            BSONObj queryObj = fromjson("{$or:[{a:1}, {b:1}], e:1}");
            const CollatorInterface* collator = nullptr;
            StatusWithMatchExpression expr = MatchExpressionParser::parse(
                queryObj, ExtensionsCallbackDisallowExtensions(), collator);
            ASSERT_OK(expr.getStatus());
            std::unique_ptr<MatchExpression> rewrittenExpr =
                SubplanStage::rewriteToRootedOr(std::move(expr.getValue()));

            std::string findCmdRewritten =
                "{find: 'testns',"
                "filter: {$or:[{a:1,e:1}, {b:1,e:1}]}}";
            std::unique_ptr<CanonicalQuery> cqRewritten = cqFromFindCommand(findCmdRewritten);

            ASSERT(rewrittenExpr->equivalent(cqRewritten->root()));
        }

        // Rewrite (AND (OR a b) e f) => (OR (AND a e f) (AND b e f))
        {
            BSONObj queryObj = fromjson("{$or:[{a:1}, {b:1}], e:1, f:1}");
            const CollatorInterface* collator = nullptr;
            StatusWithMatchExpression expr = MatchExpressionParser::parse(
                queryObj, ExtensionsCallbackDisallowExtensions(), collator);
            ASSERT_OK(expr.getStatus());
            std::unique_ptr<MatchExpression> rewrittenExpr =
                SubplanStage::rewriteToRootedOr(std::move(expr.getValue()));

            std::string findCmdRewritten =
                "{find: 'testns',"
                "filter: {$or:[{a:1,e:1,f:1}, {b:1,e:1,f:1}]}}";
            std::unique_ptr<CanonicalQuery> cqRewritten = cqFromFindCommand(findCmdRewritten);

            ASSERT(rewrittenExpr->equivalent(cqRewritten->root()));
        }

        // Rewrite (AND (OR (AND a b) (AND c d) e f) => (OR (AND a b e f) (AND c d e f))
        {
            BSONObj queryObj = fromjson("{$or:[{a:1,b:1}, {c:1,d:1}], e:1,f:1}");
            const CollatorInterface* collator = nullptr;
            StatusWithMatchExpression expr = MatchExpressionParser::parse(
                queryObj, ExtensionsCallbackDisallowExtensions(), collator);
            ASSERT_OK(expr.getStatus());
            std::unique_ptr<MatchExpression> rewrittenExpr =
                SubplanStage::rewriteToRootedOr(std::move(expr.getValue()));

            std::string findCmdRewritten =
                "{find: 'testns',"
                "filter: {$or:[{a:1,b:1,e:1,f:1},"
                "{c:1,d:1,e:1,f:1}]}}";
            std::unique_ptr<CanonicalQuery> cqRewritten = cqFromFindCommand(findCmdRewritten);

            ASSERT(rewrittenExpr->equivalent(cqRewritten->root()));
        }
    }
Пример #2
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(
            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();
    }
Пример #4
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);

        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();
    }
Пример #5
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();
}
Пример #6
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();
        Status validStatus = this->normalize(root);
        if (!validStatus.isOK()) {
            return validStatus;
        }
        this->generateCacheKey();

        // 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();
    }
Пример #7
0
    Status ModifierPull::init(const BSONElement& modExpr, const Options& opts) {
        // 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 (foundDollar && foundCount > 1) {
            return Status(ErrorCodes::BadValue, "too many positional($) elements found.");
        }

        _exprElt = modExpr;
        if (_exprElt.type() == Object) {

            _exprObj = _exprElt.embeddedObject();
            _matcherOnPrimitive = (_exprObj.firstElement().getGtLtOp() != 0);
            if (_matcherOnPrimitive)
                _exprObj = BSON( "" << _exprObj );

            StatusWithMatchExpression parseResult = MatchExpressionParser::parse(_exprObj);
            if (!parseResult.isOK())
                return parseResult.getStatus();

            _matchExpr.reset(parseResult.getValue());
        }

        return Status::OK();
    }
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, 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();
    }
Пример #10
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);

        if (!_pq->getProj().isEmpty()) {
            ParsedProjection* proj;
            Status projStatus = ProjectionParser::parseFindSyntax(_pq->getProj(), &proj);
            if (!projStatus.isOK()) {
                return projStatus;
            }
            _proj.reset(proj);
        }

        return Status::OK();
    }
Пример #11
0
        bool run(OperationContext* txn,
                 const string& dbname,
                 BSONObj& jsobj,
                 int,
                 string& errmsg,
                 BSONObjBuilder& result,
                 bool /*fromRepl*/) {

            ScopedTransaction scopedXact(txn, MODE_IS);
            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;
        }
Пример #12
0
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());
}
Пример #13
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();
    }
Пример #14
0
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());
}
Пример #15
0
Matcher::Matcher(const BSONObj& pattern,
                 const boost::intrusive_ptr<ExpressionContext>& expCtx,
                 const ExtensionsCallback& extensionsCallback,
                 const MatchExpressionParser::AllowedFeatureSet allowedFeatures)
    : _pattern(pattern) {
    StatusWithMatchExpression statusWithMatcher =
        MatchExpressionParser::parse(pattern, expCtx, extensionsCallback, allowedFeatures);
    uassert(16810,
            mongoutils::str::stream() << "bad query: " << statusWithMatcher.getStatus().toString(),
            statusWithMatcher.isOK());

    _expression = std::move(statusWithMatcher.getValue());
}
Пример #16
0
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
    OperationContext* opCtx,
    std::unique_ptr<QueryRequest> qr,
    const boost::intrusive_ptr<ExpressionContext>& expCtx,
    const ExtensionsCallback& extensionsCallback,
    MatchExpressionParser::AllowedFeatureSet allowedFeatures) {
    auto qrStatus = qr->validate();
    if (!qrStatus.isOK()) {
        return qrStatus;
    }

    std::unique_ptr<CollatorInterface> collator;
    if (!qr->getCollation().isEmpty()) {
        auto statusWithCollator = CollatorFactoryInterface::get(opCtx->getServiceContext())
                                      ->makeFromBSON(qr->getCollation());
        if (!statusWithCollator.isOK()) {
            return statusWithCollator.getStatus();
        }
        collator = std::move(statusWithCollator.getValue());
    }

    // Make MatchExpression.
    boost::intrusive_ptr<ExpressionContext> newExpCtx;
    if (!expCtx.get()) {
        newExpCtx.reset(new ExpressionContext(opCtx, collator.get()));
    } else {
        newExpCtx = expCtx;
        invariant(CollatorInterface::collatorsMatch(collator.get(), expCtx->getCollator()));
    }
    StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(
        qr->getFilter(), newExpCtx, extensionsCallback, allowedFeatures);
    if (!statusWithMatcher.isOK()) {
        return statusWithMatcher.getStatus();
    }
    std::unique_ptr<MatchExpression> me = std::move(statusWithMatcher.getValue());

    // Make the CQ we'll hopefully return.
    std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery());

    Status initStatus =
        cq->init(opCtx,
                 std::move(qr),
                 parsingCanProduceNoopMatchNodes(extensionsCallback, allowedFeatures),
                 std::move(me),
                 std::move(collator));

    if (!initStatus.isOK()) {
        return initStatus;
    }
    return std::move(cq);
}
Пример #17
0
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
    const std::string& ns,
    const BSONObj& query,
    const BSONObj& sort,
    const BSONObj& proj,
    long long skip,
    long long limit,
    const BSONObj& hint,
    const BSONObj& minObj,
    const BSONObj& maxObj,
    bool snapshot,
    bool explain,
    const MatchExpressionParser::WhereCallback& whereCallback) {
    // Pass empty sort and projection.
    BSONObj emptyObj;

    auto lpqStatus = LiteParsedQuery::makeAsOpQuery(NamespaceString(ns),
                                                    skip,
                                                    limit,
                                                    0,
                                                    query,
                                                    proj,
                                                    sort,
                                                    hint,
                                                    minObj,
                                                    maxObj,
                                                    snapshot,
                                                    explain);
    if (!lpqStatus.isOK()) {
        return lpqStatus.getStatus();
    }

    auto& lpq = lpqStatus.getValue();

    // Build a parse tree from the BSONObj in the parsed query.
    StatusWithMatchExpression statusWithMatcher =
        MatchExpressionParser::parse(lpq->getFilter(), whereCallback);
    if (!statusWithMatcher.isOK()) {
        return statusWithMatcher.getStatus();
    }
    std::unique_ptr<MatchExpression> me = std::move(statusWithMatcher.getValue());

    // Make the CQ we'll hopefully return.
    std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery());
    Status initStatus = cq->init(lpq.release(), whereCallback, me.release());

    if (!initStatus.isOK()) {
        return initStatus;
    }
    return std::move(cq);
}
Пример #18
0
    Status ModifierPull::init(const BSONElement& modExpr, const Options& opts) {
        // 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 (foundDollar && foundCount > 1) {
            return Status(ErrorCodes::BadValue,
                          str::stream() << "Too many positional (i.e. '$') elements found in path '"
                                        << _fieldRef.dottedField() << "'");
        }

        _exprElt = modExpr;

        // 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 = (_exprObj.firstElement().getGtLtOp() != 0);

                // 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.
            StatusWithMatchExpression parseResult = MatchExpressionParser::parse(_exprObj);
            if (!parseResult.isOK())
                return parseResult.getStatus();

            _matchExpr.reset(parseResult.getValue());
        }

        return Status::OK();
    }
Пример #19
0
IndexCatalogEntryImpl::IndexCatalogEntryImpl(IndexCatalogEntry* const this_,
                                             OperationContext* const opCtx,
                                             const StringData ns,
                                             CollectionCatalogEntry* const collection,
                                             std::unique_ptr<IndexDescriptor> descriptor,
                                             CollectionInfoCache* const infoCache)
    : _ns(ns.toString()),
      _collection(collection),
      _descriptor(std::move(descriptor)),
      _infoCache(infoCache),
      _headManager(stdx::make_unique<HeadManagerImpl>(this_)),
      _ordering(Ordering::make(_descriptor->keyPattern())),
      _isReady(false),
      _prefix(collection->getIndexPrefix(opCtx, _descriptor->indexName())) {
    _descriptor->_cachedEntry = this_;

    _isReady = _catalogIsReady(opCtx);
    _head = _catalogHead(opCtx);

    {
        stdx::lock_guard<stdx::mutex> lk(_indexMultikeyPathsMutex);
        _isMultikey.store(_catalogIsMultikey(opCtx, &_indexMultikeyPaths));
        _indexTracksPathLevelMultikeyInfo = !_indexMultikeyPaths.empty();
    }

    if (BSONElement collationElement = _descriptor->getInfoElement("collation")) {
        invariant(collationElement.isABSONObj());
        BSONObj collation = collationElement.Obj();
        auto statusWithCollator =
            CollatorFactoryInterface::get(opCtx->getServiceContext())->makeFromBSON(collation);

        // Index spec should have already been validated.
        invariantOK(statusWithCollator.getStatus());

        _collator = std::move(statusWithCollator.getValue());
    }

    if (BSONElement filterElement = _descriptor->getInfoElement("partialFilterExpression")) {
        invariant(filterElement.isABSONObj());
        BSONObj filter = filterElement.Obj();
        StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(
            filter, ExtensionsCallbackDisallowExtensions(), _collator.get());
        // 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() << " "
               << redact(filter);
    }
}
Пример #20
0
    Status CanonicalQuery::canonicalize(const string& ns, const BSONObj& query,
                                        CanonicalQuery** out) {
        auto_ptr<CanonicalQuery> cq(new CanonicalQuery());

        LiteParsedQuery* lpq;
        Status parseStatus = LiteParsedQuery::make(ns, 0, 0, 0, query, &lpq);
        if (!parseStatus.isOK()) { return parseStatus; }
        cq->_pq.reset(lpq);

        StatusWithMatchExpression swme = MatchExpressionParser::parse(cq->_pq->getFilter());
        if (!swme.isOK()) { return swme.getStatus(); }

        cq->_root.reset(swme.getValue());
        *out = cq.release();
        return Status::OK();
    }
Пример #21
0
    Status MatchExpressionParser::_parseSub( const char* name,
                                             const BSONObj& sub,
                                             AndMatchExpression* root ) {
        // The one exception to {field : {fully contained argument} } is, of course, geo.  Example:
        // sub == { field : {$near[Sphere]: [0,0], $maxDistance: 1000, $minDistance: 10 } }
        // We peek inside of 'sub' to see if it's possibly a $near.  If so, we can't iterate over
        // its subfields and parse them one at a time (there is no $maxDistance without $near), so
        // we hand the entire object over to the geo parsing routines.

        BSONObjIterator geoIt(sub);
        if (geoIt.more()) {
            BSONElement firstElt = geoIt.next();
            if (firstElt.isABSONObj()) {
                const char* fieldName = firstElt.fieldName();
                // TODO: Having these $fields here isn't ideal but we don't want to pull in anything
                // from db/geo at this point, since it may not actually be linked in...
                if (mongoutils::str::equals(fieldName, "$near")
                    || mongoutils::str::equals(fieldName, "$nearSphere")
                    || mongoutils::str::equals(fieldName, "$geoNear")
                    || mongoutils::str::equals(fieldName, "$maxDistance")
                    || mongoutils::str::equals(fieldName, "$minDistance")) {

                    StatusWithMatchExpression s = expressionParserGeoCallback(name,
                                                                              firstElt.getGtLtOp(),
                                                                              sub);
                    if (s.isOK()) {
                        root->add(s.getValue());
                        return Status::OK();
                    }
                }
            }
        }

        BSONObjIterator j( sub );
        while ( j.more() ) {
            BSONElement deep = j.next();

            StatusWithMatchExpression s = _parseSubField( sub, root, name, deep );
            if ( !s.isOK() )
                return s.getStatus();

            if ( s.getValue() )
                root->add( s.getValue() );
        }

        return Status::OK();
    }
Пример #22
0
    // static
    Status CanonicalQuery::canonicalize(const QueryMessage& qm, CanonicalQuery** out) {
        auto_ptr<CanonicalQuery> cq(new CanonicalQuery());

        // Parse the query.
        LiteParsedQuery* lpq;
        Status parseStatus = LiteParsedQuery::make(qm, &lpq);
        if (!parseStatus.isOK()) { return parseStatus; }
        cq->_pq.reset(lpq);

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

        cq->_root.reset(swme.getValue());
        *out = cq.release();
        return Status::OK();
    }
Пример #23
0
IndexCatalogEntry::IndexCatalogEntry(OperationContext* txn,
                                     StringData ns,
                                     CollectionCatalogEntry* collection,
                                     IndexDescriptor* descriptor,
                                     CollectionInfoCache* infoCache)
    : _ns(ns.toString()),
      _collection(collection),
      _descriptor(descriptor),
      _infoCache(infoCache),
      _headManager(new HeadManagerImpl(this)),
      _ordering(Ordering::make(descriptor->keyPattern())),
      _isReady(false) {
    _descriptor->_cachedEntry = this;

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

    {
        stdx::lock_guard<stdx::mutex> lk(_indexMultikeyPathsMutex);
        _isMultikey.store(_catalogIsMultikey(txn, &_indexMultikeyPaths));
        _indexTracksPathLevelMultikeyInfo = !_indexMultikeyPaths.empty();
    }

    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());
    }

    if (BSONElement filterElement = _descriptor->getInfoElement("partialFilterExpression")) {
        invariant(filterElement.isABSONObj());
        BSONObj filter = filterElement.Obj();
        StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(
            filter, ExtensionsCallbackDisallowExtensions(), _collator.get());
        // 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;
    }
}
Пример #24
0
    // static
    Status CanonicalQuery::canonicalize(LiteParsedQuery* lpq,
                                        CanonicalQuery** out,
                                        const MatchExpressionParser::WhereCallback& whereCallback) {
        std::auto_ptr<LiteParsedQuery> autoLpq(lpq);

        // Make MatchExpression.
        StatusWithMatchExpression swme = MatchExpressionParser::parse(autoLpq->getFilter(),
                                                                      whereCallback);
        if (!swme.isOK()) {
            return swme.getStatus();
        }

        // Make the CQ we'll hopefully return.
        std::auto_ptr<CanonicalQuery> cq(new CanonicalQuery());
        // Takes ownership of lpq and the MatchExpression* in swme.
        Status initStatus = cq->init(autoLpq.release(), whereCallback, swme.getValue());

        if (!initStatus.isOK()) { return initStatus; }
        *out = cq.release();
        return Status::OK();
    }
Пример #25
0
    Status MatchExpressionParser::_parseTreeList( const BSONObj& arr, ListOfMatchExpression* out ) {
        if ( arr.isEmpty() )
            return Status( ErrorCodes::BadValue,
                           "$and/$or/$nor must be a nonempty array" );

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

            if ( e.type() != Object )
                return Status( ErrorCodes::BadValue,
                               "$or/$and/$nor entries need to be full objects" );

            StatusWithMatchExpression sub = _parse( e.Obj(), false );
            if ( !sub.isOK() )
                return sub.getStatus();

            out->add( sub.getValue() );
        }
        return Status::OK();
    }
Пример #26
0
    // static
    Status CanonicalQuery::canonicalize(const std::string& ns,
                                        const BSONObj& query,
                                        const BSONObj& sort,
                                        const BSONObj& proj,
                                        long long skip,
                                        long long limit,
                                        const BSONObj& hint,
                                        const BSONObj& minObj,
                                        const BSONObj& maxObj,
                                        bool snapshot,
                                        bool explain,
                                        CanonicalQuery** out,
                                        const MatchExpressionParser::WhereCallback& whereCallback) {
        LiteParsedQuery* lpqRaw;
        // Pass empty sort and projection.
        BSONObj emptyObj;
        Status parseStatus = LiteParsedQuery::make(ns, skip, limit, 0, query, proj, sort,
                                                   hint, minObj, maxObj, snapshot, explain,
                                                   &lpqRaw);
        if (!parseStatus.isOK()) {
            return parseStatus;
        }
        std::auto_ptr<LiteParsedQuery> lpq(lpqRaw);

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

        // Make the CQ we'll hopefully return.
        std::auto_ptr<CanonicalQuery> cq(new CanonicalQuery());
        // Takes ownership of lpq and the MatchExpression* in swme.
        Status initStatus = cq->init(lpq.release(), whereCallback, swme.getValue());

        if (!initStatus.isOK()) { return initStatus; }
        *out = cq.release();
        return Status::OK();
    }
Пример #27
0
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
    LiteParsedQuery* lpq, const MatchExpressionParser::WhereCallback& whereCallback) {
    std::unique_ptr<LiteParsedQuery> autoLpq(lpq);

    // Make MatchExpression.
    StatusWithMatchExpression statusWithMatcher =
        MatchExpressionParser::parse(autoLpq->getFilter(), whereCallback);
    if (!statusWithMatcher.isOK()) {
        return statusWithMatcher.getStatus();
    }
    std::unique_ptr<MatchExpression> me = std::move(statusWithMatcher.getValue());

    // Make the CQ we'll hopefully return.
    std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery());

    Status initStatus = cq->init(autoLpq.release(), whereCallback, me.release());

    if (!initStatus.isOK()) {
        return initStatus;
    }
    return std::move(cq);
}
    Status AuthzManagerExternalStateMock::_findUser(const std::string& usersNamespace,
                                                    const BSONObj& query,
                                                    BSONObj* result) const {
        StatusWithMatchExpression parseResult = MatchExpressionParser::parse(query);
        if (!parseResult.isOK()) {
            return parseResult.getStatus();
        }
        MatchExpression* matcher = parseResult.getValue();

        unordered_map<std::string, std::vector<BSONObj> >::const_iterator mapIt;
        for (mapIt = _userDocuments.begin(); mapIt != _userDocuments.end(); ++mapIt) {
            for (std::vector<BSONObj>::const_iterator vecIt = mapIt->second.begin();
                    vecIt != mapIt->second.end(); ++vecIt) {
                if (nsToDatabase(usersNamespace) == mapIt->first &&
                        matcher->matchesBSON(*vecIt)) {
                    *result = *vecIt;
                    return Status::OK();
                }
            }
        }
        return Status(ErrorCodes::UserNotFound, "User not found");
    }
Пример #29
0
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
    OperationContext* opCtx,
    std::unique_ptr<QueryRequest> qr,
    const ExtensionsCallback& extensionsCallback,
    const boost::intrusive_ptr<ExpressionContext>& expCtx) {
    auto qrStatus = qr->validate();
    if (!qrStatus.isOK()) {
        return qrStatus;
    }

    std::unique_ptr<CollatorInterface> collator;
    if (!qr->getCollation().isEmpty()) {
        auto statusWithCollator = CollatorFactoryInterface::get(opCtx->getServiceContext())
                                      ->makeFromBSON(qr->getCollation());
        if (!statusWithCollator.isOK()) {
            return statusWithCollator.getStatus();
        }
        collator = std::move(statusWithCollator.getValue());
    }

    // Make MatchExpression.
    StatusWithMatchExpression statusWithMatcher =
        MatchExpressionParser::parse(qr->getFilter(), extensionsCallback, collator.get(), expCtx);
    if (!statusWithMatcher.isOK()) {
        return statusWithMatcher.getStatus();
    }
    std::unique_ptr<MatchExpression> me = std::move(statusWithMatcher.getValue());

    // Make the CQ we'll hopefully return.
    std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery());

    Status initStatus =
        cq->init(std::move(qr), extensionsCallback, me.release(), std::move(collator));

    if (!initStatus.isOK()) {
        return initStatus;
    }
    return std::move(cq);
}
    Status ModifierPull::init(const BSONElement& modExpr) {
        // 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.
        fieldchecker::isPositional(_fieldRef, &_posDollar);

        // The matcher wants this as a BSONObj, not a BSONElement. Ignore the field name (the
        // matcher does too).
        BSONObjBuilder builder;
        builder.appendAs(modExpr, StringData());
        _exprObj = builder.obj();

        // Try to parse this into a match expression.
        StatusWithMatchExpression parseResult = MatchExpressionParser::parse(_exprObj);
        if (parseResult.isOK())
            _matchExpression.reset(parseResult.getValue());
        return parseResult.getStatus();
    }