// 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); }
void Type::setConfiguration(unsigned conf) { //Raises an error if the configuration type is invalid if(conf < BASE_TYPE || conf > RANGE_TYPE) throw Exception(ERR_ASG_INV_TYPE_CONFIG,__PRETTY_FUNCTION__,__FILE__,__LINE__); type_attribs.clear(); enumerations.clear(); for(unsigned idx=0; idx < sizeof(functions)/sizeof(Function *); idx++) functions[idx]=nullptr; setCollation(nullptr); subtype_opclass=nullptr; alignment=QString("integer"); delimiter='\0'; storage=StorageType::plain; element=QString("\"any\""); internal_len=0; category=CategoryType::userdefined; preferred=collatable=by_value=false; like_type=QString("\"any\""); this->config=conf; setCodeInvalidated(true); }
Status ParsedDelete::parseQueryToCQ() { dassert(!_canonicalQuery.get()); const ExtensionsCallbackReal extensionsCallback(_txn, &_request->getNamespaceString()); // The projection needs to be applied after the delete operation, so we do not specify a // projection during canonicalization. auto lpq = stdx::make_unique<LiteParsedQuery>(_request->getNamespaceString()); lpq->setFilter(_request->getQuery()); lpq->setSort(_request->getSort()); lpq->setCollation(_request->getCollation()); lpq->setExplain(_request->isExplain()); // Limit should only used for the findAndModify command when a sort is specified. If a sort // is requested, we want to use a top-k sort for efficiency reasons, so should pass the // limit through. Generally, a delete stage expects to be able to skip documents that were // deleted out from under it, but a limit could inhibit that and give an EOF when the delete // has not actually deleted a document. This behavior is fine for findAndModify, but should // not apply to deletes in general. if (!_request->isMulti() && !_request->getSort().isEmpty()) { lpq->setLimit(1); } auto statusWithCQ = CanonicalQuery::canonicalize(_txn, std::move(lpq), extensionsCallback); if (statusWithCQ.isOK()) { _canonicalQuery = std::move(statusWithCQ.getValue()); } return statusWithCQ.getStatus(); }
// 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* txn, const NamespaceString& nss, const BSONObj& cmdObj, const ExtensionsCallback& extensionsCallback, bool isExplain) { // Extract the key field. BSONElement keyElt; auto statusKey = bsonExtractTypedField(cmdObj, kKeyField, BSONType::String, &keyElt); if (!statusKey.isOK()) { return {statusKey}; } auto key = keyElt.valuestrsafe(); auto qr = stdx::make_unique<QueryRequest>(nss); // Extract the query field. If the query field is nonexistent, an empty query is used. if (BSONElement queryElt = cmdObj[kQueryField]) { if (queryElt.type() == BSONType::Object) { qr->setFilter(queryElt.embeddedObject()); } else if (queryElt.type() != BSONType::jstNULL) { return Status(ErrorCodes::TypeMismatch, str::stream() << "\"" << kQueryField << "\" had the wrong type. Expected " << typeName(BSONType::Object) << " or " << typeName(BSONType::jstNULL) << ", found " << typeName(queryElt.type())); } } // Extract the collation field, if it exists. if (BSONElement collationElt = cmdObj[kCollationField]) { if (collationElt.type() != BSONType::Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "\"" << kCollationField << "\" had the wrong type. Expected " << typeName(BSONType::Object) << ", found " << typeName(collationElt.type())); } qr->setCollation(collationElt.embeddedObject()); } qr->setExplain(isExplain); auto cq = CanonicalQuery::canonicalize(txn, std::move(qr), extensionsCallback); if (!cq.isOK()) { return cq.getStatus(); } return ParsedDistinct(std::move(cq.getValue()), std::move(key)); }
static void findUtf8OrDie(void) { char *old_locale, *localeRes; old_locale = setlocale(LC_ALL, ""); localeRes = strstr(old_locale, "UTF"); if (localeRes == NULL) { utf8Errmsg(getProgramName(), old_locale); exit(1); } else { char *collation = setlocale(LC_COLLATE, ""); setCollation(collation); } }
Status ParsedUpdate::parseQueryToCQ() { dassert(!_canonicalQuery.get()); const ExtensionsCallbackReal extensionsCallback(_opCtx, &_request->getNamespaceString()); // The projection needs to be applied after the update operation, so we do not specify a // projection during canonicalization. auto qr = stdx::make_unique<QueryRequest>(_request->getNamespaceString()); qr->setFilter(_request->getQuery()); qr->setSort(_request->getSort()); qr->setCollation(_request->getCollation()); qr->setExplain(_request->isExplain()); // Limit should only used for the findAndModify command when a sort is specified. If a sort // is requested, we want to use a top-k sort for efficiency reasons, so should pass the // limit through. Generally, a update stage expects to be able to skip documents that were // deleted/modified under it, but a limit could inhibit that and give an EOF when the update // has not actually updated a document. This behavior is fine for findAndModify, but should // not apply to update in general. if (!_request->isMulti() && !_request->getSort().isEmpty()) { qr->setLimit(1); } // $expr is not allowed in the query for an upsert, since it is not clear what the equality // extraction behavior for $expr should be. MatchExpressionParser::AllowedFeatureSet allowedMatcherFeatures = MatchExpressionParser::kAllowAllSpecialFeatures; if (_request->isUpsert()) { allowedMatcherFeatures &= ~MatchExpressionParser::AllowedFeatures::kExpr; } boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize( _opCtx, std::move(qr), std::move(expCtx), extensionsCallback, allowedMatcherFeatures); if (statusWithCQ.isOK()) { _canonicalQuery = std::move(statusWithCQ.getValue()); } if (statusWithCQ.getStatus().code() == ErrorCodes::QueryFeatureNotAllowed) { // The default error message for disallowed $expr is not descriptive enough, so we rewrite // it here. return {ErrorCodes::QueryFeatureNotAllowed, "$expr is not allowed in the query predicate for an upsert"}; } return statusWithCQ.getStatus(); }
Status ParsedUpdate::parseQueryToCQ() { dassert(!_canonicalQuery.get()); const ExtensionsCallbackReal extensionsCallback(_opCtx, &_request->getNamespaceString()); // The projection needs to be applied after the update operation, so we do not specify a // projection during canonicalization. auto qr = stdx::make_unique<QueryRequest>(_request->getNamespaceString()); qr->setFilter(_request->getQuery()); qr->setSort(_request->getSort()); qr->setCollation(_request->getCollation()); qr->setExplain(_request->isExplain()); // Limit should only used for the findAndModify command when a sort is specified. If a sort // is requested, we want to use a top-k sort for efficiency reasons, so should pass the // limit through. Generally, a update stage expects to be able to skip documents that were // deleted/modified under it, but a limit could inhibit that and give an EOF when the update // has not actually updated a document. This behavior is fine for findAndModify, but should // not apply to update in general. if (!_request->isMulti() && !_request->getSort().isEmpty()) { qr->setLimit(1); } const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(_opCtx, std::move(qr), expCtx, extensionsCallback, MatchExpressionParser::kAllowAllSpecialFeatures & ~MatchExpressionParser::AllowedFeatures::kExpr); if (statusWithCQ.isOK()) { _canonicalQuery = std::move(statusWithCQ.getValue()); } return statusWithCQ.getStatus(); }
StatusWith<std::vector<ShardEndpoint>> ChunkManagerTargeter::targetDelete( OperationContext* opCtx, const write_ops::DeleteOpEntry& deleteDoc) const { BSONObj shardKey; if (_routingInfo->cm()) { // // Sharded collections have the following further requirements for targeting: // // Limit-1 deletes must be targeted exactly by shard key *or* exact _id // // Get the shard key StatusWith<BSONObj> status = _routingInfo->cm()->getShardKeyPattern().extractShardKeyFromQuery(opCtx, deleteDoc.getQ()); // Bad query if (!status.isOK()) return status.getStatus(); shardKey = status.getValue(); } const auto collation = write_ops::collationOf(deleteDoc); // Target the shard key or delete query if (!shardKey.isEmpty()) { try { return std::vector<ShardEndpoint>{_targetShardKey(shardKey, collation, 0)}; } catch (const DBException&) { // This delete is potentially not constrained to a single shard } } // We failed to target a single shard. // Parse delete query. auto qr = stdx::make_unique<QueryRequest>(getNS()); qr->setFilter(deleteDoc.getQ()); if (!collation.isEmpty()) { qr->setCollation(collation); } const boost::intrusive_ptr<ExpressionContext> expCtx; auto cq = CanonicalQuery::canonicalize(opCtx, std::move(qr), expCtx, ExtensionsCallbackNoop(), MatchExpressionParser::kAllowAllSpecialFeatures); if (!cq.isOK()) { return cq.getStatus().withContext(str::stream() << "Could not parse delete query " << deleteDoc.getQ()); } // Single deletes must target a single shard or be exact-ID. if (_routingInfo->cm() && !deleteDoc.getMulti() && !isExactIdQuery(opCtx, *cq.getValue(), _routingInfo->cm().get())) { return Status(ErrorCodes::ShardKeyNotFound, str::stream() << "A single delete on a sharded collection must contain an exact " "match on _id (and have the collection default collation) or " "contain the shard key (and have the simple collation). Delete " "request: " << deleteDoc.toBSON() << ", shard key pattern: " << _routingInfo->cm()->getShardKeyPattern().toString()); } return _targetQuery(opCtx, deleteDoc.getQ(), collation); }
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()); }