// static StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( OperationContext* opCtx, const CanonicalQuery& baseQuery, MatchExpression* root, const ExtensionsCallback& extensionsCallback) { // TODO: we should be passing the filter corresponding to 'root' to the QR rather than the base // query's filter, baseQuery.getQueryRequest().getFilter(). auto qr = stdx::make_unique<QueryRequest>(baseQuery.nss()); qr->setFilter(baseQuery.getQueryRequest().getFilter()); qr->setProj(baseQuery.getQueryRequest().getProj()); qr->setSort(baseQuery.getQueryRequest().getSort()); qr->setCollation(baseQuery.getQueryRequest().getCollation()); qr->setExplain(baseQuery.getQueryRequest().isExplain()); auto qrStatus = qr->validate(); if (!qrStatus.isOK()) { return qrStatus; } std::unique_ptr<CollatorInterface> collator; if (baseQuery.getCollator()) { collator = baseQuery.getCollator()->clone(); } // Make the CQ we'll hopefully return. std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery()); Status initStatus = cq->init( std::move(qr), extensionsCallback, root->shallowClone().release(), std::move(collator)); if (!initStatus.isOK()) { return initStatus; } return std::move(cq); }
// static StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( OperationContext* opCtx, const CanonicalQuery& baseQuery, MatchExpression* root) { auto qr = stdx::make_unique<QueryRequest>(baseQuery.nss()); BSONObjBuilder builder; root->serialize(&builder); qr->setFilter(builder.obj()); qr->setProj(baseQuery.getQueryRequest().getProj()); qr->setSort(baseQuery.getQueryRequest().getSort()); qr->setCollation(baseQuery.getQueryRequest().getCollation()); qr->setExplain(baseQuery.getQueryRequest().isExplain()); auto qrStatus = qr->validate(); if (!qrStatus.isOK()) { return qrStatus; } std::unique_ptr<CollatorInterface> collator; if (baseQuery.getCollator()) { collator = baseQuery.getCollator()->clone(); } // Make the CQ we'll hopefully return. std::unique_ptr<CanonicalQuery> cq(new CanonicalQuery()); Status initStatus = cq->init(opCtx, std::move(qr), baseQuery.canHaveNoopMatchNodes(), root->shallowClone(), std::move(collator)); if (!initStatus.isOK()) { return initStatus; } return std::move(cq); }
StatusWith<ParsedDistinct> ParsedDistinct::parse(OperationContext* opCtx, const NamespaceString& nss, const BSONObj& cmdObj, const ExtensionsCallback& extensionsCallback, bool isExplain, const CollatorInterface* defaultCollator) { IDLParserErrorContext ctx("distinct"); DistinctCommand parsedDistinct(nss); try { parsedDistinct = DistinctCommand::parse(ctx, cmdObj); } catch (...) { return exceptionToStatus(); } auto qr = stdx::make_unique<QueryRequest>(nss); if (parsedDistinct.getKey().find('\0') != std::string::npos) { return Status(ErrorCodes::Error(31032), "Key field cannot contain an embedded null byte"); } // Create a projection on the fields needed by the distinct command, so that the query planner // will produce a covered plan if possible. qr->setProj(getDistinctProjection(std::string(parsedDistinct.getKey()))); if (auto query = parsedDistinct.getQuery()) { qr->setFilter(query.get()); } if (auto collation = parsedDistinct.getCollation()) { qr->setCollation(collation.get()); } if (auto comment = parsedDistinct.getComment()) { qr->setComment(comment.get().toString()); } // The IDL parser above does not handle generic command arguments. Since the underlying query // request requires the following options, manually parse and verify them here. if (auto readConcernElt = cmdObj[repl::ReadConcernArgs::kReadConcernFieldName]) { if (readConcernElt.type() != BSONType::Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "\"" << repl::ReadConcernArgs::kReadConcernFieldName << "\" had the wrong type. Expected " << typeName(BSONType::Object) << ", found " << typeName(readConcernElt.type())); } qr->setReadConcern(readConcernElt.embeddedObject()); } if (auto queryOptionsElt = cmdObj[QueryRequest::kUnwrappedReadPrefField]) { if (queryOptionsElt.type() != BSONType::Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "\"" << QueryRequest::kUnwrappedReadPrefField << "\" had the wrong type. Expected " << typeName(BSONType::Object) << ", found " << typeName(queryOptionsElt.type())); } qr->setUnwrappedReadPref(queryOptionsElt.embeddedObject()); } if (auto maxTimeMSElt = cmdObj[QueryRequest::cmdOptionMaxTimeMS]) { auto maxTimeMS = QueryRequest::parseMaxTimeMS(maxTimeMSElt); if (!maxTimeMS.isOK()) { return maxTimeMS.getStatus(); } qr->setMaxTimeMS(static_cast<unsigned int>(maxTimeMS.getValue())); } qr->setExplain(isExplain); const boost::intrusive_ptr<ExpressionContext> expCtx; auto cq = CanonicalQuery::canonicalize(opCtx, std::move(qr), expCtx, extensionsCallback, MatchExpressionParser::kAllowAllSpecialFeatures); if (!cq.isOK()) { return cq.getStatus(); } if (cq.getValue()->getQueryRequest().getCollation().isEmpty() && defaultCollator) { cq.getValue()->setCollator(defaultCollator->clone()); } return ParsedDistinct(std::move(cq.getValue()), parsedDistinct.getKey().toString()); }