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